X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=windows%2Fwinhandl.c;h=7c282fc7d5502f128f300d3ea09d942026d4c525;hb=a063e522970946bf7d5dc052079d7773c0dee76d;hp=b15d1f2620066b4fb4596a418477a26dfac11770;hpb=c0f7178f634229d6baec6b94d464e53abab142d8;p=PuTTY.git diff --git a/windows/winhandl.c b/windows/winhandl.c index b15d1f26..7c282fc7 100644 --- a/windows/winhandl.c +++ b/windows/winhandl.c @@ -115,7 +115,7 @@ static DWORD WINAPI handle_input_threadfunc(void *param) struct handle_input *ctx = (struct handle_input *) param; OVERLAPPED ovl, *povl; HANDLE oev; - int readret, readlen; + int readret, readlen, finished; if (ctx->flags & HANDLE_FLAG_OVERLAPPED) { povl = &ovl; @@ -165,14 +165,32 @@ static DWORD WINAPI handle_input_threadfunc(void *param) (ctx->flags & HANDLE_FLAG_IGNOREEOF)) continue; + /* + * If we just set ctx->len to 0, that means the read operation + * has returned end-of-file. Telling that to the main thread + * will cause it to set its 'defunct' flag and dispose of the + * handle structure at the next opportunity, in which case we + * mustn't touch ctx at all after the SetEvent. (Hence we do + * even _this_ check before the SetEvent.) + */ + finished = (ctx->len == 0); + SetEvent(ctx->ev_to_main); - if (!ctx->len) + if (finished) break; WaitForSingleObject(ctx->ev_from_main, INFINITE); - if (ctx->done) - break; /* main thread told us to shut down */ + if (ctx->done) { + /* + * The main thread has asked us to shut down. Send back an + * event indicating that we've done so. Hereafter we must + * not touch ctx at all, because the main thread might + * have freed it. + */ + SetEvent(ctx->ev_to_main); + break; + } } if (povl) @@ -278,6 +296,12 @@ static DWORD WINAPI handle_output_threadfunc(void *param) while (1) { WaitForSingleObject(ctx->ev_from_main, INFINITE); if (ctx->done) { + /* + * The main thread has asked us to shut down. Send back an + * event indicating that we've done so. Hereafter we must + * not touch ctx at all, because the main thread might + * have freed it. + */ SetEvent(ctx->ev_to_main); break; } @@ -302,8 +326,16 @@ static DWORD WINAPI handle_output_threadfunc(void *param) } SetEvent(ctx->ev_to_main); - if (!writeret) + if (!writeret) { + /* + * The write operation has suffered an error. Telling that + * to the main thread will cause it to set its 'defunct' + * flag and dispose of the handle structure at the next + * opportunity, so we must not touch ctx at all after + * this. + */ break; + } } if (povl) @@ -599,10 +631,12 @@ void handle_got_event(HANDLE event) if (h->u.g.moribund) { /* - * A moribund handle is already treated as dead from the - * external user's point of view, so do nothing with the - * actual event. Just signal the thread to die if - * necessary, or destroy the handle if not. + * A moribund handle is one which we have either already + * signalled to die, or are waiting until its current I/O op + * completes to do so. Either way, it's treated as already + * dead from the external user's point of view, so we ignore + * the actual I/O result. We just signal the thread to die if + * we haven't yet done so, or destroy the handle if not. */ if (h->u.g.done) { handle_destroy(h); @@ -627,8 +661,8 @@ void handle_got_event(HANDLE event) /* * EOF, or (nearly equivalently) read error. */ - h->u.i.gotdata(h, NULL, -h->u.i.readerr); h->u.i.defunct = TRUE; + h->u.i.gotdata(h, NULL, -h->u.i.readerr); } else { backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len); handle_throttle(&h->u.i, backlog); @@ -649,8 +683,8 @@ void handle_got_event(HANDLE event) * and mark the thread as defunct (because the output * thread is terminating by now). */ - h->u.o.sentdata(h, -h->u.o.writeerr); h->u.o.defunct = TRUE; + h->u.o.sentdata(h, -h->u.o.writeerr); } else { bufchain_consume(&h->u.o.queued_data, h->u.o.lenwritten); h->u.o.sentdata(h, bufchain_size(&h->u.o.queued_data));