diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d07638cd0..7bfdc5d80 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,16 @@ +2011-12-17 Christopher Faylor + + * fhandler.cc (fhandler_base::close): Move setting isclosed() from here + to closed(). + (fhandler_base_overlapped::close): Correct comment. + (fhandler_base_overlapped::destroy_overlapped): Signal overlapped event + before closing it to potentially wake up a waiting thread. + (fhandler_base_overlapped::wait_overlapped): Expand setting of err when + closed to encompass non-signal event. Test for a cancel event before + making nonblocking decisions. + * syscalls.cc (close): Set closed flag here so that any concurrently + executing functions will be notified ASAP. + 2011-12-17 Corinna Vinschen * dcrt0.cc (_dll_crt0): Fix formatting. diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 6624bc7da..a93b45436 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1148,7 +1148,6 @@ fhandler_base::close () paranoid_printf ("CloseHandle failed, %E"); __seterrno (); } - isclosed (true); return res; } @@ -1219,9 +1218,8 @@ fhandler_base_overlapped::close () } else { - /* Cancelling seems to be necessary for cases where a reader is - still executing either in another thread or when a signal handler - performs a close. */ + /* Cancelling seems to be necessary for cases where a reader is + still executing when a signal handler performs a close. */ CancelIo (get_io_handle ()); destroy_overlapped (); res = fhandler_base::close (); @@ -1882,6 +1880,7 @@ fhandler_base_overlapped::destroy_overlapped () OVERLAPPED *ov = get_overlapped (); if (ov && ov->hEvent) { + SetEvent (ov->hEvent); CloseHandle (ov->hEvent); ov->hEvent = NULL; } @@ -1931,7 +1930,21 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte HANDLE h = writing ? get_output_handle () : get_handle (); BOOL wores; if (isclosed ()) - wores = 0; /* closed in another thread or via signal handler */ + { + switch (err) + { + case WAIT_OBJECT_0: + err = ERROR_INVALID_HANDLE; + break; + case WAIT_OBJECT_0 + 1: + err = ERROR_INVALID_AT_INTERRUPT_TIME; + break; + default: + err = GetLastError (); + break; + } + res = overlapped_error; + } else { /* Cancelling here to prevent races. It's possible that the I/O has @@ -1945,23 +1958,23 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte err = GetLastError (); ResetEvent (get_overlapped ()->hEvent); /* Probably not needed but CYA */ debug_printf ("wfres %d, wores %d, bytes %u", wfres, wores, *bytes); - } - if (wores) - res = overlapped_success; /* operation succeeded */ - else if (wfres == WAIT_OBJECT_0 + 1) - { - err = ERROR_INVALID_AT_INTERRUPT_TIME; /* forces an EINTR below */ - debug_printf ("signal"); - res = overlapped_error; - } - else if (nonblocking) - res = overlapped_nonblocking_no_data; /* more handling below */ - else if (wfres == WAIT_OBJECT_0 + 2) - pthread::static_cancel_self (); /* never returns */ - else - { - debug_printf ("GetOverLappedResult failed, h %p, bytes %u, %E", h, *bytes); - res = overlapped_error; + if (wores) + res = overlapped_success; /* operation succeeded */ + else if (wfres == WAIT_OBJECT_0 + 1) + { + err = ERROR_INVALID_AT_INTERRUPT_TIME; /* forces an EINTR below */ + debug_printf ("signal"); + res = overlapped_error; + } + else if (wfres == WAIT_OBJECT_0 + 2) + pthread::static_cancel_self (); /* never returns */ + else if (nonblocking) + res = overlapped_nonblocking_no_data; /* more handling below */ + else + { + debug_printf ("GetOverLappedResult failed, h %p, bytes %u, %E", h, *bytes); + res = overlapped_error; + } } } diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index ea0c23d0b..f86e0442a 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1373,6 +1373,7 @@ close (int fd) res = -1; else { + cfd->isclosed (true); res = cfd->close_with_arch (); cfd.release (); }