Cygwin: remove the fhandler_base_overlapped class
Also remove the 'was_nonblocking' flag, which was needed only for fhandler_base_overlapped.
This commit is contained in:
parent
f56206cd86
commit
f002d02b17
|
@ -30,16 +30,10 @@ details. */
|
||||||
#include <asm/socket.h>
|
#include <asm/socket.h>
|
||||||
#include "cygwait.h"
|
#include "cygwait.h"
|
||||||
|
|
||||||
#define MAX_OVERLAPPED_WRITE_LEN (64 * 1024 * 1024)
|
|
||||||
#define MIN_OVERLAPPED_WRITE_LEN (1 * 1024 * 1024)
|
|
||||||
|
|
||||||
static const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
|
static const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
|
||||||
|
|
||||||
struct __cygwin_perfile *perfile_table;
|
struct __cygwin_perfile *perfile_table;
|
||||||
|
|
||||||
HANDLE NO_COPY fhandler_base_overlapped::asio_done;
|
|
||||||
LONG NO_COPY fhandler_base_overlapped::asio_close_counter;
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_base::puts_readahead (const char *s, size_t len)
|
fhandler_base::puts_readahead (const char *s, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -184,8 +178,6 @@ fhandler_base::set_flags (int flags, int supplied_bin)
|
||||||
bin = wbinary () || rbinary () ? O_BINARY : O_TEXT;
|
bin = wbinary () || rbinary () ? O_BINARY : O_TEXT;
|
||||||
|
|
||||||
openflags = flags | bin;
|
openflags = flags | bin;
|
||||||
if (openflags & O_NONBLOCK)
|
|
||||||
was_nonblocking (true);
|
|
||||||
|
|
||||||
bin &= O_BINARY;
|
bin &= O_BINARY;
|
||||||
rbinary (bin ? true : false);
|
rbinary (bin ? true : false);
|
||||||
|
@ -1222,88 +1214,6 @@ fhandler_base::close ()
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI
|
|
||||||
flush_async_io (void *arg)
|
|
||||||
{
|
|
||||||
fhandler_base_overlapped *fh = (fhandler_base_overlapped *) arg;
|
|
||||||
debug_only_printf ("waiting for write I/O for %s", fh->get_name ());
|
|
||||||
DWORD nbytes;
|
|
||||||
bool res = GetOverlappedResult (fh->get_output_handle (),
|
|
||||||
fh->get_overlapped (), &nbytes, true);
|
|
||||||
debug_printf ("finished waiting for I/O from %s, res %d", fh->get_name (),
|
|
||||||
res);
|
|
||||||
fh->close ();
|
|
||||||
delete fh;
|
|
||||||
|
|
||||||
InterlockedDecrement (&fhandler_base_overlapped::asio_close_counter);
|
|
||||||
SetEvent (fhandler_base_overlapped::asio_done);
|
|
||||||
|
|
||||||
_my_tls._ctinfo->auto_release ();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fhandler_base_overlapped::flush_all_async_io ()
|
|
||||||
{
|
|
||||||
while (asio_close_counter > 0)
|
|
||||||
if (WaitForSingleObject (asio_done, INFINITE) != WAIT_OBJECT_0)
|
|
||||||
{
|
|
||||||
system_printf ("WaitForSingleObject failed, possible data loss in pipe, %E");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
asio_close_counter = 0;
|
|
||||||
if (asio_done)
|
|
||||||
CloseHandle (asio_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start a thread to handle closing of overlapped asynchronous I/O since
|
|
||||||
Windows amazingly does not seem to always flush I/O on close. */
|
|
||||||
void
|
|
||||||
fhandler_base_overlapped::check_later ()
|
|
||||||
{
|
|
||||||
set_close_on_exec (true);
|
|
||||||
char buf[MAX_PATH];
|
|
||||||
if (!asio_done
|
|
||||||
&& !(asio_done = CreateEvent (&sec_none_nih, false, false,
|
|
||||||
shared_name (buf, "asio",
|
|
||||||
GetCurrentProcessId ()))))
|
|
||||||
api_fatal ("CreateEvent failed, %E");
|
|
||||||
|
|
||||||
InterlockedIncrement (&asio_close_counter);
|
|
||||||
if (!new cygthread(flush_async_io, this, "flasio"))
|
|
||||||
api_fatal ("couldn't create a thread to track async I/O, %E");
|
|
||||||
debug_printf ("started thread to handle asynchronous closing for %s", get_name ());
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fhandler_base_overlapped::close ()
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
int writer = (get_access () & GENERIC_WRITE);
|
|
||||||
/* Need to treat non-blocking I/O specially because Windows appears to
|
|
||||||
be brain-dead. We're checking here if the descriptor was ever set
|
|
||||||
to nonblocking, rather than checking if it's nonblocking at close time.
|
|
||||||
The reason is that applications may switch back to blocking (for the
|
|
||||||
sake of some other application accessing this descriptor) without
|
|
||||||
performaing any further I/O. These applications would suffer data
|
|
||||||
loss, which this workaround is trying to fix. */
|
|
||||||
if (writer && was_nonblocking () && has_ongoing_io ())
|
|
||||||
{
|
|
||||||
clone (HEAP_3_FHANDLER)->check_later ();
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Cancelling seems to be necessary for cases where a reader is
|
|
||||||
still executing when a signal handler performs a close. */
|
|
||||||
if (!writer)
|
|
||||||
CancelIo (get_handle ());
|
|
||||||
destroy_overlapped ();
|
|
||||||
res = fhandler_base::close ();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_base::ioctl (unsigned int cmd, void *buf)
|
fhandler_base::ioctl (unsigned int cmd, void *buf)
|
||||||
{
|
{
|
||||||
|
@ -1421,14 +1331,6 @@ fhandler_base::dup (fhandler_base *child, int)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
fhandler_base_overlapped::dup (fhandler_base *child, int flags)
|
|
||||||
{
|
|
||||||
int res = fhandler_base::dup (child, flags) ||
|
|
||||||
((fhandler_base_overlapped *) child)->setup_overlapped ();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fhandler_base::fcntl (int cmd, intptr_t arg)
|
int fhandler_base::fcntl (int cmd, intptr_t arg)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -1648,13 +1550,6 @@ fhandler_base::fixup_after_fork (HANDLE parent)
|
||||||
del_my_locks (after_fork);
|
del_my_locks (after_fork);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
fhandler_base_overlapped::fixup_after_fork (HANDLE parent)
|
|
||||||
{
|
|
||||||
setup_overlapped ();
|
|
||||||
fhandler_base::fixup_after_fork (parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fhandler_base::fixup_after_exec ()
|
fhandler_base::fixup_after_exec ()
|
||||||
{
|
{
|
||||||
|
@ -1663,12 +1558,6 @@ fhandler_base::fixup_after_exec ()
|
||||||
del_my_locks (after_exec);
|
del_my_locks (after_exec);
|
||||||
mandatory_locking (false);
|
mandatory_locking (false);
|
||||||
}
|
}
|
||||||
void
|
|
||||||
fhandler_base_overlapped::fixup_after_exec ()
|
|
||||||
{
|
|
||||||
setup_overlapped ();
|
|
||||||
fhandler_base::fixup_after_exec ();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
fhandler_base::is_nonblocking ()
|
fhandler_base::is_nonblocking ()
|
||||||
|
@ -1682,8 +1571,6 @@ fhandler_base::set_nonblocking (int yes)
|
||||||
int current = openflags & O_NONBLOCK_MASK;
|
int current = openflags & O_NONBLOCK_MASK;
|
||||||
int new_flags = yes ? (!current ? O_NONBLOCK : current) : 0;
|
int new_flags = yes ? (!current ? O_NONBLOCK : current) : 0;
|
||||||
openflags = (openflags & ~O_NONBLOCK_MASK) | new_flags;
|
openflags = (openflags & ~O_NONBLOCK_MASK) | new_flags;
|
||||||
if (new_flags)
|
|
||||||
was_nonblocking (true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1946,273 +1833,3 @@ fhandler_base::fpathconf (int v)
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overlapped I/O */
|
|
||||||
|
|
||||||
int __reg1
|
|
||||||
fhandler_base_overlapped::setup_overlapped ()
|
|
||||||
{
|
|
||||||
OVERLAPPED *ov = get_overlapped_buffer ();
|
|
||||||
memset (ov, 0, sizeof (*ov));
|
|
||||||
set_overlapped (ov);
|
|
||||||
ov->hEvent = CreateEvent (&sec_none_nih, true, true, NULL);
|
|
||||||
io_pending = false;
|
|
||||||
return ov->hEvent ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __reg1
|
|
||||||
fhandler_base_overlapped::destroy_overlapped ()
|
|
||||||
{
|
|
||||||
OVERLAPPED *ov = get_overlapped ();
|
|
||||||
if (ov && ov->hEvent)
|
|
||||||
{
|
|
||||||
SetEvent (ov->hEvent);
|
|
||||||
CloseHandle (ov->hEvent);
|
|
||||||
ov->hEvent = NULL;
|
|
||||||
}
|
|
||||||
io_pending = false;
|
|
||||||
get_overlapped () = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool __reg1
|
|
||||||
fhandler_base_overlapped::has_ongoing_io ()
|
|
||||||
{
|
|
||||||
if (!io_pending)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!IsEventSignalled (get_overlapped ()->hEvent))
|
|
||||||
return true;
|
|
||||||
io_pending = false;
|
|
||||||
DWORD nbytes;
|
|
||||||
GetOverlappedResult (get_output_handle (), get_overlapped (), &nbytes, false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fhandler_base_overlapped::wait_return __reg3
|
|
||||||
fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *bytes, bool nonblocking, DWORD len)
|
|
||||||
{
|
|
||||||
if (!get_overlapped ())
|
|
||||||
return inres ? overlapped_success : overlapped_error;
|
|
||||||
|
|
||||||
wait_return res = overlapped_unknown;
|
|
||||||
DWORD err;
|
|
||||||
if (inres)
|
|
||||||
/* handle below */;
|
|
||||||
else if ((err = GetLastError ()) != ERROR_IO_PENDING)
|
|
||||||
res = overlapped_error;
|
|
||||||
else if (!nonblocking)
|
|
||||||
/* handle below */;
|
|
||||||
else if (!writing)
|
|
||||||
SetEvent (get_overlapped ()->hEvent); /* Force immediate WFMO return */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*bytes = len; /* Assume that this worked */
|
|
||||||
io_pending = true; /* but don't allow subsequent */
|
|
||||||
res = overlapped_success; /* writes until completed */
|
|
||||||
}
|
|
||||||
if (res == overlapped_unknown)
|
|
||||||
{
|
|
||||||
DWORD wfres = cygwait (get_overlapped ()->hEvent);
|
|
||||||
HANDLE h = writing ? get_output_handle () : get_handle ();
|
|
||||||
BOOL wores;
|
|
||||||
if (isclosed ())
|
|
||||||
{
|
|
||||||
switch (wfres)
|
|
||||||
{
|
|
||||||
case WAIT_OBJECT_0:
|
|
||||||
err = ERROR_INVALID_HANDLE;
|
|
||||||
break;
|
|
||||||
case WAIT_SIGNALED:
|
|
||||||
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
|
|
||||||
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);
|
|
||||||
wores = GetOverlappedResult (h, get_overlapped (), bytes, false);
|
|
||||||
err = GetLastError ();
|
|
||||||
ResetEvent (get_overlapped ()->hEvent); /* Probably not needed but CYA */
|
|
||||||
debug_printf ("wfres %u, 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 (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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == overlapped_success)
|
|
||||||
{
|
|
||||||
debug_printf ("normal %s, %u bytes ispipe() %d", writing ? "write" : "read", *bytes, ispipe ());
|
|
||||||
if (*bytes == 0 && !writing && ispipe ())
|
|
||||||
res = overlapped_nullread;
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
debug_printf ("EOF, %E");
|
|
||||||
*bytes = 0;
|
|
||||||
res = overlapped_success;
|
|
||||||
if (writing && err == ERROR_BROKEN_PIPE)
|
|
||||||
raise (SIGPIPE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug_printf ("res %u, Win32 Error %u", (unsigned) res, err);
|
|
||||||
*bytes = (DWORD) -1;
|
|
||||||
__seterrno_from_win_error (err);
|
|
||||||
if (writing && err == ERROR_NO_DATA)
|
|
||||||
raise (SIGPIPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __reg3
|
|
||||||
fhandler_base_overlapped::raw_read (void *ptr, size_t& len)
|
|
||||||
{
|
|
||||||
DWORD nbytes;
|
|
||||||
bool keep_looping;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
bool res = ReadFile (get_handle (), ptr, len, &nbytes,
|
|
||||||
get_overlapped ());
|
|
||||||
switch (wait_overlapped (res, false, &nbytes, is_nonblocking ()))
|
|
||||||
{
|
|
||||||
case overlapped_nullread:
|
|
||||||
keep_looping = true;
|
|
||||||
break;
|
|
||||||
default: /* Added to quiet gcc */
|
|
||||||
case overlapped_success:
|
|
||||||
case overlapped_error:
|
|
||||||
keep_looping = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (keep_looping);
|
|
||||||
len = (nbytes == (DWORD) -1) ? (size_t) -1 : (size_t) nbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t __reg3
|
|
||||||
fhandler_base_overlapped::raw_write (const void *ptr, size_t len)
|
|
||||||
{
|
|
||||||
size_t nbytes;
|
|
||||||
if (has_ongoing_io ())
|
|
||||||
{
|
|
||||||
set_errno (EAGAIN);
|
|
||||||
nbytes = (size_t) -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t chunk;
|
|
||||||
if (!max_atomic_write || len < max_atomic_write)
|
|
||||||
chunk = MIN (len, INT_MAX);
|
|
||||||
else if (is_nonblocking ())
|
|
||||||
chunk = len = max_atomic_write;
|
|
||||||
else
|
|
||||||
chunk = max_atomic_write;
|
|
||||||
|
|
||||||
/* MSDN "WriteFile" contains the following note: "Accessing the output
|
|
||||||
buffer while a write operation is using the buffer may lead to
|
|
||||||
corruption of the data written from that buffer. [...] This can
|
|
||||||
be particularly problematic when using an asynchronous file handle.
|
|
||||||
(https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747)
|
|
||||||
|
|
||||||
MSDN "Synchronous and Asynchronous I/O" contains the following note:
|
|
||||||
"Do not deallocate or modify [...] the data buffer until all
|
|
||||||
asynchronous I/O operations to the file object have been completed."
|
|
||||||
(https://msdn.microsoft.com/en-us/library/windows/desktop/aa365683)
|
|
||||||
|
|
||||||
This problem is a non-issue for blocking I/O, but it can lead to
|
|
||||||
problems when using nonblocking I/O. Consider:
|
|
||||||
- The application uses a static buffer in repeated calls to
|
|
||||||
non-blocking write.
|
|
||||||
- The previous write returned with success, but the overlapped I/O
|
|
||||||
operation is ongoing.
|
|
||||||
- The application copies the next set of data to the static buffer,
|
|
||||||
thus overwriting data still accessed by the previous write call.
|
|
||||||
--> potential data corruption.
|
|
||||||
|
|
||||||
What we do here is to allocate a per-fhandler buffer big enough
|
|
||||||
to perform the maximum atomic operation from, copy the user space
|
|
||||||
data over to this buffer and then call NtWriteFile on this buffer.
|
|
||||||
This decouples the write operation from the user buffer and the
|
|
||||||
user buffer can be reused without data corruption issues.
|
|
||||||
|
|
||||||
Since no further write can occur while we're still having ongoing
|
|
||||||
I/O, this should be reasanably safe.
|
|
||||||
|
|
||||||
Note: We only have proof that this problem actually occurs on Wine
|
|
||||||
yet. However, the MSDN language indicates that this may be a real
|
|
||||||
problem on real Windows as well. */
|
|
||||||
if (is_nonblocking ())
|
|
||||||
{
|
|
||||||
if (!atomic_write_buf)
|
|
||||||
atomic_write_buf = cmalloc_abort (HEAP_BUF, max_atomic_write);
|
|
||||||
ptr = memcpy (atomic_write_buf, ptr, chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes = 0;
|
|
||||||
DWORD nbytes_now = 0;
|
|
||||||
/* Write to fd in smaller chunks, accumulating 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 (nbytes < len)
|
|
||||||
{
|
|
||||||
size_t left = len - nbytes;
|
|
||||||
size_t len1;
|
|
||||||
if (left > chunk)
|
|
||||||
len1 = chunk;
|
|
||||||
else
|
|
||||||
len1 = left;
|
|
||||||
bool res = WriteFile (get_output_handle (), ptr, len1, &nbytes_now,
|
|
||||||
get_overlapped ());
|
|
||||||
switch (wait_overlapped (res, true, &nbytes_now,
|
|
||||||
is_nonblocking (), len1))
|
|
||||||
{
|
|
||||||
case overlapped_success:
|
|
||||||
ptr = ((char *) ptr) + chunk;
|
|
||||||
nbytes += nbytes_now;
|
|
||||||
break;
|
|
||||||
case overlapped_error:
|
|
||||||
len = 0; /* terminate loop */
|
|
||||||
case overlapped_unknown:
|
|
||||||
case overlapped_nullread:
|
|
||||||
case overlapped_nonblocking_no_data:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!nbytes)
|
|
||||||
nbytes = (nbytes_now == (DWORD) -1) ? (size_t) -1 : nbytes_now;
|
|
||||||
}
|
|
||||||
return nbytes;
|
|
||||||
}
|
|
||||||
|
|
|
@ -178,16 +178,12 @@ class fhandler_base
|
||||||
unsigned need_fork_fixup : 1; /* Set if need to fixup after fork. */
|
unsigned need_fork_fixup : 1; /* Set if need to fixup after fork. */
|
||||||
unsigned isclosed : 1; /* Set when fhandler is closed. */
|
unsigned isclosed : 1; /* Set when fhandler is closed. */
|
||||||
unsigned mandatory_locking : 1; /* Windows mandatory locking */
|
unsigned mandatory_locking : 1; /* Windows mandatory locking */
|
||||||
unsigned was_nonblocking : 1; /* Set when setting O_NONBLOCK. Never
|
|
||||||
reset. This is for the sake of
|
|
||||||
fhandler_base_overlapped::close. */
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
status_flags () :
|
status_flags () :
|
||||||
rbinary (0), rbinset (0), wbinary (0), wbinset (0), nohandle (0),
|
rbinary (0), rbinset (0), wbinary (0), wbinset (0), nohandle (0),
|
||||||
did_lseek (0), query_open (no_query), close_on_exec (0),
|
did_lseek (0), query_open (no_query), close_on_exec (0),
|
||||||
need_fork_fixup (0), isclosed (0), mandatory_locking (0),
|
need_fork_fixup (0), isclosed (0), mandatory_locking (0)
|
||||||
was_nonblocking (0)
|
|
||||||
{}
|
{}
|
||||||
} status, open_status;
|
} status, open_status;
|
||||||
|
|
||||||
|
@ -289,7 +285,6 @@ class fhandler_base
|
||||||
IMPLEMENT_STATUS_FLAG (bool, need_fork_fixup)
|
IMPLEMENT_STATUS_FLAG (bool, need_fork_fixup)
|
||||||
IMPLEMENT_STATUS_FLAG (bool, isclosed)
|
IMPLEMENT_STATUS_FLAG (bool, isclosed)
|
||||||
IMPLEMENT_STATUS_FLAG (bool, mandatory_locking)
|
IMPLEMENT_STATUS_FLAG (bool, mandatory_locking)
|
||||||
IMPLEMENT_STATUS_FLAG (bool, was_nonblocking)
|
|
||||||
|
|
||||||
int get_default_fmode (int flags);
|
int get_default_fmode (int flags);
|
||||||
|
|
||||||
|
@ -1170,74 +1165,6 @@ class fhandler_socket_unix : public fhandler_socket
|
||||||
|
|
||||||
#endif /* __WITH_AF_UNIX */
|
#endif /* __WITH_AF_UNIX */
|
||||||
|
|
||||||
class fhandler_base_overlapped: public fhandler_base
|
|
||||||
{
|
|
||||||
static HANDLE asio_done;
|
|
||||||
static LONG asio_close_counter;
|
|
||||||
protected:
|
|
||||||
enum wait_return
|
|
||||||
{
|
|
||||||
overlapped_unknown = 0,
|
|
||||||
overlapped_success,
|
|
||||||
overlapped_nonblocking_no_data,
|
|
||||||
overlapped_nullread,
|
|
||||||
overlapped_error
|
|
||||||
};
|
|
||||||
bool io_pending;
|
|
||||||
OVERLAPPED io_status;
|
|
||||||
OVERLAPPED *overlapped;
|
|
||||||
size_t max_atomic_write;
|
|
||||||
void *atomic_write_buf;
|
|
||||||
public:
|
|
||||||
wait_return __reg3 wait_overlapped (bool, bool, DWORD *, bool, DWORD = 0);
|
|
||||||
int __reg1 setup_overlapped ();
|
|
||||||
void __reg1 destroy_overlapped ();
|
|
||||||
virtual void __reg3 raw_read (void *ptr, size_t& len);
|
|
||||||
virtual ssize_t __reg3 raw_write (const void *ptr, size_t len);
|
|
||||||
OVERLAPPED *&get_overlapped () {return overlapped;}
|
|
||||||
OVERLAPPED *get_overlapped_buffer () {return &io_status;}
|
|
||||||
void set_overlapped (OVERLAPPED *ov) {overlapped = ov;}
|
|
||||||
fhandler_base_overlapped (): io_pending (false), overlapped (NULL), max_atomic_write (0), atomic_write_buf (NULL)
|
|
||||||
{
|
|
||||||
memset (&io_status, 0, sizeof io_status);
|
|
||||||
}
|
|
||||||
bool __reg1 has_ongoing_io ();
|
|
||||||
|
|
||||||
void fixup_after_fork (HANDLE);
|
|
||||||
void fixup_after_exec ();
|
|
||||||
|
|
||||||
int close ();
|
|
||||||
int dup (fhandler_base *child, int);
|
|
||||||
|
|
||||||
void check_later ();
|
|
||||||
static void __reg1 flush_all_async_io ();;
|
|
||||||
|
|
||||||
fhandler_base_overlapped (void *) {}
|
|
||||||
~fhandler_base_overlapped ()
|
|
||||||
{
|
|
||||||
if (atomic_write_buf)
|
|
||||||
cfree (atomic_write_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void copy_from (fhandler_base *x)
|
|
||||||
{
|
|
||||||
pc.free_strings ();
|
|
||||||
*this = *reinterpret_cast<fhandler_base_overlapped *> (x);
|
|
||||||
atomic_write_buf = NULL;
|
|
||||||
_copy_from_reset_helper ();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual fhandler_base_overlapped *clone (cygheap_types malloc_type = HEAP_FHANDLER)
|
|
||||||
{
|
|
||||||
void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_base_overlapped));
|
|
||||||
fhandler_base_overlapped *fh = new (ptr) fhandler_base_overlapped (ptr);
|
|
||||||
fh->copy_from (this);
|
|
||||||
return fh;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend DWORD WINAPI flush_async_io (void *);
|
|
||||||
};
|
|
||||||
|
|
||||||
class fhandler_pipe: public fhandler_base
|
class fhandler_pipe: public fhandler_base
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -108,7 +108,6 @@ close_all_files (bool norelease)
|
||||||
if (!have_execed && cygheap->ctty)
|
if (!have_execed && cygheap->ctty)
|
||||||
cygheap->close_ctty ();
|
cygheap->close_ctty ();
|
||||||
|
|
||||||
fhandler_base_overlapped::flush_all_async_io ();
|
|
||||||
if (h)
|
if (h)
|
||||||
SetStdHandle (STD_ERROR_HANDLE, h);
|
SetStdHandle (STD_ERROR_HANDLE, h);
|
||||||
cygheap->fdtab.unlock ();
|
cygheap->fdtab.unlock ();
|
||||||
|
|
Loading…
Reference in New Issue