Preliminary change to make fifos/pipes interruptible and fifos reliable.

* dtable.cc (dtable::find_fifo): Eliminate definition.
* dtable.h (dtable::find_fifo): Ditto for declaration.
* fhandler.cc (fhandler_base::raw_read): Remove pipe-specific stuff.
(fhandler_base::fhandler_base): Ditto.
(fhandler_base::close): Handle overlapped I/O structure if appropriate.
(fhandler_base::dup): Ditto.
(fhandler_base::fork_fixup): Ditto.
(fhandler_base::setup_overlapped): Define new function.
(fhandler_base::destroy_overlapped): Ditto.
(fhandler_base::wait_overlapped): Ditto.
(fhandler_base::read_overlapped): Ditto.
(fhandler_base::write_overlapped): Ditto.
* fhandler.h (fhandler_base::get_overlapped): Declare new function.
(fhandler_base::setup_overlapped): Ditto.
(fhandler_base::destroy_overlapped): Ditto.
(fhandler_base::wait_overlapped): Ditto.
(fhandler_base::read_overlapped): Ditto.
(fhandler_base::write_overlapped): Ditto.
(fhandler_base::get_guard): Eliminate.
(fhandler_pipe::*): Rework to eliminate most Win9x related cruft, removing many
variables and defining a new overlapped capability.
(fhandler_fifo::*): Ditto.
(fifo_state): Declare new enum.
* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove old Win9x stuff.
Initialize overlapped handle to NULL.
(fhandler_fifo::set_use): Eliminate.
(fhandler_fifo::open_nonserver): Define.
(fhandler_fifo::open): Rework to use named pipes and overlapped I/O.
(fhandler_fifo::wait): Define new function to wait for named pipe connection.
(fhandler_fifo::read): Rework to use wait() and new overlapped I/O
functionality.
(fhandler_fifo::write): Ditto.
(fhandler_fifo::dup): Eliminate.
* pinfo.cc (commune_process): Remove fifo handling.
(_pinfo::commune_request): Ditto.
* pinfo.h (picom): Ditto.
* pipe.cc (fhandler_pipe::fhandler_pipe): Remove Win9x stuff.  Initialize
overlapped handle to NULL.
(fhandler_pipe::open): Eliminate Win9x stuff.
(fhandler_pipe::set_close_on_exec): Eliminate.
(read_pipe): Eliminate.
(fhandler_pipe::close): Ditto.
(fhandler_pipe::fixup_after_exec): Ditto.
(fhandler_pipe::fixup_in_child): Ditto.
(fhandler_pipe::read): Rework to use overlapped I/O.
(fhandler_pipe::write): New function using overlapped I/O.
(fhandler_pipe::dup): Rework to eliminate Win9x stuff.
(fhandler_pipe::create_selectable): Rework to eliminate Win9x and use
overlapped I/O.
* select.cc (peek_pipe): Rework to eliminate Win9x stuff and use overlapped
I/O.
(fhandler_base::ready_for_read): Ditto.
This commit is contained in:
Christopher Faylor 2007-07-07 17:00:33 +00:00
parent dee5588839
commit d9c0e3ec35
10 changed files with 308 additions and 507 deletions

View File

