* dtable.cc (dtable::select_write): Add missing argument to debug_printf.
* fhandler.cc (fhandler_base_overlapped::setup_overlapped): Explicitly set io_pending to false. (fhandler_base_overlapped::has_ongoing_io): Call GetOverlappedResult to force completion of I/O. (fhandler_base_overlapped::wait_overlapped): Rewrite to correctly deal with nonblocking reads and to make more race proof. (fhandler_base_overlapped::raw_write): Deal with new enum values. (fhandler_base_overlapped::raw_read): Ditto. Don't deal with ongoing I/O here since it makes no sense in the read context. * fhandler.h (enum wait_return): Add overlapped_unknown, overlapped_nonblocking_no_data. * pipe.cc (pipe): Add debugging output.
This commit is contained in:
parent
de3c57f06e
commit
106e3acf59
@ -1,3 +1,21 @@
|
|||||||
|
2011-05-30 Christopher Faylor <me.cygwin2011@cgf.cx>
|
||||||
|
|
||||||
|
* dtable.cc (dtable::select_write): Add missing argument to
|
||||||
|
debug_printf.
|
||||||
|
|
||||||
|
* fhandler.cc (fhandler_base_overlapped::setup_overlapped): Explicitly
|
||||||
|
set io_pending to false.
|
||||||
|
(fhandler_base_overlapped::has_ongoing_io): Call GetOverlappedResult
|
||||||
|
to force completion of I/O.
|
||||||
|
(fhandler_base_overlapped::wait_overlapped): Rewrite to correctly deal
|
||||||
|
with nonblocking reads and to make more race proof.
|
||||||
|
(fhandler_base_overlapped::raw_write): Deal with new enum values.
|
||||||
|
(fhandler_base_overlapped::raw_read): Ditto. Don't deal with ongoing
|
||||||
|
I/O here since it makes no sense in the read context.
|
||||||
|
* fhandler.h (enum wait_return): Add overlapped_unknown,
|
||||||
|
overlapped_nonblocking_no_data.
|
||||||
|
* pipe.cc (pipe): Add debugging output.
|
||||||
|
|
||||||
2011-05-30 Christopher Faylor <me.cygwin2011@cgf.cx>
|
2011-05-30 Christopher Faylor <me.cygwin2011@cgf.cx>
|
||||||
|
|
||||||
* dll_init.cc (dll_list::append): Eliminate increment of unused tot
|
* dll_init.cc (dll_list::append): Eliminate increment of unused tot
|
||||||
|
@ -712,7 +712,7 @@ dtable::select_write (int fd, select_stuff *ss)
|
|||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->fh = fh;
|
s->fh = fh;
|
||||||
s->thread_errno = 0;
|
s->thread_errno = 0;
|
||||||
debug_printf ("%s fd %d", fh->get_name ());
|
debug_printf ("%s fd %d", fh->get_name (), fd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1770,6 +1770,7 @@ fhandler_base_overlapped::setup_overlapped ()
|
|||||||
memset (ov, 0, sizeof (*ov));
|
memset (ov, 0, sizeof (*ov));
|
||||||
set_overlapped (ov);
|
set_overlapped (ov);
|
||||||
ov->hEvent = CreateEvent (&sec_none_nih, true, true, NULL);
|
ov->hEvent = CreateEvent (&sec_none_nih, true, true, NULL);
|
||||||
|
io_pending = false;
|
||||||
return ov->hEvent ? 0 : -1;
|
return ov->hEvent ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1791,12 +1792,15 @@ fhandler_base_overlapped::has_ongoing_io ()
|
|||||||
{
|
{
|
||||||
if (!io_pending)
|
if (!io_pending)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!IsEventSignalled (get_overlapped ()->hEvent))
|
if (!IsEventSignalled (get_overlapped ()->hEvent))
|
||||||
{
|
{
|
||||||
set_errno (EAGAIN);
|
set_errno (EAGAIN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
io_pending = false;
|
io_pending = false;
|
||||||
|
DWORD nbytes;
|
||||||
|
GetOverlappedResult (get_output_handle (), get_overlapped (), &nbytes, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1806,75 +1810,74 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
|
|||||||
if (!get_overlapped ())
|
if (!get_overlapped ())
|
||||||
return inres ? overlapped_success : overlapped_error;
|
return inres ? overlapped_success : overlapped_error;
|
||||||
|
|
||||||
wait_return res;
|
wait_return res = overlapped_unknown;
|
||||||
DWORD err = GetLastError ();
|
DWORD err;
|
||||||
if (nonblocking)
|
|
||||||
{
|
|
||||||
if (inres)
|
if (inres)
|
||||||
res = overlapped_success;
|
/* handle below */;
|
||||||
else if (err != ERROR_IO_PENDING)
|
else if ((err = GetLastError ()) != ERROR_IO_PENDING)
|
||||||
res = overlapped_error;
|
res = overlapped_error;
|
||||||
|
else if (!nonblocking)
|
||||||
|
/* handle below */;
|
||||||
|
else if (!writing)
|
||||||
|
SetEvent (get_overlapped ()->hEvent); /* Force immediate WFMO return */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (writing)
|
*bytes = len; /* Assume that this worked */
|
||||||
*bytes = len;
|
io_pending = true; /* but don't allow subsequent */
|
||||||
else
|
res = overlapped_success; /* writes until completed */
|
||||||
|
}
|
||||||
|
if (res == overlapped_unknown)
|
||||||
{
|
{
|
||||||
set_errno (EAGAIN);
|
|
||||||
*bytes = (DWORD) -1;
|
|
||||||
}
|
|
||||||
res = overlapped_success;
|
|
||||||
io_pending = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!inres && err != ERROR_IO_PENDING)
|
|
||||||
res = overlapped_error;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DEBUGGING
|
|
||||||
if (!get_overlapped ()->hEvent)
|
|
||||||
system_printf ("hEvent is zero?");
|
|
||||||
#endif
|
|
||||||
HANDLE w4[3] = { get_overlapped ()->hEvent, signal_arrived,
|
HANDLE w4[3] = { get_overlapped ()->hEvent, signal_arrived,
|
||||||
pthread::get_cancel_event () };
|
pthread::get_cancel_event () };
|
||||||
DWORD n = w4[2] ? 3 : 2;
|
DWORD n = w4[2] ? 3 : 2;
|
||||||
HANDLE h = writing ? get_output_handle () : get_handle ();
|
HANDLE h = writing ? get_output_handle () : get_handle ();
|
||||||
DWORD wfres = WaitForMultipleObjects (n, w4, false, INFINITE);
|
DWORD wfres = WaitForMultipleObjects (n, w4, false, INFINITE);
|
||||||
if (wfres != WAIT_OBJECT_0)
|
/* Cancelling here to prevent races. It's possible that the I/O has
|
||||||
|
completed already, in which case this is a no-op. Otherwise,
|
||||||
|
WFMO returned because 1) This is a non-blocking call, 2) a signal
|
||||||
|
arrived, or 3) the operation was cancelled. These cases may be
|
||||||
|
overridden by the return of GetOverlappedResult which could detect
|
||||||
|
that I/O completion occurred. */
|
||||||
CancelIo (h);
|
CancelIo (h);
|
||||||
*bytes = 0;
|
|
||||||
BOOL wores = GetOverlappedResult (h, get_overlapped (), bytes, false);
|
BOOL wores = GetOverlappedResult (h, get_overlapped (), bytes, false);
|
||||||
bool signalled = !wores && (wfres == WAIT_OBJECT_0 + 1);
|
err = GetLastError ();
|
||||||
bool canceled = !wores && (wfres == WAIT_OBJECT_0 + 2);
|
ResetEvent (get_overlapped ()->hEvent); /* Probably not needed but CYA */
|
||||||
if (signalled)
|
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)
|
||||||
{
|
{
|
||||||
debug_printf ("got a signal");
|
|
||||||
if (_my_tls.call_signal_handler ())
|
if (_my_tls.call_signal_handler ())
|
||||||
res = overlapped_signal;
|
res = overlapped_signal;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
set_errno (EINTR);
|
err = ERROR_INVALID_AT_INTERRUPT_TIME; /* forces an EINTR below */
|
||||||
res = overlapped_error;
|
debug_printf ("unhandled signal");
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (canceled)
|
|
||||||
pthread::static_cancel_self ();
|
|
||||||
else if (!wores)
|
|
||||||
{
|
|
||||||
err = GetLastError ();
|
|
||||||
debug_printf ("GetOverLappedResult failed, bytes %u", *bytes);
|
|
||||||
res = overlapped_error;
|
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
|
else
|
||||||
{
|
{
|
||||||
debug_printf ("normal %s, %u bytes", writing ? "write" : "read", *bytes);
|
debug_printf ("GetOverLappedResult failed, h %p, bytes %u, w4: %p, %p, %p %E", h, *bytes, w4[0], w4[1], w4[2]);
|
||||||
res = overlapped_success;
|
res = overlapped_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == overlapped_success)
|
if (res == overlapped_success)
|
||||||
/* nothing to do */;
|
debug_printf ("normal %s, %u bytes", writing ? "write" : "read", *bytes);
|
||||||
|
else if (res == overlapped_signal)
|
||||||
|
debug_printf ("handled signal");
|
||||||
|
else if (res == overlapped_nonblocking_no_data)
|
||||||
|
{
|
||||||
|
*bytes = (DWORD) -1;
|
||||||
|
set_errno (EAGAIN);
|
||||||
|
debug_printf ("no data to read for nonblocking I/O");
|
||||||
|
}
|
||||||
else if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
|
else if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE)
|
||||||
{
|
{
|
||||||
debug_printf ("EOF");
|
debug_printf ("EOF");
|
||||||
@ -1883,18 +1886,12 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug_printf ("err %u", err);
|
debug_printf ("res %u, err %u", (unsigned) res, err);
|
||||||
HANDLE h = writing ? get_output_handle () : get_handle ();
|
|
||||||
CancelIo (h);
|
|
||||||
ResetEvent (get_overlapped ());
|
|
||||||
*bytes = (DWORD) -1;
|
*bytes = (DWORD) -1;
|
||||||
if (res == overlapped_error)
|
|
||||||
{
|
|
||||||
__seterrno_from_win_error (err);
|
__seterrno_from_win_error (err);
|
||||||
if (writing && (err == ERROR_NO_DATA || err == ERROR_BROKEN_PIPE))
|
if (writing && (err == ERROR_NO_DATA || err == ERROR_BROKEN_PIPE))
|
||||||
raise (SIGPIPE);
|
raise (SIGPIPE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -1903,10 +1900,6 @@ void __stdcall __attribute__ ((regparm (3)))
|
|||||||
fhandler_base_overlapped::raw_read (void *ptr, size_t& len)
|
fhandler_base_overlapped::raw_read (void *ptr, size_t& len)
|
||||||
{
|
{
|
||||||
DWORD nbytes;
|
DWORD nbytes;
|
||||||
if (has_ongoing_io ())
|
|
||||||
nbytes = (DWORD) -1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool keep_looping;
|
bool keep_looping;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -1925,7 +1918,6 @@ fhandler_base_overlapped::raw_read (void *ptr, size_t& len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (keep_looping);
|
while (keep_looping);
|
||||||
}
|
|
||||||
len = (size_t) nbytes;
|
len = (size_t) nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1972,6 +1964,8 @@ fhandler_base_overlapped::raw_write (const void *ptr, size_t len)
|
|||||||
break; /* keep looping */
|
break; /* keep looping */
|
||||||
case overlapped_error:
|
case overlapped_error:
|
||||||
len = 0; /* terminate loop */
|
len = 0; /* terminate loop */
|
||||||
|
case overlapped_unknown:
|
||||||
|
case overlapped_nonblocking_no_data:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,8 +578,10 @@ class fhandler_base_overlapped: public fhandler_base
|
|||||||
protected:
|
protected:
|
||||||
enum wait_return
|
enum wait_return
|
||||||
{
|
{
|
||||||
overlapped_success = 0,
|
overlapped_unknown = 0,
|
||||||
|
overlapped_success,
|
||||||
overlapped_signal,
|
overlapped_signal,
|
||||||
|
overlapped_nonblocking_no_data,
|
||||||
overlapped_error
|
overlapped_error
|
||||||
};
|
};
|
||||||
bool io_pending;
|
bool io_pending;
|
||||||
|
@ -378,6 +378,7 @@ pipe (int filedes[2])
|
|||||||
fdout = fhs[1];
|
fdout = fhs[1];
|
||||||
filedes[0] = fdin;
|
filedes[0] = fdin;
|
||||||
filedes[1] = fdout;
|
filedes[1] = fdout;
|
||||||
|
debug_printf ("%d, %d", (int) fdin, (int) fdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user