diff options
author | Craig Tiller <craig.tiller@gmail.com> | 2015-03-02 16:41:32 +0000 |
---|---|---|
committer | Craig Tiller <craig.tiller@gmail.com> | 2015-03-02 16:41:32 +0000 |
commit | b9eb180d4d5801c24d8578b8a0c85bfbe667c9bd (patch) | |
tree | db5dfb6adda8efc07eecc91adca9bb7897db13a2 /src/core | |
parent | f2350183be15f1ba2260e85e7c972cbee016f0d2 (diff) |
Fix some shutdown races
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/transport/chttp2_transport.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 4230b523b1..1ad4819fd1 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -519,12 +519,22 @@ static void destroy_transport(grpc_transport *gt) { lock(t); t->destroying = 1; - while (t->calling_back) { + /* Wait for pending stuff to finish. + We need to be not calling back to ensure that closed() gets a chance to + trigger if needed during unlock() before we die. + We need to be not writing as cancellation finalization may produce some + callbacks that NEED to be made to close out some streams when t->writing + becomes 0. */ + while (t->calling_back || t->writing) { gpr_cv_wait(&t->cv, &t->mu, gpr_inf_future); } drop_connection(t); unlock(t); + lock(t); + GPR_ASSERT(!t->cb); + unlock(t); + unref_transport(t); } @@ -681,6 +691,7 @@ static void stream_list_add_tail(transport *t, stream *s, stream_list_id id) { } static void stream_list_join(transport *t, stream *s, stream_list_id id) { + if (id == PENDING_CALLBACKS) GPR_ASSERT(t->cb != NULL || t->error_state == ERROR_STATE_NONE); if (s->included[id]) { return; } @@ -739,7 +750,7 @@ static void unlock(transport *t) { if (perform_callbacks) { t->calling_back = 1; } - if (t->error_state == ERROR_STATE_SEEN) { + if (t->error_state == ERROR_STATE_SEEN && !t->writing) { call_closed = 1; t->calling_back = 1; t->cb = NULL; /* no more callbacks */ @@ -904,13 +915,16 @@ static void finish_write_common(transport *t, int success) { } while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) { s->sent_write_closed = 1; - stream_list_join(t, s, PENDING_CALLBACKS); + if (!s->cancelled) stream_list_join(t, s, PENDING_CALLBACKS); } t->outbuf.count = 0; t->outbuf.length = 0; /* leave the writing flag up on shutdown to prevent further writes in unlock() from starting */ t->writing = 0; + if (t->destroying) { + gpr_cv_signal(&t->cv); + } if (!t->reading) { grpc_endpoint_destroy(t->ep); t->ep = NULL; |