@ -1,3 +1,60 @@
2007-07-07 Christopher Faylor <me+cygwin@cgf.cx>
Preliminary change to make pipes interruptible and fifos reliable.
* dtable.cc (dtable::find_fifo): Eliminate definition.
* dtable.h (dtable::find_fifo): Ditto for declaration.
* fhandler.cc (fhandler_base::raw_read): Remove pipe-specific stuff.
(fhandler_base::fhandler_base): Ditto.
(fhandler_base::close): Handle overlapped I/O structure if appropriate.
(fhandler_base::dup): Ditto.
(fhandler_base::fork_fixup): Ditto.
(fhandler_base::setup_overlapped): Define new function.
(fhandler_base::destroy_overlapped): Ditto.
(fhandler_base::wait_overlapped): Ditto.
(fhandler_base::read_overlapped): Ditto.
(fhandler_base::write_overlapped): Ditto.
* fhandler.h (fhandler_base::get_overlapped): Declare new function.
(fhandler_base::setup_overlapped): Ditto.
(fhandler_base::destroy_overlapped): Ditto.
(fhandler_base::wait_overlapped): Ditto.
(fhandler_base::read_overlapped): Ditto.
(fhandler_base::write_overlapped): Ditto.
(fhandler_base::get_guard): Eliminate.
(fhandler_pipe::*): Rework to eliminate most Win9x related cruft,
removing many variables and defining a new overlapped capability.
(fhandler_fifo::*): Ditto.
(fifo_state): Declare new enum.
* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove old Win9x
stuff. Initialize overlapped handle to NULL.
(fhandler_fifo::set_use): Eliminate.
(fhandler_fifo::open_nonserver): Define.
(fhandler_fifo::open): Rework to use named pipes and overlapped I/O.
(fhandler_fifo::wait): Define new function to wait for named pipe
connection.
(fhandler_fifo::read): Rework to use wait() and new overlapped I/O
functionality.
(fhandler_fifo::write): Ditto.
(fhandler_fifo::dup): Eliminate.
* pinfo.cc (commune_process): Remove fifo handling.
(_pinfo::commune_request): Ditto.
* pinfo.h (picom): Ditto.
* pipe.cc (fhandler_pipe::fhandler_pipe): Remove Win9x stuff.
Initialize overlapped handle to NULL.
(fhandler_pipe::open): Eliminate Win9x stuff.
(fhandler_pipe::set_close_on_exec): Eliminate.
(read_pipe): Eliminate.
(fhandler_pipe::close): Ditto.
(fhandler_pipe::fixup_after_exec): Ditto.
(fhandler_pipe::fixup_in_child): Ditto.
(fhandler_pipe::read): Rework to use overlapped I/O.
(fhandler_pipe::write): New function using overlapped I/O.
(fhandler_pipe::dup): Rework to eliminate Win9x stuff.
(fhandler_pipe::create_selectable): Rework to eliminate Win9x and use
overlapped I/O.
* select.cc (peek_pipe): Rework to eliminate Win9x stuff and use
overlapped I/O.
(fhandler_base::ready_for_read): Ditto.
2007-07-07 Christopher Faylor <me+cygwin@cgf.cx>
* path.cc (symlink_info::check_shortcut): Handle device "symlinks"
@ -12,7 +69,7 @@
2007-07-07 Christopher Faylor <me+cygwin@cgf.cx>
* fork.cc: White space.
* net.cc: Ditto.
* net.cc: Ditto.
* posix_ipc.cc: Ditto.
2007-07-06 Corinna Vinschen <corinna@vinschen.de>

View File

