#include "ntdll.h"
#include "cygtls.h"
#include "sigproc.h"
+#include "shared_info.h"
#include <asm/socket.h>
#define MAX_OVERLAPPED_WRITE_LEN (64 * 1024 * 1024)
struct __cygwin_perfile *perfile_table;
+HANDLE NO_COPY fhandler_base_overlapped::asio_done;
+LONG NO_COPY fhandler_base_overlapped::asio_close_counter;
+
void
fhandler_base::reset (const fhandler_base *from)
{
return res;
}
+DWORD WINAPI
+flush_async_io (void *arg)
+{
+ fhandler_base_overlapped *fh = (fhandler_base_overlapped *) arg;
+ debug_only_printf ("waiting for %s I/O for %s",
+ (fh->get_access () & GENERIC_WRITE) ? "write" : "read",
+ fh->get_name ());
+ SetEvent (fh->get_overlapped ()->hEvent); /* force has_ongoing_io to block */
+ bool res = fh->has_ongoing_io ();
+ 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 ()
{
- if (is_nonblocking () && io_pending)
+ int res;
+ /* Need to treat non-blocking I/O specially because Windows appears to
+ be brain-dead */
+ if (is_nonblocking () && has_ongoing_io ())
{
- DWORD bytes;
- wait_overlapped (1, !!(get_access () & GENERIC_WRITE), &bytes, false);
+ clone (HEAP_3_FHANDLER)->check_later ();
+ res = 0;
}
- destroy_overlapped ();
- return fhandler_base::close ();
+ else
+ {
+ destroy_overlapped ();
+ res = fhandler_base::close ();
+ }
+ return res;
}
int
return ENOTTY;
}
-void
-fhandler_base::operator delete (void *p)
-{
- cfree (p);
-}
-
/* Normal I/O constructor */
fhandler_base::fhandler_base () :
status (),
return false;
if (!IsEventSignalled (get_overlapped ()->hEvent))
- {
- set_errno (EAGAIN);
- return true;
- }
+ return true;
io_pending = false;
DWORD nbytes;
- GetOverlappedResult (get_output_handle (), get_overlapped (), &nbytes, 0);
+ GetOverlappedResult (get_output_handle (), get_overlapped (), &nbytes, true);
return false;
}
}
else
{
- debug_printf ("res %u, err %u", (unsigned) res, err);
+ debug_printf ("res %u, Win32 Error %u", (unsigned) res, err);
*bytes = (DWORD) -1;
__seterrno_from_win_error (err);
if (writing && err == ERROR_NO_DATA)
{
size_t nbytes;
if (has_ongoing_io ())
- nbytes = (DWORD) -1;
+ {
+ set_errno (EAGAIN);
+ nbytes = (DWORD) -1;
+ }
else
{
size_t chunk;
raixput = raixget = ralen = rabuflen = 0;
rabuf = NULL;
}
- void operator delete (void *);
+ void operator delete (void *p) {cfree (p);}
virtual void set_eof () {}
virtual int mkdir (mode_t mode);
virtual int rmdir ();
x->reset (this);
}
- virtual fhandler_base *clone ()
+ virtual fhandler_base *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_base));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_base));
fhandler_base *fh = new (ptr) fhandler_base (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_socket *clone ()
+ fhandler_socket *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_socket));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_socket));
fhandler_socket *fh = new (ptr) fhandler_socket (ptr);
copyto (fh);
return fh;
class fhandler_base_overlapped: public fhandler_base
{
+ static HANDLE asio_done;
+ static LONG asio_close_counter;
protected:
enum wait_return
{
int close ();
int dup (fhandler_base *child, int);
+ void check_later ();
+ static void flush_all_async_io () __attribute__ ((regparm (1)));;
+
fhandler_base_overlapped (void *) {}
virtual void copyto (fhandler_base *x)
x->reset (this);
}
- virtual fhandler_base_overlapped *clone ()
+ virtual fhandler_base_overlapped *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_base_overlapped));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_base_overlapped));
fhandler_base_overlapped *fh = new (ptr) fhandler_base_overlapped (ptr);
copyto (fh);
return fh;
}
+
+ friend DWORD WINAPI flush_async_io (void *);
};
class fhandler_pipe: public fhandler_base_overlapped
x->reset (this);
}
- fhandler_pipe *clone ()
+ fhandler_pipe *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_pipe));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pipe));
fhandler_pipe *fh = new (ptr) fhandler_pipe (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_fifo *clone ()
+ fhandler_fifo *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_fifo));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_fifo));
fhandler_fifo *fh = new (ptr) fhandler_fifo (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_mailslot *clone ()
+ fhandler_mailslot *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_mailslot));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_mailslot));
fhandler_mailslot *fh = new (ptr) fhandler_mailslot (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_raw *clone ()
+ fhandler_dev_raw *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_raw));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_raw));
fhandler_dev_raw *fh = new (ptr) fhandler_dev_raw (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_floppy *clone ()
+ fhandler_dev_floppy *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_floppy));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_floppy));
fhandler_dev_floppy *fh = new (ptr) fhandler_dev_floppy (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_tape *clone ()
+ fhandler_dev_tape *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_tape));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_tape));
fhandler_dev_tape *fh = new (ptr) fhandler_dev_tape (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_disk_file *clone ()
+ fhandler_disk_file *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_disk_file));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_disk_file));
fhandler_disk_file *fh = new (ptr) fhandler_disk_file (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_cygdrive *clone ()
+ fhandler_cygdrive *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_cygdrive));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_cygdrive));
fhandler_cygdrive *fh = new (ptr) fhandler_cygdrive (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_serial *clone ()
+ fhandler_serial *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_serial));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_serial));
fhandler_serial *fh = new (ptr) fhandler_serial (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- virtual fhandler_termios *clone ()
+ virtual fhandler_termios *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_termios));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_termios));
fhandler_termios *fh = new (ptr) fhandler_termios (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_console *clone ()
+ fhandler_console *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_console));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_console));
fhandler_console *fh = new (ptr) fhandler_console (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- virtual fhandler_pty_common *clone ()
+ virtual fhandler_pty_common *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_pty_common));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pty_common));
fhandler_pty_common *fh = new (ptr) fhandler_pty_common (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_pty_slave *clone ()
+ fhandler_pty_slave *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_pty_slave));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pty_slave));
fhandler_pty_slave *fh = new (ptr) fhandler_pty_slave (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_pty_master *clone ()
+ fhandler_pty_master *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_pty_master));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pty_master));
fhandler_pty_master *fh = new (ptr) fhandler_pty_master (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_null *clone ()
+ fhandler_dev_null *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_null));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_null));
fhandler_dev_null *fh = new (ptr) fhandler_dev_null (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_zero *clone ()
+ fhandler_dev_zero *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_zero));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_zero));
fhandler_dev_zero *fh = new (ptr) fhandler_dev_zero (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_random *clone ()
+ fhandler_dev_random *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_random));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_random));
fhandler_dev_random *fh = new (ptr) fhandler_dev_random (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_mem *clone ()
+ fhandler_dev_mem *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_mem));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_mem));
fhandler_dev_mem *fh = new (ptr) fhandler_dev_mem (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_clipboard *clone ()
+ fhandler_dev_clipboard *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_clipboard));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_clipboard));
fhandler_dev_clipboard *fh = new (ptr) fhandler_dev_clipboard (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_windows *clone ()
+ fhandler_windows *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_windows));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_windows));
fhandler_windows *fh = new (ptr) fhandler_windows (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_dev_dsp *clone ()
+ fhandler_dev_dsp *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_dev_dsp));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_dsp));
fhandler_dev_dsp *fh = new (ptr) fhandler_dev_dsp (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- virtual fhandler_virtual *clone ()
+ virtual fhandler_virtual *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_virtual));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_virtual));
fhandler_virtual *fh = new (ptr) fhandler_virtual (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- virtual fhandler_proc *clone ()
+ virtual fhandler_proc *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_proc));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_proc));
fhandler_proc *fh = new (ptr) fhandler_proc (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_procsys *clone ()
+ fhandler_procsys *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_procsys));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_procsys));
fhandler_procsys *fh = new (ptr) fhandler_procsys (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_procsysvipc *clone ()
+ fhandler_procsysvipc *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_procsysvipc));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_procsysvipc));
fhandler_procsysvipc *fh = new (ptr) fhandler_procsysvipc (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_netdrive *clone ()
+ fhandler_netdrive *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_netdrive));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_netdrive));
fhandler_netdrive *fh = new (ptr) fhandler_netdrive (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_registry *clone ()
+ fhandler_registry *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_registry));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_registry));
fhandler_registry *fh = new (ptr) fhandler_registry (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_process *clone ()
+ fhandler_process *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_process));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_process));
fhandler_process *fh = new (ptr) fhandler_process (ptr);
copyto (fh);
return fh;
x->reset (this);
}
- fhandler_procnet *clone ()
+ fhandler_procnet *clone (cygheap_types malloc_type = HEAP_FHANDLER)
{
- void *ptr = (void *) ccalloc (HEAP_FHANDLER, 1, sizeof (fhandler_procnet));
+ void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_procnet));
fhandler_procnet *fh = new (ptr) fhandler_procnet (ptr);
copyto (fh);
return fh;
FILE_PIPE_LOCAL_INFORMATION fpli = {0};
bool res = false;
- if (NtQueryInformationFile (h,
- &iosb,
- &fpli,
- sizeof (fpli),
- FilePipeLocalInformation))
+ if (!fh->has_ongoing_io ())
{
- /* If NtQueryInformationFile fails, optimistically assume the
- pipe is writable. This could happen if we somehow
- inherit a pipe that doesn't permit FILE_READ_ATTRIBUTES
- access on the write end. */
- select_printf ("fd %d, %s, NtQueryInformationFile failed",
- fd, fh->get_name ());
- res = writing ? true : -1;
- }
- else if (!writing)
- {
- res = !!fpli.ReadDataAvailable;
- paranoid_printf ("fd %d, %s, read avail %u", fd, fh->get_name (), fpli.ReadDataAvailable);
- }
- else
- {
- /* If there is anything available in the pipe buffer then signal
- that. This means that a pipe could still block since you could
- be trying to write more to the pipe than is available in the
- buffer but that is the hazard of select(). */
- if ((fpli.WriteQuotaAvailable = (fpli.OutboundQuota - fpli.ReadDataAvailable)))
+ if (NtQueryInformationFile (h,
+ &iosb,
+ &fpli,
+ sizeof (fpli),
+ FilePipeLocalInformation))
+ {
+ /* If NtQueryInformationFile fails, optimistically assume the
+ pipe is writable. This could happen if we somehow
+ inherit a pipe that doesn't permit FILE_READ_ATTRIBUTES
+ access on the write end. */
+ select_printf ("fd %d, %s, NtQueryInformationFile failed",
+ fd, fh->get_name ());
+ res = writing ? true : -1;
+ }
+ else if (!writing)
{
- paranoid_printf ("fd %d, %s, write: size %lu, avail %lu", fd,
- fh->get_name (), fpli.OutboundQuota,
- fpli.WriteQuotaAvailable);
- res = true;
+ res = !!fpli.ReadDataAvailable;
+ paranoid_printf ("fd %d, %s, read avail %u", fd, fh->get_name (), fpli.ReadDataAvailable);
}
- /* If we somehow inherit a tiny pipe (size < PIPE_BUF), then consider
- the pipe writable only if it is completely empty, to minimize the
- probability that a subsequent write will block. */
- else if (fpli.OutboundQuota < PIPE_BUF &&
- fpli.WriteQuotaAvailable == fpli.OutboundQuota)
+ else
{
- select_printf ("fd, %s, write tiny pipe: size %lu, avail %lu",
- fd, fh->get_name (), fpli.OutboundQuota,
- fpli.WriteQuotaAvailable);
- res = true;
+ /* If there is anything available in the pipe buffer then signal
+ that. This means that a pipe could still block since you could
+ be trying to write more to the pipe than is available in the
+ buffer but that is the hazard of select(). */
+ if ((fpli.WriteQuotaAvailable = (fpli.OutboundQuota - fpli.ReadDataAvailable)))
+ {
+ paranoid_printf ("fd %d, %s, write: size %lu, avail %lu", fd,
+ fh->get_name (), fpli.OutboundQuota,
+ fpli.WriteQuotaAvailable);
+ res = true;
+ }
+ /* If we somehow inherit a tiny pipe (size < PIPE_BUF), then consider
+ the pipe writable only if it is completely empty, to minimize the
+ probability that a subsequent write will block. */
+ else if (fpli.OutboundQuota < PIPE_BUF &&
+ fpli.WriteQuotaAvailable == fpli.OutboundQuota)
+ {
+ select_printf ("fd, %s, write tiny pipe: size %lu, avail %lu",
+ fd, fh->get_name (), fpli.OutboundQuota,
+ fpli.WriteQuotaAvailable);
+ res = true;
+ }
}
}
return res ?: -!!(fpli.NamedPipeState & FILE_PIPE_CLOSING_STATE);