From: Christopher Faylor Date: Wed, 9 Mar 2011 22:48:05 +0000 (+0000) Subject: * fhandler.cc (fhandler_base_overlapped::wait_overlapped): Handle X-Git-Tag: cygwin-1_7_9-release~57 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=904e3e20049bf7c76cc16a1cd1a35e77cca2ffdd;p=newlib-cygwin.git * fhandler.cc (fhandler_base_overlapped::wait_overlapped): Handle overlapped_fallback error condition like other error conditions. Set res carefully and specifically for each condition rather than resorting to a default. (fhandler_base_overlapped::write_overlapped): Preserve errno in overlapped_fallback condition. Correct write_overlapped_fallback to avoid inappropriate looping. (fhandler_base_overlapped::write_overlapped_fallback): Add some more comments. --- diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5f0418599..a01d83b04 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2011-03-09 Christopher Faylor + + * fhandler.cc (fhandler_base_overlapped::wait_overlapped): Handle + overlapped_fallback error condition like other error conditions. Set + res carefully and specifically for each condition rather than resorting + to a default. + (fhandler_base_overlapped::write_overlapped): Preserve errno in + overlapped_fallback condition. Correct write_overlapped_fallback to + avoid inappropriate looping. + (fhandler_base_overlapped::write_overlapped_fallback): Add some more + comments. + 2011-03-09 Christopher Faylor * fhandler.cc (fhandler_base_overlapped::write_overlapp): Oops! diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 7c95b33c6..56d2872cd 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1731,14 +1731,15 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte if (!get_overlapped ()) return inres ? overlapped_success : overlapped_error; + wait_return res; DWORD err = GetLastError (); if (err == ERROR_NO_SYSTEM_RESOURCES) - return overlapped_fallback; - - wait_return res = overlapped_error; - if (nonblocking) + res = overlapped_fallback; + else if (nonblocking) { - if (inres || err == ERROR_IO_PENDING) + if (!inres && err != ERROR_IO_PENDING) + res = overlapped_error; + else { io_pending = err == ERROR_IO_PENDING; if (writing && !inres) @@ -1747,7 +1748,9 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte err = 0; } } - else if (inres || err == ERROR_IO_PENDING) + else if (!inres && err != ERROR_IO_PENDING) + res = overlapped_error; + else { #ifdef DEBUGGING if (!get_overlapped ()->hEvent) @@ -1768,10 +1771,13 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte if (signalled) { debug_printf ("got a signal"); - if (!_my_tls.call_signal_handler ()) - set_errno (EINTR); - else + if (_my_tls.call_signal_handler ()) res = overlapped_signal; + else + { + set_errno (EINTR); + res = overlapped_error; + } *bytes = (DWORD) -1; err = 0; } @@ -1779,30 +1785,30 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte { err = GetLastError (); debug_printf ("GetOverLappedResult failed, bytes %u", *bytes); + res = overlapped_error; } else { + err = 0; debug_printf ("normal %s, %u bytes", writing ? "write" : "read", *bytes); res = overlapped_success; - err = 0; } } if (!err) /* nothing to do */; - else if (err != ERROR_HANDLE_EOF && err != ERROR_BROKEN_PIPE) - { - debug_printf ("err %u", err); - __seterrno_from_win_error (err); - *bytes = (DWORD) -1; - res = overlapped_error; - } - else + else if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE) { debug_printf ("EOF"); *bytes = 0; res = overlapped_success; } + else + { + debug_printf ("err %u", err); + __seterrno_from_win_error (err); + *bytes = (DWORD) -1; + } if (writing && (err == ERROR_NO_DATA || err == ERROR_BROKEN_PIPE)) raise (SIGPIPE); @@ -1848,6 +1854,7 @@ fhandler_base_overlapped::write_overlapped (const void *ptr, size_t len) nbytes = (DWORD) -1; else { + int last_errno = get_errno (); bool keep_looping; if (is_nonblocking () && max_atomic_write && len > max_atomic_write) len = max_atomic_write; @@ -1857,12 +1864,13 @@ fhandler_base_overlapped::write_overlapped (const void *ptr, size_t len) get_overlapped ()); switch (wait_overlapped (res, true, &nbytes, is_nonblocking (), (size_t) len)) { - case overlapped_fallback: - nbytes = write_overlapped_fallback (ptr, len); - /* fall through intentionally */; case overlapped_signal: keep_looping = true; break; + case overlapped_fallback: + set_errno (last_errno); /* Avoid setting a random EFBIG errno */ + nbytes = write_overlapped_fallback (ptr, len); + /* fall through intentionally */; default: /* Added to quiet gcc */ case overlapped_success: case overlapped_error: @@ -1885,6 +1893,7 @@ ssize_t __stdcall __attribute__ ((regparm (3))) fhandler_base_overlapped::write_overlapped_fallback (const void *ptr, size_t orig_len) { size_t chunk; + /* So far, in testing, only the first if test has been necessary */ if (orig_len > MAX_OVERLAPPED_WRITE_LEN) chunk = MAX_OVERLAPPED_WRITE_LEN; else if (orig_len > MIN_OVERLAPPED_WRITE_LEN) @@ -1893,6 +1902,10 @@ fhandler_base_overlapped::write_overlapped_fallback (const void *ptr, size_t ori chunk = orig_len / 4; ssize_t nbytes = 0; DWORD nbytes_now = 0; + /* Write to fd in smaller chunks, accumlating a total. + If there's an error, just return the accumulated total + unless the first write fails, in which case return value + from wait_overlapped(). */ while ((size_t) nbytes < orig_len) { size_t left = orig_len - nbytes; @@ -1913,11 +1926,11 @@ fhandler_base_overlapped::write_overlapped_fallback (const void *ptr, size_t ori nbytes += nbytes_now; /* fall through intentionally */ case overlapped_signal: - break; /* keep looping */ + break; /* keep looping */ case overlapped_error: - case overlapped_fallback: /* Could make this more adaptive + case overlapped_fallback: /* XXX Could make this more adaptive if needed */ - orig_len = 0; /* terminate loop */ + orig_len = 0; /* terminate loop */ break; } }