* fhandler.h (fhandler_pipe::create_selectable): Remove optional argument, take

an options argument for CreateNamedPipe/CreateFile.  Change handle arguments to
expect pointers.
(fhandler_fifo::fifo_state): Delete.
(fhandler_fifo::dummy_client): Ditto.
(fhandler_fifo::open_nonserver): Ditto.
(fhandler_fifo::wait_state): Ditto.
(fhandler_fifo::raw_write): Ditto.
(fhandler_fifo::read_ready): New field.
(fhandler_fifo::write_ready): Ditto.
(fhandler_fifo::wait): Modify argument.
(fhandler_fifo::fifo_name): Add a new argument.
(fhandler_fifo::fixup_after_fork): New function.
* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove initialization of
expunged elements.  Initialize new handles to NULL.
(fhandler_fifo::open_nonserver): Delete.
(fnevent): New macro for creating a named event.
(fnpipe): New macro for creating a unique named pipe name.
(create_pipe): New macro for simplification of named pipe creation.
(fhandler_fifo::fifo_name): Use new argument when creating a shared name.
(fhandler_fifo::open): Rewrite.  Use events to synchronize.
(pure_debug_printf): New macro, active only when DEBUGGING.
(fhandler_fifo::wait): Rewrite to wait for new fifo events which are supplied
as a parameter.
(fhandler_fifo::raw_read): Rewrite to use handle mechanism to detect
client-side disconnect.
(fhandler_fifo::raw_write): Delete.
(fhandler_fifo::close): Remove accommodations for expunged fields.  Close event
handles.
(fhandler_fifo::dup): Remove accommodations for expunged fields.  Duplicate
event handles.
(fhandler_fifo::fixup_after_fork): New function.  Perform fixups on event
handles.
(fhandler_fifo::set_close_on_exec): Remove accommodations for expunged fields.
Set inheritance for new handle fields.
* miscfuncs.cc (CreatePipeOverlapped): Accommodate changes in
fhandler_pipe::create_selectable.
* tty.cc (tty::not_allocated): Ditto.
* pipe.cc (fhandler_pipe::create): Ditto.
(fhandler_pipe::create_selectable): Accept an extra open_mode argument.  Pass
arguments by reference and allow opening one end of the pipe at a time.
* sys/strace.h (debug_only_printf): Define new macro which calls debug_printf
only when DEBUGGING is defined.
This commit is contained in:
Christopher Faylor 2011-10-30 04:50:36 +00:00
parent 673a691372
commit cd071d1363
9 changed files with 449 additions and 369 deletions

View File

@ -1,3 +1,52 @@
2011-10-30 Christopher Faylor <me.cygwin2011@cgf.cx>
* fhandler.h (fhandler_pipe::create_selectable): Remove optional
argument, take an options argument for CreateNamedPipe/CreateFile.
Change handle arguments to expect pointers.
(fhandler_fifo::fifo_state): Delete.
(fhandler_fifo::dummy_client): Ditto.
(fhandler_fifo::open_nonserver): Ditto.
(fhandler_fifo::wait_state): Ditto.
(fhandler_fifo::raw_write): Ditto.
(fhandler_fifo::read_ready): New field.
(fhandler_fifo::write_ready): Ditto.
(fhandler_fifo::wait): Modify argument.
(fhandler_fifo::fifo_name): Add a new argument.
(fhandler_fifo::fixup_after_fork): New function.
* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove
initialization of expunged elements. Initialize new handles to NULL.
(fhandler_fifo::open_nonserver): Delete.
(fnevent): New macro for creating a named event.
(fnpipe): New macro for creating a unique named pipe name.
(create_pipe): New macro for simplification of named pipe creation.
(fhandler_fifo::fifo_name): Use new argument when creating a shared
name.
(fhandler_fifo::open): Rewrite. Use events to synchronize.
(pure_debug_printf): New macro, active only when DEBUGGING.
(fhandler_fifo::wait): Rewrite to wait for new fifo events which are
supplied as a parameter.
(fhandler_fifo::raw_read): Rewrite to use handle mechanism to detect
client-side disconnect.
(fhandler_fifo::raw_write): Delete.
(fhandler_fifo::close): Remove accommodations for expunged fields.
Close event handles.
(fhandler_fifo::dup): Remove accommodations for expunged fields.
Duplicate event handles.
(fhandler_fifo::fixup_after_fork): New function. Perform fixups on
event handles.
(fhandler_fifo::set_close_on_exec): Remove accommodations for expunged
fields. Set inheritance for new handle fields.
* miscfuncs.cc (CreatePipeOverlapped): Accommodate changes in
fhandler_pipe::create_selectable.
* tty.cc (tty::not_allocated): Ditto.
* pipe.cc (fhandler_pipe::create): Ditto.
(fhandler_pipe::create_selectable): Accept an extra open_mode argument.
Pass arguments by reference and allow opening one end of the pipe at a
time.
* sys/strace.h (debug_only_printf): Define new macro which calls
debug_printf only when DEBUGGING is defined.
2011-10-28 Christopher Faylor <me.cygwin2011@cgf.cx> 2011-10-28 Christopher Faylor <me.cygwin2011@cgf.cx>
* exceptions.cc (sigpacket::process): Avoid a potential deadlock when * exceptions.cc (sigpacket::process): Avoid a potential deadlock when

