* errno.cc (errmap): Change mapping of NO_SYSTEM_RESOURCES to EFBIG.

* fhandler.cc (MAX_OVERLAPPED_WRITE_LEN): New constant.
(MIN_OVERLAPPED_WRITE_LEN): Ditto.
(fhandler_base_overlapped::close): Accommodate change in arguments to
wait_overlapped.
(fhandler_base_overlapped::setup_overlapped): Add __stdcall and regparm
modifiers.
(fhandler_base_overlapped::destroy_overlapped): Ditto.
(fhandler_base_overlapped::has_ongoing_io): Ditto.
(fhandler_base_overlapped::wait_overlapped): Modify to return an enum returning
various states.  Accept nonblocking parameter.
(fhandler_base_overlapped::read_overlapped): Add __stdcall and regparm
modifiers.  Rework to attempt to be smarter about reacting to states returned
by wait_overlapped.
(fhandler_base_overlapped::write_overlapped): Ditto.  Add fallback option for
when wait_overlapped detects that smaller chunks must be written.
(fhandler_base_overlapped::write_overlapped_fallback): Ditto.
* fhandler.h (DEFAULT_PIPEBUFSIZE): Move definition here from pipe.cc.
(fhandler_base::has_ongoing_io): Define with __stdcall and regparm modifiers.
(fhandler_base_overlapped::wait_return): New enum.
(fhandler_base_overlapped::max_atomic_write): New variable.
(fhandler_base_overlapped:: wait_overlapped): Accommodate changes mentioned
above to arguments and modifiers.
(fhandler_base_overlapped::setup_overlapped): Ditto for modifiers.
(fhandler_base_overlapped::read_overlapped): Ditto.
(fhandler_base_overlapped::write_overlapped): Ditto.
(fhandler_base_overlapped::destroy_overlapped): Ditto.
(fhandler_base_overlapped::has_ongoing_io): Ditto.
(fhandler_base_overlapped::fhandler_base_overlapped): Zero max_atomic_write.
* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Set max_atomic_write to the
size of the DEFAULT_PIPEBUFSIZE.
(fhandler_fifo::wait): Accommodate change in arguments to wait_overlapped.
* pipe.cc (fhandler_pipe::fhandler_pipe): Set max_atomic_write to the size of
the DEFAULT_PIPEBUFSIZE.
(fhandler_pipe::create_selectable): Allow minimum size of DEFAULT_PIPEBUFSIZE.
(DEFAULT_PIPEBUFSIZE): Delete here, move to fhandler.h.
This commit is contained in:
Christopher Faylor 2011-03-09 16:47:44 +00:00
parent e7b5eaaac9
commit 779ece3ce0
6 changed files with 193 additions and 57 deletions

View File

@ -1,3 +1,46 @@
2011-03-09 Christopher Faylor <me+cygwin@cgf.cx>
* errno.cc (errmap): Change mapping of NO_SYSTEM_RESOURCES to EFBIG.
* fhandler.cc (MAX_OVERLAPPED_WRITE_LEN): New constant.
(MIN_OVERLAPPED_WRITE_LEN): Ditto.
(fhandler_base_overlapped::close): Accommodate change in arguments to
wait_overlapped.
(fhandler_base_overlapped::setup_overlapped): Add __stdcall and regparm
modifiers.
(fhandler_base_overlapped::destroy_overlapped): Ditto.
(fhandler_base_overlapped::has_ongoing_io): Ditto.
(fhandler_base_overlapped::wait_overlapped): Modify to return an enum
returning various states. Accept nonblocking parameter.
(fhandler_base_overlapped::read_overlapped): Add __stdcall and regparm
modifiers. Rework to attempt to be smarter about reacting to states
returned by wait_overlapped.
(fhandler_base_overlapped::write_overlapped): Ditto. Add fallback
option for when wait_overlapped detects that smaller chunks must be
written.
(fhandler_base_overlapped::write_overlapped_fallback): Ditto.
* fhandler.h (DEFAULT_PIPEBUFSIZE): Move definition here from pipe.cc.
(fhandler_base::has_ongoing_io): Define with __stdcall and regparm
modifiers.
(fhandler_base_overlapped::wait_return): New enum.
(fhandler_base_overlapped::max_atomic_write): New variable.
(fhandler_base_overlapped:: wait_overlapped): Accommodate changes
mentioned above to arguments and modifiers.
(fhandler_base_overlapped::setup_overlapped): Ditto for modifiers.
(fhandler_base_overlapped::read_overlapped): Ditto.
(fhandler_base_overlapped::write_overlapped): Ditto.
(fhandler_base_overlapped::destroy_overlapped): Ditto.
(fhandler_base_overlapped::has_ongoing_io): Ditto.
(fhandler_base_overlapped::fhandler_base_overlapped): Zero
max_atomic_write.
* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Set max_atomic_write
to the size of the DEFAULT_PIPEBUFSIZE.
(fhandler_fifo::wait): Accommodate change in arguments to
wait_overlapped.
* pipe.cc (fhandler_pipe::fhandler_pipe): Set max_atomic_write to the
size of the DEFAULT_PIPEBUFSIZE.
(fhandler_pipe::create_selectable): Allow minimum size of DEFAULT_PIPEBUFSIZE.
(DEFAULT_PIPEBUFSIZE): Delete here, move to fhandler.h.
2011-03-08 Corinna Vinschen <corinna@vinschen.de>
* security.cc: Fix copyright dates.