@ -580,24 +580,6 @@ done:
return res;
}
fhandler_fifo *
dtable::find_fifo (const char *path)
{
lock ();
fhandler_fifo *fh_res = NULL;
for (unsigned i = 0; i < size; i++)
{
fhandler_base *fh = fds[i];
if (fh && fh->isfifo () && strcmp (path, fh->get_win32_name ()) == 0)
{
fh_res = (fhandler_fifo *) fh;
break;
}
}
unlock ();
return fh_res;
}
select_record *
dtable::select_read (int fd, select_record *s)
{

View File

@ -15,7 +15,6 @@ details. */
#include "sync.h"
class suffix_info;
class fhandler_fifo;
#define BFH_OPTS (PC_NULLEMPTY | PC_FULL | PC_POSIX)
class dtable
@ -78,7 +77,6 @@ public:
#ifdef NEWVFORK
bool in_vfork_cleanup () {return fds_on_hold == fds;}
#endif
fhandler_fifo *find_fifo (const char *);
fhandler_base *find_archetype (device& dev);
fhandler_base **add_archetype ();
void delete_archetype (fhandler_base *);

View File

@ -32,6 +32,8 @@ details. */
#include <winioctl.h>
#include <ntdef.h>
#include "ntdll.h"
#include "cygtls.h"
#include "sigproc.h"
static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
@ -222,26 +224,12 @@ fhandler_base::raw_read (void *ptr, size_t& ulen)
{
#define bytes_read ulen
HANDLE h = NULL; /* grumble */
int prio = 0; /* ditto */
int try_noreserve = 1;
DWORD len = ulen;
retry:
ulen = (size_t) -1;
if (read_state)
{
h = GetCurrentThread ();
prio = GetThreadPriority (h);
SetThreadPriority (h, THREAD_PRIORITY_TIME_CRITICAL);
signal_read_state (1);
}
BOOL res = ReadFile (get_handle (), ptr, len, (DWORD *) &ulen, 0);
if (read_state)
{
signal_read_state (1);
SetThreadPriority (h, prio);
}
BOOL res = ReadFile (get_handle (), ptr, len, (DWORD *) &ulen, NULL);
if (!res)
{
/* Some errors are not really errors. Detect such cases here. */
@ -713,7 +701,7 @@ fhandler_base::write (const void *ptr, size_t len)
LONG off_high = 0;
DWORD ret = SetFilePointer (get_output_handle (), 0, &off_high, FILE_END);
if (ret == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
{
{
debug_printf ("Seeking to EOF in append mode failed");
__seterrno ();
return -1;
@ -996,6 +984,7 @@ fhandler_base::close ()
__seterrno ();
}
destroy_overlapped ();
return res;
}
@ -1201,6 +1190,8 @@ fhandler_base::dup (fhandler_base *child)
VerifyHandle (nh);
child->set_io_handle (nh);
}
if (get_overlapped ())
child->setup_overlapped ();
set_flags (child->get_flags ());
return 0;
}
@ -1332,7 +1323,6 @@ fhandler_base::fhandler_base () :
raixput (0),
rabuflen (0),
fs_flags (0),
read_state (NULL),
archetype (NULL),
usecount (0)
{
@ -1381,6 +1371,8 @@ fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name)
VerifyHandle (h);
res = true;
}
if (get_overlapped ())
setup_overlapped ();
return res;
}
@ -1399,12 +1391,16 @@ fhandler_base::fixup_after_fork (HANDLE parent)
debug_printf ("inheriting '%s' from parent", get_name ());
if (!nohandle ())
fork_fixup (parent, io_handle, "io_handle");
if (get_overlapped ())
setup_overlapped ();
}
void
fhandler_base::fixup_after_exec ()
{
debug_printf ("here for '%s'", get_name ());
if (get_overlapped ())
setup_overlapped ();
}
bool
@ -1678,3 +1674,86 @@ fhandler_base::fpathconf (int v)
}
return -1;
}
/* Overlapped I/O */
bool
fhandler_base::setup_overlapped ()
{
OVERLAPPED *ov = get_overlapped ();
memset (ov, 0, sizeof (*ov));
return ov->hEvent = CreateEvent (&sec_none_nih, true, false, NULL);
}
void
fhandler_base::destroy_overlapped ()
{
OVERLAPPED *ov = get_overlapped ();
if (ov && ov->hEvent)
{
CloseHandle (ov->hEvent);
ov->hEvent = NULL;
}
}
bool
fhandler_base::wait_overlapped (bool& res, bool writing)
{
if (!res && GetLastError () != ERROR_IO_PENDING)
__seterrno ();
else
{
#ifdef DEBUGGING
if (!get_overlapped ())
system_printf ("get_overlapped is zero?");
if (!get_overlapped ()->hEvent)
system_printf ("hEvent is zero?");
#endif
DWORD n = 1;
HANDLE w4[2];
w4[0] = get_overlapped ()->hEvent;
if (&_my_tls == _main_tls)
w4[n++] = signal_arrived;
switch (WaitForMultipleObjects (n, w4, false, INFINITE))
{
case WAIT_OBJECT_0:
res = true;
break;
case WAIT_OBJECT_0 + 1:
CancelIo (writing ? get_output_handle () : get_handle ());
set_errno (EINTR);
res = false;
break;
}
}
ResetEvent (get_overlapped ()->hEvent);
return res;
}
void
fhandler_base::read_overlapped (void *ptr, size_t& len)
{
#ifdef DEBUGGING
assert (get_overlapped ());
assert (get_overlapped ()->hEvent);
#endif
bool res = ReadFile (get_handle (), ptr, len, (DWORD *) &len,
get_overlapped ());
if (!wait_overlapped (res, false)
|| !GetOverlappedResult (get_handle (), get_overlapped (), (DWORD *) &len, false))
len = 0;
}
int
fhandler_base::write_overlapped (const void *ptr, size_t len)
{
DWORD bytes_written;
bool res = WriteFile (get_output_handle (), ptr, len, &bytes_written,
get_overlapped ());
if (!wait_overlapped (res, true)
|| !GetOverlappedResult (get_handle (), get_overlapped (),
&bytes_written, false))
return -1;
return bytes_written;
}

View File