View File

@ -275,8 +275,8 @@ retry:
/* Cover function to WriteFile to provide Posix interface and semantics /* Cover function to WriteFile to provide Posix interface and semantics
(as much as possible). */ (as much as possible). */
static LARGE_INTEGER off_current = { QuadPart:FILE_USE_FILE_POINTER_POSITION }; static NO_COPY LARGE_INTEGER off_current = { QuadPart:FILE_USE_FILE_POINTER_POSITION };
static LARGE_INTEGER off_append = { QuadPart:FILE_WRITE_TO_END_OF_FILE }; static NO_COPY LARGE_INTEGER off_append = { QuadPart:FILE_WRITE_TO_END_OF_FILE };
ssize_t __stdcall ssize_t __stdcall
fhandler_base::raw_write (const void *ptr, size_t len) fhandler_base::raw_write (const void *ptr, size_t len)
@ -1914,7 +1914,7 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte
} }
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, %E");
*bytes = 0; *bytes = 0;
res = overlapped_success; res = overlapped_success;
if (writing && err == ERROR_BROKEN_PIPE) if (writing && err == ERROR_BROKEN_PIPE)

View File

@ -690,9 +690,8 @@ public:
int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
int init (HANDLE, DWORD, mode_t); int init (HANDLE, DWORD, mode_t);
static int create (fhandler_pipe *[2], unsigned, int); static int create (fhandler_pipe *[2], unsigned, int);
static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD, const char * = NULL); static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE *, HANDLE *, DWORD,
friend class fhandler_fifo; const char *, DWORD);
fhandler_pipe (void *) {} fhandler_pipe (void *) {}
void copyto (fhandler_base *x) void copyto (fhandler_base *x)
@ -713,31 +712,19 @@ public:
class fhandler_fifo: public fhandler_base_overlapped class fhandler_fifo: public fhandler_base_overlapped
{ {
enum fifo_state HANDLE read_ready;
{ HANDLE write_ready;
fifo_unknown, bool wait (HANDLE) __attribute__ ((regparm (2)));
fifo_wait_for_client, char *fifo_name (char *, const char *) __attribute__ ((regparm (2)));
fifo_wait_for_server,
fifo_wait_for_next_client,
fifo_eof,
fifo_error,
fifo_eintr,
fifo_ok
};
fifo_state wait_state;
HANDLE dummy_client;
HANDLE open_nonserver (const char *, unsigned, LPSECURITY_ATTRIBUTES);
bool wait (bool) __attribute__ ((regparm (1)));
char *fifo_name (char *) __attribute__ ((regparm (2)));
public: public:
fhandler_fifo (); fhandler_fifo ();
void __stdcall raw_read (void *, size_t&) __attribute__ ((regparm (3)));
ssize_t __stdcall raw_write (const void *, size_t) __attribute__ ((regparm (3)));
int open (int, mode_t); int open (int, mode_t);
int close (); int close ();
int dup (fhandler_base *child, int); int dup (fhandler_base *child, int);
bool isfifo () const { return true; } bool isfifo () const { return true; }
void set_close_on_exec (bool val); void set_close_on_exec (bool val);
void __stdcall raw_read (void *ptr, size_t& ulen) __attribute__ ((regparm (3)));
void fixup_after_fork (HANDLE);
int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2)));
select_record *select_read (select_stuff *); select_record *select_read (select_stuff *);
select_record *select_write (select_stuff *); select_record *select_write (select_stuff *);