View File

@ -118,7 +118,7 @@ static NO_COPY struct
X (NO_MORE_SEARCH_HANDLES, ENFILE),
X (NO_PROC_SLOTS, EAGAIN),
X (NO_SIGNAL_SENT, EIO),
X (NO_SYSTEM_RESOURCES, EAGAIN),
X (NO_SYSTEM_RESOURCES, EFBIG),
X (NO_TOKEN, EINVAL),
X (OPEN_FAILED, EIO),
X (OPEN_FILES, EAGAIN),

View File

@ -29,6 +29,9 @@ details. */
#include "cygtls.h"
#include "sigproc.h"
#define MAX_OVERLAPPED_WRITE_LEN (64 * 1024 * 1024)
#define MIN_OVERLAPPED_WRITE_LEN (1 * 1024 * 1024)
static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
struct __cygwin_perfile *perfile_table;
@ -1056,8 +1059,7 @@ fhandler_base_overlapped::close ()
if (is_nonblocking () && io_pending)
{
DWORD bytes;
set_nonblocking (false);
wait_overlapped (1, !!(get_access () & GENERIC_WRITE), &bytes);
wait_overlapped (1, !!(get_access () & GENERIC_WRITE), &bytes, false);
}
destroy_overlapped ();
return fhandler_base::close ();
@ -1686,7 +1688,7 @@ fhandler_base::fpathconf (int v)
/* Overlapped I/O */
int
int __stdcall __attribute__ ((regparm (1)))
fhandler_base_overlapped::setup_overlapped ()
{
OVERLAPPED *ov = get_overlapped_buffer ();
@ -1696,7 +1698,7 @@ fhandler_base_overlapped::setup_overlapped ()
return ov->hEvent ? 0 : -1;
}
void
void __stdcall __attribute__ ((regparm (1)))
fhandler_base_overlapped::destroy_overlapped ()
{
OVERLAPPED *ov = get_overlapped ();
@ -1709,7 +1711,7 @@ fhandler_base_overlapped::destroy_overlapped ()
get_overlapped () = NULL;
}
bool
bool __stdcall __attribute__ ((regparm (1)))
fhandler_base_overlapped::has_ongoing_io ()
{
if (!io_pending)
@ -1723,27 +1725,25 @@ fhandler_base_overlapped::has_ongoing_io ()
return false;
}
int
fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *bytes, DWORD len)
fhandler_base_overlapped::wait_return __stdcall __attribute__ ((regparm (3)))
fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *bytes, bool nonblocking, DWORD len)
{
if (!get_overlapped ())
return inres;
int res = 0;
return inres ? overlapped_success : overlapped_error;
DWORD err = GetLastError ();
if (is_nonblocking ())
if (err == ERROR_NO_SYSTEM_RESOURCES)
return overlapped_fallback;
wait_return res = overlapped_error;
if (nonblocking)
{
if (inres || err == ERROR_IO_PENDING)
{
io_pending = err == ERROR_IO_PENDING;
if (writing && !inres)
*bytes = len; /* This really isn't true but it seems like
this is a corner-case for linux's
non-blocking I/O implementation. How can
you know how many bytes were written until
the I/O operation really completes? */
res = 1;
*bytes = len;
res = overlapped_success;
err = 0;
}
}
@ -1768,9 +1768,11 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
if (signalled)
{
debug_printf ("got a signal");
set_errno (EINTR);
if (!_my_tls.call_signal_handler ())
set_errno (EINTR);
else
res = overlapped_signal;
*bytes = (DWORD) -1;
res = 0;
err = 0;
}
else if (!wores)
@ -1781,7 +1783,7 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
else
{
debug_printf ("normal %s, %u bytes", writing ? "write" : "read", *bytes);
res = 1;
res = overlapped_success;
err = 0;
}
}
@ -1793,14 +1795,13 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
debug_printf ("err %u", err);
__seterrno_from_win_error (err);
*bytes = (DWORD) -1;
res = 0;
res = overlapped_error;
}
else
{
res = 1;
*bytes = 0;
err = 0;
debug_printf ("EOF");
*bytes = 0;
res = overlapped_success;
}
if (writing && (err == ERROR_NO_DATA || err == ERROR_BROKEN_PIPE))
@ -1808,39 +1809,119 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
return res;
}
void __stdcall
void __stdcall __attribute__ ((regparm (3)))
fhandler_base_overlapped::read_overlapped (void *ptr, size_t& len)
{
DWORD nbytes;
if (has_ongoing_io ())
nbytes = (DWORD) -1;
else
while (1)
{
bool res = ReadFile (get_handle (), ptr, len, &nbytes,
get_overlapped ());
int wres = wait_overlapped (res, false, &nbytes);
if (wres || !_my_tls.call_signal_handler ())
break;
}
{
bool keep_looping;
do
{
bool res = ReadFile (get_handle (), ptr, len, &nbytes,
get_overlapped ());
switch (wait_overlapped (res, false, &nbytes, is_nonblocking ()))
{
case overlapped_signal:
keep_looping = true;
break;
default: /* Added to quiet gcc */
case overlapped_success:
case overlapped_error:
case overlapped_fallback:
keep_looping = false;
break;
}
}
while (keep_looping);
}
len = (size_t) nbytes;
}
ssize_t __stdcall
ssize_t __stdcall __attribute__ ((regparm (3)))
fhandler_base_overlapped::write_overlapped (const void *ptr, size_t len)
{
DWORD nbytes;
if (has_ongoing_io ())
nbytes = (DWORD) -1;
else
while (1)
{
bool res = WriteFile (get_output_handle (), ptr, len, &nbytes,
get_overlapped ());
int wres = wait_overlapped (res, true, &nbytes, (size_t) len);
if (wres || !_my_tls.call_signal_handler ())
break;
}
{
bool keep_looping;
if (is_nonblocking () && max_atomic_write && len > max_atomic_write)
len = max_atomic_write;
do
{
bool res = WriteFile (get_output_handle (), ptr, len, &nbytes,
get_overlapped ());
switch (wait_overlapped (res, true, &nbytes, (size_t) len))
{
case overlapped_fallback:
nbytes = write_overlapped_fallback (ptr, len);
/* fall through intentionally */;
case overlapped_signal:
keep_looping = true;
break;
default: /* Added to quiet gcc */
case overlapped_success:
case overlapped_error:
keep_looping = false;
break;
}
}
while (keep_looping);
}
debug_printf ("returning %u", nbytes);
return nbytes;
}
/* On XP (at least) the size of the buffer that can be used to write to a pipe
(pipes are currently the only thing using the overlapped methods) is
limited. This function is a fallback for when that problem is detected.
It writes to the pipe using smaller buffers but masks this behavior
to the caller. */
ssize_t __stdcall __attribute__ ((regparm (3)))
fhandler_base_overlapped::write_overlapped_fallback (const void *ptr, size_t orig_len)
{
size_t chunk;
if (orig_len > MAX_OVERLAPPED_WRITE_LEN)
chunk = MAX_OVERLAPPED_WRITE_LEN;
else if (orig_len > MIN_OVERLAPPED_WRITE_LEN)
chunk = MIN_OVERLAPPED_WRITE_LEN;
else
chunk = orig_len / 4;
ssize_t nbytes = 0;
DWORD nbytes_now = 0;
while ((size_t) nbytes < orig_len)
{
size_t left = orig_len - nbytes;
size_t len;
if (left > chunk)
len = chunk;
else
len = left;
bool res = WriteFile (get_output_handle (), ptr, len, &nbytes_now,
get_overlapped ());
/* The nonblocking case is not going to be used currently and may
eventually disappear. */
switch (wait_overlapped (res, true, &nbytes_now,
left <= chunk ? is_nonblocking () : false,
(size_t) len))
{
case overlapped_success:
nbytes += nbytes_now;
/* fall through intentionally */
case overlapped_signal:
break; /* keep looping */
case overlapped_error:
case overlapped_fallback: /* Could make this more adaptive
if needed */
orig_len = 0; /* terminate loop */
break;
}
}
if (!nbytes)
nbytes = nbytes_now;
return nbytes;
}