@ -141,6 +141,9 @@ class fhandler_base
DWORD fs_flags;
HANDLE read_state;
path_conv pc;
bool wait_overlapped (bool&, bool) __attribute__ ((regparm (2)));
bool setup_overlapped () __attribute__ ((regparm (1)));
void destroy_overlapped () __attribute__ ((regparm (1)));
public:
class fhandler_base *archetype;
@ -294,7 +297,9 @@ class fhandler_base
virtual int fcntl (int cmd, void *);
virtual char const *ttyname () { return get_name (); }
virtual void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
virtual int write (const void *ptr, size_t len);
virtual void __stdcall read_overlapped (void *ptr, size_t& len) __attribute__ ((regparm (3)));
virtual int __stdcall write (const void *ptr, size_t len);
virtual int __stdcall write_overlapped (const void *ptr, size_t len);
virtual ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
virtual ssize_t __stdcall pread (void *, size_t, _off64_t) __attribute__ ((regparm (3)));
@ -334,6 +339,7 @@ class fhandler_base
virtual void raw_read (void *ptr, size_t& ulen);
virtual int raw_write (const void *ptr, size_t ulen);
virtual OVERLAPPED *get_overlapped () {return NULL;}
/* Virtual accessor functions to hide the fact
that some fd's have two handles. */
@ -356,7 +362,6 @@ class fhandler_base
rabuf = NULL;
}
void operator delete (void *);
virtual HANDLE get_guard () const {return NULL;}
virtual void set_eof () {}
virtual int mkdir (mode_t mode);
virtual int rmdir ();
@ -372,7 +377,6 @@ class fhandler_base
bool issymlink () {return pc.issymlink ();}
bool device_access_denied (int) __attribute__ ((regparm (2)));
int fhaccess (int flags) __attribute__ ((regparm (2)));
friend class fhandler_fifo;
};
class fhandler_mailslot : public fhandler_base
@ -521,13 +525,12 @@ class fhandler_socket: public fhandler_base
class fhandler_pipe: public fhandler_base
{
protected:
HANDLE guard;
bool broken_pipe;
private:
pid_t popen_pid;
OVERLAPPED io_status;
public:
fhandler_pipe ();
OVERLAPPED *get_overlapped () {return &io_status;}
void set_popen_pid (pid_t pid) {popen_pid = pid;}
pid_t get_popen_pid () const {return popen_pid;}
_off64_t lseek (_off64_t offset, int whence);
@ -535,53 +538,40 @@ public:
select_record *select_write (select_record *s);
select_record *select_except (select_record *s);
char *get_proc_fd_name (char *buf);
void set_close_on_exec (bool val);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
int __stdcall write (const void *, size_t);
int open (int flags, mode_t mode = 0);
int close ();
void create_guard (SECURITY_ATTRIBUTES *sa)
{
guard = CreateMutex (sa, FALSE, NULL);
ProtectHandleINH (guard);
}
int dup (fhandler_base *child);
int ioctl (unsigned int cmd, void *);
int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2)));
int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3)));
int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3)));
void fixup_in_child ();
virtual void fixup_after_fork (HANDLE);
void fixup_after_exec ();
bool hit_eof () {return broken_pipe;}
void set_eof () {broken_pipe = true;}
HANDLE get_guard () const {return guard;}
int ready_for_read (int fd, DWORD howlong);
static int create (fhandler_pipe *[2], unsigned, int, bool = false);
bool is_slow () {return true;}
static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD, bool);
friend class fhandler_fifo;
};
class fhandler_fifo: public fhandler_pipe
enum fifo_state
{
HANDLE output_handle;
long read_use;
long write_use;
virtual HANDLE& get_io_handle () { return io_handle ?: output_handle; }
fifo_unknown,
fifo_wait_for_client,
fifo_wait_for_server,
fifo_ok
};
class fhandler_fifo: public fhandler_base
{
fifo_state wait_state;
HANDLE open_nonserver (const char *, unsigned, LPSECURITY_ATTRIBUTES);
OVERLAPPED io_status;
bool wait (bool) __attribute__ ((regparm (1)));
public:
fhandler_fifo ();
int open (int flags, mode_t mode = 0);
int open_not_mine (int flags) __attribute__ ((regparm (2)));
int close ();
void set_use (int flags) __attribute__ ((regparm (2)));
void __stdcall read (void *, size_t&) __attribute__ ((regparm (3)));
int __stdcall write (const void *, size_t);
int open (int, mode_t);
bool isfifo () { return true; }
HANDLE& get_output_handle () { return output_handle; }
void set_output_handle (HANDLE h) { output_handle = h; }
void set_use ();
int dup (fhandler_base *child);
int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2)));
bool is_slow () {return true;}
void close_one_end ();
OVERLAPPED *get_overlapped () {return &io_status;}
};
class fhandler_dev_raw: public fhandler_base

View File