View File

@ -24,52 +24,27 @@
#include "ntdll.h" #include "ntdll.h"
fhandler_fifo::fhandler_fifo (): fhandler_fifo::fhandler_fifo ():
fhandler_base_overlapped (), wait_state (fifo_unknown), dummy_client (NULL) fhandler_base_overlapped (),
read_ready (NULL), write_ready (NULL)
{ {
max_atomic_write = DEFAULT_PIPEBUFSIZE; max_atomic_write = DEFAULT_PIPEBUFSIZE;
need_fork_fixup (true); need_fork_fixup (true);
} }
HANDLE #define fnevent(w) fifo_name (npbuf, w "-event")
fhandler_fifo::open_nonserver (const char *npname, unsigned low_flags, #define fnpipe() fifo_name (npbuf, "fifo")
LPSECURITY_ATTRIBUTES sa_buf) #define create_pipe(r, w) \
{ fhandler_pipe::create_selectable (sa_buf, (r), (w), 0, fnpipe (), open_mode)
DWORD mode = 0;
if (low_flags == O_RDONLY)
mode = GENERIC_READ;
else if (low_flags == O_WRONLY)
mode = GENERIC_WRITE;
else
mode = GENERIC_READ | GENERIC_WRITE;
while (1)
{
HANDLE h = CreateFile (npname, mode, 0, sa_buf, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, NULL);
if (h != INVALID_HANDLE_VALUE || GetLastError () != ERROR_PIPE_NOT_CONNECTED)
return h;
if (IsEventSignalled (signal_arrived))
{
set_errno (EINTR);
return NULL;
}
}
}
char * char *
fhandler_fifo::fifo_name (char *buf) fhandler_fifo::fifo_name (char *buf, const char *what)
{ {
/* Generate a semi-unique name to associate with this fifo. */ /* Generate a semi-unique name to associate with this fifo. */
__small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%S_%08x_%016X", __small_sprintf (buf, "%s.%08x.%016X", what, get_dev (),
&installation_key, get_dev (), get_ino ()); get_ino ());
return buf; return buf;
} }
#define FIFO_PIPE_MODE (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE)
#define FIFO_BUF_SIZE 4096
#define cnp(m, s) CreateNamedPipe(npname, (m), FIFO_PIPE_MODE, \
PIPE_UNLIMITED_INSTANCES, (s), (s), \
NMPWAIT_WAIT_FOREVER, sa_buf)
inline PSECURITY_ATTRIBUTES inline PSECURITY_ATTRIBUTES
sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid) sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid)
{ {
@ -79,207 +54,242 @@ sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid)
int int
fhandler_fifo::open (int flags, mode_t) fhandler_fifo::open (int flags, mode_t)
{ {
int res = 1; enum
char npname[MAX_PATH];
fifo_name (npname);
unsigned low_flags = flags & O_ACCMODE;
DWORD mode = 0;
if (low_flags == O_WRONLY)
mode = PIPE_ACCESS_OUTBOUND;
else if (low_flags == O_RDONLY || low_flags == O_RDWR)
mode = PIPE_ACCESS_DUPLEX;
else
{ {
success,
error_errno_set,
error_set_errno
} res;
bool reader, writer;
DWORD open_mode = FILE_FLAG_OVERLAPPED;
/* Determine what we're doing with this fhandler: reading, writing, both */
switch (flags & O_ACCMODE)
{
case O_RDONLY:
reader = true;
writer = false;
break;
case O_WRONLY:
writer = true;
reader = false;
break;
case O_RDWR:
reader = true;
writer = true;
open_mode |= PIPE_ACCESS_DUPLEX;
break;
default:
set_errno (EINVAL); set_errno (EINVAL);
res = 0; res = error_errno_set;
goto out;
} }
if (res)
{
char char_sa_buf[1024];
LPSECURITY_ATTRIBUTES sa_buf =
sec_user_cloexec (flags & O_CLOEXEC, (PSECURITY_ATTRIBUTES) char_sa_buf,
cygheap->user.sid());
bool do_seterrno = true;
HANDLE h;
bool nonblocking_write = !!((flags & (O_WRONLY | O_NONBLOCK)) == (O_WRONLY | O_NONBLOCK));
wait_state = fifo_unknown;
if (mode != PIPE_ACCESS_OUTBOUND)
{
h = cnp (mode | FILE_FLAG_OVERLAPPED, FIFO_BUF_SIZE);
wait_state = fifo_wait_for_client;
}
else
{
h = open_nonserver (npname, low_flags, sa_buf);
if (h != INVALID_HANDLE_VALUE)
wait_state = fifo_ok;
else if (nonblocking_write)
{
set_errno (ENXIO);
do_seterrno = false;
}
else if ((h = cnp (PIPE_ACCESS_DUPLEX, 1)) != INVALID_HANDLE_VALUE)
{
if ((dummy_client = open_nonserver (npname, low_flags, sa_buf))
!= INVALID_HANDLE_VALUE)
{
wait_state = fifo_wait_for_server;
ProtectHandle (dummy_client);
}
else
{
DWORD saveerr = GetLastError ();
CloseHandle (h);
h = INVALID_HANDLE_VALUE;
SetLastError (saveerr);
}
}
}
if (h == INVALID_HANDLE_VALUE)
{
if (do_seterrno)
__seterrno ();
res = 0;
}
else if (setup_overlapped ())
{
CloseHandle (h);
__seterrno ();
res = 0;
}
else
{
set_io_handle (h);
set_flags (flags); set_flags (flags);
res = 1; char char_sa_buf[1024];
LPSECURITY_ATTRIBUTES sa_buf;
sa_buf = sec_user_cloexec (flags & O_CLOEXEC, (PSECURITY_ATTRIBUTES) char_sa_buf,
cygheap->user.sid());
char npbuf[MAX_PATH];
/* Create control events for this named pipe */
if (!(read_ready = CreateEvent (sa_buf, true, false, fnevent ("r"))))
{
debug_printf ("CreatEvent for %s failed, %E", npbuf);
res = error_set_errno;
goto out;
}
if (!(write_ready = CreateEvent (sa_buf, true, false, fnevent ("w"))))
{
debug_printf ("CreatEvent for %s failed, %E", npbuf);
res = error_set_errno;
goto out;
}
/* If we're reading, create the pipe, signal that we're ready and wait for
a writer.
FIXME: Probably need to special case O_RDWR case. */
if (!reader)
/* We are not a reader */;
else if (create_pipe (&get_io_handle (), NULL))
{
debug_printf ("create of reader failed");
res = error_set_errno;
goto out;
}
else if (!SetEvent (read_ready))
{
debug_printf ("SetEvent for read_ready failed, %E");
res = error_set_errno;
goto out;
}
else if (!writer && !wait (write_ready))
{
debug_printf ("wait for write_ready failed, %E");
res = error_errno_set;
goto out;
}
/* If we're writing, it's a little tricky since it is possible that
we're attempting to open the other end of a pipe which is already
connected. In that case, we detect ERROR_PIPE_BUSY, reset the
read_ready event and wait for the reader to allow us to connect
by signalling read_ready.
Once the pipe has been set up, we signal write_ready. */
if (writer)
{
int err;
while (1)
if (!wait (read_ready))
{
res = error_errno_set;
goto out;
}
else if ((err = create_pipe (NULL, &get_io_handle ())) == 0)
break;
else if (err == ERROR_PIPE_BUSY)
{
debug_only_printf ("pipe busy");
ResetEvent (read_ready);
}
else
{
debug_printf ("create of writer failed");
res = error_set_errno;
goto out;
}
if (!SetEvent (write_ready))
{
debug_printf ("SetEvent for write_ready failed, %E");
res = error_set_errno;
goto out;
} }
} }
debug_printf ("returning %d, errno %d", res, get_errno ()); /* If setup_overlapped() succeeds (and why wouldn't it?) we are all set. */
return res; if (setup_overlapped () == 0)
res = success;
else
{
debug_printf ("setup_overlapped failed, %E");
res = error_set_errno;
}
out:
if (res == error_set_errno)
__seterrno ();
if (res != success)
{
if (read_ready)
{
CloseHandle (read_ready);
read_ready = NULL;
}
if (write_ready)
{
CloseHandle (write_ready);
write_ready = NULL;
}
if (get_io_handle ())
CloseHandle (get_io_handle ());
}
debug_printf ("res %d", res);
return res == success;
} }
bool bool
fhandler_fifo::wait (bool iswrite) fhandler_fifo::wait (HANDLE h)
{ {
DWORD ninstances; #ifdef DEBUGGING
switch (wait_state) const char *what;
{ if (h == read_ready)
case fifo_wait_for_next_client: what = "reader";
DisconnectNamedPipe (get_handle ()); else if (h == write_ready)
if (!GetNamedPipeHandleState (get_handle (), NULL, &ninstances, NULL, NULL, NULL, 0)) what = "writer";
{
__seterrno ();
wait_state = fifo_error;
return false;
}
if (ninstances <= 1)
{
wait_state = fifo_eof;
return false;
}
case fifo_wait_for_client:
{
DWORD dummy_bytes;
while (1)
{
int res = ConnectNamedPipe (get_handle (), get_overlapped ());
if (GetLastError () != ERROR_NO_DATA && GetLastError () != ERROR_PIPE_CONNECTED)
{
res = wait_overlapped (res, iswrite, &dummy_bytes, false);
if (!res)
{
if (get_errno () != EINTR)
wait_state = fifo_error;
else if (!_my_tls.call_signal_handler ())
wait_state = fifo_eintr;
else else
continue; what = "overlapped event";
return false; #endif
} HANDLE w4[3] = {h, signal_arrived, pthread::get_cancel_event ()};
}
wait_state = fifo_ok; /* Set the wait to zero for non-blocking I/O-related events. */
break; DWORD wait = ((h == read_ready || h == write_ready)
} && get_flags () & O_NONBLOCK) ? 0 : INFINITE;
}
break; debug_only_printf ("waiting for %s", what);
case fifo_wait_for_server: /* Wait for the event. Set errno, as appropriate if something goes wrong. */
char npname[MAX_PATH]; switch (WaitForMultipleObjects (3, w4, false, wait))
fifo_name (npname);
char char_sa_buf[1024];
LPSECURITY_ATTRIBUTES sa_buf;
sa_buf = sec_user_cloexec (close_on_exec (),
(PSECURITY_ATTRIBUTES) char_sa_buf,
cygheap->user.sid());
while (1)
{ {
if (WaitNamedPipe (npname, 10)) case WAIT_OBJECT_0:
/* connected, maybe */; debug_only_printf ("successfully waited for %s", what);
else if (GetLastError () != ERROR_SEM_TIMEOUT) return true;
case WAIT_TIMEOUT:
if (h == write_ready)
{ {
__seterrno (); debug_only_printf ("wait timed out waiting for write but will still open reader since non-blocking mode");
return false; return true;
} }
else if (!IsEventSignalled (signal_arrived))
continue;
else if (_my_tls.call_signal_handler ())
continue;
else else
{ {
set_errno (ENXIO);
return false;
}
break;
case WAIT_OBJECT_0 + 1:
debug_only_printf ("interrupted by signal while waiting for %s", what);
set_errno (EINTR); set_errno (EINTR);
return false; return false;
} case WAIT_OBJECT_0 + 2:
HANDLE h = open_nonserver (npname, get_flags () & O_ACCMODE, sa_buf); debug_only_printf ("cancellable interruption while waiting for %s", what);
if (h != INVALID_HANDLE_VALUE) pthread::static_cancel_self (); /* never returns */
{
ForceCloseHandle (get_handle ());
ForceCloseHandle (dummy_client);
dummy_client = NULL;
wait_state = fifo_ok;
set_io_handle (h);
break; break;
} default:
if (GetLastError () == ERROR_PIPE_LISTENING) debug_only_printf ("unknown error while waiting for %s", what);
continue;
else
{
__seterrno (); __seterrno ();
return false; return false;
} }
} }
default:
break;
}
return true;
}
void __stdcall void __stdcall
fhandler_fifo::raw_read (void *in_ptr, size_t& len) fhandler_fifo::raw_read (void *in_ptr, size_t& len)
{ {
while (wait_state != fifo_eof && wait_state != fifo_error && wait_state != fifo_eintr) size_t orig_len = len;
if (!wait (false)) for (int i = 0; i < 2; i++)
len = (wait_state == fifo_error || wait_state == fifo_eintr) ? (size_t) -1 : 0;
else
{ {
size_t prev_len = len;
fhandler_base_overlapped::raw_read (in_ptr, len); fhandler_base_overlapped::raw_read (in_ptr, len);
if (len) if (len || i || WaitForSingleObject (read_ready, 0) == WAIT_OBJECT_0)
break; break;
wait_state = fifo_wait_for_next_client; /* If we got here, then fhandler_base_overlapped::raw_read returned 0,
len = prev_len; indicating "EOF" and something has set read_ready to zero. That means
} we should have a client waiting to connect.
if (wait_state == fifo_eintr) FIXME: If the client CTRL-C's the open during this time then this
wait_state = fifo_wait_for_client; could hang indefinitely. Maybe implement a timeout? */
debug_printf ("returning %d, mode %d, %E\n", len, get_errno ()); if (!DisconnectNamedPipe (get_io_handle ()))
}
ssize_t __stdcall
fhandler_fifo::raw_write (const void *ptr, size_t len)
{ {
return wait (true) ? fhandler_base_overlapped::raw_write (ptr, len) : -1; debug_printf ("DisconnecttNamedPipe failed, %E");
goto errno_out;
}
else if (!ConnectNamedPipe (get_io_handle (), get_overlapped ())
&& GetLastError () != ERROR_IO_PENDING)
{
debug_printf ("ConnectNamedPipe failed, %E");
goto errno_out;
}
else if (!SetEvent (read_ready))
{
debug_printf ("SetEvent (read_ready) failed, %E");
goto errno_out;
}
else if (!wait (get_overlapped_buffer ()->hEvent))
goto errout; /* If wait() fails, errno is set so no need to set it */
len = orig_len; /* Reset since raw_read above set it to zero. */
}
return;
errno_out:
__seterrno ();
errout:
len = -1;
} }
int __stdcall int __stdcall
@ -293,41 +303,52 @@ fhandler_fifo::fstatvfs (struct statvfs *sfs)
int int
fhandler_fifo::close () fhandler_fifo::close ()
{ {
wait_state = fifo_eof; CloseHandle (read_ready);
if (dummy_client) CloseHandle (write_ready);
{
ForceCloseHandle (dummy_client);
dummy_client = NULL;
}
return fhandler_base::close (); return fhandler_base::close ();
} }
int int
fhandler_fifo::dup (fhandler_base *child, int flags) fhandler_fifo::dup (fhandler_base *child, int flags)
{ {
int res = fhandler_base_overlapped::dup (child, flags); if (fhandler_base_overlapped::dup (child, flags))
fhandler_fifo *fifo_child = (fhandler_fifo *) child;
if (res == 0 && dummy_client)
{ {
bool dres = DuplicateHandle (GetCurrentProcess (), dummy_client,
GetCurrentProcess (),
&fifo_child->dummy_client, 0,
TRUE, DUPLICATE_SAME_ACCESS);
if (!dres)
{
fifo_child->dummy_client = NULL;
child->close ();
__seterrno (); __seterrno ();
res = -1; return -1;
} }
fhandler_fifo *fhf = (fhandler_fifo *) child;
if (!DuplicateHandle (GetCurrentProcess (), read_ready,
GetCurrentProcess (), &fhf->read_ready,
0, true, DUPLICATE_SAME_ACCESS))
{
fhf->close ();
__seterrno ();
return -1;
} }
return res; if (!DuplicateHandle (GetCurrentProcess (), write_ready,
GetCurrentProcess (), &fhf->write_ready,
0, true, DUPLICATE_SAME_ACCESS))
{
CloseHandle (fhf->read_ready);
fhf->close ();
__seterrno ();
return -1;
}
return 0;
}
void
fhandler_fifo::fixup_after_fork (HANDLE parent)
{
fhandler_base_overlapped::fixup_after_fork (parent);
fork_fixup (parent, read_ready, "read_ready");
fork_fixup (parent, write_ready, "write_ready");
} }
void void
fhandler_fifo::set_close_on_exec (bool val) fhandler_fifo::set_close_on_exec (bool val)
{ {
fhandler_base::set_close_on_exec (val); fhandler_base::set_close_on_exec (val);
if (dummy_client) set_no_inheritance (read_ready, val);
set_no_inheritance (dummy_client, val); set_no_inheritance (write_ready, val);
} }

View File

@ -1624,8 +1624,8 @@ fhandler_pty_master::setup ()
char pipename[sizeof("ptyNNNN-from-master")]; char pipename[sizeof("ptyNNNN-from-master")];
__small_sprintf (pipename, "pty%d-to-master", unit); __small_sprintf (pipename, "pty%d-to-master", unit);
res = fhandler_pipe::create_selectable (&sec_none, get_io_handle (), res = fhandler_pipe::create_selectable (&sec_none, &get_io_handle (),
to_master, 128 * 1024, pipename); &to_master, 128 * 1024, pipename, 0);
if (res) if (res)
{ {
errstr = "output pipe"; errstr = "output pipe";

View File

@ -125,6 +125,11 @@ void strace_printf (unsigned, const char *func, const char *, ...);
})) }))
#endif /*NOSTRACE*/ #endif /*NOSTRACE*/
#ifdef DEBUGGING
#define debug_only_printf(fmt, args...) debug_printf (fmt , ## args)
#else
#define debug_only_printf(fmt, args...) do {} while (0)
#endif
#define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args) #define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args)
#define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args) #define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args)
#define minimal_printf(fmt, args...) strace_printf_wrap1(MINIMAL, fmt , ## args) #define minimal_printf(fmt, args...) strace_printf_wrap1(MINIMAL, fmt , ## args)