View File

@ -29,6 +29,7 @@ details. */
Using this blocksize in read/write calls in the application results
in a much better performance than using smaller values. */
#define PREFERRED_IO_BLKSIZE ((blksize_t) 65536)
#define DEFAULT_PIPEBUFSIZE PREFERRED_IO_BLKSIZE
extern const char *windows_device_names[];
extern struct __cygwin_perfile *perfile_table;
@ -397,7 +398,7 @@ public:
bool issymlink () {return pc.issymlink ();}
bool device_access_denied (int) __attribute__ ((regparm (2)));
int fhaccess (int flags, bool) __attribute__ ((regparm (3)));
virtual bool has_ongoing_io () {return false;}
virtual bool __stdcall has_ongoing_io () __attribute__ ((regparm (1))) {return false;}
};
class fhandler_mailslot : public fhandler_base
@ -565,23 +566,33 @@ class fhandler_socket: public fhandler_base
class fhandler_base_overlapped: public fhandler_base
{
protected:
enum wait_return
{
overlapped_success = 0,
overlapped_signal,
overlapped_error,
overlapped_fallback
};
bool io_pending;
OVERLAPPED io_status;
OVERLAPPED *overlapped;
size_t max_atomic_write;
public:
int wait_overlapped (bool, bool, DWORD *, DWORD = 0) __attribute__ ((regparm (3)));
int setup_overlapped () __attribute__ ((regparm (1)));
void destroy_overlapped () __attribute__ ((regparm (1)));
wait_return __stdcall wait_overlapped (bool, bool, DWORD *, bool, DWORD = 0) __attribute__ ((regparm (3)));
int __stdcall setup_overlapped () __attribute__ ((regparm (1)));
void __stdcall destroy_overlapped () __attribute__ ((regparm (1)));
void __stdcall read_overlapped (void *ptr, size_t& len) __attribute__ ((regparm (3)));
ssize_t __stdcall write_overlapped (const void *ptr, size_t len);
ssize_t __stdcall write_overlapped (const void *ptr, size_t len) __attribute__ ((regparm (3)));
ssize_t __stdcall write_overlapped_fallback (const void *ptr, size_t orig_len)
__attribute__ ((regparm (3)));
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)
fhandler_base_overlapped (): io_pending (false), overlapped (NULL), max_atomic_write (0)
{
memset (&io_status, 0, sizeof io_status);
}
bool has_ongoing_io ();
bool __stdcall has_ongoing_io () __attribute__ ((regparm (1)));
void fixup_after_fork (HANDLE);
void fixup_after_exec ();

