Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / fhandler / fifo.cc
blobee49ce695e5ac29eb8ae7cdd7602b4c74ec7f873
1 /* fhandler_fifo.cc - See fhandler.h for a description of the fhandler classes.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include <w32api/winioctl.h>
11 #include "miscfuncs.h"
13 #include "cygerrno.h"
14 #include "security.h"
15 #include "path.h"
16 #include "fhandler.h"
17 #include "dtable.h"
18 #include "cygheap.h"
19 #include "sigproc.h"
20 #include "cygtls.h"
21 #include "shared_info.h"
22 #include "ntdll.h"
23 #include "cygwait.h"
24 #include <sys/param.h>
27 Overview:
29 FIFOs are implemented via Windows named pipes. The server end of
30 the pipe corresponds to an fhandler_fifo open for reading (a.k.a,
31 a "reader"), and the client end corresponds to an fhandler_fifo
32 open for writing (a.k.a, a "writer").
34 The server can have multiple instances. The reader (assuming for
35 the moment that there is only one) creates a pipe instance for
36 each writer that opens. The reader maintains a list of
37 "fifo_client_handler" structures, one for each writer. A
38 fifo_client_handler contains the handle for the pipe server
39 instance and information about the state of the connection with
40 the writer. Access to the list is controlled by a
41 "fifo_client_lock".
43 The reader runs a "fifo_reader_thread" that creates new pipe
44 instances as needed and listens for client connections.
46 The connection state of a fifo_client_handler has one of the
47 following values, in which order is important:
49 fc_unknown
50 fc_error
51 fc_disconnected
52 fc_closing
53 fc_listening
54 fc_connected
55 fc_input_avail
57 It can be changed in the following places:
59 - It is set to fc_listening when the pipe instance is created.
61 - It is set to fc_connected when the fifo_reader_thread detects
62 a connection.
64 - It is set to a value reported by the O/S when
65 query_and_set_state is called. This can happen in
66 select.cc:peek_fifo and a couple other places.
68 - It is set to fc_disconnected by raw_read when an attempt to
69 read yields STATUS_PIPE_BROKEN.
71 - It is set to fc_error in various places when unexpected
72 things happen.
74 State changes are always guarded by fifo_client_lock.
76 If there are multiple readers open, only one of them, called the
77 "owner", maintains the fifo_client_handler list. The owner is
78 therefore the only reader that can read at any given time. If a
79 different reader wants to read, it has to take ownership and
80 duplicate the fifo_client_handler list.
82 A reader that is not an owner also runs a fifo_reader_thread,
83 which is mostly idle. The thread wakes up if that reader might
84 need to take ownership.
86 There is a block of named shared memory, accessible to all
87 fhandlers for a given FIFO. It keeps track of the number of open
88 readers and writers; it contains information needed for the owner
89 change process; and it contains some locks to prevent races and
90 deadlocks between the various threads.
92 The shared memory is created by the first reader to open the
93 FIFO. It is opened by subsequent readers and by all writers. It
94 is destroyed by Windows when the last handle to it is closed.
96 If a handle to it somehow remains open after all processes
97 holding file descriptors to the FIFO have closed, the shared
98 memory can persist and be reused with stale data by the next
99 process that opens the FIFO. So far I've seen this happen only
100 as a result of a bug in the code, but there are some debug_printf
101 statements in fhandler_fifo::open to help detect this if it
102 happens again.
104 At this writing, I know of only one application (Midnight
105 Commander when running under tcsh) that *explicitly* opens two
106 readers of a FIFO. But many applications will have multiple
107 readers open via dup/fork/exec.
111 /* This is only to be used for writers. When reading,
112 STATUS_PIPE_EMPTY simply means there's no data to be read. */
113 #define STATUS_PIPE_IS_CLOSED(status) \
114 ({ NTSTATUS _s = (status); \
115 _s == STATUS_PIPE_CLOSING \
116 || _s == STATUS_PIPE_BROKEN \
117 || _s == STATUS_PIPE_EMPTY; })
119 #define STATUS_PIPE_NO_INSTANCE_AVAILABLE(status) \
120 ({ NTSTATUS _s = (status); \
121 _s == STATUS_INSTANCE_NOT_AVAILABLE \
122 || _s == STATUS_PIPE_NOT_AVAILABLE \
123 || _s == STATUS_PIPE_BUSY; })
125 /* Number of pages reserved for shared_fc_handler. */
126 #define SH_FC_HANDLER_PAGES 100
128 static NO_COPY fifo_reader_id_t null_fr_id = { .winpid = 0, .fh = NULL };
130 fhandler_fifo::fhandler_fifo ():
131 fhandler_pipe_fifo (),
132 read_ready (NULL), write_ready (NULL), writer_opening (NULL),
133 owner_needed_evt (NULL), owner_found_evt (NULL), update_needed_evt (NULL),
134 cancel_evt (NULL), thr_sync_evt (NULL), pipe_name_buf (NULL),
135 fc_handler (NULL), shandlers (0), nhandlers (0),
136 reader (false), writer (false), duplexer (false),
137 me (null_fr_id), shmem_handle (NULL), shmem (NULL),
138 shared_fc_hdl (NULL), shared_fc_handler (NULL)
140 need_fork_fixup (true);
143 PUNICODE_STRING
144 fhandler_fifo::get_pipe_name ()
146 if (!pipe_name_buf)
148 pipe_name.Length = CYGWIN_FIFO_PIPE_NAME_LEN * sizeof (WCHAR);
149 pipe_name.MaximumLength = pipe_name.Length + sizeof (WCHAR);
150 pipe_name_buf = (PWCHAR) cmalloc_abort (HEAP_STR,
151 pipe_name.MaximumLength);
152 pipe_name.Buffer = pipe_name_buf;
153 __small_swprintf (pipe_name_buf, L"%S-fifo.%08x.%016X",
154 &cygheap->installation_key, get_dev (), get_ino ());
156 return &pipe_name;
159 inline PSECURITY_ATTRIBUTES
160 sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid)
162 return cloexec ? sec_user_nih (sa, sid) : sec_user (sa, sid);
165 static HANDLE
166 create_event ()
168 NTSTATUS status;
169 OBJECT_ATTRIBUTES attr;
170 HANDLE evt = NULL;
172 InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
173 status = NtCreateEvent (&evt, EVENT_ALL_ACCESS, &attr,
174 NotificationEvent, FALSE);
175 if (!NT_SUCCESS (status))
176 __seterrno_from_nt_status (status);
177 return evt;
181 static void
182 set_pipe_non_blocking (HANDLE ph, bool nonblocking)
184 NTSTATUS status;
185 IO_STATUS_BLOCK io;
186 FILE_PIPE_INFORMATION fpi;
188 fpi.ReadMode = FILE_PIPE_MESSAGE_MODE;
189 fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION
190 : FILE_PIPE_QUEUE_OPERATION;
191 status = NtSetInformationFile (ph, &io, &fpi, sizeof fpi,
192 FilePipeInformation);
193 if (!NT_SUCCESS (status))
194 debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status);
197 /* Called when a FIFO is first opened for reading and again each time
198 a new client handler is needed. Each pipe instance is created in
199 blocking mode so that we can easily wait for a connection. After
200 it is connected, it is put in nonblocking mode. */
201 HANDLE
202 fhandler_fifo::create_pipe_instance ()
204 NTSTATUS status;
205 HANDLE npfsh;
206 HANDLE ph = NULL;
207 ACCESS_MASK access;
208 OBJECT_ATTRIBUTES attr;
209 IO_STATUS_BLOCK io;
210 ULONG hattr;
211 ULONG sharing;
212 ULONG nonblocking = FILE_PIPE_QUEUE_OPERATION;
213 ULONG max_instances = -1;
214 LARGE_INTEGER timeout;
216 status = npfs_handle (npfsh);
217 if (!NT_SUCCESS (status))
219 __seterrno_from_nt_status (status);
220 return NULL;
222 access = GENERIC_READ | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES
223 | SYNCHRONIZE;
224 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
225 hattr = (openflags & O_CLOEXEC ? 0 : OBJ_INHERIT) | OBJ_CASE_INSENSITIVE;
226 InitializeObjectAttributes (&attr, get_pipe_name (),
227 hattr, npfsh, NULL);
228 timeout.QuadPart = -500000;
229 status = NtCreateNamedPipeFile (&ph, access, &attr, &io, sharing,
230 FILE_OPEN_IF, 0,
231 FILE_PIPE_MESSAGE_TYPE
232 | FILE_PIPE_REJECT_REMOTE_CLIENTS,
233 FILE_PIPE_MESSAGE_MODE,
234 nonblocking, max_instances,
235 DEFAULT_PIPEBUFSIZE, DEFAULT_PIPEBUFSIZE,
236 &timeout);
237 if (!NT_SUCCESS (status))
238 __seterrno_from_nt_status (status);
239 return ph;
242 /* Connect to a pipe instance. */
243 NTSTATUS
244 fhandler_fifo::open_pipe (HANDLE& ph)
246 NTSTATUS status;
247 HANDLE npfsh;
248 ACCESS_MASK access;
249 OBJECT_ATTRIBUTES attr;
250 IO_STATUS_BLOCK io;
251 ULONG sharing;
253 status = npfs_handle (npfsh);
254 if (!NT_SUCCESS (status))
255 return status;
256 access = GENERIC_WRITE | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
257 InitializeObjectAttributes (&attr, get_pipe_name (),
258 openflags & O_CLOEXEC ? 0 : OBJ_INHERIT,
259 npfsh, NULL);
260 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
261 return NtOpenFile (&ph, access, &attr, &io, sharing, 0);
264 /* Wait up to 100ms for a pipe instance to be available, then connect. */
265 NTSTATUS
266 fhandler_fifo::wait_open_pipe (HANDLE& ph)
268 HANDLE npfsh;
269 HANDLE evt;
270 NTSTATUS status;
271 IO_STATUS_BLOCK io;
272 ULONG pwbuf_size;
273 PFILE_PIPE_WAIT_FOR_BUFFER pwbuf;
274 LONGLONG stamp;
275 LONGLONG orig_timeout = -100 * NS100PERSEC / MSPERSEC; /* 100ms */
277 status = npfs_handle (npfsh);
278 if (!NT_SUCCESS (status))
279 return status;
280 if (!(evt = create_event ()))
281 api_fatal ("Can't create event, %E");
282 pwbuf_size
283 = offsetof (FILE_PIPE_WAIT_FOR_BUFFER, Name) + get_pipe_name ()->Length;
284 pwbuf = (PFILE_PIPE_WAIT_FOR_BUFFER) alloca (pwbuf_size);
285 pwbuf->Timeout.QuadPart = orig_timeout;
286 pwbuf->NameLength = get_pipe_name ()->Length;
287 pwbuf->TimeoutSpecified = TRUE;
288 memcpy (pwbuf->Name, get_pipe_name ()->Buffer, get_pipe_name ()->Length);
289 stamp = get_clock (CLOCK_MONOTONIC)->n100secs ();
290 bool retry;
293 retry = false;
294 status = NtFsControlFile (npfsh, evt, NULL, NULL, &io, FSCTL_PIPE_WAIT,
295 pwbuf, pwbuf_size, NULL, 0);
296 if (status == STATUS_PENDING)
298 if (WaitForSingleObject (evt, INFINITE) == WAIT_OBJECT_0)
299 status = io.Status;
300 else
301 api_fatal ("WFSO failed, %E");
303 if (NT_SUCCESS (status))
304 status = open_pipe (ph);
305 if (STATUS_PIPE_NO_INSTANCE_AVAILABLE (status))
307 /* Another writer has grabbed the pipe instance. Adjust
308 the timeout and keep waiting if there's time left. */
309 pwbuf->Timeout.QuadPart = orig_timeout
310 + get_clock (CLOCK_MONOTONIC)->n100secs () - stamp;
311 if (pwbuf->Timeout.QuadPart < 0)
312 retry = true;
313 else
314 status = STATUS_IO_TIMEOUT;
317 while (retry);
318 NtClose (evt);
319 return status;
322 /* Always called with fifo_client_lock in place. */
324 fhandler_fifo::add_client_handler (bool new_pipe_instance)
326 fifo_client_handler fc;
328 if (nhandlers >= shandlers)
330 void *temp = realloc (fc_handler,
331 (shandlers += 64) * sizeof (fc_handler[0]));
332 if (!temp)
334 shandlers -= 64;
335 set_errno (ENOMEM);
336 return -1;
338 fc_handler = (fifo_client_handler *) temp;
340 if (new_pipe_instance)
342 HANDLE ph = create_pipe_instance ();
343 if (!ph)
344 return -1;
345 fc.h = ph;
346 fc.set_state (fc_listening);
348 fc_handler[nhandlers++] = fc;
349 return 0;
352 /* Always called with fifo_client_lock in place. Delete a
353 client_handler by swapping it with the last one in the list. */
354 void
355 fhandler_fifo::delete_client_handler (int i)
357 fc_handler[i].close ();
358 if (i < --nhandlers)
359 fc_handler[i] = fc_handler[nhandlers];
362 /* Delete handlers that we will never read from. Always called with
363 fifo_client_lock in place. */
364 void
365 fhandler_fifo::cleanup_handlers ()
367 /* Work from the top down to try to avoid copying. */
368 for (int i = nhandlers - 1; i >= 0; --i)
369 if (fc_handler[i].get_state () < fc_connected)
370 delete_client_handler (i);
373 /* Always called with fifo_client_lock in place. */
374 void
375 fhandler_fifo::record_connection (fifo_client_handler& fc, bool set,
376 fifo_client_connect_state s)
378 if (set)
379 fc.set_state (s);
380 set_pipe_non_blocking (fc.h, true);
383 /* Called from fifo_reader_thread_func with owner_lock in place. */
385 fhandler_fifo::update_my_handlers ()
387 int ret = 0;
389 close_all_handlers ();
390 fifo_reader_id_t prev = get_prev_owner ();
391 if (!prev)
393 debug_printf ("No previous owner to copy handles from");
394 return 0;
396 HANDLE prev_proc;
397 if (prev.winpid == me.winpid)
398 prev_proc = GetCurrentProcess ();
399 else
400 prev_proc = OpenProcess (PROCESS_DUP_HANDLE, false, prev.winpid);
401 if (!prev_proc)
402 api_fatal ("Can't open process of previous owner, %E");
404 fifo_client_lock ();
405 for (int i = 0; i < get_shared_nhandlers (); i++)
407 if (add_client_handler (false) < 0)
408 api_fatal ("Can't add client handler, %E");
409 fifo_client_handler &fc = fc_handler[nhandlers - 1];
410 if (!DuplicateHandle (prev_proc, shared_fc_handler[i].h,
411 GetCurrentProcess (), &fc.h, 0,
412 !close_on_exec (), DUPLICATE_SAME_ACCESS))
414 debug_printf ("Can't duplicate handle of previous owner, %E");
415 __seterrno ();
416 fc.set_state (fc_error);
417 fc.last_read = false;
418 ret = -1;
420 else
422 fc.set_state (shared_fc_handler[i].get_state ());
423 fc.last_read = shared_fc_handler[i].last_read;
426 fifo_client_unlock ();
427 NtClose (prev_proc);
428 set_prev_owner (null_fr_id);
429 return ret;
432 /* Always called with fifo_client_lock and owner_lock in place. */
434 fhandler_fifo::update_shared_handlers ()
436 cleanup_handlers ();
437 if (nhandlers > get_shared_shandlers ())
439 if (remap_shared_fc_handler (nhandlers * sizeof (fc_handler[0])) < 0)
440 return -1;
442 set_shared_nhandlers (nhandlers);
443 memcpy (shared_fc_handler, fc_handler, nhandlers * sizeof (fc_handler[0]));
444 shared_fc_handler_updated (true);
445 set_prev_owner (me);
446 return 0;
449 static DWORD
450 fifo_reader_thread (LPVOID param)
452 fhandler_fifo *fh = (fhandler_fifo *) param;
453 return fh->fifo_reader_thread_func ();
456 DWORD
457 fhandler_fifo::fifo_reader_thread_func ()
459 HANDLE conn_evt;
461 if (!(conn_evt = CreateEvent (NULL, false, false, NULL)))
462 api_fatal ("Can't create connection event, %E");
464 while (1)
466 fifo_reader_id_t cur_owner, pending_owner;
467 bool idle = false, take_ownership = false;
469 owner_lock ();
470 cur_owner = get_owner ();
471 pending_owner = get_pending_owner ();
473 if (pending_owner)
475 if (pending_owner == me)
476 take_ownership = true;
477 else if (cur_owner != me)
478 idle = true;
479 else
481 /* I'm the owner but someone else wants to be. Have I
482 already seen and reacted to update_needed_evt? */
483 if (WaitForSingleObject (update_needed_evt, 0) == WAIT_OBJECT_0)
485 /* No, I haven't. */
486 fifo_client_lock ();
487 if (update_shared_handlers () < 0)
488 api_fatal ("Can't update shared handlers, %E");
489 fifo_client_unlock ();
491 owner_unlock ();
492 /* Yield to pending owner. */
493 Sleep (1);
494 continue;
497 else if (!cur_owner)
498 take_ownership = true;
499 else if (cur_owner != me)
500 idle = true;
501 else
502 /* I'm the owner and there's no pending owner. */
503 goto owner_listen;
504 if (idle)
506 owner_unlock ();
507 HANDLE w[2] = { owner_needed_evt, cancel_evt };
508 switch (WaitForMultipleObjects (2, w, false, INFINITE))
510 case WAIT_OBJECT_0:
511 continue;
512 case WAIT_OBJECT_0 + 1:
513 goto canceled;
514 default:
515 api_fatal ("WFMO failed, %E");
518 else if (take_ownership)
520 if (!shared_fc_handler_updated ())
522 owner_unlock ();
523 if (IsEventSignalled (cancel_evt))
524 goto canceled;
525 continue;
527 else
529 set_owner (me);
530 set_pending_owner (null_fr_id);
531 if (update_my_handlers () < 0)
532 debug_printf ("error updating my handlers, %E");
533 owner_found ();
534 /* Fall through to owner_listen. */
538 owner_listen:
539 fifo_client_lock ();
540 cleanup_handlers ();
541 if (add_client_handler () < 0)
542 api_fatal ("Can't add a client handler, %E");
544 /* Listen for a writer to connect to the new client handler. */
545 fifo_client_handler& fc = fc_handler[nhandlers - 1];
546 fifo_client_unlock ();
547 shared_fc_handler_updated (false);
548 owner_unlock ();
549 NTSTATUS status;
550 IO_STATUS_BLOCK io;
551 bool cancel = false;
552 bool update = false;
554 status = NtFsControlFile (fc.h, conn_evt, NULL, NULL, &io,
555 FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
556 if (status == STATUS_PENDING)
558 HANDLE w[3] = { conn_evt, update_needed_evt, cancel_evt };
559 switch (WaitForMultipleObjects (3, w, false, INFINITE))
561 case WAIT_OBJECT_0:
562 status = io.Status;
563 debug_printf ("NtFsControlFile STATUS_PENDING, then %y",
564 status);
565 break;
566 case WAIT_OBJECT_0 + 1:
567 status = STATUS_WAIT_1;
568 update = true;
569 break;
570 case WAIT_OBJECT_0 + 2:
571 status = STATUS_THREAD_IS_TERMINATING;
572 cancel = true;
573 update = true;
574 break;
575 default:
576 api_fatal ("WFMO failed, %E");
579 else
580 debug_printf ("NtFsControlFile status %y, no STATUS_PENDING",
581 status);
582 HANDLE ph = NULL;
583 NTSTATUS status1;
585 fifo_client_lock ();
586 if (fc.get_state () != fc_listening)
587 /* select.cc:peek_fifo has already recorded a connection. */
589 else
591 switch (status)
593 case STATUS_SUCCESS:
594 case STATUS_PIPE_CONNECTED:
595 record_connection (fc);
596 break;
597 case STATUS_PIPE_CLOSING:
598 debug_printf ("NtFsControlFile got STATUS_PIPE_CLOSING...");
599 /* Maybe a writer already connected, wrote, and closed.
600 Just query the O/S. */
601 fc.query_and_set_state ();
602 debug_printf ("...O/S reports state %d", fc.get_state ());
603 record_connection (fc, false);
604 break;
605 case STATUS_THREAD_IS_TERMINATING:
606 case STATUS_WAIT_1:
607 /* Try to connect a bogus client. Otherwise fc is still
608 listening, and the next connection might not get recorded. */
609 status1 = open_pipe (ph);
610 WaitForSingleObject (conn_evt, INFINITE);
611 if (NT_SUCCESS (status1))
612 /* Bogus cilent connected. */
613 delete_client_handler (nhandlers - 1);
614 else
615 /* Did a real client connect? */
616 switch (io.Status)
618 case STATUS_SUCCESS:
619 case STATUS_PIPE_CONNECTED:
620 record_connection (fc);
621 break;
622 case STATUS_PIPE_CLOSING:
623 debug_printf ("got STATUS_PIPE_CLOSING when trying to connect bogus client...");
624 fc.query_and_set_state ();
625 debug_printf ("...O/S reports state %d", fc.get_state ());
626 record_connection (fc, false);
627 break;
628 default:
629 debug_printf ("NtFsControlFile status %y after failing to connect bogus client or real client", io.Status);
630 fc.set_state (fc_error);
631 break;
633 break;
634 default:
635 debug_printf ("NtFsControlFile got unexpected status %y", status);
636 fc.set_state (fc_error);
637 break;
640 if (ph)
641 NtClose (ph);
642 if (update)
644 owner_lock ();
645 if (get_owner () == me && update_shared_handlers () < 0)
646 api_fatal ("Can't update shared handlers, %E");
647 owner_unlock ();
649 fifo_client_unlock ();
650 if (cancel)
651 goto canceled;
653 canceled:
654 if (conn_evt)
655 NtClose (conn_evt);
656 /* automatically return the cygthread to the cygthread pool */
657 _my_tls._ctinfo->auto_release ();
658 return 0;
661 /* Return -1 on error and 0 or 1 on success. If ONLY_OPEN is true, we
662 expect the shared memory to exist, and we only try to open it. In
663 this case, we return 0 on success.
665 Otherwise, we create the shared memory if it doesn't exist, and we
666 return 1 if it already existed and we successfully open it. */
668 fhandler_fifo::create_shmem (bool only_open)
670 HANDLE sect;
671 OBJECT_ATTRIBUTES attr;
672 NTSTATUS status = STATUS_SUCCESS;
673 LARGE_INTEGER size = { .QuadPart = sizeof (fifo_shmem_t) };
674 SIZE_T viewsize = sizeof (fifo_shmem_t);
675 PVOID addr = NULL;
676 UNICODE_STRING uname;
677 WCHAR shmem_name[MAX_PATH];
678 bool already_exists = false;
680 __small_swprintf (shmem_name, L"fifo-shmem.%08x.%016X", get_dev (),
681 get_ino ());
682 RtlInitUnicodeString (&uname, shmem_name);
683 InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT,
684 get_shared_parent_dir (), NULL);
685 if (!only_open)
687 status = NtCreateSection (&sect, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
688 | SECTION_MAP_READ | SECTION_MAP_WRITE,
689 &attr, &size, PAGE_READWRITE, SEC_COMMIT, NULL);
690 if (status == STATUS_OBJECT_NAME_COLLISION)
691 already_exists = true;
693 if (only_open || already_exists)
694 status = NtOpenSection (&sect, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
695 | SECTION_MAP_READ | SECTION_MAP_WRITE, &attr);
696 if (!NT_SUCCESS (status))
698 __seterrno_from_nt_status (status);
699 return -1;
701 status = NtMapViewOfSection (sect, NtCurrentProcess (), &addr, 0, viewsize,
702 NULL, &viewsize, ViewShare, 0, PAGE_READWRITE);
703 if (!NT_SUCCESS (status))
705 NtClose (sect);
706 __seterrno_from_nt_status (status);
707 return -1;
709 shmem_handle = sect;
710 shmem = (fifo_shmem_t *) addr;
711 return already_exists ? 1 : 0;
714 /* shmem_handle must be valid when this is called. */
716 fhandler_fifo::reopen_shmem ()
718 NTSTATUS status;
719 SIZE_T viewsize = sizeof (fifo_shmem_t);
720 PVOID addr = NULL;
722 status = NtMapViewOfSection (shmem_handle, NtCurrentProcess (), &addr,
723 0, viewsize, NULL, &viewsize, ViewShare,
724 0, PAGE_READWRITE);
725 if (!NT_SUCCESS (status))
727 __seterrno_from_nt_status (status);
728 return -1;
730 shmem = (fifo_shmem_t *) addr;
731 return 0;
734 /* On first creation, map and commit one page of memory. */
736 fhandler_fifo::create_shared_fc_handler ()
738 HANDLE sect;
739 OBJECT_ATTRIBUTES attr;
740 NTSTATUS status;
741 LARGE_INTEGER size
742 = { .QuadPart = (LONGLONG) (SH_FC_HANDLER_PAGES * wincap.page_size ()) };
743 SIZE_T viewsize = get_shared_fc_handler_committed () ?: wincap.page_size ();
744 PVOID addr = NULL;
745 UNICODE_STRING uname;
746 WCHAR shared_fc_name[MAX_PATH];
748 __small_swprintf (shared_fc_name, L"fifo-shared-fc.%08x.%016X", get_dev (),
749 get_ino ());
750 RtlInitUnicodeString (&uname, shared_fc_name);
751 InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT,
752 get_shared_parent_dir (), NULL);
753 status = NtCreateSection (&sect, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
754 | SECTION_MAP_READ | SECTION_MAP_WRITE, &attr,
755 &size, PAGE_READWRITE, SEC_RESERVE, NULL);
756 if (status == STATUS_OBJECT_NAME_COLLISION)
757 status = NtOpenSection (&sect, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY
758 | SECTION_MAP_READ | SECTION_MAP_WRITE, &attr);
759 if (!NT_SUCCESS (status))
761 __seterrno_from_nt_status (status);
762 return -1;
764 status = NtMapViewOfSection (sect, NtCurrentProcess (), &addr, 0, viewsize,
765 NULL, &viewsize, ViewShare, 0, PAGE_READWRITE);
766 if (!NT_SUCCESS (status))
768 NtClose (sect);
769 __seterrno_from_nt_status (status);
770 return -1;
772 shared_fc_hdl = sect;
773 shared_fc_handler = (fifo_client_handler *) addr;
774 if (!get_shared_fc_handler_committed ())
775 set_shared_fc_handler_committed (viewsize);
776 set_shared_shandlers (viewsize / sizeof (fifo_client_handler));
777 return 0;
780 /* shared_fc_hdl must be valid when this is called. */
782 fhandler_fifo::reopen_shared_fc_handler ()
784 NTSTATUS status;
785 SIZE_T viewsize = get_shared_fc_handler_committed ();
786 PVOID addr = NULL;
788 status = NtMapViewOfSection (shared_fc_hdl, NtCurrentProcess (),
789 &addr, 0, viewsize, NULL, &viewsize,
790 ViewShare, 0, PAGE_READWRITE);
791 if (!NT_SUCCESS (status))
793 __seterrno_from_nt_status (status);
794 return -1;
796 shared_fc_handler = (fifo_client_handler *) addr;
797 return 0;
801 fhandler_fifo::remap_shared_fc_handler (size_t nbytes)
803 NTSTATUS status;
804 SIZE_T viewsize = roundup2 (nbytes, wincap.page_size ());
805 PVOID addr = NULL;
807 if (viewsize > SH_FC_HANDLER_PAGES * wincap.page_size ())
809 set_errno (ENOMEM);
810 return -1;
813 NtUnmapViewOfSection (NtCurrentProcess (), shared_fc_handler);
814 status = NtMapViewOfSection (shared_fc_hdl, NtCurrentProcess (),
815 &addr, 0, viewsize, NULL, &viewsize,
816 ViewShare, 0, PAGE_READWRITE);
817 if (!NT_SUCCESS (status))
819 __seterrno_from_nt_status (status);
820 return -1;
822 shared_fc_handler = (fifo_client_handler *) addr;
823 set_shared_fc_handler_committed (viewsize);
824 set_shared_shandlers (viewsize / sizeof (fc_handler[0]));
825 return 0;
829 fhandler_fifo::open (int flags, mode_t)
831 int saved_errno = 0, shmem_res = 0;
833 if (flags & O_PATH)
834 return open_fs (flags);
836 /* Determine what we're doing with this fhandler: reading, writing, both */
837 switch (flags & O_ACCMODE)
839 case O_RDONLY:
840 reader = true;
841 break;
842 case O_WRONLY:
843 writer = true;
844 break;
845 case O_RDWR:
846 reader = writer = duplexer = true;
847 break;
848 default:
849 set_errno (EINVAL);
850 goto err;
853 debug_only_printf ("reader %d, writer %d, duplexer %d", reader, writer, duplexer);
854 set_flags (flags);
855 if (reader && !duplexer)
856 nohandle (true);
858 /* Create control events for this named pipe */
859 char char_sa_buf[1024];
860 LPSECURITY_ATTRIBUTES sa_buf;
861 sa_buf = sec_user_cloexec (flags & O_CLOEXEC, (PSECURITY_ATTRIBUTES) char_sa_buf,
862 cygheap->user.sid());
864 char npbuf[MAX_PATH];
865 __small_sprintf (npbuf, "r-event.%08x.%016X", get_dev (), get_ino ());
866 if (!(read_ready = CreateEvent (sa_buf, true, false, npbuf)))
868 debug_printf ("CreateEvent for %s failed, %E", npbuf);
869 __seterrno ();
870 goto err;
872 npbuf[0] = 'w';
873 if (!(write_ready = CreateEvent (sa_buf, true, false, npbuf)))
875 debug_printf ("CreateEvent for %s failed, %E", npbuf);
876 __seterrno ();
877 goto err_close_read_ready;
879 npbuf[0] = 'o';
880 if (!(writer_opening = CreateEvent (sa_buf, true, false, npbuf)))
882 debug_printf ("CreateEvent for %s failed, %E", npbuf);
883 __seterrno ();
884 goto err_close_write_ready;
887 /* If we're reading, create the shared memory and the shared
888 fc_handler memory, create some events, start the
889 fifo_reader_thread, signal read_ready, and wait for a writer. */
890 if (reader)
892 /* Create/open shared memory. */
893 if ((shmem_res = create_shmem ()) < 0)
894 goto err_close_writer_opening;
895 else if (shmem_res == 0)
896 debug_printf ("shmem created");
897 else
898 debug_printf ("shmem existed; ok if we're not the first reader");
899 if (create_shared_fc_handler () < 0)
900 goto err_close_shmem;
901 npbuf[0] = 'n';
902 if (!(owner_needed_evt = CreateEvent (sa_buf, true, false, npbuf)))
904 debug_printf ("CreateEvent for %s failed, %E", npbuf);
905 __seterrno ();
906 goto err_close_shared_fc_handler;
908 npbuf[0] = 'f';
909 if (!(owner_found_evt = CreateEvent (sa_buf, true, false, npbuf)))
911 debug_printf ("CreateEvent for %s failed, %E", npbuf);
912 __seterrno ();
913 goto err_close_owner_needed_evt;
915 npbuf[0] = 'u';
916 if (!(update_needed_evt = CreateEvent (sa_buf, false, false, npbuf)))
918 debug_printf ("CreateEvent for %s failed, %E", npbuf);
919 __seterrno ();
920 goto err_close_owner_found_evt;
922 if (!(cancel_evt = create_event ()))
923 goto err_close_update_needed_evt;
924 if (!(thr_sync_evt = create_event ()))
925 goto err_close_cancel_evt;
927 me.winpid = GetCurrentProcessId ();
928 me.fh = this;
929 nreaders_lock ();
930 if (inc_nreaders () == 1)
932 /* Reinitialize _sh_fc_handler_updated, which starts as 0. */
933 shared_fc_handler_updated (true);
934 set_owner (me);
936 new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
937 SetEvent (read_ready);
938 nreaders_unlock ();
940 /* If we're a duplexer, we need a handle for writing. */
941 if (duplexer)
943 HANDLE ph = NULL;
944 NTSTATUS status;
946 nwriters_lock ();
947 inc_nwriters ();
948 SetEvent (write_ready);
949 nwriters_unlock ();
951 while (1)
953 status = open_pipe (ph);
954 if (NT_SUCCESS (status))
956 set_handle (ph);
957 set_pipe_non_blocking (ph, flags & O_NONBLOCK);
958 break;
960 else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
962 /* The pipe hasn't been created yet. */
963 yield ();
964 continue;
966 else
968 __seterrno_from_nt_status (status);
969 nohandle (true);
970 goto err_close_reader;
974 /* Not a duplexer; wait for a writer to connect if we're blocking. */
975 else if (!wait (write_ready))
976 goto err_close_reader;
977 goto success;
980 /* If we're writing, wait for read_ready, connect to the pipe, open
981 the shared memory, and signal write_ready. */
982 if (writer)
984 NTSTATUS status;
986 /* Don't let a reader see EOF at this point. */
987 SetEvent (writer_opening);
988 while (1)
990 if (!wait (read_ready))
992 ResetEvent (writer_opening);
993 goto err_close_writer_opening;
995 status = open_pipe (get_handle ());
996 if (NT_SUCCESS (status))
997 goto writer_shmem;
998 else if (status == STATUS_OBJECT_NAME_NOT_FOUND)
1000 /* The pipe hasn't been created yet or there's no longer
1001 a reader open. */
1002 yield ();
1003 continue;
1005 else if (STATUS_PIPE_NO_INSTANCE_AVAILABLE (status))
1006 break;
1007 else
1009 debug_printf ("create of writer failed");
1010 __seterrno_from_nt_status (status);
1011 ResetEvent (writer_opening);
1012 goto err_close_writer_opening;
1016 /* We should get here only if the system is heavily loaded
1017 and/or many writers are trying to connect simultaneously */
1018 while (1)
1020 if (!wait (read_ready))
1022 ResetEvent (writer_opening);
1023 goto err_close_writer_opening;
1025 status = wait_open_pipe (get_handle ());
1026 if (NT_SUCCESS (status))
1027 goto writer_shmem;
1028 else if (status == STATUS_IO_TIMEOUT)
1029 continue;
1030 else
1032 debug_printf ("create of writer failed");
1033 __seterrno_from_nt_status (status);
1034 ResetEvent (writer_opening);
1035 goto err_close_writer_opening;
1039 writer_shmem:
1040 if (create_shmem (true) < 0)
1041 goto err_close_writer_opening;
1042 /* writer_success: */
1043 set_pipe_non_blocking (get_handle (), flags & O_NONBLOCK);
1044 nwriters_lock ();
1045 inc_nwriters ();
1046 set_writer_opened ();
1047 SetEvent (write_ready);
1048 ResetEvent (writer_opening);
1049 nwriters_unlock ();
1050 success:
1051 if (!select_sem)
1053 __small_sprintf (npbuf, "semaphore.%08x.%016X", get_dev (), get_ino ());
1054 select_sem = CreateSemaphore (sa_buf, 0, INT32_MAX, npbuf);
1056 return 1;
1057 err_close_reader:
1058 saved_errno = get_errno ();
1059 close ();
1060 set_errno (saved_errno);
1061 return 0;
1062 /* err_close_thr_sync_evt: */
1063 /* NtClose (thr_sync_evt); */
1064 err_close_cancel_evt:
1065 NtClose (cancel_evt);
1066 err_close_update_needed_evt:
1067 NtClose (update_needed_evt);
1068 err_close_owner_found_evt:
1069 NtClose (owner_found_evt);
1070 err_close_owner_needed_evt:
1071 NtClose (owner_needed_evt);
1072 err_close_shared_fc_handler:
1073 NtUnmapViewOfSection (NtCurrentProcess (), shared_fc_handler);
1074 NtClose (shared_fc_hdl);
1075 err_close_shmem:
1076 NtUnmapViewOfSection (NtCurrentProcess (), shmem);
1077 NtClose (shmem_handle);
1078 err_close_writer_opening:
1079 NtClose (writer_opening);
1080 err_close_write_ready:
1081 NtClose (write_ready);
1082 err_close_read_ready:
1083 NtClose (read_ready);
1084 err:
1085 if (get_handle ())
1086 NtClose (get_handle ());
1087 return 0;
1090 off_t
1091 fhandler_fifo::lseek (off_t offset, int whence)
1093 debug_printf ("(%D, %d)", offset, whence);
1094 set_errno (ESPIPE);
1095 return -1;
1098 bool
1099 fhandler_fifo::wait (HANDLE h)
1101 #ifdef DEBUGGING
1102 const char *what;
1103 if (h == read_ready)
1104 what = "reader";
1105 else
1106 what = "writer";
1107 #endif
1108 /* Set the wait to zero for non-blocking I/O-related events. */
1109 DWORD wait = ((h == read_ready || h == write_ready)
1110 && get_flags () & O_NONBLOCK) ? 0 : INFINITE;
1112 debug_only_printf ("waiting for %s", what);
1113 /* Wait for the event. Set errno, as appropriate if something goes wrong. */
1114 switch (cygwait (h, wait))
1116 case WAIT_OBJECT_0:
1117 debug_only_printf ("successfully waited for %s", what);
1118 return true;
1119 case WAIT_SIGNALED:
1120 debug_only_printf ("interrupted by signal while waiting for %s", what);
1121 set_errno (EINTR);
1122 return false;
1123 case WAIT_CANCELED:
1124 debug_only_printf ("cancellable interruption while waiting for %s", what);
1125 pthread::static_cancel_self (); /* never returns */
1126 break;
1127 case WAIT_TIMEOUT:
1128 if (h == write_ready)
1130 debug_only_printf ("wait timed out waiting for write but will still open reader since non-blocking mode");
1131 return true;
1133 else
1135 set_errno (ENXIO);
1136 return false;
1138 break;
1139 default:
1140 debug_only_printf ("unknown error while waiting for %s", what);
1141 __seterrno ();
1142 return false;
1146 /* Called from raw_read and select.cc:peek_fifo. */
1148 fhandler_fifo::take_ownership (DWORD timeout)
1150 int ret = 0;
1152 owner_lock ();
1153 if (get_owner () == me)
1155 owner_unlock ();
1156 return 0;
1158 set_pending_owner (me);
1159 /* Wake up my fifo_reader_thread. */
1160 owner_needed ();
1161 if (get_owner ())
1162 /* Wake up the owner and request an update of the shared fc_handlers. */
1163 SetEvent (update_needed_evt);
1164 owner_unlock ();
1165 /* The reader threads should now do the transfer. */
1166 switch (WaitForSingleObject (owner_found_evt, timeout))
1168 case WAIT_OBJECT_0:
1169 owner_lock ();
1170 if (get_owner () != me)
1172 debug_printf ("owner_found_evt signaled, but I'm not the owner");
1173 ret = -1;
1175 owner_unlock ();
1176 break;
1177 case WAIT_TIMEOUT:
1178 debug_printf ("timed out");
1179 ret = -1;
1180 break;
1181 default:
1182 debug_printf ("WFSO failed, %E");
1183 ret = -1;
1184 break;
1186 return ret;
1189 void
1190 fhandler_fifo::release_select_sem (const char *from)
1192 LONG n_release;
1193 if (reader) /* Number of select() call. */
1194 n_release = get_obj_handle_count (select_sem)
1195 - get_obj_handle_count (read_ready);
1196 else /* Number of select() and reader */
1197 n_release = get_obj_handle_count (select_sem)
1198 - get_obj_handle_count (get_handle ());
1199 debug_printf("%s(%s) release %d", from,
1200 reader ? "reader" : "writer", n_release);
1201 if (n_release)
1202 ReleaseSemaphore (select_sem, n_release, NULL);
1205 /* Read from a non-blocking pipe and wait for completion. */
1206 static NTSTATUS
1207 nt_read (HANDLE h, HANDLE evt, PIO_STATUS_BLOCK pio, void *in_ptr, size_t& len)
1209 NTSTATUS status;
1211 ResetEvent (evt);
1212 status = NtReadFile (h, evt, NULL, NULL, pio, in_ptr, len, NULL, NULL);
1213 if (status == STATUS_PENDING)
1215 /* Very short-lived */
1216 status = NtWaitForSingleObject (evt, FALSE, NULL);
1217 if (NT_SUCCESS (status))
1218 status = pio->Status;
1220 return status;
1223 void
1224 fhandler_fifo::raw_read (void *in_ptr, size_t& len)
1226 HANDLE evt;
1228 if (!len)
1229 return;
1231 if (!(evt = CreateEvent (NULL, false, false, NULL)))
1233 __seterrno ();
1234 len = (size_t) -1;
1235 return;
1238 while (1)
1240 int nconnected = 0;
1242 /* No one else can take ownership while we hold the reading_lock. */
1243 reading_lock ();
1244 if (take_ownership (10) < 0)
1245 goto maybe_retry;
1247 fifo_client_lock ();
1248 /* Poll the connected clients for input. Make three passes.
1250 On the first pass, just try to read from the client from
1251 which we last read successfully. This should minimize
1252 interleaving of writes from different clients.
1254 On the second pass, just try to read from the clients in the
1255 state fc_input_avail. This should be more efficient if
1256 select has been called and detected input available.
1258 On the third pass, try to read from all connected clients. */
1260 /* First pass. */
1261 int j;
1262 for (j = 0; j < nhandlers; j++)
1263 if (fc_handler[j].last_read)
1264 break;
1265 if (j < nhandlers && fc_handler[j].get_state () < fc_connected)
1267 fc_handler[j].last_read = false;
1268 j = nhandlers;
1270 if (j < nhandlers)
1272 NTSTATUS status;
1273 IO_STATUS_BLOCK io;
1275 status = nt_read (fc_handler[j].h, evt, &io, in_ptr, len);
1276 switch (status)
1278 case STATUS_SUCCESS:
1279 case STATUS_BUFFER_OVERFLOW:
1280 if (io.Information > 0)
1282 len = io.Information;
1283 goto unlock_out;
1285 break;
1286 case STATUS_PIPE_EMPTY:
1287 /* Update state in case it's fc_input_avail. */
1288 fc_handler[j].set_state (fc_connected);
1289 break;
1290 case STATUS_PIPE_BROKEN:
1291 fc_handler[j].set_state (fc_disconnected);
1292 break;
1293 default:
1294 debug_printf ("nt_read status %y", status);
1295 fc_handler[j].set_state (fc_error);
1296 break;
1300 /* Second pass. */
1301 for (int i = 0; i < nhandlers; i++)
1302 if (fc_handler[i].get_state () == fc_input_avail)
1304 NTSTATUS status;
1305 IO_STATUS_BLOCK io;
1307 status = nt_read (fc_handler[i].h, evt, &io, in_ptr, len);
1308 switch (status)
1310 case STATUS_SUCCESS:
1311 case STATUS_BUFFER_OVERFLOW:
1312 if (io.Information > 0)
1314 len = io.Information;
1315 if (j < nhandlers)
1316 fc_handler[j].last_read = false;
1317 fc_handler[i].last_read = true;
1318 goto unlock_out;
1320 break;
1321 case STATUS_PIPE_EMPTY:
1322 /* No input available after all. */
1323 fc_handler[i].set_state (fc_connected);
1324 break;
1325 case STATUS_PIPE_BROKEN:
1326 fc_handler[i].set_state (fc_disconnected);
1327 break;
1328 default:
1329 debug_printf ("nt_read status %y", status);
1330 fc_handler[i].set_state (fc_error);
1331 break;
1335 /* Third pass. */
1336 for (int i = 0; i < nhandlers; i++)
1337 if (fc_handler[i].get_state () >= fc_connected)
1339 NTSTATUS status;
1340 IO_STATUS_BLOCK io;
1342 nconnected++;
1343 status = nt_read (fc_handler[i].h, evt, &io, in_ptr, len);
1344 switch (status)
1346 case STATUS_SUCCESS:
1347 case STATUS_BUFFER_OVERFLOW:
1348 if (io.Information > 0)
1350 len = io.Information;
1351 if (j < nhandlers)
1352 fc_handler[j].last_read = false;
1353 fc_handler[i].last_read = true;
1354 goto unlock_out;
1356 break;
1357 case STATUS_PIPE_EMPTY:
1358 break;
1359 case STATUS_PIPE_BROKEN:
1360 fc_handler[i].set_state (fc_disconnected);
1361 nconnected--;
1362 break;
1363 default:
1364 debug_printf ("nt_read status %y", status);
1365 fc_handler[i].set_state (fc_error);
1366 nconnected--;
1367 break;
1370 if (!nconnected && hit_eof ())
1372 len = 0;
1373 goto unlock_out;
1375 fifo_client_unlock ();
1376 maybe_retry:
1377 reading_unlock ();
1378 if (is_nonblocking ())
1380 set_errno (EAGAIN);
1381 len = (size_t) -1;
1382 goto out;
1384 else
1386 /* Allow interruption and don't hog the CPU. */
1387 DWORD waitret = cygwait (select_sem, 1, cw_cancel | cw_sig_eintr);
1388 if (waitret == WAIT_CANCELED)
1389 pthread::static_cancel_self ();
1390 else if (waitret == WAIT_SIGNALED)
1392 if (_my_tls.call_signal_handler ())
1393 continue;
1394 else
1396 set_errno (EINTR);
1397 len = (size_t) -1;
1398 goto out;
1402 /* We might have been closed by a signal handler or another thread. */
1403 if (isclosed ())
1405 set_errno (EBADF);
1406 len = (size_t) -1;
1407 goto out;
1410 unlock_out:
1411 fifo_client_unlock ();
1412 reading_unlock ();
1413 out:
1414 if (select_sem)
1415 release_select_sem ("raw_read");
1416 CloseHandle (evt);
1420 fhandler_fifo::fstat (struct stat *buf)
1422 if (reader || writer || duplexer)
1424 /* fhandler_fifo::open has been called, and O_PATH is not set.
1425 We don't want to call fhandler_base::fstat. In the writer
1426 and duplexer cases we have a handle, but it's a pipe handle
1427 rather than a file handle, so it's not suitable for stat. In
1428 the reader case we don't have a handle, but
1429 fhandler_base::fstat would call fhandler_base::open, which
1430 would modify the flags and status_flags. */
1431 fhandler_disk_file fh (pc);
1432 fh.get_device () = FH_FS;
1433 int res = fh.fstat (buf);
1434 buf->st_dev = buf->st_rdev = dev ();
1435 buf->st_mode = dev ().mode ();
1436 buf->st_size = 0;
1437 return res;
1439 return fhandler_base::fstat (buf);
1443 fhandler_fifo::fstatvfs (struct statvfs *sfs)
1445 if (get_flags () & O_PATH)
1446 /* We already have a handle. */
1448 HANDLE h = get_handle ();
1449 if (h)
1450 return fstatvfs_by_handle (h, sfs);
1453 fhandler_disk_file fh (pc);
1454 fh.get_device () = FH_FS;
1455 return fh.fstatvfs (sfs);
1458 void
1459 fhandler_fifo::close_all_handlers ()
1461 fifo_client_lock ();
1462 for (int i = 0; i < nhandlers; i++)
1463 fc_handler[i].close ();
1464 nhandlers = 0;
1465 fifo_client_unlock ();
1468 /* Return previous state. */
1469 fifo_client_connect_state
1470 fifo_client_handler::query_and_set_state ()
1472 IO_STATUS_BLOCK io;
1473 FILE_PIPE_LOCAL_INFORMATION fpli;
1474 NTSTATUS status;
1475 fifo_client_connect_state prev_state = get_state ();
1477 if (!h)
1479 set_state (fc_unknown);
1480 goto out;
1483 status = NtQueryInformationFile (h, &io, &fpli,
1484 sizeof (fpli), FilePipeLocalInformation);
1485 if (!NT_SUCCESS (status))
1487 debug_printf ("NtQueryInformationFile status %y", status);
1488 set_state (fc_error);
1490 else if (fpli.ReadDataAvailable > 0)
1491 set_state (fc_input_avail);
1492 else
1493 switch (fpli.NamedPipeState)
1495 case FILE_PIPE_DISCONNECTED_STATE:
1496 set_state (fc_disconnected);
1497 break;
1498 case FILE_PIPE_LISTENING_STATE:
1499 set_state (fc_listening);
1500 break;
1501 case FILE_PIPE_CONNECTED_STATE:
1502 set_state (fc_connected);
1503 break;
1504 case FILE_PIPE_CLOSING_STATE:
1505 set_state (fc_closing);
1506 break;
1507 default:
1508 set_state (fc_error);
1509 break;
1511 out:
1512 return prev_state;
1515 void
1516 fhandler_fifo::cancel_reader_thread ()
1518 if (cancel_evt)
1519 SetEvent (cancel_evt);
1520 if (thr_sync_evt)
1521 WaitForSingleObject (thr_sync_evt, INFINITE);
1525 fhandler_fifo::close ()
1527 if (select_sem)
1529 release_select_sem ("close");
1530 NtClose (select_sem);
1532 if (writer)
1534 nwriters_lock ();
1535 if (dec_nwriters () == 0)
1536 ResetEvent (write_ready);
1537 nwriters_unlock ();
1539 if (reader)
1541 /* If we're the owner, we can't close our fc_handlers if a new
1542 owner might need to duplicate them. */
1543 bool close_fc_ok = false;
1545 cancel_reader_thread ();
1546 nreaders_lock ();
1547 if (dec_nreaders () == 0)
1549 close_fc_ok = true;
1550 ResetEvent (read_ready);
1551 ResetEvent (owner_needed_evt);
1552 ResetEvent (owner_found_evt);
1553 set_owner (null_fr_id);
1554 set_prev_owner (null_fr_id);
1555 set_pending_owner (null_fr_id);
1556 set_shared_nhandlers (0);
1558 else
1560 owner_lock ();
1561 if (get_owner () != me)
1562 close_fc_ok = true;
1563 else
1565 set_owner (null_fr_id);
1566 set_prev_owner (me);
1567 if (!get_pending_owner ())
1568 owner_needed ();
1570 owner_unlock ();
1572 nreaders_unlock ();
1573 while (!close_fc_ok)
1575 if (WaitForSingleObject (owner_found_evt, 1) == WAIT_OBJECT_0)
1576 close_fc_ok = true;
1577 else
1579 nreaders_lock ();
1580 if (!nreaders ())
1582 close_fc_ok = true;
1583 nreaders_unlock ();
1585 else
1587 nreaders_unlock ();
1588 owner_lock ();
1589 if (get_owner () || get_prev_owner () != me)
1590 close_fc_ok = true;
1591 owner_unlock ();
1595 close_all_handlers ();
1596 if (fc_handler)
1597 free (fc_handler);
1598 if (owner_needed_evt)
1599 NtClose (owner_needed_evt);
1600 if (owner_found_evt)
1601 NtClose (owner_found_evt);
1602 if (update_needed_evt)
1603 NtClose (update_needed_evt);
1604 if (cancel_evt)
1605 NtClose (cancel_evt);
1606 if (thr_sync_evt)
1607 NtClose (thr_sync_evt);
1608 if (shared_fc_handler)
1609 NtUnmapViewOfSection (NtCurrentProcess (), shared_fc_handler);
1610 if (shared_fc_hdl)
1611 NtClose (shared_fc_hdl);
1613 if (shmem)
1614 NtUnmapViewOfSection (NtCurrentProcess (), shmem);
1615 if (shmem_handle)
1616 NtClose (shmem_handle);
1617 if (read_ready)
1618 NtClose (read_ready);
1619 if (write_ready)
1620 NtClose (write_ready);
1621 if (writer_opening)
1622 NtClose (writer_opening);
1623 if (nohandle ())
1624 return 0;
1625 else
1626 return fhandler_base::close ();
1629 /* If we have a write handle (i.e., we're a duplexer or a writer),
1630 keep the nonblocking state of the windows pipe in sync with our
1631 nonblocking state. */
1633 fhandler_fifo::fcntl (int cmd, intptr_t arg)
1635 if (cmd != F_SETFL || nohandle () || (get_flags () & O_PATH))
1636 return fhandler_base::fcntl (cmd, arg);
1638 const bool was_nonblocking = is_nonblocking ();
1639 int res = fhandler_base::fcntl (cmd, arg);
1640 const bool now_nonblocking = is_nonblocking ();
1641 if (now_nonblocking != was_nonblocking)
1642 set_pipe_non_blocking (get_handle (), now_nonblocking);
1643 return res;
1647 fhandler_fifo::dup (fhandler_base *child, int flags)
1649 fhandler_fifo *fhf = NULL;
1651 if (get_flags () & O_PATH)
1652 return fhandler_base::dup (child, flags);
1654 if (fhandler_base::dup (child, flags))
1655 goto err;
1657 fhf = (fhandler_fifo *) child;
1658 if (!DuplicateHandle (GetCurrentProcess (), read_ready,
1659 GetCurrentProcess (), &fhf->read_ready,
1660 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1662 __seterrno ();
1663 goto err;
1665 if (!DuplicateHandle (GetCurrentProcess (), write_ready,
1666 GetCurrentProcess (), &fhf->write_ready,
1667 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1669 __seterrno ();
1670 goto err_close_read_ready;
1672 if (!DuplicateHandle (GetCurrentProcess (), writer_opening,
1673 GetCurrentProcess (), &fhf->writer_opening,
1674 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1676 __seterrno ();
1677 goto err_close_write_ready;
1679 if (!DuplicateHandle (GetCurrentProcess (), shmem_handle,
1680 GetCurrentProcess (), &fhf->shmem_handle,
1681 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1683 __seterrno ();
1684 goto err_close_writer_opening;
1686 if (fhf->reopen_shmem () < 0)
1687 goto err_close_shmem_handle;
1688 if (select_sem &&
1689 !DuplicateHandle (GetCurrentProcess (), select_sem,
1690 GetCurrentProcess (), &fhf->select_sem,
1691 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1693 __seterrno ();
1694 goto err_close_shmem;
1696 if (reader)
1698 /* Make sure the child starts unlocked. */
1699 fhf->fifo_client_unlock ();
1701 /* Clear fc_handler list; the child never starts as owner. */
1702 fhf->nhandlers = fhf->shandlers = 0;
1703 fhf->fc_handler = NULL;
1705 if (!DuplicateHandle (GetCurrentProcess (), shared_fc_hdl,
1706 GetCurrentProcess (), &fhf->shared_fc_hdl,
1707 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1709 __seterrno ();
1710 goto err_close_select_sem;
1712 if (fhf->reopen_shared_fc_handler () < 0)
1713 goto err_close_shared_fc_hdl;
1714 if (!DuplicateHandle (GetCurrentProcess (), owner_needed_evt,
1715 GetCurrentProcess (), &fhf->owner_needed_evt,
1716 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1718 __seterrno ();
1719 goto err_close_shared_fc_handler;
1721 if (!DuplicateHandle (GetCurrentProcess (), owner_found_evt,
1722 GetCurrentProcess (), &fhf->owner_found_evt,
1723 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1725 __seterrno ();
1726 goto err_close_owner_needed_evt;
1728 if (!DuplicateHandle (GetCurrentProcess (), update_needed_evt,
1729 GetCurrentProcess (), &fhf->update_needed_evt,
1730 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS))
1732 __seterrno ();
1733 goto err_close_owner_found_evt;
1735 if (!(fhf->cancel_evt = create_event ()))
1736 goto err_close_update_needed_evt;
1737 if (!(fhf->thr_sync_evt = create_event ()))
1738 goto err_close_cancel_evt;
1739 inc_nreaders ();
1740 fhf->me.fh = fhf;
1741 new cygthread (fifo_reader_thread, fhf, "fifo_reader", fhf->thr_sync_evt);
1743 if (writer)
1744 inc_nwriters ();
1745 return 0;
1746 err_close_cancel_evt:
1747 NtClose (fhf->cancel_evt);
1748 err_close_update_needed_evt:
1749 NtClose (fhf->update_needed_evt);
1750 err_close_owner_found_evt:
1751 NtClose (fhf->owner_found_evt);
1752 err_close_owner_needed_evt:
1753 NtClose (fhf->owner_needed_evt);
1754 err_close_shared_fc_handler:
1755 NtUnmapViewOfSection (GetCurrentProcess (), fhf->shared_fc_handler);
1756 err_close_shared_fc_hdl:
1757 NtClose (fhf->shared_fc_hdl);
1758 err_close_select_sem:
1759 NtClose (fhf->select_sem);
1760 err_close_shmem:
1761 NtUnmapViewOfSection (GetCurrentProcess (), fhf->shmem);
1762 err_close_shmem_handle:
1763 NtClose (fhf->shmem_handle);
1764 err_close_writer_opening:
1765 NtClose (fhf->writer_opening);
1766 err_close_write_ready:
1767 NtClose (fhf->write_ready);
1768 err_close_read_ready:
1769 NtClose (fhf->read_ready);
1770 err:
1771 return -1;
1774 void
1775 fhandler_fifo::fixup_after_fork (HANDLE parent)
1777 fhandler_base::fixup_after_fork (parent);
1778 fork_fixup (parent, read_ready, "read_ready");
1779 fork_fixup (parent, write_ready, "write_ready");
1780 fork_fixup (parent, writer_opening, "writer_opening");
1781 fork_fixup (parent, shmem_handle, "shmem_handle");
1782 if (reopen_shmem () < 0)
1783 api_fatal ("Can't reopen shared memory during fork, %E");
1784 if (select_sem)
1785 fork_fixup (parent, select_sem, "select_sem");
1786 if (reader)
1788 /* Make sure the child starts unlocked. */
1789 fifo_client_unlock ();
1791 fork_fixup (parent, shared_fc_hdl, "shared_fc_hdl");
1792 if (reopen_shared_fc_handler () < 0)
1793 api_fatal ("Can't reopen shared fc_handler memory during fork, %E");
1794 fork_fixup (parent, owner_needed_evt, "owner_needed_evt");
1795 fork_fixup (parent, owner_found_evt, "owner_found_evt");
1796 fork_fixup (parent, update_needed_evt, "update_needed_evt");
1797 if (close_on_exec ())
1798 /* Prevent a later attempt to close the non-inherited
1799 pipe-instance handles copied from the parent. */
1800 nhandlers = 0;
1801 if (!(cancel_evt = create_event ()))
1802 api_fatal ("Can't create reader thread cancel event during fork, %E");
1803 if (!(thr_sync_evt = create_event ()))
1804 api_fatal ("Can't create reader thread sync event during fork, %E");
1805 inc_nreaders ();
1806 me.winpid = GetCurrentProcessId ();
1807 new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
1809 if (writer)
1810 inc_nwriters ();
1813 void
1814 fhandler_fifo::fixup_after_exec ()
1816 fhandler_base::fixup_after_exec ();
1817 if (close_on_exec ())
1818 return;
1819 if (reopen_shmem () < 0)
1820 api_fatal ("Can't reopen shared memory during exec, %E");
1821 if (reader)
1823 /* Make sure the child starts unlocked. */
1824 fifo_client_unlock ();
1826 if (reopen_shared_fc_handler () < 0)
1827 api_fatal ("Can't reopen shared fc_handler memory during exec, %E");
1828 fc_handler = NULL;
1829 nhandlers = shandlers = 0;
1830 if (!(cancel_evt = create_event ()))
1831 api_fatal ("Can't create reader thread cancel event during exec, %E");
1832 if (!(thr_sync_evt = create_event ()))
1833 api_fatal ("Can't create reader thread sync event during exec, %E");
1834 /* At this moment we're a new reader. The count will be
1835 decremented when the parent closes. */
1836 inc_nreaders ();
1837 me.winpid = GetCurrentProcessId ();
1838 new cygthread (fifo_reader_thread, this, "fifo_reader", thr_sync_evt);
1840 if (writer)
1841 inc_nwriters ();
1844 void
1845 fhandler_fifo::set_close_on_exec (bool val)
1847 fhandler_base::set_close_on_exec (val);
1848 set_no_inheritance (read_ready, val);
1849 set_no_inheritance (write_ready, val);
1850 set_no_inheritance (writer_opening, val);
1851 if (reader)
1853 set_no_inheritance (owner_needed_evt, val);
1854 set_no_inheritance (owner_found_evt, val);
1855 set_no_inheritance (update_needed_evt, val);
1856 fifo_client_lock ();
1857 for (int i = 0; i < nhandlers; i++)
1858 set_no_inheritance (fc_handler[i].h, val);
1859 fifo_client_unlock ();
1861 if (select_sem)
1862 set_no_inheritance (select_sem, val);