@ -22,223 +22,143 @@
#include "dtable.h"
#include "cygheap.h"
#include "pinfo.h"
#include "sigproc.h"
#include "cygtls.h"
fhandler_fifo::fhandler_fifo ()
: fhandler_pipe (), output_handle (NULL),
read_use (0), write_use (0)
fhandler_fifo::fhandler_fifo ():
wait_state (fifo_unknown)
{
get_overlapped ()->hEvent = NULL;
need_fork_fixup (true);
}
void
fhandler_fifo::set_use (int incr)
HANDLE
fhandler_fifo::open_nonserver (const char *npname, unsigned low_flags,
LPSECURITY_ATTRIBUTES sa_buf)
{
long oread_use = read_use;
if (get_flags () & (O_WRONLY | O_APPEND))
write_use += incr;
else if (get_flags () & O_RDWR)
{
write_use += incr;
read_use += incr;
}
DWORD mode = 0;
if (low_flags == O_RDONLY)
mode = GENERIC_READ;
else if (low_flags = O_WRONLY)
mode = GENERIC_WRITE;
else
read_use += incr;
if (incr >= 0)
return;
if (read_use <= 0 && oread_use != read_use)
mode = GENERIC_READ | GENERIC_WRITE;
while (1)
{
HANDLE h = get_handle ();
if (h)
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 (&_my_tls != _main_tls)
low_priority_sleep (0);
else if (WaitForSingleObject (signal_arrived, 0) == WAIT_OBJECT_0)
{
set_io_handle (NULL);
CloseHandle (h);
set_errno (EINTR);
return NULL;
}
}
}
int
fhandler_fifo::close ()
{
fhandler_pipe::close ();
if (get_output_handle ())
CloseHandle (get_output_handle ());
if (!hExeced)
set_use (-1);
return 0;
}
#define DUMMY_O_RDONLY 4
void
fhandler_fifo::close_one_end ()
{
int testflags = (get_flags () & (O_RDWR | O_WRONLY | O_APPEND)) ?: DUMMY_O_RDONLY;
static int flagtypes[] = {DUMMY_O_RDONLY | O_RDWR, O_WRONLY | O_APPEND | O_RDWR};
HANDLE *handles[2] = {&(get_handle ()), &(get_output_handle ())};
for (int i = 0; i < 2; i++)
if (!(testflags & flagtypes[i]))
{
CloseHandle (*handles[i]);
*handles[i] = NULL;
}
else if (i == 0 && !read_state)
{
create_read_state (2);
need_fork_fixup (true);
}
}
int
fhandler_fifo::open_not_mine (int flags)
{
winpids pids ((DWORD) 0);
int res = 0;
for (unsigned i = 0; i < pids.npids; i++)
{
_pinfo *p = pids[i];
commune_result r;
if (p->pid != myself->pid)
{
r = p->commune_request (PICOM_FIFO, get_win32_name ());
if (r.handles[0] == NULL)
continue; // process doesn't own fifo
debug_printf ("pid %d, handles[0] %p, handles[1] %p", p->pid,
r.handles[0], r.handles[1]);
}
else
{
/* FIXME: racy? */
fhandler_fifo *fh = cygheap->fdtab.find_fifo (get_win32_name ());
if (!fh)
continue;
if (!DuplicateHandle (hMainProc, fh->get_handle (), hMainProc,
&r.handles[0], 0, false, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
goto out;
}
if (!DuplicateHandle (hMainProc, fh->get_output_handle (), hMainProc,
&r.handles[1], 0, false, DUPLICATE_SAME_ACCESS))
{
CloseHandle (r.handles[0]);
__seterrno ();
goto out;
}
}
set_io_handle (r.handles[0]);
set_output_handle (r.handles[1]);
set_flags (flags);
close_one_end ();
res = 1;
goto out;
}
set_errno (EAGAIN);
out:
debug_printf ("res %d", res);
return res;
}
#define FIFO_PREFIX "_cygfifo_"
#define FIFO_PIPE_MODE (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE)
int
fhandler_fifo::open (int flags, mode_t)
{
int res = 1;
char mutex[CYG_MAX_PATH];
char *emutex = mutex + CYG_MAX_PATH;
char *p, *p1;
DWORD resw;
int res;
char npname[CYG_MAX_PATH];
DWORD mode = 0;
/* Generate a semi-unique name to associate with this fifo but try to ensure
that it is no larger than CYG_MAX_PATH */
strcpy (mutex, cygheap->shared_prefix);
for (p = mutex + strlen (mutex), p1 = strchr (get_name (), '\0');
--p1 >= get_name () && p < emutex ; p++)
*p = (*p1 == '/') ? '_' : *p1;
strncpy (p, FIFO_PREFIX, emutex - p);
mutex[CYG_MAX_PATH - 1] = '\0';
/* Generate a semi-unique name to associate with this fifo.
FIXME: Probably should use "inode" and "dev" from stat for this. */
__small_sprintf (npname, "\\\\.\\pipe\\__cygfifo__%lx", get_namehash ());
/* Create a mutex lock access to this fifo to prevent a race by two processes
trying to figure out if they own the fifo or if they should create it. */
HANDLE h = CreateMutex (&sec_none_nih, false, mutex);
if (!h)
unsigned low_flags = flags & O_ACCMODE;
if (low_flags == O_RDONLY)
mode = PIPE_ACCESS_INBOUND;
else if (low_flags == O_WRONLY)
mode = PIPE_ACCESS_OUTBOUND;
else if (low_flags == O_RDWR)
mode = PIPE_ACCESS_DUPLEX;
if (!mode)
{
__seterrno ();
system_printf ("couldn't open fifo mutex '%s', %E", mutex);
res = 0;
goto out;
}
lock_process::locker.release (); /* Since we may be a while, release the
process lock that is held when we
open an fd. */
/* FIXME? Need to wait for signal here?
This shouldn't block for long, but... */
resw = WaitForSingleObject (h, INFINITE);
lock_process::locker.acquire (); /* Restore the lock */
if (resw != WAIT_OBJECT_0 && resw != WAIT_ABANDONED_0)
{
__seterrno ();
system_printf ("Wait for fifo mutex '%s' failed, %E", mutex);
goto out;
}
set_io_handle (NULL);
set_output_handle (NULL);
if (open_not_mine (flags))
goto out;
fhandler_pipe *fhs[2];
if (create (fhs, 1, flags, true))
{
__seterrno ();
set_errno (EINVAL);
res = 0;
}
else
{
set_flags (flags);
set_io_handle (fhs[0]->get_handle ());
set_output_handle (fhs[1]->get_handle ());
guard = fhs[0]->guard;
read_state = fhs[0]->read_state;
delete (fhs[0]);
delete (fhs[1]);
set_use (1);
need_fork_fixup (true);
char char_sa_buf[1024];
LPSECURITY_ATTRIBUTES sa_buf =
sec_user ((PSECURITY_ATTRIBUTES) char_sa_buf, cygheap->user.sid());
mode |= FILE_FLAG_OVERLAPPED;
HANDLE h = CreateNamedPipe(npname, mode, FIFO_PIPE_MODE,
PIPE_UNLIMITED_INSTANCES, 0, 0,
NMPWAIT_WAIT_FOREVER, sa_buf);
if (h != INVALID_HANDLE_VALUE)
wait_state = fifo_wait_for_client;
else
switch (GetLastError ())
{
case ERROR_ACCESS_DENIED:
h = open_nonserver (npname, low_flags, sa_buf);
if (h != INVALID_HANDLE_VALUE)
{
wait_state = fifo_wait_for_server;
break;
}
/* fall through intentionally */
default:
__seterrno ();
break;
}
if (!h || h == INVALID_HANDLE_VALUE)
res = 0;
else if (!setup_overlapped ())
{
__seterrno ();
res = 0;
}
else
{
set_io_handle (h);
set_flags (flags);
res = 1;
}
}
out:
if (h)
{
ReleaseMutex (h);
CloseHandle (h);
}
debug_printf ("returning %d, errno %d", res, get_errno ());
return res;
}
int
fhandler_fifo::dup (fhandler_base *child)
bool
fhandler_fifo::wait (bool iswrite)
{
int res = fhandler_pipe::dup (child);
if (!res)
switch (wait_state)
{
fhandler_fifo *ff = (fhandler_fifo *) child;
if (get_output_handle ()
&& !DuplicateHandle (hMainProc, get_output_handle (), hMainProc,
&ff->get_output_handle (), false, true,
DUPLICATE_SAME_ACCESS))
{
__seterrno ();
child->close ();
res = -1;
}
case fifo_wait_for_client:
bool res = ConnectNamedPipe (get_handle (), get_overlapped ());
if (res || GetLastError () == ERROR_PIPE_CONNECTED)
return true;
return wait_overlapped (res, iswrite);
default:
break;
}
return res;
return true;
}
void
fhandler_fifo::read (void *in_ptr, size_t& len)
{
if (!wait (false))
len = 0;
else
read_overlapped (in_ptr, len);
}
int
fhandler_fifo::write (const void *ptr, size_t len)
{
return wait (true) ? write_overlapped (ptr, len) : -1;
}
int __stdcall

View File

@ -517,31 +517,6 @@ commune_process (void *arg)
sigproc_printf ("WriteFile fd failed, %E");
break;
}
case PICOM_FIFO:
{
sigproc_printf ("processing PICOM_FIFO for %s", si._si_commune._si_str);
fhandler_fifo *fh = cygheap->fdtab.find_fifo (si._si_commune._si_str);
HANDLE it[2];
if (fh == NULL)
it[0] = it[1] = NULL;
else
{
it[0] = fh->get_handle ();
it[1] = fh->get_output_handle ();
}
debug_printf ("fifo %sfound %p, %p", fh ? "" : "not ", it[0], it[1]);
if (!WriteFile (tothem, it, sizeof (it), &nr, NULL))
{
/*__seterrno ();*/ // this is run from the signal thread, so don't set errno
sigproc_printf ("WriteFile read handle failed, %E");
}
WaitForSingleObject (process_sync, INFINITE);
process_sync = NULL;
if (fh)
fh->close_one_end ();
break;
}
}
if (process_sync)
{
@ -591,8 +566,6 @@ _pinfo::commune_request (__uint32_t code, ...)
si._si_commune._si_fd = va_arg (args, int);
break;
case PICOM_FIFO:
si._si_commune._si_str = va_arg (args, char *);
break;
}
@ -642,26 +615,6 @@ _pinfo::commune_request (__uint32_t code, ...)
res.n = p - res.s;
}
break;
case PICOM_FIFO:
{
lock_process now ();
DWORD x = ReadFile (fromthem, res.handles, sizeof (res.handles), &nr, NULL);
if (!x || nr != sizeof (res.handles))
{
__seterrno ();
goto err;
}
for (int i = 0; i < 2; i++)
if (!DuplicateHandle (hp, res.handles[i], hMainProc, &res.handles[i],
0, false, DUPLICATE_SAME_ACCESS))
{
if (i)
CloseHandle (res.handles[0]);
res.handles[0] = res.handles[1] = NULL; /* FIXME: possibly left a handle open in child? */
goto err;
}
break;
}
}
goto out;

