OSDN Git Service

* dir.cc: Change __off32_t to _off_t and __off64_t to _off64_t
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / pipe.cc
1 /* pipe.cc: pipe for Cygwin.
2
3    Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 /* FIXME: Should this really be fhandler_pipe.cc? */
12
13 #include "winsup.h"
14 #include <unistd.h>
15 #include <errno.h>
16 #include <sys/socket.h>
17 #include "cygerrno.h"
18 #include "security.h"
19 #include "fhandler.h"
20 #include "path.h"
21 #include "dtable.h"
22 #include "cygheap.h"
23 #include "thread.h"
24 #include "pinfo.h"
25 #include "cygthread.h"
26
27 static unsigned pipecount;
28 static const NO_COPY char pipeid_fmt[] = "stupid_pipe.%u.%u";
29
30 fhandler_pipe::fhandler_pipe (DWORD devtype)
31   : fhandler_base (devtype), guard (NULL), broken_pipe (false), writepipe_exists(0),
32     orig_pid (0), id (0)
33 {
34 }
35
36 _off64_t
37 fhandler_pipe::lseek (_off64_t offset, int whence)
38 {
39   debug_printf ("(%d, %d)", offset, whence);
40   set_errno (ESPIPE);
41   return -1;
42 }
43
44 void
45 fhandler_pipe::set_close_on_exec (int val)
46 {
47   fhandler_base::set_close_on_exec (val);
48   if (guard)
49     set_inheritance (guard, val);
50   if (writepipe_exists)
51     set_inheritance (writepipe_exists, val);
52 }
53
54 struct pipeargs
55 {
56   fhandler_base *fh;
57   void *ptr;
58   size_t *len;
59 };
60
61 static DWORD WINAPI
62 read_pipe (void *arg)
63 {
64   pipeargs *pi = (pipeargs *) arg;
65   pi->fh->fhandler_base::read (pi->ptr, *pi->len);
66   return 0;
67 }
68
69 void __stdcall
70 fhandler_pipe::read (void *in_ptr, size_t& in_len)
71 {
72   if (broken_pipe)
73     in_len = 0;
74   else
75     {
76       pipeargs pi = {this, in_ptr, &in_len};
77       ResetEvent (read_state);
78       cygthread *th = new cygthread (read_pipe, &pi, "read_pipe");
79       if (th->detach (read_state) && !in_len)
80         (ssize_t) in_len = -1;  /* received a signal */
81     }
82   (void) ReleaseMutex (guard);
83   return;
84 }
85
86 int fhandler_pipe::close ()
87 {
88   int res = fhandler_base::close ();
89 #undef guard
90   if (guard)
91     CloseHandle (guard);
92   if (writepipe_exists)
93     CloseHandle (writepipe_exists);
94   if (read_state && !cygheap->fdtab.in_vfork_cleanup ())
95     CloseHandle (read_state);
96   return res;
97 }
98
99 bool
100 fhandler_pipe::hit_eof ()
101 {
102   char buf[80];
103   HANDLE ev;
104   if (broken_pipe)
105     return 1;
106   if (!orig_pid)
107     return false;
108   __small_sprintf (buf, pipeid_fmt, orig_pid, id);
109   if ((ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf)))
110     CloseHandle (ev);
111   debug_printf ("%s %p", buf, ev);
112   return ev == NULL;
113 }
114
115 void
116 fhandler_pipe::fixup_after_exec (HANDLE parent)
117 {
118   if (read_state)
119     read_state = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
120 }
121
122 void
123 fhandler_pipe::fixup_after_fork (HANDLE parent)
124 {
125   fhandler_base::fixup_after_fork (parent);
126   if (guard)
127     fork_fixup (parent, guard, "guard");
128   if (writepipe_exists)
129     fork_fixup (parent, writepipe_exists, "guard");
130   fixup_after_exec (parent);
131 }
132
133 int
134 fhandler_pipe::dup (fhandler_base *child)
135 {
136   if (get_handle ())
137     {
138       int res = fhandler_base::dup (child);
139       if (res)
140         return res;
141     }
142
143   fhandler_pipe *ftp = (fhandler_pipe *) child;
144
145   /* FIXME: This leaks handles in the failing condition */
146   if (guard == NULL)
147     ftp->guard = NULL;
148   else if (!DuplicateHandle (hMainProc, guard, hMainProc, &ftp->guard, 0, 1,
149                              DUPLICATE_SAME_ACCESS))
150     {
151       debug_printf ("couldn't duplicate guard %p, %E", guard);
152       return -1;
153     }
154
155   if (writepipe_exists == NULL)
156     ftp->writepipe_exists = NULL;
157   else if (!DuplicateHandle (hMainProc, writepipe_exists, hMainProc,
158                              &ftp->writepipe_exists, 0, 1,
159                              DUPLICATE_SAME_ACCESS))
160     {
161       debug_printf ("couldn't duplicate writepipe_exists %p, %E", writepipe_exists);
162       return -1;
163     }
164
165   if (read_state == NULL)
166     ftp->read_state = NULL;
167   else if (!DuplicateHandle (hMainProc, read_state, hMainProc,
168                              &ftp->read_state, 0, 1,
169                              DUPLICATE_SAME_ACCESS))
170     {
171       debug_printf ("couldn't duplicate read_state %p, %E", writepipe_exists);
172       return -1;
173     }
174
175   ftp->id = id;
176   ftp->orig_pid = orig_pid;
177   return 0;
178 }
179
180 int
181 make_pipe (int fildes[2], unsigned int psize, int mode)
182 {
183   HANDLE r, w;
184   SECURITY_ATTRIBUTES *sa = (mode & O_NOINHERIT) ?  &sec_none_nih : &sec_none;
185   int res = -1;
186
187   cygheap_fdnew fdr;
188   if (fdr >= 0)
189     {
190       cygheap_fdnew fdw (fdr, false);
191       if (fdw < 0)
192         /* out of fds? */;
193       else if (!CreatePipe (&r, &w, sa, psize))
194         __seterrno ();
195       else
196         {
197           fhandler_pipe *fhr = (fhandler_pipe *) cygheap->fdtab.build_fhandler (fdr, FH_PIPER, "/dev/piper");
198           fhandler_pipe *fhw = (fhandler_pipe *) cygheap->fdtab.build_fhandler (fdw, FH_PIPEW, "/dev/pipew");
199
200           int binmode = mode & O_TEXT ?: O_BINARY;
201           fhr->init (r, GENERIC_READ, binmode);
202           fhw->init (w, GENERIC_WRITE, binmode);
203           if (mode & O_NOINHERIT)
204            {
205              fhr->set_close_on_exec_flag (1);
206              fhw->set_close_on_exec_flag (1);
207            }
208
209           fildes[0] = fdr;
210           fildes[1] = fdw;
211           fhr->read_state = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
212           fhr->set_need_fork_fixup ();
213
214           res = 0;
215           fhr->create_guard (sa);
216           if (wincap.has_unreliable_pipes ())
217             {
218               char buf[80];
219               int count = pipecount++;  /* FIXME: Should this be InterlockedIncrement? */
220               __small_sprintf (buf, pipeid_fmt, myself->pid, count);
221               fhw->writepipe_exists = CreateEvent (sa, TRUE, FALSE, buf);
222               fhr->orig_pid = myself->pid;
223               fhr->id = count;
224             }
225         }
226     }
227
228   syscall_printf ("%d = make_pipe ([%d, %d], %d, %p)", res, fildes[0],
229                   fildes[1], psize, mode);
230   return res;
231 }
232
233 int
234 fhandler_pipe::ioctl (unsigned int cmd, void *p)
235 {
236   int n;
237
238   switch (cmd)
239     {
240     case FIONREAD:
241       if (get_device () == FH_PIPEW)
242         {
243           set_errno (EINVAL);
244           return -1;
245         }
246       if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, (DWORD *) &n, NULL))
247         {
248           __seterrno ();
249           return -1;
250         }
251       break;
252     default:
253       return fhandler_base::ioctl (cmd, p);
254       break;
255     }
256   *(int *) p = n;
257   return 0;
258 }
259
260 extern "C" int
261 pipe (int filedes[2])
262 {
263   extern DWORD binmode;
264   return make_pipe (filedes, 16384, (!binmode || binmode == O_BINARY) ? O_BINARY : O_TEXT);
265 }
266
267 extern "C" int
268 _pipe (int filedes[2], unsigned int psize, int mode)
269 {
270   int res = make_pipe (filedes, psize, mode);
271   /* This type of pipe is not interruptible so set the appropriate flag. */
272   if (!res)
273     cygheap->fdtab[filedes[0]]->set_r_no_interrupt (1);
274   return res;
275 }