From 7ac6173643b13a5a3bc7daf3649eb20c48c9c908 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 25 Sep 2003 00:37:18 +0000 Subject: * devices.cc: New file. * devices.gperf: New file. * devices.shilka: New file. * cygwin-gperf: New file. * cygwin-shilka: New file. * fhandler_fifo.cc: New file. * fhandler_nodevice.cc : New file. Reorganize headers so that path.h precedes fhandler.h throughout. Remove device argument and unit arguments from fhandler constructors throughout. Remove pc arguments to fhandler functions and use internal pc element instead, throughout. Use dev element in pc throughout. Use major/minor elements rather than units and device numbers previously in fhandler class. Use correct methods for fhandler file names rather than directly accessing file name variables, throughout. * Makefile.in (DLL_OFILES): Add devices.o, fhandler_fifo.o * dcrt0.cc (dll_crt0_1): Call device::init. * devices.h: Renumber devices based on more Linux-like major/minor numbers. Add more devices. Declare standard device storage. (device): Declare struct. * dir.cc (opendir): Use new 'build_fh_name' to construct a fhandler_* type. * dtable.cc (dtable::get_debugger_info): Ditto. (cygwin_attach_handle_to_fd): Ditto. (dtable::release): Remove special FH_SOCKET case in favor of generic "need_fixup_before" test. (dtable::init_std_file_from_handle): Use either build_fh_dev or build_fh_name to build standard fhandler. (dtable::build_fh_name): Renamed from dtable::build_fhandler_from_name. Move out of dtable class. Don't accept a path_conv argument. Just build it here and pass it to: (build_fh_pc): Renamed from dtable::build_fhandler. Move out of dtable class. Use intrinsic device type in path_conv to create new fhandler. (build_fh_dev): Renamed from dtable::build_fhandler. Move out of dtable class. Simplify arguments to just take new 'device' type and a name. Just return pointer to fhandler rather than trying to insert into dtable. (dtable::dup_worker): Accommodate above build_fh name changes. (dtable::find_fifo): New (currently broken) function. (handle_to_fn): Use strechr for efficiency. * dtable.h: Reflect above build_fh name changes and argument differences. (fhandler_base *&operator []): Return self rather than copy of self. * fhandler.cc (fhandler_base::operator =): Use pc element to set normalized path. (fhandler_base::set_name): Ditto. (fhandler_base::raw_read): Use method to access name. (fhandler_base::write): Correctly use get_output_handle rather than get_handle. (handler_base::device_access_denied): New function. (fhandler_base::open): Eliminate pc argument and use pc element of fhandler_base throughout. (fhandler_base::fstat): Detect if device is based in filesystem and use fstat_fs to calculate stat, if so. (fhandler_base::fhandler_base): Eliminate handling of file names and, instead, just free appropriate component from pc. (fhandler_base::opendir): Remove path_conv parameter. * fhandler.h: Remove all device flags. (fhandler_base::pc): New element. (fhandler_base::set_name): Change argument to path_conv. (fhandler_base::error): New function. (fhandler_base::exists): New function. (fhandler_base::pc_binmode): New function. (fhandler_base::dev): New function. (fhandler_base::open_fs): New function. (fhandler_base::fstat_fs): New function. (fhandler_base::fstat_by_name): New function. (fhandler_base::fstat_by_handle): New function. (fhandler_base::isfifo): New function. (fhandler_base::is_slow): New function. (fhandler_base::is_auto_device): New function. (fhandler_base::is_fs_special): New function. (fhandler_base::device_access_denied): New function. (fhandler_base::operator DWORD&): New operator. (fhandler_base::get_name): Return normalized path from pc. (fhandler_base::get_win32_name): Return windows path from pc. (fhandler_base::isdevice): Renamed from is_device. (fhandler_base::get_native_name): Return device format. (fhandler_fifo): New class. (fhandler_nodevice): New class. (select_stuff::device_specific): Remove array. (select_stuff::device_specific_pipe): New class element. (select_stuff::device_specific_socket): New class element. (select_stuff::device_specific_serial): New class element. (select_stuff::select_stuff): Initialize new elements. * fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Move to base class from fhandler_disk_file. (fhandler_base::fstat_by_name): Ditto. (fhandler_base::fstat_by_name): Ditto. (fhandler_disk_file::open): Move most functionality into fhandler_base::open_fs. (fhandler_base::open_fs): New function. (fhandler_disk_file::close): Move most functionality into fhandler_base::close_fs. (fhandler_base::close_fs): New function. * fhandler_mem.cc (fhandler_dev_mem::open): Use device name in debugging output. * fhandler_socket.cc (fhandler_socket::set_connect_secret): Copy standard urandom device into appropriate place. (fhandler_socket::accept): Reflect change in fdsock return value. * fhandler_tty.cc: See "throughouts" above. * net.cc: Accommodate fdsock change throughout. (fdsock): Return success or failure, accept fd argument and device argument. * path.cc (symlink_info::major): New element. (symlink_info::minor): New element. (symlink_info::parse_device): Declare new function. (fs_info::update): Accommodate changes in path_conv class. (path_conv::fillin): Ditto. (path_conv::return_and_clear_normalized_path): Eliminate. (path_conv::set_normalized_path): New function. (path_conv::path_conv): Set info in dev element. Use path_conv methods Check for FH_FS rather than FH_BAD to indicate when to fill in filesystem stuff. where appropriate rather than direct access. Use set_normalized_path to set normalized path. (windows_device_names): Eliminate. (get_dev): Ditto. (get_raw_device_number): Ditto. (get_device_number): Ditto. (win32_device_name): Call new device name parser to do most of the heavy lifting. (mount_info::conv_to_win32_path): Fill in dev field as appropriate. (symlink_worker): Handle new device files. (symlink_info::check): Ditto. (symlink_info::parse_device): Define new function. * path.h (executable_states): Move here from fhandler.h. (fs_info): Rename variables to *_storage and create methods for accessing same. (path_conv): Add dev element, remove devn and unit and adjust inline methods to accommodate. (set_normalized_path): Declare new function. * pinfo.cc (_pinfo::commune_recv): Add broken support for handling fifos. (_pinfo::commune_send): Ditto. * pipe.cc (fhandler_pipe::close): check for existence of handle before closing it. (handler_pipe::create): Rename from make_pipe. Change arguments to accept fhandler_pipe array. Accommodate fifos. (pipe): Rework to deal with fhandler_pipe::create changes. (_pipe): Ditto. * select.cc: Use individual device_specific types throughout rather than indexing with obsolete device number. (set_bits): Use is_socket call rather than checking device number. * shared_info.h (CURR_MOUNT_MAGIC): Update. (conv_to_win32_path): Reflect addition of device argument. * syscalls.cc (mknod_worker): New function. (open): Use build_fh_name to build fhandler. (chown_worker): Detect if this is an 'auto' device rather than an on-filesystem device and handle appropriately. (chmod_device): New function. (chmod): Detect if this is an 'auto' device rather than an on-filesystem device and handle appropriately. Use chmod_device to set mode of in-filesystem devices. (stat_worker): Eliminate path_conv argument. Call build_fh_name to construct fhandler. Use fh->error() rather than pc->error to detect errors in fhandler construction. (access_worker): New function pulled from access. Accommodate in-filesystem devices. (access): Use access_worker. (fpathconf): Detect if this is an 'auto' device rather than an on-filesystem device and handle appropriately. (mknod_worker): New function. (mknod32): New function. (chroot): Free normalized path -- assuming it was actually cmalloced. * tty.cc (create_tty_master): Tweak for new device class. (tty::common_init): Ditto. * winsup.h (stat_worker): Remove. (symlink_worker): Declare. * exceptions.cc (set_process_mask): Just call sig_dispatch_pending and don't worry about pending_signals since sig_dispatch_pending should always do the right thing now. (sig_handle): Reorganize SIGCONT handling to more closely conform to SUSv3. * pinfo.h: Move __SIG enum to sigproc.h. (PICOM_FIFO): New enum element. (_pinfo): Remove 'thread2signal' stuff throughout class. (_pinfo::commune_send): Make varargs. (_pinfo::sigtodo): Eliminate. (_pinfo::thread2signal): Ditto. * signal.cc (kill_worker): Eliminate call to setthread2signal. * sigproc.cc (local_sigtodo): Eliminate. (getlocal_sigtodo): Ditto. (sigelem): New class. (pending_signals): New class. (sigqueue): New variable, start of sigqueue linked list. (sigcatch_nonmain): Eliminate. (sigcatch_main): Eliminate. (sigcatch_nosync): Eliminate. (sigcomplete_nonmain): Eliminate. (pending_signals): Eliminate. (sig_clear): Call signal thread to clear pending signals, unless already in signal thread. (sigpending): Call signal thread to get pending signals. (sig_dispatch_pending): Eliminate use of pending_signals and just check sigqueue. (sigproc_terminate): Eliminate all of the obsolete semaphore stuff. Close signal pipe handle. (sig_send): Eliminate all of the obsolete semaphore stuff and use pipe to send signals. (getevent): Eliminate. (pending_signals::add): New function. (pending_signals::del): New function. (pending_signals::next): New function. (wait_sig): Eliminate all of the obsolete semaphore stuff. Use pipe to communicate and maintain a linked list of signals. * sigproc.h: Move __SIG defines here. Add __SIGPENDING. (sig_dispatch_pending): Remove "C" specifier. (sig_handle): Accept a mask argument. * thread.cc: Remove signal handling considerations throughout. --- winsup/cygwin/sigproc.cc | 591 +++++++++++++++++++---------------------------- 1 file changed, 232 insertions(+), 359 deletions(-) (limited to 'winsup/cygwin/sigproc.cc') diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index dad5c7f8a..349974eb9 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -23,12 +23,11 @@ details. */ #include "sigproc.h" #include "pinfo.h" #include "security.h" -#include "fhandler.h" #include "path.h" +#include "fhandler.h" #include "dtable.h" #include "cygheap.h" #include "child_info_magic.h" -#define NEED_VFORK #include "perthread.h" #include "shared_info.h" #include "cygthread.h" @@ -49,14 +48,33 @@ details. */ #define NZOMBIES 256 -static LONG local_sigtodo[TOTSIGS]; -struct sigaction *global_sigs; +class sigelem +{ + int sig; + class sigelem *next; + friend class pending_signals; + friend int __stdcall sig_dispatch_pending (); +}; -inline LONG * -getlocal_sigtodo (int sig) +class pending_signals { - return local_sigtodo + __SIGOFFSET + sig; -} + sigelem sigs[NSIG + 1]; + sigelem start; + sigelem *end; + sigelem *prev; + sigelem *curr; + int empty; +public: + void reset () {curr = &start; prev = &start;} + void add (int sig); + void del (); + int next (); + friend int __stdcall sig_dispatch_pending (); +}; + +static pending_signals sigqueue; + +struct sigaction *global_sigs; void __stdcall sigalloc () @@ -88,7 +106,7 @@ char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes // current process but no wait is required char NO_COPY myself_nowait_nonmain_dummy[1] = {'1'};// Flag to sig_send that signal goes to // current process but no wait is required - // if this is not the main thread. + // if this is the main thread. HANDLE NO_COPY signal_arrived; // Event signaled when a signal has // resulted in a user-specified @@ -107,20 +125,9 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit Static DWORD sig_loop_wait = INFINITE; // Wait for signals to arrive -Static HANDLE sigcatch_nonmain; // The semaphore signaled when - // signals are available for - // processing from non-main thread -Static HANDLE sigcatch_main; // Signalled when main thread sends a - // signal -Static HANDLE sigcatch_nosync; // Signal wait_sig to scan sigtodo - // but not to bother with any - // synchronization Static HANDLE sigcomplete_main; // Event signaled when a signal has // finished processing for the main // thread -Static HANDLE sigcomplete_nonmain; // Semaphore raised for non-main - // threads when a signal has finished - // processing HANDLE NO_COPY sigCONT; // Used to "STOP" a process Static cygthread *hwait_sig; // Handle of wait_sig thread Static cygthread *hwait_subproc; // Handle of sig_subproc thread @@ -147,13 +154,10 @@ muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff DWORD NO_COPY sigtid = 0; // ID of the signal thread -bool NO_COPY pending_signals = false; // true if signals pending - /* Functions */ static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1))); static __inline__ BOOL get_proc_lock (DWORD, DWORD); -static HANDLE __stdcall getevent (_pinfo *, const char *) __attribute__ ((regparm (2))); static void __stdcall remove_zombie (int); static DWORD WINAPI wait_sig (VOID *arg); static int __stdcall stopped_or_terminated (waitq *, _pinfo *); @@ -530,56 +534,45 @@ proc_terminate (void) sigproc_printf ("leaving"); } -/* Clear pending signal from the sigtodo array - */ +/* Clear pending signal */ void __stdcall -sig_clear (int sig) +sig_clear (int target_sig) { - (void) InterlockedExchange (myself->getsigtodo (sig), 0L); - (void) InterlockedExchange (getlocal_sigtodo (sig), 0L); + if (GetCurrentThreadId () != sigtid) + sig_send (myself, -target_sig); + else + { + int sig; + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (sig == target_sig) + { + sigqueue.del (); + break; + } + } return; } extern "C" int -sigpending (sigset_t *set) +sigpending (sigset_t *mask) { - unsigned bit; - *set = 0; - for (int sig = 1; sig < NSIG; sig++) - if ((*getlocal_sigtodo (sig) || *myself->getsigtodo (sig)) - && (myself->getsigmask () & (bit = SIGTOMASK (sig)))) - *set |= bit; + sigset_t outset = (sigset_t) sig_send (myself, __SIGPENDING); + if (outset == SIG_BAD_MASK) + return -1; + *mask = outset; return 0; } -/* Force the wait_sig thread to wake up and scan the sigtodo array. - */ -extern "C" int __stdcall +/* Force the wait_sig thread to wake up and scan for pending signals */ +int __stdcall sig_dispatch_pending () { - if (exit_state || !hwait_sig || GetCurrentThreadId () == sigtid) + if (exit_state || GetCurrentThreadId () == sigtid || !sigqueue.start.next) return 0; sigframe thisframe (mainthread); - -#ifdef DEBUGGING - sigproc_printf ("pending_signals %d", pending_signals); -#endif - - if (!pending_signals) -#ifdef DEBUGGING - sigproc_printf ("no need to wake anything up"); -#else - ; -#endif - else - { - (void) sig_send (myself, __SIGFLUSH); -#ifdef DEBUGGING - sigproc_printf ("woke up wait_sig"); -#endif - } - + (void) sig_send (myself, __SIGFLUSH); return thisframe.call_signal_handler (); } @@ -641,12 +634,7 @@ sigproc_terminate (void) sig_loop_wait = 0; // Tell wait_sig to exit when it is // finished with anything it is doing ForceCloseHandle (sigcomplete_main); - for (int i = 0; i < 20; i++) - (void) ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); - // ForceCloseHandle (sigcomplete_nonmain); - // ForceCloseHandle (sigcatch_main); - // ForceCloseHandle (sigcatch_nonmain); - // ForceCloseHandle (sigcatch_nosync); + CloseHandle (myself->sendsig); } proc_terminate (); // Terminate process handling thread @@ -664,15 +652,15 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) int rc = 1; DWORD tid = GetCurrentThreadId (); BOOL its_me; - HANDLE thiscatch = NULL; - HANDLE thiscomplete = NULL; - BOOL wait_for_completion; + HANDLE thiscomplete; + HANDLE sendsig; + bool wait_for_completion; sigframe thisframe; if (p == myself_nowait_nonmain) p = (tid == mainthread.id) ? (_pinfo *) myself : myself_nowait; if (!(its_me = (p == NULL || p == myself || p == myself_nowait))) - wait_for_completion = FALSE; + wait_for_completion = false; else { if (no_signals_available ()) @@ -696,79 +684,78 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me); - LONG *todo; - bool issem; if (its_me) { - if (!wait_for_completion) - { - thiscatch = sigcatch_nosync; - todo = myself->getsigtodo (sig); - issem = false; - } - else if (tid != mainthread.id) - { - thiscatch = sigcatch_nonmain; - thiscomplete = sigcomplete_nonmain; - todo = getlocal_sigtodo (sig); - issem = true; - } - else + sendsig = myself->sendsig; + if (wait_for_completion) { - thiscatch = sigcatch_main; + if (tid == mainthread.id) + thisframe.init (mainthread, ebp, exception); thiscomplete = sigcomplete_main; - thisframe.init (mainthread, ebp, exception); - todo = getlocal_sigtodo (sig); - issem = true; } } - else if ((thiscatch = getevent (p, "sigcatch"))) + else { - todo = p->getsigtodo (sig); - if (IsBadWritePtr (todo, sizeof (*todo))) + HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId); + if (!hp) + { + __seterrno (); + goto out; + } + if (!DuplicateHandle (hp, p->sendsig, hMainProc, &sendsig, false, 0, + DUPLICATE_SAME_ACCESS) || !sendsig) { - set_errno (EACCES); + __seterrno (); goto out; } - issem = false; + thiscomplete = NULL; } - else - goto out; // Couldn't get the semaphore. getevent issued - // an error, if appropriate. - -#if WHEN_MULTI_THREAD_SIGNALS_WORK - signal_dispatch *sd; - sd = signal_dispatch_storage.get (); - if (sd == NULL) - sd = signal_dispatch_storage.create (); -#endif - - /* Increment the sigtodo array to signify which signal to assert. - */ - (void) InterlockedIncrement (todo); - /* Notify the process that a signal has arrived. - */ - if (issem ? !ReleaseSemaphore (thiscatch, 1, NULL) : !SetEvent (thiscatch)) + DWORD nb; + if (!WriteFile (sendsig, &sig, sizeof (sig), &nb, NULL) || nb != sizeof (sig)) { /* Couldn't signal the semaphore. This probably means that the * process is exiting. */ if (!its_me) - ForceCloseHandle (thiscatch); + { + __seterrno (); + ForceCloseHandle (sendsig); + } else { if (no_signals_available ()) sigproc_printf ("I'm going away now"); - else if ((int) GetLastError () == -1) - rc = WaitForSingleObject (thiscomplete, 500); else - system_printf ("error sending signal %d to pid %d, semaphore %p, %E", - sig, p->pid, thiscatch); + system_printf ("error sending signal %d to pid %d, pipe handle %p, %E", + sig, p->pid, sendsig); } goto out; } + /* Write completion handle or NULL */ + if (!WriteFile (sendsig, &thiscomplete, sizeof (thiscomplete), &nb, NULL) + || nb != sizeof (thiscomplete)) + { + __seterrno (); + goto out; + } + + sigset_t pending; + sigset_t *mask; + if (sig == __SIGPENDING) + mask = &pending; + else if (sig == __SIGFLUSH || sig > 0) + mask = &myself->getsigmask (); + else + mask = NULL; + if (mask && !WriteFile (sendsig, &mask, sizeof (mask), &nb, NULL) + || nb != sizeof (pending)) + { + __seterrno (); + goto out; + } + /* No need to wait for signal completion unless this was a signal to * this process. * @@ -781,7 +768,7 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) rc = WAIT_OBJECT_0; sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig); if (!its_me) - ForceCloseHandle (thiscatch); + ForceCloseHandle (sendsig); } else { @@ -802,19 +789,16 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) } out: - sigproc_printf ("returning %d from sending signal %d", rc, sig); + if (sig != __SIGPENDING) + /* nothing */; + else if (!rc) + rc = (int) pending; + else + rc = SIG_BAD_MASK; + sigproc_printf ("returning %p from sending signal %d", rc, sig); return rc; } -/* Set pending signal from the sigtodo array - */ -void __stdcall -sig_set_pending (int sig) -{ - (void) InterlockedIncrement (getlocal_sigtodo (sig)); - return; -} - /* Initialize the wait_subproc thread. * Called from fork() or spawn() to initialize the handling of subprocesses. */ @@ -896,71 +880,6 @@ out: return potential_match; } -/* Get or create a process specific semaphore used in message passing. - */ -static HANDLE __stdcall -getevent (_pinfo *p, const char *str) -{ - HANDLE h; - char sem_name[MAX_PATH]; - - if (p != NULL) - { - if (!proc_can_be_signalled (p)) - { - set_errno (ESRCH); - return NULL; - } - int wait = 1000; - /* Wait for new process to generate its semaphores. */ - sigproc_printf ("pid %d, ppid %d, wait %d, initializing %x", p->pid, p->ppid, wait, - ISSTATE (p, PID_INITIALIZING)); - for (int i = 0; ISSTATE (p, PID_INITIALIZING) && i < wait; i++) - low_priority_sleep (1); - } - - if (p == NULL) - { - char sa_buf[1024]; - - DWORD winpid = GetCurrentProcessId (); -#if 0 - h = CreateSemaphore (sec_user_nih (sa_buf), init, max, - str = shared_name (sem_name, str, winpid)); -#else - h = CreateEvent (sec_user_nih (sa_buf), FALSE, FALSE, - str = shared_name (sem_name, str, winpid)); -#endif - p = myself; - if (!h) - { - system_printf ("can't create semaphore %s, %E", str); - __seterrno (); - } - } - else - { -#if 0 - h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, - shared_name (sem_name, str, p->dwProcessId)); -#else - h = OpenEvent (EVENT_ALL_ACCESS, FALSE, - shared_name (sem_name, str, p->dwProcessId)); -#endif - - if (!h) - { - if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p)) - set_errno (ESRCH); /* No such process */ - else - set_errno (EPERM); /* Couldn't access the semaphore -- - different cygwin DLL maybe? */ - } - } - - return h; -} - /* Remove a zombie from zombies by swapping it with the last child in the list. */ static void __stdcall @@ -1063,62 +982,94 @@ talktome () pids[i]->commune_recv (); } -#define RC_MAIN 0 -#define RC_NONMAIN 1 -#define RC_NOSYNC 2 /* Process signals by waiting for a semaphore to become signaled. - * Then scan an in-memory array representing queued signals. - * Executes in a separate thread. - * - * Signals sent from this process are sent a completion signal so - * that returns from kill/raise do not occur until the signal has - * has been handled, as per POSIX. - */ + Then scan an in-memory array representing queued signals. + Executes in a separate thread. + + Signals sent from this process are sent a completion signal so + that returns from kill/raise do not occur until the signal has + has been handled, as per POSIX. */ + +void +pending_signals::add (int sig) +{ + sigelem *se; + for (se = start.next; se; se = se->next) + if (se->sig == sig) + return; + while (sigs[empty].sig) + if (++empty == NSIG) + empty = 0; + se = sigs + empty; + se->sig = sig; + se->next = NULL; + if (end) + end->next = se; + end = se; + if (!start.next) + start.next = se; + empty++; +} + +void +pending_signals::del () +{ + sigelem *next = curr->next; + prev->next = next; + curr->sig = 0; +#ifdef DEBUGGING + curr->next = NULL; +#endif + if (end == curr) + end = prev; + empty = curr - sigs; + curr = next; +} + +int +pending_signals::next () +{ + int sig; + prev = curr; + if (!curr || !(curr = curr->next)) + sig = 0; + else + sig = curr->sig; + return sig; +} + +/* Process signals by waiting for signal data to arrive in a pipe. + Set a completion event if one was specified. */ static DWORD WINAPI wait_sig (VOID *self) { - LONG *todos[] = {getlocal_sigtodo (0), myself->getsigtodo (0)}; + HANDLE readsig; + char sa_buf[1024]; + /* Initialization */ (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); - /* sigcatch_nosync - semaphore incremented by sig_dispatch_pending and - * by foreign processes to force an examination of - * the sigtodo array. - * sigcatch_main - ditto for local main thread. - * sigcatch_nonmain - ditto for local non-main threads. - * - * sigcomplete_main - event used to signal main thread on signal - * completion - * sigcomplete_nonmain - semaphore signaled for non-main thread on signal - * completion - */ - sigcatch_nosync = getevent (NULL, "sigcatch"); - sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); - sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); - sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); + /* sigcomplete_main - event used to signal main thread on signal + completion */ + if (!CreatePipe (&readsig, &myself->sendsig, sec_user_nih (sa_buf), 0)) + api_fatal ("couldn't create signal pipe, %E"); sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); - sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main); + sigproc_printf ("sigcomplete_main %p", sigcomplete_main); sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); /* Setting dwProcessId flags that this process is now capable of receiving - * signals. Prior to this, dwProcessId was set to the windows pid of - * of the original windows process which spawned us unless this was a - * "toplevel" process. - */ + signals. Prior to this, dwProcessId was set to the windows pid of + of the original windows process which spawned us unless this was a + "toplevel" process. */ myself->dwProcessId = GetCurrentProcessId (); myself->process_state |= PID_ACTIVE; myself->process_state &= ~PID_INITIALIZING; - ProtectHandle (sigcatch_nosync); - ProtectHandle (sigcatch_nonmain); - ProtectHandle (sigcatch_main); - ProtectHandle (sigcomplete_nonmain); ProtectHandle (sigcomplete_main); /* If we've been execed, then there is still a stub left in the previous - * windows process waiting to see if it's started a cygwin process or not. - * Signalling subproc_ready indicates that we are a cygwin process. - */ + windows process waiting to see if it's started a cygwin process or not. + Signalling subproc_ready indicates that we are a cygwin process. */ if (child_proc_info && child_proc_info->type == PROC_EXEC) { debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); @@ -1135,149 +1086,71 @@ wait_sig (VOID *self) SetEvent (wait_sig_inited); sigtid = GetCurrentThreadId (); - HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync}; - sigproc_printf ("Ready. dwProcessid %d", myself->dwProcessId); - DWORD rc = RC_NOSYNC; - bool flush = false; for (;;) { - DWORD i; - if (rc == RC_MAIN || rc == RC_NONMAIN) - i = RC_NOSYNC; - else - i = RC_MAIN; - rc = WaitForSingleObject (catchem[i], 0); - if (rc != WAIT_OBJECT_0) - rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait); - else - rc = i + WAIT_OBJECT_0; - (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); + int sig; + DWORD nb; + if (!ReadFile (readsig, &sig, sizeof (sig), &nb, NULL)) + break; - /* sigproc_terminate sets sig_loop_wait to zero to indicate that - this thread should terminate. */ - if (rc == WAIT_TIMEOUT) + HANDLE wakeup; + if (!ReadFile (readsig, &wakeup, sizeof (wakeup), &nb, NULL) + || nb != sizeof (wakeup)) { - if (!sig_loop_wait) - break; // Exiting - else - continue; + system_printf ("signal notification handle read failure, %E"); + continue; } - if (rc == WAIT_FAILED) + if (!sig) + continue; /* Just checking to see if we exist */ + + sigset_t *mask; + if ((sig == __SIGFLUSH || sig == __SIGPENDING || sig > 0) + && (!ReadFile (readsig, &mask, sizeof (mask), &nb, NULL) + || nb != sizeof (mask))) { - if (sig_loop_wait != 0) - system_printf ("WFMO failed, %E"); - break; + system_printf ("signal mask handle read failure, %E"); + continue; } - rc -= WAIT_OBJECT_0; - sigproc_printf ("awake, rc %d", rc); - LONG *todo; - if (rc != RC_NOSYNC) - todo = todos[0]; - else - todo = todos[1]; - - /* A sigcatch semaphore has been signaled. Scan the sigtodo - array looking for any unprocessed signals. */ - pending_signals = false; - unsigned more_signals = 0; - bool saw_failed_interrupt = false; - do + switch (sig) { - more_signals = 0; - for (int sig = -__SIGOFFSET; sig < NSIG; sig++) + case __SIGCOMMUNE: + talktome (); + continue; + case __SIGSTRACE: + strace.hello (); + continue; + case __SIGPENDING: + *mask = 0; + unsigned bit; + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (myself->getsigmask () & (bit = SIGTOMASK (sig))) + *mask |= bit; + break; + default: + if (sig < 0) + sig_clear (-sig); + else { - LONG x = InterlockedDecrement (todo + sig); - if (x < 0) - InterlockedIncrement (todo + sig); - else if (x >= 0) - { - /* If x > 0, we have to deal with a signal at some later point */ - if (rc != RC_NOSYNC && x > 0) - /*pending_signals = true*/; // There should be an armed semaphore, in this case - - if (sig > 0 && sig != SIGKILL && sig != SIGSTOP && - (sigismember (&myself->getsigmask (), sig) || - main_vfork->pid || - (sig != SIGCONT && ISSTATE (myself, PID_STOPPED)))) - { - sigproc_printf ("signal %d blocked", sig); - x = InterlockedIncrement (myself->getsigtodo (sig)); - /* pending_signals = true;*/ // will be set by set_process_mask - } - else - { - sigproc_printf ("processing signal %d", sig); - switch (sig) - { - case __SIGFLUSH: - if (rc == RC_MAIN) - { - flush = true; - SetEvent (sigcatch_nosync); - goto out1; - } - break; - - /* Internal signal to turn on stracing. */ - case __SIGSTRACE: - strace.hello (); - break; - - case __SIGCOMMUNE: - talktome (); - break; - - /* A normal UNIX signal */ - default: - sigproc_printf ("Got signal %d", sig); - if (!sig_handle (sig)) - { - pending_signals = true; - saw_failed_interrupt = true; - x = InterlockedIncrement (myself->getsigtodo (sig)); - } - } - if (rc == RC_NOSYNC && x > 0) - more_signals++; - } - - if (sig == SIGCHLD) - proc_subproc (PROC_CLEARWAIT, 0); - - /* Need to take special action if an interrupt failed due to main thread not - getting around to calling handler yet. */ - if (saw_failed_interrupt || rc != RC_NOSYNC) - goto out; - } + int sh; + for (int i = 0; !(sh = sig_handle (sig, *mask)) && i < 100 ; i++) + low_priority_sleep (0); // hopefully a temporary condition + if (sh <= 0) + sigqueue.add (sig); // FIXME: Shouldn't add this in !sh condition + if (sig == SIGCHLD) + proc_subproc (PROC_CLEARWAIT, 0); } -#ifdef DEBUGGING - if (more_signals > 100) - system_printf ("hmm. infinite loop? more_signals %u\n", more_signals); -#endif - } - while (more_signals && sig_loop_wait); - - out: - /* Signal completion of signal handling depending on which semaphore - woke up the WaitForMultipleObjects above. */ - if (rc == RC_NONMAIN) // FIXME: This is broken - ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); - else if (rc == RC_MAIN || flush) - { - SetEvent (sigcomplete_main); - sigproc_printf ("set main thread completion event"); - flush = false; - } - - out1: - if (saw_failed_interrupt) - { - SetEvent (sigcatch_nosync); - low_priority_sleep (0); /* Hopefully, other thread will be waking up soon. */ + case __SIGFLUSH: + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (sig_handle (sig, *mask) > 0) + sigqueue.del (); + break; } - sigproc_printf ("looping"); + if (wakeup) + SetEvent (wakeup); } sigproc_printf ("done"); -- cgit v1.2.3