View File

@ -24,12 +24,11 @@ enum picom
{
PICOM_EXTRASTR = 0x80000000,
PICOM_CMDLINE = 1,
PICOM_FIFO = PICOM_EXTRASTR | 2,
PICOM_CWD = 3,
PICOM_ROOT = 4,
PICOM_FDS = 5,
PICOM_FD = 6,
PICOM_PIPE_FHANDLER = 7
PICOM_CWD = 2,
PICOM_ROOT = 3,
PICOM_FDS = 4,
PICOM_FD = 5,
PICOM_PIPE_FHANDLER = 6
};
#define EXITCODE_SET 0x8000000

View File

@ -28,8 +28,9 @@ details. */
#include "ntdll.h"
fhandler_pipe::fhandler_pipe ()
: fhandler_base (), guard (NULL), broken_pipe (false), popen_pid (0)
: fhandler_base (), popen_pid (0)
{
get_overlapped ()->hEvent = NULL;
need_fork_fixup (true);
}
@ -97,18 +98,6 @@ fhandler_pipe::open (int flags, mode_t mode)
__seterrno ();
goto out;
}
if (!fh->guard)
/* nothing to do */;
else if (DuplicateHandle (proc, fh->guard, hMainProc, &guard,
0, inh, DUPLICATE_SAME_ACCESS))
ProtectHandle (guard);
else
{
__seterrno ();
goto out;
}
if (fh->read_state)
create_read_state (2);
init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY);
if (flags & O_NOINHERIT)
close_on_exec (true);
@ -117,8 +106,6 @@ fhandler_pipe::open (int flags, mode_t mode)
CloseHandle (proc);
return 1;
out:
if (guard)
CloseHandle (guard);
if (nio_hdl)
CloseHandle (nio_hdl);
if (fh)
@ -150,17 +137,6 @@ fhandler_pipe::ftruncate (_off64_t length, bool allow_truncate)
return -1;
}
void
fhandler_pipe::set_close_on_exec (bool val)
{
fhandler_base::set_close_on_exec (val);
if (guard)
{
set_no_inheritance (guard, val);
ModifyHandle (guard, !val);
}
}
char *
fhandler_pipe::get_proc_fd_name (char *buf)
{
@ -168,120 +144,30 @@ fhandler_pipe::get_proc_fd_name (char *buf)
return buf;
}
struct pipeargs
{
fhandler_base *fh;
void *ptr;
size_t *len;
};
static DWORD WINAPI
read_pipe (void *arg)
{
pipeargs *pi = (pipeargs *) arg;
pi->fh->fhandler_base::read (pi->ptr, *pi->len);
return 0;
}
void __stdcall
fhandler_pipe::read (void *in_ptr, size_t& in_len)
{
if (broken_pipe)
in_len = 0;
else
{
pipeargs pi = {dynamic_cast<fhandler_base *>(this), in_ptr, &in_len};
cygthread *th = new cygthread (read_pipe, 0, &pi, "read_pipe");
if (th->detach (read_state) && !in_len)
in_len = (size_t) -1; /* received a signal */
}
ReleaseMutex (guard);
return read_overlapped (in_ptr, in_len);
}
int
fhandler_pipe::close ()
fhandler_pipe::write (const void *ptr, size_t len)
{
if (guard)
ForceCloseHandle (guard);
#ifndef NEWVFORK
if (read_state)
#else
// FIXME is this vfork_cleanup test right? Is it responsible for some of
// the strange pipe behavior that has been reported in the cygwin mailing
// list?
if (read_state && !cygheap->fdtab.in_vfork_cleanup ())
#endif
ForceCloseHandle (read_state);
return fhandler_base::close ();
}
void
fhandler_pipe::fixup_in_child ()
{
if (read_state)
create_read_state (2);
}
void
fhandler_pipe::fixup_after_exec ()
{
if (!close_on_exec ())
fixup_in_child ();
}
void
fhandler_pipe::fixup_after_fork (HANDLE parent)
{
fhandler_base::fixup_after_fork (parent);
if (guard && fork_fixup (parent, guard, "guard"))
ProtectHandle (guard);
fixup_in_child ();
return write_overlapped (ptr, len);
}
int
fhandler_pipe::dup (fhandler_base *child)
{
int res = -1;
fhandler_pipe *ftp = (fhandler_pipe *) child;
ftp->set_popen_pid (0);
ftp->guard = ftp->read_state = NULL;
int res;
if (get_handle () && fhandler_base::dup (child))
goto err;
if (!guard)
/* nothing to do */;
else if (DuplicateHandle (hMainProc, guard, hMainProc, &ftp->guard, 0, true,
DUPLICATE_SAME_ACCESS))
ProtectHandle1 (ftp->guard, guard);
res = -1;
else
{
debug_printf ("couldn't duplicate guard %p, %E", guard);
goto err;
}
res = 0;
if (!read_state)
/* nothing to do */;
else if (DuplicateHandle (hMainProc, read_state, hMainProc,
&ftp->read_state, 0, false,
DUPLICATE_SAME_ACCESS))
ProtectHandle1 (ftp->read_state, read_state);
else
{
debug_printf ("couldn't duplicate read_state %p, %E", read_state);
goto err;
}
res = 0;
goto out;
err:
if (ftp->guard)
ForceCloseHandle1 (ftp->guard, guard);
if (ftp->read_state)
ForceCloseHandle1 (ftp->read_state, read_state);
out:
debug_printf ("res %d", res);
return res;
}
@ -327,7 +213,7 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
the pipe was not created earlier by some other process, even if
the pid has been reused. We avoid FILE_FLAG_FIRST_PIPE_INSTANCE
because that is only available for Win2k SP2 and WinXP. */
r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND,
r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, psize,
psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
@ -352,19 +238,11 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
debug_printf ("pipe access denied, retrying");
break;
default:
/* CreateNamePipe failed. Maybe we are on an older Win9x platform without
named pipes. Return an anonymous pipe as the best approximation. */
debug_printf ("CreateNamedPipe failed, resorting to CreatePipe size %lu",
psize);
if (CreatePipe (&r, &w, sa_ptr, psize))
{
debug_printf ("pipe read handle %p", r);
debug_printf ("pipe write handle %p", w);
return 0;
}
err = GetLastError ();
debug_printf ("CreatePipe failed, %E");
return err;
{
err = GetLastError ();
debug_printf ("CreatePipe failed, %E");
return err;
}
}
}
@ -373,7 +251,7 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r,
/* Open the named pipe for writing.
Be sure to permit FILE_READ_ATTRIBUTES access. */
w = CreateFile (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, sa_ptr,
OPEN_EXISTING, 0, 0);
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (!w || w == INVALID_HANDLE_VALUE)
{
@ -414,10 +292,9 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode, bool fif
fhs[1]->close_on_exec (true);
}
fhs[0]->create_read_state (2);
fhs[0]->setup_overlapped ();
fhs[1]->setup_overlapped ();
res = 0;
fhs[0]->create_guard (sa);
}
syscall_printf ("%d = pipe ([%p, %p], %d, %p)", res, fhs[0], fhs[1], psize, mode);

