aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2011-03-09 16:47:44 +0000
committerChristopher Faylor <me@cgf.cx>2011-03-09 16:47:44 +0000
commit779ece3ce001d7edc79e5dce22816dde9f61ed27 (patch)
treea399111a88528a71668ad657a8fecb81e24b2de6
parente7b5eaaac9c1c05b033c40228ac0662774c9a45b (diff)
downloadnewlib-779ece3ce001d7edc79e5dce22816dde9f61ed27.zip
newlib-779ece3ce001d7edc79e5dce22816dde9f61ed27.tar.gz
newlib-779ece3ce001d7edc79e5dce22816dde9f61ed27.tar.bz2
* 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.
-rw-r--r--winsup/cygwin/ChangeLog43
-rw-r--r--winsup/cygwin/errno.cc2
-rw-r--r--winsup/cygwin/fhandler.cc165
-rw-r--r--winsup/cygwin/fhandler.h25
-rw-r--r--winsup/cygwin/fhandler_fifo.cc6
-rw-r--r--winsup/cygwin/pipe.cc9
6 files changed, 193 insertions, 57 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 5912f9e..e833d9f 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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.
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index eb9fa3d..b837609 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -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),
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 963635c..24a67de 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -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;
+}
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 74eebf5..ee08e59 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -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 ();
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index 746409c..9142947 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -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)
diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc
index 2f3bebe..2a44839 100644
--- a/winsup/cygwin/pipe.cc
+++ b/winsup/cygwin/pipe.cc
@@ -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])
{