]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - windows/winhandl.c
Key rollover: rewrite the PGP keys manual appendix.
[PuTTY.git] / windows / winhandl.c
index b15d1f2620066b4fb4596a418477a26dfac11770..7c282fc7d5502f128f300d3ea09d942026d4c525 100644 (file)
@@ -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));