View File

@ -1,6 +1,7 @@
/* fhandler_fifo.cc - See fhandler.h for a description of the fhandler classes.
Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Red Hat, Inc.
This file is part of Cygwin.
@ -24,6 +25,7 @@
fhandler_fifo::fhandler_fifo ():
fhandler_base_overlapped (), wait_state (fifo_unknown), dummy_client (NULL)
{
max_atomic_write = DEFAULT_PIPEBUFSIZE;
need_fork_fixup (true);
}
@ -188,7 +190,7 @@ fhandler_fifo::wait (bool iswrite)
int res = ConnectNamedPipe (get_handle (), get_overlapped ());
if (GetLastError () != ERROR_NO_DATA && GetLastError () != ERROR_PIPE_CONNECTED)
{
res = wait_overlapped (res, iswrite, &dummy_bytes);
res = wait_overlapped (res, iswrite, &dummy_bytes, false);
if (!res)
{
if (get_errno () != EINTR)

View File

@ -1,7 +1,7 @@
/* pipe.cc: pipe for Cygwin.
Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2009, 2010 Hat, Inc.
2008, 2009, 2010, 2011 Hat, Inc.
This file is part of Cygwin.
@ -26,6 +26,7 @@ details. */
fhandler_pipe::fhandler_pipe ()
: fhandler_base_overlapped (), popen_pid (0)
{
max_atomic_write = DEFAULT_PIPEBUFSIZE;
need_fork_fixup (true);
uninterruptible_io (true);
}
@ -217,8 +218,8 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
r = w = INVALID_HANDLE_VALUE;
/* Ensure that there is enough pipe buffer space for atomic writes. */
if (psize < PIPE_BUF)
psize = PIPE_BUF;
if (psize < DEFAULT_PIPEBUFSIZE)
psize = DEFAULT_PIPEBUFSIZE;
char pipename[MAX_PATH];
const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-",
@ -373,8 +374,6 @@ fhandler_pipe::fstatvfs (struct statvfs *sfs)
return -1;
}
#define DEFAULT_PIPEBUFSIZE 65536
extern "C" int
pipe (int filedes[2])
{