View File

@ -337,7 +337,8 @@ nice_to_winprio (int &nice)
BOOL WINAPI BOOL WINAPI
CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa) CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa)
{ {
int ret = fhandler_pipe::create_selectable (sa, *hr, *hw, 0); int ret = fhandler_pipe::create_selectable (sa, hr, hw, 0, NULL,
FILE_FLAG_OVERLAPPED);
if (ret) if (ret)
SetLastError (ret); SetLastError (ret);
return ret == 0; return ret == 0;

View File

@ -197,11 +197,14 @@ fhandler_pipe::dup (fhandler_base *child, int flags)
Note that the return value is either 0 or GetLastError, Note that the return value is either 0 or GetLastError,
unlike CreatePipe, which returns a bool for success or failure. */ unlike CreatePipe, which returns a bool for success or failure. */
int int
fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE *r,
HANDLE& w, DWORD psize, const char *name) HANDLE *w, DWORD psize, const char *name, DWORD open_mode)
{ {
/* Default to error. */ /* Default to error. */
r = w = INVALID_HANDLE_VALUE; if (r)
*r = NULL;
if (w)
*w = NULL;
/* Ensure that there is enough pipe buffer space for atomic writes. */ /* Ensure that there is enough pipe buffer space for atomic writes. */
if (psize < DEFAULT_PIPEBUFSIZE) if (psize < DEFAULT_PIPEBUFSIZE)
@ -210,26 +213,24 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
char pipename[MAX_PATH]; char pipename[MAX_PATH];
const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-",
&installation_key); &installation_key);
if (name)
strcpy (pipename + len, name);
/* FIXME: Eventually make ttys work with overlapped I/O. */ open_mode |= PIPE_ACCESS_INBOUND;
DWORD overlapped = name ? 0 : FILE_FLAG_OVERLAPPED;
/* Retry CreateNamedPipe as long as the pipe name is in use. /* Retry CreateNamedPipe as long as the pipe name is in use.
Retrying will probably never be necessary, but we want Retrying will probably never be necessary, but we want
to be as robust as possible. */ to be as robust as possible. */
DWORD err; DWORD err = 0;
do while (r && !*r)
{ {
static volatile ULONG pipe_unique_id; static volatile ULONG pipe_unique_id;
if (!name) if (!name)
__small_sprintf (pipename + len, "pipe-%p-%p", myself->pid, __small_sprintf (pipename + len, "pipe-%p-%p", myself->pid,
InterlockedIncrement ((LONG *) &pipe_unique_id)); InterlockedIncrement ((LONG *) &pipe_unique_id));
else
strcpy (pipename + len, name);
debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize); debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize);
err = 0;
/* Use CreateNamedPipe instead of CreatePipe, because the latter /* Use CreateNamedPipe instead of CreatePipe, because the latter
returns a write handle that does not permit FILE_READ_ATTRIBUTES returns a write handle that does not permit FILE_READ_ATTRIBUTES
access, on versions of win32 earlier than WinXP SP2. access, on versions of win32 earlier than WinXP SP2.
@ -245,13 +246,14 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
definitely required for pty handling since fhandler_pty_master definitely required for pty handling since fhandler_pty_master
writes to the pipe in chunks, terminated by newline when CANON mode writes to the pipe in chunks, terminated by newline when CANON mode
is specified. */ is specified. */
r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND | overlapped, *r = CreateNamedPipe (pipename, open_mode,
PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE, 1, psize, PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE, 1, psize,
psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
if (r != INVALID_HANDLE_VALUE) if (*r != INVALID_HANDLE_VALUE)
{ {
debug_printf ("pipe read handle %p", r); debug_printf ("pipe read handle %p", *r);
err = 0;
break; break;
} }
@ -261,43 +263,58 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
case ERROR_PIPE_BUSY: case ERROR_PIPE_BUSY:
/* The pipe is already open with compatible parameters. /* The pipe is already open with compatible parameters.
Pick a new name and retry. */ Pick a new name and retry. */
debug_printf ("pipe busy", name ? ", retrying" : ""); debug_printf ("pipe busy", !name ? ", retrying" : "");
if (!*name)
*r = NULL;
break; break;
case ERROR_ACCESS_DENIED: case ERROR_ACCESS_DENIED:
/* The pipe is already open with incompatible parameters. /* The pipe is already open with incompatible parameters.
Pick a new name and retry. */ Pick a new name and retry. */
debug_printf ("pipe access denied%s", name ? ", retrying" : ""); debug_printf ("pipe access denied%s", !name ? ", retrying" : "");
if (!*name)
*r = NULL;
break; break;
default: default:
{ {
err = GetLastError (); err = GetLastError ();
debug_printf ("CreatePipe failed, %E"); debug_printf ("failed, %E");
return err;
} }
} }
} }
while (!name);
if (err) if (err)
{
*r = NULL;
return err; return err;
}
if (!w)
debug_printf ("pipe write handle NULL");
else
{
debug_printf ("CreateFile: name %s", pipename); debug_printf ("CreateFile: name %s", pipename);
/* Open the named pipe for writing. /* Open the named pipe for writing.
Be sure to permit FILE_READ_ATTRIBUTES access. */ Be sure to permit FILE_READ_ATTRIBUTES access. */
w = CreateFile (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, sa_ptr, DWORD access = GENERIC_WRITE | FILE_READ_ATTRIBUTES;
OPEN_EXISTING, overlapped, 0); if ((open_mode & PIPE_ACCESS_DUPLEX) == PIPE_ACCESS_DUPLEX)
access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
*w = CreateFile (pipename, access, 0, sa_ptr, OPEN_EXISTING,
open_mode & FILE_FLAG_OVERLAPPED, 0);
if (!w || w == INVALID_HANDLE_VALUE) if (!*w || *w == INVALID_HANDLE_VALUE)
{ {
/* Failure. */ /* Failure. */
DWORD err = GetLastError (); DWORD err = GetLastError ();
debug_printf ("CreateFile failed, %E"); debug_printf ("CreateFile failed, %E");
CloseHandle (r); if (r)
CloseHandle (*r);
*w = NULL;
return err; return err;
} }
debug_printf ("pipe write handle %p", w); debug_printf ("pipe write handle %p", *w);
}
/* Success. */ /* Success. */
return 0; return 0;
@ -310,7 +327,7 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode)
SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode);
int res = -1; int res = -1;
int ret = create_selectable (sa, r, w, psize); int ret = create_selectable (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED);
if (ret) if (ret)
__seterrno_from_win_error (ret); __seterrno_from_win_error (ret);
else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL)

View File

@ -159,8 +159,8 @@ tty::not_allocated (HANDLE& r, HANDLE& w)
char pipename[sizeof("ptyNNNN-from-master")]; char pipename[sizeof("ptyNNNN-from-master")];
__small_sprintf (pipename, "pty%d-from-master", get_unit ()); __small_sprintf (pipename, "pty%d-from-master", get_unit ());
/* fhandler_pipe::create_selectable returns 0 when creation succeeds */ /* fhandler_pipe::create_selectable returns 0 when creation succeeds */
return fhandler_pipe::create_selectable (&sec_none, r, w, 128 * 1024, return fhandler_pipe::create_selectable (&sec_none, &r, &w, 128 * 1024,
pipename) == 0; pipename, 0) == 0;
} }
bool bool