View File

@ -429,15 +429,6 @@ peek_pipe (select_record *s, bool from_select)
HANDLE h;
set_handle_or_return_if_not_open (h, s);
/* pipes require a guard mutex to guard against the situation where multiple
readers are attempting to read from the same pipe. In this scenario, it
is possible for PeekNamedPipe to report available data to two readers but
only one will actually get the data. This will result in the other reader
entering fhandler_base::raw_read and blocking indefinitely in an interruptible
state. This causes things like "make -j2" to hang. So, for the non-select case
we use the pipe mutex, if it is available. */
HANDLE guard_mutex = from_select ? NULL : fh->get_guard ();
/* Don't perform complicated tests if we don't need to. */
if (!s->read_selected && !s->except_selected)
goto out;
@ -484,30 +475,9 @@ peek_pipe (select_record *s, bool from_select)
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
n = -1;
}
else if (!n || !guard_mutex)
/* no guard mutex or nothing to read from the pipe. */;
else if (WaitForSingleObject (guard_mutex, 0) != WAIT_OBJECT_0)
{
select_printf ("%s, couldn't get mutex %p, %E", fh->get_name (),
guard_mutex);
n = 0;
}
else
{
/* Now that we have the mutex, make sure that no one else has snuck
in and grabbed the data that we originally saw. */
if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL))
{
select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ());
n = -1;
}
if (n <= 0)
ReleaseMutex (guard_mutex); /* Oops. We lost the race. */
}
if (n < 0)
{
fh->set_eof (); /* Flag that other end of pipe is gone */
select_printf ("%s, n %d", fh->get_name (), n);
if (s->except_selected)
gotone += s->except_ready = true;
@ -546,10 +516,6 @@ out:
/* FIXME: This code is not quite correct. There's no better solution
so far but to always treat the write side of the pipe as writable. */
/* We don't worry about the guard mutex, because that only applies
when from_select is false, and peek_pipe is never called that
way for writes. */
IO_STATUS_BLOCK iosb = {0};
FILE_PIPE_LOCAL_INFORMATION fpli = {0};
@ -685,25 +651,8 @@ fhandler_pipe::ready_for_read (int fd, DWORD howlong)
int res;
if (!howlong)
res = fhandler_base::ready_for_read (fd, howlong);
else if (!get_guard ())
res = 1;
else
{
const HANDLE w4[2] = {get_guard (), signal_arrived};
switch (WaitForMultipleObjects (2, w4, 0, INFINITE))
{
case WAIT_OBJECT_0:
res = 1;
break;
case WAIT_OBJECT_0 + 1:
set_sig_errno (EINTR);
res = 0;
break;
default:
__seterrno ();
res = 0;
}
}
res = 1;
return res;
}
@ -1202,9 +1151,6 @@ fhandler_base::ready_for_read (int fd, DWORD howlong)
}
}
if (get_guard () && !avail && me.read_ready)
ReleaseMutex (get_guard ());
select_printf ("read_ready %d, avail %d", me.read_ready, avail);
return avail;
}