diff options
author | Christopher Faylor <cgf@redhat.com> | 2004-01-15 18:29:36 +0000 |
---|---|---|
committer | Christopher Faylor <cgf@redhat.com> | 2004-01-15 18:29:36 +0000 |
commit | f45e9b4d5654d6667b3f6e06903f47df713f1052 (patch) | |
tree | 3d81a6dce900e161b97a6525c890b20af11f9cc2 | |
parent | 9294f69cba58d397d8de931fca9269b406da1588 (diff) | |
download | gdb-f45e9b4d5654d6667b3f6e06903f47df713f1052.tar.gz |
* gentls_offsets: Reinstate unlink of temp files.
-rw-r--r-- | winsup/cygwin/ChangeLog | 4 | ||||
-rw-r--r-- | winsup/cygwin/cygtls.cc | 7 | ||||
-rw-r--r-- | winsup/cygwin/cygtls.h | 3 | ||||
-rw-r--r-- | winsup/cygwin/dcrt0.cc | 6 | ||||
-rw-r--r-- | winsup/cygwin/exceptions.cc | 157 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_termios.cc | 349 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_tty.cc | 1415 | ||||
-rwxr-xr-x | winsup/cygwin/gentls_offsets | 79 | ||||
-rw-r--r-- | winsup/cygwin/include/cygwin/signal.h | 187 | ||||
-rw-r--r-- | winsup/cygwin/signal.cc | 507 | ||||
-rw-r--r-- | winsup/cygwin/sigproc.cc | 132 | ||||
-rw-r--r-- | winsup/cygwin/sigproc.h | 110 | ||||
-rw-r--r-- | winsup/cygwin/thread.cc | 6 | ||||
-rw-r--r-- | winsup/cygwin/winsup.h | 4 |
14 files changed, 2835 insertions, 131 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index f1e3f2f0dc0..16aa73fe5b4 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,7 @@ +2004-01-15 Christopher Faylor <cgf@redhat.com> + + * gentls_offsets: Reinstate unlink of temp files. + 2004-01-14 Christopher Faylor <cgf@redhat.com> * fhandler_console.cc (fhandler_console::close): Fix debugging output. diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 5c9fa615f2e..ecec3f52bd0 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -20,6 +20,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "cygthread.h" +#include "sigproc.h" class sentry { @@ -189,6 +190,12 @@ _threadinfo::find_tls (int sig) return res; } +void +_threadinfo::set_siginfo (sigpacket *pack) +{ + infodata = pack->si; +} + extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD); static int handle_threadlist_exception (EXCEPTION_RECORD *e, void *frame, CONTEXT *, void *) diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index 779e42b8981..ab82bac9dfe 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -120,7 +120,7 @@ struct _threadinfo static void call2 (DWORD (*) (void *, void *), void *, void *) __attribute__ ((regparm (3))); static struct _threadinfo *find_tls (int sig); void remove (DWORD); - void push (__stack_t, bool = false); + void push (__stack_t, bool = false) __attribute__ ((regparm (3))); __stack_t pop (); bool isinitialized () {return initialized == CYGTLS_INITIALIZED || initialized == CYGTLS_EXCEPTION;} void set_state (bool); @@ -131,6 +131,7 @@ struct _threadinfo __attribute__((regparm(3))); void init_threadlist_exceptions (struct _exception_list *); operator HANDLE () const {return tid->win32_obj_id;} + void set_siginfo (struct sigpacket *) __attribute__ ((regparm (3))); /*gentls_offsets*/ }; #pragma pack(pop) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 3d6b7a89b4e..4b905b77488 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -1042,9 +1042,13 @@ do_exit (int status) /* Kill orphaned children on group leader exit */ if (myself->has_pgid_children && myself->pid == myself->pgid) { + siginfo_t si; + si.si_signo = -SIGHUP; + si.si_code = SI_KERNEL; + si.si_pid = si.si_uid = si.si_errno = 0; sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children", myself->pid, myself->pgid); - kill_pgrp (myself->pgid, -SIGHUP); + kill_pgrp (myself->pgid, si); } } diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 597c58e47d1..1fea4cd7c23 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -419,30 +419,56 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) RtlUnwind (frame, ret_here, e0, 0); __asm__ volatile (".equ _ret_here,."); - int sig; + siginfo_t si; /* Coerce win32 value to posix value. */ switch (e.ExceptionCode) { case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: - case STATUS_FLOAT_INEXACT_RESULT: case STATUS_FLOAT_INVALID_OPERATION: - case STATUS_FLOAT_OVERFLOW: case STATUS_FLOAT_STACK_CHECK: + si.si_signo = SIGFPE; + si.si_sigval.sival_int = FPE_FLTSUB; + break; + case STATUS_FLOAT_INEXACT_RESULT: + si.si_signo = SIGFPE; + si.si_sigval.sival_int = FPE_FLTRES; + break; + case STATUS_FLOAT_OVERFLOW: + si.si_signo = SIGFPE; + si.si_sigval.sival_int = FPE_FLTOVF; + break; case STATUS_FLOAT_UNDERFLOW: + si.si_signo = SIGFPE; + si.si_sigval.sival_int = FPE_FLTUND; + break; case STATUS_INTEGER_DIVIDE_BY_ZERO: + si.si_signo = SIGFPE; + si.si_sigval.sival_int = FPE_INTDIV; + break; case STATUS_INTEGER_OVERFLOW: - sig = SIGFPE; + si.si_signo = SIGFPE; + si.si_sigval.sival_int = FPE_INTOVF; break; case STATUS_ILLEGAL_INSTRUCTION: + si.si_signo = SIGILL; + si.si_sigval.sival_int = ILL_ILLOPC; + break; + case STATUS_PRIVILEGED_INSTRUCTION: + si.si_signo = SIGILL; + si.si_sigval.sival_int = ILL_PRVOPC; + break; + case STATUS_NONCONTINUABLE_EXCEPTION: - sig = SIGILL; + si.si_signo = SIGILL; + si.si_sigval.sival_int = ILL_ILLADR; break; case STATUS_TIMEOUT: - sig = SIGALRM; + si.si_signo = SIGALRM; + si.si_sigval.sival_int = 0; break; case STATUS_ACCESS_VIOLATION: @@ -453,11 +479,13 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) case STATUS_NO_MEMORY: case STATUS_INVALID_DISPOSITION: case STATUS_STACK_OVERFLOW: - sig = SIGSEGV; + si.si_signo = SIGSEGV; + si.si_sigval.sival_int = SEGV_MAPERR; break; case STATUS_CONTROL_C_EXIT: - sig = SIGINT; + si.si_signo = SIGINT; + si.si_sigval.sival_int = 0; break; case STATUS_INVALID_HANDLE: @@ -476,13 +504,14 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) } debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e.ExceptionCode, in.Eip, in.Esp); - debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in.Eip); + debug_printf ("In cygwin_except_handler sig = %d at %p", si.si_signo, in.Eip); - if (global_sigs[sig].sa_mask & SIGTOMASK (sig)) - syscall_printf ("signal %d, masked %p", sig, global_sigs[sig].sa_mask); + if (global_sigs[si.si_signo].sa_mask & SIGTOMASK (si.si_signo)) + syscall_printf ("signal %d, masked %p", si.si_signo, + global_sigs[si.si_signo].sa_mask); debug_printf ("In cygwin_except_handler calling %p", - global_sigs[sig].sa_handler); + global_sigs[si.si_signo].sa_handler); DWORD *ebp = (DWORD *)in.Esp; for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--) @@ -494,23 +523,18 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) if (!myself->progname[0] || GetCurrentThreadId () == sigtid - || (void *) global_sigs[sig].sa_handler == (void *) SIG_DFL - || (void *) global_sigs[sig].sa_handler == (void *) SIG_IGN - || (void *) global_sigs[sig].sa_handler == (void *) SIG_ERR) + || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL + || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN + || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR) { /* Print the exception to the console */ - if (1) - { - for (int i = 0; status_info[i].name; i++) - { - if (status_info[i].code == e.ExceptionCode) - { - if (!myself->ppid_handle) - system_printf ("Exception: %s", status_info[i].name); - break; - } - } - } + for (int i = 0; status_info[i].name; i++) + if (status_info[i].code == e.ExceptionCode) + { + if (!myself->ppid_handle) + system_printf ("Exception: %s", status_info[i].name); + break; + } /* Another exception could happen while tracing or while exiting. Only do this once. */ @@ -529,11 +553,13 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *) stackdump ((DWORD) ebp, 0, 1); } - signal_exit (0x80 | sig); // Flag signal + core dump + signal_exit (0x80 | si.si_signo); // Flag signal + core dump } - _my_tls.push ((__stack_t) ebp, true); - sig_send (NULL, sig, &_my_tls); // Signal myself + si.si_addr = ebp; + si.si_code = SI_KERNEL; + si.si_errno = si.si_pid = si.si_uid = 0; + sig_send (NULL, si, &_my_tls); // Signal myself return 1; } #endif /* __i386__ */ @@ -605,7 +631,14 @@ sig_handle_tty_stop (int sig) { pinfo parent (myself->ppid); if (ISSTATE (parent, PID_NOCLDSTOP)) - sig_send (parent, SIGCHLD); + { + siginfo_t si; + si.si_signo = SIGCHLD; + si.si_code = SI_KERNEL; + si.si_sigval.sival_int = CLD_STOPPED; + si.si_errno = si.si_pid = si.si_uid = si.si_errno = 0; + sig_send (parent, si); + } } sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p", myself->pid, sig, myself->ppid_handle); @@ -814,8 +847,8 @@ ctrl_c_handler (DWORD type) { if (type == CTRL_CLOSE_EVENT) { - saw_close = true; sig_send (NULL, SIGHUP); + saw_close = true; return FALSE; } if (!saw_close && type == CTRL_LOGOFF_EVENT) @@ -849,7 +882,7 @@ ctrl_c_handler (DWORD type) a CTRL_C_EVENT or CTRL_BREAK_EVENT. */ { t->last_ctrl_c = GetTickCount (); - kill (-myself->pid, SIGINT); + killsys (-myself->pid, SIGINT); t->last_ctrl_c = GetTickCount (); return TRUE; } @@ -884,9 +917,9 @@ set_signal_mask (sigset_t newmask, sigset_t oldmask) } int __stdcall -sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls) +sigpacket::process () { - if (sig == SIGCONT) + if (si.si_signo == SIGCONT) { DWORD stopped = myself->process_state & PID_STOPPED; myself->stopsig = 0; @@ -901,41 +934,44 @@ sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls) } int rc = 1; - bool insigwait_mask = tls ? sigismember (&tls->sigwait_mask, sig) : false; + bool insigwait_mask = tls ? sigismember (&tls->sigwait_mask, si.si_signo) : false; bool special_case = ISSTATE (myself, PID_STOPPED) || main_vfork->pid; - bool masked = sigismember (&mask, sig); - if (sig != SIGKILL && sig != SIGSTOP + bool masked = sigismember (mask, si.si_signo); + if (si.si_signo != SIGKILL && si.si_signo != SIGSTOP && (special_case || main_vfork->pid || masked || insigwait_mask - || (tls && sigismember (&tls->sigmask, sig)))) + || (tls && sigismember (&tls->sigmask, si.si_signo)))) { - sigproc_printf ("signal %d blocked", sig); + sigproc_printf ("signal %d blocked", si.si_signo); if ((!special_case && !masked) - && (insigwait_mask || (tls = _threadinfo::find_tls (sig)) != NULL)) + && (insigwait_mask || (tls = _threadinfo::find_tls (si.si_signo)) != NULL)) goto thread_specific; rc = -1; goto done; } /* Clear pending SIGCONT on stop signals */ - if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + if (si.si_signo == SIGSTOP || si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) sig_clear (SIGCONT); - sigproc_printf ("signal %d processing", sig); - struct sigaction thissig = global_sigs[sig]; + sigproc_printf ("signal %d processing", si.si_signo); + struct sigaction thissig = global_sigs[si.si_signo]; void *handler; handler = (void *) thissig.sa_handler; myself->rusage_self.ru_nsignals++; - if (sig == SIGKILL) + if (si.si_signo == SIGKILL) goto exit_sig; - if (sig == SIGSTOP) + if (!tls) + tls = _main_tls; + + if (si.si_signo == SIGSTOP) goto stop; #if 0 char sigmsg[24]; - __small_sprintf (sigmsg, "cygwin: signal %d\n", sig); + __small_sprintf (sigmsg, "cygwin: signal %d\n", si.si_signo); OutputDebugString (sigmsg); #endif @@ -943,14 +979,14 @@ sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls) { if (insigwait_mask) goto thread_specific; - if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH - || sig == SIGURG) + if (si.si_signo == SIGCHLD || si.si_signo == SIGIO || si.si_signo == SIGCONT || si.si_signo == SIGWINCH + || si.si_signo == SIGURG) { - sigproc_printf ("default signal %d ignored", sig); + sigproc_printf ("default signal %d ignored", si.si_signo); goto done; } - if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) goto stop; goto exit_sig; @@ -958,7 +994,7 @@ sig_handle (int sig, sigset_t mask, int pid, _threadinfo *tls) if (handler == (void *) SIG_IGN) { - sigproc_printf ("signal %d ignored", sig); + sigproc_printf ("signal %d ignored", si.si_signo); goto done; } @@ -973,34 +1009,37 @@ stop: goto done; handler = (void *) sig_handle_tty_stop; thissig = global_sigs[SIGSTOP]; + goto dosig1; dosig: + tls->set_siginfo (this); +dosig1: /* Dispatch to the appropriate function. */ - sigproc_printf ("signal %d, about to call %p", sig, handler); - rc = setup_handler (sig, handler, thissig, tls ?: _main_tls); + sigproc_printf ("signal %d, about to call %p", si.si_signo, handler); + rc = setup_handler (si.si_signo, handler, thissig, tls); done: sigproc_printf ("returning %d", rc); return rc; thread_specific: - tls->sig = sig; + tls->sig = si.si_signo; sigproc_printf ("releasing sigwait for thread"); SetEvent (tls->event); goto done; exit_sig: - if (sig == SIGQUIT || sig == SIGABRT) + if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT) { CONTEXT c; c.ContextFlags = CONTEXT_FULL; GetThreadContext (hMainThread, &c); if (!try_to_debug ()) stackdump (c.Ebp, 1, 1); - sig |= 0x80; + si.si_signo |= 0x80; } - sigproc_printf ("signal %d, about to call do_exit", sig); - signal_exit (sig); + sigproc_printf ("signal %d, about to call do_exit", si.si_signo); + signal_exit (si.si_signo); /* Never returns */ } diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc new file mode 100644 index 00000000000..398dabd9eec --- /dev/null +++ b/winsup/cygwin/fhandler_termios.cc @@ -0,0 +1,349 @@ +/* fhandler_termios.cc + + Copyright 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include <sys/termios.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "sigproc.h" +#include "pinfo.h" +#include "tty.h" +#include "sys/cygwin.h" + +/* Common functions shared by tty/console */ + +void +fhandler_termios::tcinit (tty_min *this_tc, bool force) +{ + /* Initial termios values */ + + tc = this_tc; + + if (force || !TTYISSETF (INITIALIZED)) + { + tc->ti.c_iflag = BRKINT | ICRNL | IXON; + tc->ti.c_oflag = OPOST | ONLCR; + tc->ti.c_cflag = B38400 | CS8 | CREAD; + tc->ti.c_lflag = ISIG | ICANON | ECHO | IEXTEN; + + tc->ti.c_cc[VDISCARD] = CFLUSH; + tc->ti.c_cc[VEOL] = CEOL; + tc->ti.c_cc[VEOL2] = CEOL2; + tc->ti.c_cc[VEOF] = CEOF; + tc->ti.c_cc[VERASE] = CERASE; + tc->ti.c_cc[VINTR] = CINTR; + tc->ti.c_cc[VKILL] = CKILL; + tc->ti.c_cc[VLNEXT] = CLNEXT; + tc->ti.c_cc[VMIN] = 1; + tc->ti.c_cc[VQUIT] = CQUIT; + tc->ti.c_cc[VREPRINT] = CRPRNT; + tc->ti.c_cc[VSTART] = CSTART; + tc->ti.c_cc[VSTOP] = CSTOP; + tc->ti.c_cc[VSUSP] = CSUSP; + tc->ti.c_cc[VSWTC] = CSWTCH; + tc->ti.c_cc[VTIME] = 0; + tc->ti.c_cc[VWERASE] = CWERASE; + + tc->ti.c_ispeed = tc->ti.c_ospeed = B38400; + tc->pgid = myself->pgid; + TTYSETF (INITIALIZED); + } +} + +int +fhandler_termios::tcsetpgrp (const pid_t pgid) +{ + termios_printf ("tty %d pgid %d, sid %d, tsid %d", tc->ntty, pgid, + myself->sid, tc->getsid ()); + if (myself->sid != tc->getsid ()) + { + set_errno (EPERM); + return -1; + } + tc->setpgid (pgid); + return 0; +} + +int +fhandler_termios::tcgetpgrp () +{ + return tc->pgid; +} + +void +tty_min::kill_pgrp (int sig) +{ + int killself = 0; + winpids pids ((DWORD) PID_MAP_RW); + siginfo_t si; + si.si_signo = sig; + si.si_code = SI_KERNEL; + si.si_pid = si.si_uid = si.si_errno = 0; + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + if (!proc_exists (p) || p->ctty != ntty || p->pgid != pgid) + continue; + if (p == myself) + killself++; + else + (void) sig_send (p, si); + } + if (killself) + sig_send (myself, si); +} + +bg_check_types +fhandler_termios::bg_check (int sig) +{ + if (!myself->pgid || tc->getpgid () == myself->pgid || + myself->ctty != tc->ntty || + ((sig == SIGTTOU) && !(tc->ti.c_lflag & TOSTOP))) + return bg_ok; + + if (sig < 0) + sig = -sig; + + termios_printf ("bg I/O pgid %d, tpgid %d, ctty %d", + myself->pgid, tc->getpgid (), myself->ctty); + + if (tc->getsid () == 0) + { + /* The pty has been closed by the master. Return an EOF + indication. FIXME: There is nothing to stop somebody + from reallocating this pty. I think this is the case + which is handled by unlockpt on a Unix system. */ + termios_printf ("closed by master"); + return bg_eof; + } + + /* If the process group is no more or if process is ignoring or blocks 'sig', + return with error */ + int pgid_gone = !pid_exists (myself->pgid); + int sigs_ignored = + ((void *) global_sigs[sig].sa_handler == (void *) SIG_IGN) || + (myself->getsigmask () & SIGTOMASK (sig)); + + if (pgid_gone) + goto setEIO; + else if (!sigs_ignored) + /* nothing */; + else if (sig == SIGTTOU) + return bg_ok; /* Just allow the output */ + else + goto setEIO; /* This is an output error */ + + /* Don't raise a SIGTT* signal if we have already been interrupted + by another signal. */ + if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0) + { + siginfo_t si; + si.si_signo = sig; + si.si_code = SI_KERNEL; + si.si_pid = si.si_uid = si.si_errno = 0; + kill_pgrp (myself->pgid, si); + } + return bg_signalled; + +setEIO: + set_errno (EIO); + return bg_error; +} + +#define set_input_done(x) input_done = input_done || (x) + +inline void +fhandler_termios::echo_erase (int force) +{ + if (force || tc->ti.c_lflag & ECHO) + doecho ("\b \b", 3); +} + +line_edit_status +fhandler_termios::line_edit (const char *rptr, int nread, termios& ti) +{ + line_edit_status ret = line_edit_ok; + char c; + int input_done = 0; + bool sawsig = false; + int iscanon = ti.c_lflag & ICANON; + + while (nread-- > 0) + { + c = *rptr++; + + termios_printf ("char %c", c); + + /* Check for special chars */ + + if (c == '\r') + { + if (ti.c_iflag & IGNCR) + continue; + if (ti.c_iflag & ICRNL) + { + c = '\n'; + set_input_done (iscanon); + } + } + else if (c == '\n') + { + if (ti.c_iflag & INLCR) + c = '\r'; + else + set_input_done (iscanon); + } + + if (ti.c_iflag & ISTRIP) + c &= 0x7f; + if (ti.c_lflag & ISIG) + { + int sig; + if (CCEQ (ti.c_cc[VINTR], c)) + sig = SIGINT; + else if (CCEQ (ti.c_cc[VQUIT], c)) + sig = SIGQUIT; + else if (CCEQ (ti.c_cc[VSUSP], c)) + sig = SIGTSTP; + else + goto not_a_sig; + + termios_printf ("got interrupt %d, sending signal %d", c, sig); + eat_readahead (-1); + tc->kill_pgrp (sig); + ti.c_lflag &= ~FLUSHO; + sawsig = true; + goto restart_output; + } + not_a_sig: + if (ti.c_iflag & IXON) + { + if (CCEQ (ti.c_cc[VSTOP], c)) + { + if (!tc->output_stopped) + { + tc->output_stopped = 1; + acquire_output_mutex (INFINITE); + } + continue; + } + else if (CCEQ (ti.c_cc[VSTART], c)) + { + restart_output: + tc->output_stopped = 0; + release_output_mutex (); + continue; + } + else if ((ti.c_iflag & IXANY) && tc->output_stopped) + goto restart_output; + } + if (iscanon && ti.c_lflag & IEXTEN && CCEQ (ti.c_cc[VDISCARD], c)) + { + ti.c_lflag ^= FLUSHO; + continue; + } + if (!iscanon) + /* nothing */; + else if (CCEQ (ti.c_cc[VERASE], c)) + { + if (eat_readahead (1)) + echo_erase (); + continue; + } + else if (CCEQ (ti.c_cc[VWERASE], c)) + { + int ch; + do + if (!eat_readahead (1)) + break; + else + echo_erase (); + while ((ch = peek_readahead (1)) >= 0 && !isspace (ch)); + continue; + } + else if (CCEQ (ti.c_cc[VKILL], c)) + { + int nchars = eat_readahead (-1); + if (ti.c_lflag & ECHO) + while (nchars--) + echo_erase (1); + continue; + } + else if (CCEQ (ti.c_cc[VREPRINT], c)) + { + if (ti.c_lflag & ECHO) + { + doecho ("\n\r", 2); + doecho (rabuf, ralen); + } + continue; + } + else if (CCEQ (ti.c_cc[VEOF], c)) + { + termios_printf ("EOF"); + (void) accept_input (); + ret = line_edit_input_done; + continue; + } + else if (CCEQ (ti.c_cc[VEOL], c) || + CCEQ (ti.c_cc[VEOL2], c) || + c == '\n') + { + set_input_done (1); + termios_printf ("EOL"); + } + + if (ti.c_iflag & IUCLC && isupper (c)) + c = cyg_tolower (c); + + put_readahead (c); + if (ti.c_lflag & ECHO) + doecho (&c, 1); + if (!iscanon || input_done) + { + int status = accept_input (); + if (status != 1) + { + ret = status ? line_edit_error : line_edit_pipe_full; + eat_readahead (1); + break; + } + ret = line_edit_input_done; + input_done = 0; + } + } + + if (!iscanon && ralen > 0) + ret = line_edit_input_done; + + if (sawsig) + ret = line_edit_signalled; + + return ret; +} + +void +fhandler_termios::fixup_after_fork (HANDLE parent) +{ + fhandler_base::fixup_after_fork (parent); + fork_fixup (parent, get_output_handle (), "output_handle"); +} + +_off64_t +fhandler_termios::lseek (_off64_t, int) +{ + set_errno (ESPIPE); + return -1; +} diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc new file mode 100644 index 00000000000..33c7f379dad --- /dev/null +++ b/winsup/cygwin/fhandler_tty.cc @@ -0,0 +1,1415 @@ +/* fhandler_tty.cc + + Copyright 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include <wingdi.h> +#include <winuser.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <limits.h> +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "sigproc.h" +#include "pinfo.h" +#include "cygheap.h" +#include "shared_info.h" +#include "cygserver.h" +#include "cygthread.h" + +/* Tty master stuff */ + +fhandler_tty_master NO_COPY *tty_master; + +static DWORD WINAPI process_input (void *); // Input queue thread +static DWORD WINAPI process_output (void *); // Output queue thread +static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread + +fhandler_tty_master::fhandler_tty_master () + : fhandler_pty_master (), console (NULL) +{ +} + +int +fhandler_tty_slave::get_unit () +{ + return dev () == FH_TTY ? myself->ctty : dev ().minor; +} + +void +fhandler_tty_master::set_winsize (bool sendSIGWINCH) +{ + winsize w; + console->ioctl (TIOCGWINSZ, &w); + get_ttyp ()->winsize = w; + if (sendSIGWINCH) + tc->kill_pgrp (SIGWINCH); +} + +int +fhandler_tty_master::init () +{ + slave = dev (); + termios_printf ("Creating master for tty%d", get_unit ()); + + if (init_console ()) + { + termios_printf ("can't create fhandler"); + return -1; + } + + termios ti; + memset (&ti, 0, sizeof (ti)); + console->tcsetattr (0, &ti); + + cygwin_shared->tty[get_unit ()]->common_init (this); + + set_winsize (false); + + inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE); + set_close_on_exec (true); + + cygthread *h; + h = new cygthread (process_input, cygself, "ttyin"); + h->SetThreadPriority (THREAD_PRIORITY_HIGHEST); + h->zap_h (); + + h = new cygthread (process_ioctl, cygself, "ttyioctl"); + h->SetThreadPriority (THREAD_PRIORITY_HIGHEST); + h->zap_h (); + + h = new cygthread (process_output, cygself, "ttyout"); + h->SetThreadPriority (THREAD_PRIORITY_HIGHEST); + h->zap_h (); + + return 0; +} + +#ifdef DEBUGGING +static class mutex_stack +{ +public: + const char *fn; + int ln; + const char *tname; +} ostack[100]; + +static int osi; +#endif /*DEBUGGING*/ + +DWORD +fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln, + DWORD ms) +{ + if (strace.active) + strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: waiting %d ms", ln, ms); + DWORD res = WaitForSingleObject (output_mutex, ms); + if (res == WAIT_OBJECT_0) + { +#ifndef DEBUGGING + if (strace.active) + strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex: acquired", ln, res); +#else + ostack[osi].fn = fn; + ostack[osi].ln = ln; + ostack[osi].tname = cygthread::name (); + termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi); + osi++; +#endif + } + return res; +} + +void +fhandler_tty_common::__release_output_mutex (const char *fn, int ln) +{ + if (ReleaseMutex (output_mutex)) + { +#ifndef DEBUGGING + if (strace.active) + strace.prntf (_STRACE_TERMIOS, fn, "(%d): tty output_mutex released", ln); +#else + if (osi > 0) + osi--; + termios_printf ("released at %s:%d, osi %d", fn, ln, osi); + termios_printf (" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname); + ostack[osi].ln = -ln; +#endif + } +} + +/* Process tty input. */ + +void +fhandler_pty_master::doecho (const void *str, DWORD len) +{ + acquire_output_mutex (INFINITE); + if (!WriteFile (get_ttyp ()->to_master, str, len, &len, NULL)) + termios_printf ("Write to %p failed, %E", get_ttyp ()->to_master); +// WaitForSingleObject (output_done_event, INFINITE); + release_output_mutex (); +} + +int +fhandler_pty_master::accept_input () +{ + DWORD bytes_left; + int ret = 1; + + (void) WaitForSingleObject (input_mutex, INFINITE); + + bytes_left = eat_readahead (-1); + + if (!bytes_left) + { + termios_printf ("sending EOF to slave"); + get_ttyp ()->read_retval = 0; + } + else + { + char *p = rabuf; + DWORD rc; + DWORD written = 0; + + termios_printf ("about to write %d chars to slave", bytes_left); + rc = WriteFile (get_output_handle (), p, bytes_left, &written, NULL); + if (!rc) + { + debug_printf ("error writing to pipe %E"); + get_ttyp ()->read_retval = -1; + ret = -1; + } + else + { + get_ttyp ()->read_retval = 1; + p += written; + bytes_left -= written; + if (bytes_left > 0) + { + debug_printf ("to_slave pipe is full"); + puts_readahead (p, bytes_left); + ret = 0; + } + } + } + + SetEvent (input_available_event); + ReleaseMutex (input_mutex); + return ret; +} + +static DWORD WINAPI +process_input (void *) +{ + char rawbuf[INP_BUFFER_SIZE]; + + while (1) + { + size_t nraw = INP_BUFFER_SIZE; + tty_master->console->read ((void *) rawbuf, nraw); + if (tty_master->line_edit (rawbuf, nraw, tty_master->get_ttyp ()->ti) + == line_edit_signalled) + tty_master->console->eat_readahead (-1); + } +} + +bool +fhandler_pty_master::hit_eof () +{ + if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ()) + { + /* We have the only remaining open handle to this pty, and + the slave pty has been opened at least once. We treat + this as EOF. */ + termios_printf ("all other handles closed"); + return 1; + } + return 0; +} + +/* Process tty output requests */ + +int +fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on) +{ + size_t rlen; + char outbuf[OUT_BUFFER_SIZE + 1]; + DWORD n; + int column = 0; + int rc = 0; + + if (len == 0) + goto out; + + if (need_nl) + { + /* We need to return a left over \n character, resulting from + \r\n conversion. Note that we already checked for FLUSHO and + output_stopped at the time that we read the character, so we + don't check again here. */ + if (buf) + buf[0] = '\n'; + need_nl = 0; + rc = 1; + goto out; + } + + + for (;;) + { + /* Set RLEN to the number of bytes to read from the pipe. */ + rlen = len; + if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR) + { + /* We are going to expand \n to \r\n, so don't read more than + half of the number of bytes requested. */ + rlen /= 2; + if (rlen == 0) + rlen = 1; + } + if (rlen > sizeof outbuf) + rlen = sizeof outbuf; + + HANDLE handle = get_io_handle (); + + n = 0; // get_readahead_into_buffer (outbuf, len); + if (!n) + { + /* Doing a busy wait like this is quite inefficient, but nothing + else seems to work completely. Windows should provide some sort + of overlapped I/O for pipes, or something, but it doesn't. */ + while (1) + { + if (!PeekNamedPipe (handle, NULL, 0, NULL, &n, NULL)) + goto err; + if (n > 0) + break; + if (hit_eof ()) + goto out; + /* DISCARD (FLUSHO) and tcflush can finish here. */ + if (n == 0 && (get_ttyp ()->ti.c_lflag & FLUSHO || !buf)) + goto out; + if (n == 0 && is_nonblocking ()) + { + set_errno (EAGAIN); + rc = -1; + break; + } + + Sleep (10); + } + + if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE) + goto err; + } + + termios_printf ("bytes read %u", n); + get_ttyp ()->write_error = 0; + if (output_done_event != NULL) + SetEvent (output_done_event); + + if (get_ttyp ()->ti.c_lflag & FLUSHO || !buf) + continue; + + char *optr; + optr = buf; + if (pktmode_on) + *optr++ = TIOCPKT_DATA; + + if (!(get_ttyp ()->ti.c_oflag & OPOST)) // post-process output + { + memcpy (optr, outbuf, n); + optr += n; + } + else // raw output mode + { + char *iptr = outbuf; + + while (n--) + { + switch (*iptr) + { + case '\r': + if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0) + { + iptr++; + continue; + } + if (get_ttyp ()->ti.c_oflag & OCRNL) + *iptr = '\n'; + else + column = 0; + break; + case '\n': + if (get_ttyp ()->ti.c_oflag & ONLCR) + { + *optr++ = '\r'; + column = 0; + } + if (get_ttyp ()->ti.c_oflag & ONLRET) + column = 0; + break; + default: + column++; + break; + } + + /* Don't store data past the end of the user's buffer. This + can happen if the user requests a read of 1 byte when + doing \r\n expansion. */ + if (optr - buf >= (int) len) + { + if (*iptr != '\n' || n != 0) + system_printf ("internal error: %d unexpected characters", n); + need_nl = 1; + break; + } + + *optr++ = *iptr++; + } + } + rc = optr - buf; + break; + + err: + if (GetLastError () == ERROR_BROKEN_PIPE) + rc = 0; + else + { + __seterrno (); + rc = -1; + } + break; + } + +out: + termios_printf ("returning %d", rc); + return rc; +} + +static DWORD WINAPI +process_output (void *) +{ + char buf[OUT_BUFFER_SIZE * 2]; + + for (;;) + { + int n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE, 0); + if (n <= 0) + { + if (n < 0) + termios_printf ("ReadFile %E"); + ExitThread (0); + } + n = tty_master->console->write ((void *) buf, (size_t) n); + tty_master->get_ttyp ()->write_error = n == -1 ? get_errno () : 0; + } +} + + +/* Process tty ioctl requests */ + +static DWORD WINAPI +process_ioctl (void *) +{ + while (1) + { + WaitForSingleObject (tty_master->ioctl_request_event, INFINITE); + termios_printf ("ioctl() request"); + tty_master->get_ttyp ()->ioctl_retval = + tty_master->console->ioctl (tty_master->get_ttyp ()->cmd, + (void *) &tty_master->get_ttyp ()->arg); + SetEvent (tty_master->ioctl_done_event); + } +} + +/**********************************************************************/ +/* Tty slave stuff */ + +fhandler_tty_slave::fhandler_tty_slave () + : fhandler_tty_common () +{ + set_r_no_interrupt (1); +} + +/* FIXME: This function needs to close handles when it has + a failing condition. */ +int +fhandler_tty_slave::open (int flags, mode_t) +{ + if (get_device () == FH_TTY) + pc.dev.tty_to_real_device (); + fhandler_tty_slave *arch = (fhandler_tty_slave *) + cygheap->fdtab.find_archetype (pc.dev); + if (arch) + { + *this = *(fhandler_tty_slave *) arch; + termios_printf ("copied tty fhandler archetype"); + cygheap->open_fhs++; + goto out; + } + + tcinit (cygwin_shared->tty[get_unit ()]); + + attach_tty (get_unit ()); + + set_flags ((flags & ~O_TEXT) | O_BINARY); + /* Create synchronisation events */ + char buf[40]; + + /* output_done_event may or may not exist. It will exist if the tty + was opened by fhandler_tty_master::init, normally called at + startup if use_tty is non-zero. It will not exist if this is a + pty opened by fhandler_pty_master::open. In the former case, tty + output is handled by a separate thread which controls output. */ + __small_sprintf (buf, OUTPUT_DONE_EVENT, get_unit ()); + output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); + + if (!(output_mutex = get_ttyp ()->open_output_mutex ())) + { + termios_printf ("open output mutex failed, %E"); + __seterrno (); + return 0; + } + if (!(input_mutex = get_ttyp ()->open_input_mutex ())) + { + termios_printf ("open input mutex failed, %E"); + __seterrno (); + return 0; + } + __small_sprintf (buf, INPUT_AVAILABLE_EVENT, get_unit ()); + if (!(input_available_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf))) + { + termios_printf ("open input event failed, %E"); + __seterrno (); + return 0; + } + + /* The ioctl events may or may not exist. See output_done_event, + above. */ + __small_sprintf (buf, IOCTL_REQUEST_EVENT, get_unit ()); + ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); + __small_sprintf (buf, IOCTL_DONE_EVENT, get_unit ()); + ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); + + /* FIXME: Needs a method to eliminate tty races */ + { + acquire_output_mutex (500); + inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE); + get_ttyp ()->was_opened = true; + release_output_mutex (); + } + + /* Duplicate tty handles. */ + + if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave) + { + termios_printf ("tty handles have been closed"); + set_errno (EACCES); + return 0; + } + + HANDLE from_master_local; + HANDLE to_master_local; + from_master_local = to_master_local = NULL; + +#ifdef USE_SERVER + if (!wincap.has_security () + || cygserver_running == CYGSERVER_UNAVAIL + || !cygserver_attach_tty (&from_master_local, &to_master_local)) +#endif + { +#ifdef USE_SERVER + termios_printf ("cannot dup handles via server. using old method."); +#endif + HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, + get_ttyp ()->master_pid); + termios_printf ("tty own handle %p",tty_owner); + if (tty_owner == NULL) + { + termios_printf ("can't open tty (%d) handle process %d", + get_unit (), get_ttyp ()->master_pid); + __seterrno (); + return 0; + } + + if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master, + hMainProc, &from_master_local, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate input, %E"); + __seterrno (); + return 0; + } + + if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master, + hMainProc, &to_master_local, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate output, %E"); + __seterrno (); + return 0; + } + CloseHandle (tty_owner); + } + + termios_printf ("duplicated from_master %p->%p from tty_owner", + get_ttyp ()->from_master, from_master_local); + termios_printf ("duplicated to_master %p->%p from tty_owner", + get_ttyp ()->to_master, to_master_local); + + set_io_handle (from_master_local); + set_output_handle (to_master_local); + + set_open_status (); + if (cygheap->open_fhs++ == 0 && !GetConsoleCP () && !output_done_event + && wincap.pty_needs_alloc_console () && !GetProcessWindowStation ()) + { + BOOL b; + HWINSTA h = CreateWindowStation (NULL, 0, GENERIC_READ | GENERIC_WRITE, &sec_none_nih); + termios_printf ("CreateWindowStation %p, %E", h); + if (h) + { + b = SetProcessWindowStation (h); + termios_printf ("SetProcessWindowStation %d, %E", b); + } + b = AllocConsole (); // will cause flashing if workstation + // stuff fails + termios_printf ("%d = AllocConsole (), %E", b); + if (b) + init_console_handler (); + } + + // FIXME: Do this better someday + arch = (fhandler_tty_slave *) cmalloc (HEAP_ARCHETYPES, sizeof (*this)); + *((fhandler_tty_slave **) cygheap->fdtab.add_archetype ()) = arch; + archetype = arch; + *arch = *this; + +out: + usecount = 0; + archetype->usecount++; + report_tty_counts (this, "opened", "incremented ", ""); + myself->set_ctty (get_ttyp (), flags, arch); + + return 1; +} + +int +fhandler_tty_slave::close () +{ + if (!--cygheap->open_fhs && myself->ctty == -1) + FreeConsole (); + + archetype->usecount--; + report_tty_counts (this, "closed", "decremented ", ""); + + if (archetype->usecount) + { +#ifdef DEBUGGING + if (archetype->usecount < 0) + system_printf ("error: usecount %d", archetype->usecount); +#endif + termios_printf ("just returning because archetype usecount is != 0"); + return 0; + } + + termios_printf ("closing last open %s handle", ttyname ()); + return fhandler_tty_common::close (); +} + +int +fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr, + LPHANDLE to_master_ptr) +{ +#ifndef USE_SERVER + return 0; +#else + if (!from_master_ptr || !to_master_ptr) + return 0; + + client_request_attach_tty req ((DWORD) get_ttyp ()->master_pid, + (HANDLE) get_ttyp ()->from_master, + (HANDLE) get_ttyp ()->to_master); + + if (req.make_request () == -1 || req.error_code ()) + return 0; + + *from_master_ptr = req.from_master (); + *to_master_ptr = req.to_master (); + + return 1; +#endif +} + +void +fhandler_tty_slave::init (HANDLE, DWORD a, mode_t) +{ + int flags = 0; + + a &= GENERIC_READ | GENERIC_WRITE; + if (a == GENERIC_READ) + flags = O_RDONLY; + if (a == GENERIC_WRITE) + flags = O_WRONLY; + if (a == (GENERIC_READ | GENERIC_WRITE)) + flags = O_RDWR; + + open (flags); +} + +int +fhandler_tty_slave::write (const void *ptr, size_t len) +{ + DWORD n, towrite = len; + + termios_printf ("tty%d, write(%x, %d)", get_unit (), ptr, len); + + acquire_output_mutex (INFINITE); + + while (len) + { + n = min (OUT_BUFFER_SIZE, len); + char *buf = (char *)ptr; + ptr = (char *) ptr + n; + len -= n; + + /* Previous write may have set write_error to != 0. Check it here. + This is less than optimal, but the alternative slows down tty + writes enormously. */ + if (get_ttyp ()->write_error) + { + set_errno (get_ttyp ()->write_error); + towrite = (DWORD) -1; + break; + } + + if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE) + { + DWORD err = GetLastError (); + termios_printf ("WriteFile failed, %E"); + switch (err) + { + case ERROR_NO_DATA: + err = ERROR_IO_DEVICE; + default: + __seterrno_from_win_error (err); + } + raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ + towrite = (DWORD) -1; + break; + } + + if (output_done_event != NULL) + { + DWORD rc; + DWORD x = n * 1000; + rc = WaitForSingleObject (output_done_event, x); + termios_printf ("waited %d ms for output_done_event, WFSO %d", x, rc); + } + } + release_output_mutex (); + return towrite; +} + +void __stdcall +fhandler_tty_slave::read (void *ptr, size_t& len) +{ + int totalread = 0; + int vmin = 0; + int vtime = 0; /* Initialized to prevent -Wuninitialized warning */ + size_t readlen; + DWORD bytes_in_pipe; + char buf[INP_BUFFER_SIZE]; + char peek_buf[INP_BUFFER_SIZE]; + DWORD time_to_wait; + DWORD rc; + HANDLE w4[2]; + + termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ()); + + if (!ptr) /* Indicating tcflush(). */ + time_to_wait = 0; + else if ((get_ttyp ()->ti.c_lflag & ICANON)) + time_to_wait = INFINITE; + else + { + vmin = get_ttyp ()->ti.c_cc[VMIN]; + if (vmin > INP_BUFFER_SIZE) + vmin = INP_BUFFER_SIZE; + vtime = get_ttyp ()->ti.c_cc[VTIME]; + if (vmin < 0) + vmin = 0; + if (vtime < 0) + vtime = 0; + if (!vmin && !vtime) + time_to_wait = 0; + else + time_to_wait = !vtime ? INFINITE : 100 * vtime; + } + + w4[0] = signal_arrived; + w4[1] = input_available_event; + + DWORD waiter = !ptr ? 0 : INFINITE; + while (len) + { + rc = WaitForMultipleObjects (2, w4, FALSE, waiter); + + if (rc == WAIT_TIMEOUT) + break; + + if (rc == WAIT_FAILED) + { + termios_printf ("wait for input event failed, %E"); + break; + } + + if (rc == WAIT_OBJECT_0) + { + /* if we've received signal after successfully reading some data, + just return all data successfully read */ + if (totalread > 0) + break; + set_sig_errno (EINTR); + len = (size_t) -1; + return; + } + + rc = WaitForSingleObject (input_mutex, 1000); + if (rc == WAIT_FAILED) + { + termios_printf ("wait for input mutex failed, %E"); + break; + } + else if (rc == WAIT_TIMEOUT) + { + termios_printf ("failed to acquire input mutex after input event arrived"); + break; + } + if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL)) + { + termios_printf ("PeekNamedPipe failed, %E"); + raise (SIGHUP); + bytes_in_pipe = 0; + } + + /* On first peek determine no. of bytes to flush. */ + if (!ptr && len == UINT_MAX) + len = (size_t) bytes_in_pipe; + + if (ptr && !vmin && !time_to_wait) + { + ReleaseMutex (input_mutex); + len = (size_t) bytes_in_pipe; + return; + } + + readlen = min (bytes_in_pipe, min (len, sizeof (buf))); + + if (ptr && vmin && readlen > (unsigned) vmin) + readlen = vmin; + + DWORD n = 0; + if (readlen) + { + termios_printf ("reading %d bytes (vtime %d)", readlen, vtime); + if (ReadFile (get_handle (), buf, readlen, &n, NULL) == FALSE) + { + termios_printf ("read failed, %E"); + raise (SIGHUP); + } + /* MSDN states that 5th prameter can be used to determine total + number of bytes in pipe, but for some reason this number doesn't + change after successful read. So we have to peek into the pipe + again to see if input is still available */ + if (!PeekNamedPipe (get_handle (), peek_buf, 1, &bytes_in_pipe, NULL, NULL)) + { + termios_printf ("PeekNamedPipe failed, %E"); + raise (SIGHUP); + bytes_in_pipe = 0; + } + if (n) + { + len -= n; + totalread += n; + if (ptr) + { + memcpy (ptr, buf, n); + ptr = (char *) ptr + n; + } + } + } + + if (!bytes_in_pipe) + ResetEvent (input_available_event); + + ReleaseMutex (input_mutex); + + if (!ptr) + { + if (!bytes_in_pipe) + break; + continue; + } + + if (get_ttyp ()->read_retval < 0) // read error + { + set_errno (-get_ttyp ()->read_retval); + totalread = -1; + break; + } + if (get_ttyp ()->read_retval == 0) //EOF + { + termios_printf ("saw EOF"); + break; + } + if (get_ttyp ()->ti.c_lflag & ICANON || is_nonblocking ()) + break; + if (vmin && totalread >= vmin) + break; + + /* vmin == 0 && vtime == 0: + * we've already read all input, if any, so return immediately + * vmin == 0 && vtime > 0: + * we've waited for input 10*vtime ms in WFSO(input_available_event), + * no matter whether any input arrived, we shouldn't wait any longer, + * so return immediately + * vmin > 0 && vtime == 0: + * here, totalread < vmin, so continue waiting until more data + * arrive + * vmin > 0 && vtime > 0: + * similar to the previous here, totalread < vmin, and timer + * hadn't expired -- WFSO(input_available_event) != WAIT_TIMEOUT, + * so "restart timer" and wait until more data arrive + */ + + if (vmin == 0) + break; + + if (n) + waiter = time_to_wait; + } + termios_printf ("%d=read(%x, %d)", totalread, ptr, len); + len = (size_t) totalread; + return; +} + +int +fhandler_tty_slave::dup (fhandler_base *child) +{ + fhandler_tty_slave *arch = (fhandler_tty_slave *) archetype; + *(fhandler_tty_slave *) child = *arch; + child->usecount = 0; + arch->usecount++; + cygheap->open_fhs++; + report_tty_counts (child, "duped", "incremented ", ""); + myself->set_ctty (get_ttyp (), openflags, arch); + return 0; +} + +int +fhandler_tty_common::dup (fhandler_base *child) +{ + fhandler_tty_slave *fts = (fhandler_tty_slave *) child; + int errind; + + fts->tcinit (get_ttyp ()); + + attach_tty (get_unit ()); + + HANDLE nh; + + if (output_done_event == NULL) + fts->output_done_event = NULL; + else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc, + &fts->output_done_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 1; + goto err; + } + if (ioctl_request_event == NULL) + fts->ioctl_request_event = NULL; + else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc, + &fts->ioctl_request_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 2; + goto err; + } + if (ioctl_done_event == NULL) + fts->ioctl_done_event = NULL; + else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc, + &fts->ioctl_done_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 3; + goto err; + } + if (!DuplicateHandle (hMainProc, input_available_event, hMainProc, + &fts->input_available_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 4; + goto err; + } + if (!DuplicateHandle (hMainProc, output_mutex, hMainProc, + &fts->output_mutex, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 5; + goto err; + } + if (!DuplicateHandle (hMainProc, input_mutex, hMainProc, + &fts->input_mutex, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 6; + goto err; + } + if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, + &nh, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 7; + goto err; + } + fts->set_io_handle (nh); + + if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc, + &nh, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 8; + goto err; + } + fts->set_output_handle (nh); + + if (inuse == NULL) + fts->inuse = NULL; + else if (!DuplicateHandle (hMainProc, inuse, hMainProc, + &fts->inuse, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 9; + goto err; + } + + return 0; + +err: + __seterrno (); + termios_printf ("dup %d failed in DuplicateHandle, %E", errind); + return -1; +} + +int +fhandler_tty_slave::tcgetattr (struct termios *t) +{ + *t = get_ttyp ()->ti; + return 0; +} + +int +fhandler_tty_slave::tcsetattr (int, const struct termios *t) +{ + acquire_output_mutex (INFINITE); + get_ttyp ()->ti = *t; + release_output_mutex (); + return 0; +} + +int +fhandler_tty_slave::tcflush (int queue) +{ + int ret = 0; + + termios_printf ("tcflush(%d) handle %p", queue, get_handle ()); + + if (queue == TCIFLUSH || queue == TCIOFLUSH) + { + size_t len = UINT_MAX; + read (NULL, len); + ret = len >= 0; + } + if (queue == TCOFLUSH || queue == TCIOFLUSH) + { + /* do nothing for now. */ + } + + termios_printf ("%d=tcflush(%d)", ret, queue); + return ret; +} + +int +fhandler_tty_slave::ioctl (unsigned int cmd, void *arg) +{ + termios_printf ("ioctl (%x)", cmd); + + if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid + && myself->ctty == get_unit () && (get_ttyp ()->ti.c_lflag & TOSTOP)) + { + /* background process */ + termios_printf ("bg ioctl pgid %d, tpgid %d, ctty %d", + myself->pgid, get_ttyp ()->getpgid (), myself->ctty); + raise (SIGTTOU); + } + + int retval; + switch (cmd) + { + case TIOCGWINSZ: + case TIOCSWINSZ: + case TIOCLINUX: + break; + case FIONBIO: + set_nonblocking (*(int *) arg); + retval = 0; + goto out; + default: + set_errno (EINVAL); + return -1; + } + + acquire_output_mutex (INFINITE); + + get_ttyp ()->cmd = cmd; + get_ttyp ()->ioctl_retval = 0; + switch (cmd) + { + case TIOCGWINSZ: + get_ttyp ()->arg.winsize = get_ttyp ()->winsize; + if (ioctl_request_event) + SetEvent (ioctl_request_event); + *(struct winsize *) arg = get_ttyp ()->arg.winsize; + if (ioctl_done_event) + WaitForSingleObject (ioctl_done_event, INFINITE); + get_ttyp ()->winsize = get_ttyp ()->arg.winsize; + break; + case TIOCSWINSZ: + if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row + || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) + { + if (!ioctl_request_event) + get_ttyp ()->ioctl_retval = -EINVAL; + else + { + get_ttyp ()->arg.winsize = *(struct winsize *) arg; + SetEvent (ioctl_request_event); + get_ttyp ()->winsize = *(struct winsize *) arg; + killsys (-get_ttyp ()->getpgid (), SIGWINCH); + if (ioctl_done_event) + WaitForSingleObject (ioctl_done_event, INFINITE); + } + } + break; + case TIOCLINUX: + int val = *(unsigned char *) arg; + if (val != 6 || !ioctl_request_event || !ioctl_done_event) + get_ttyp ()->ioctl_retval = -EINVAL; + else + { + get_ttyp ()->arg.value = val; + SetEvent (ioctl_request_event); + WaitForSingleObject (ioctl_done_event, INFINITE); + *(unsigned char *) arg = get_ttyp ()->arg.value & 0xFF; + } + break; + } + + release_output_mutex (); + retval = get_ttyp ()->ioctl_retval; + if (retval < 0) + { + set_errno (-retval); + retval = -1; + } + +out: + termios_printf ("%d = ioctl (%x)", retval, cmd); + return retval; +} + +/******************************************************* + fhandler_pty_master +*/ +fhandler_pty_master::fhandler_pty_master () + : fhandler_tty_common () +{ +} + +int +fhandler_pty_master::open (int flags, mode_t) +{ + int ntty = cygwin_shared->tty.allocate_tty (0); + if (ntty < 0) + return 0; + + slave = *ttys_dev; + slave.setunit (ntty); + cygwin_shared->tty[ntty]->common_init (this); + inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE); + set_flags ((flags & ~O_TEXT) | O_BINARY); + set_open_status (); + + termios_printf ("opened pty master tty%d", get_unit ()); + return 1; +} + +int +fhandler_tty_common::close () +{ + termios_printf ("tty%d <%p,%p> closing", get_unit (), get_handle (), get_output_handle ()); + if (output_done_event && !CloseHandle (output_done_event)) + termios_printf ("CloseHandle (output_done_event), %E"); + if (ioctl_done_event && !CloseHandle (ioctl_done_event)) + termios_printf ("CloseHandle (ioctl_done_event), %E"); + if (ioctl_request_event && !CloseHandle (ioctl_request_event)) + termios_printf ("CloseHandle (ioctl_request_event), %E"); + if (inuse && !CloseHandle (inuse)) + termios_printf ("CloseHandle (inuse), %E"); + if (!ForceCloseHandle (input_mutex)) + termios_printf ("CloseHandle (input_mutex<%p>), %E", input_mutex); + if (!ForceCloseHandle (output_mutex)) + termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); + + /* Send EOF to slaves if master side is closed */ + if (!get_ttyp ()->master_alive ()) + { + termios_printf ("no more masters left. sending EOF"); + SetEvent (input_available_event); + } + + if (!ForceCloseHandle (input_available_event)) + termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); + if (!ForceCloseHandle1 (get_handle (), from_pty)) + termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ()); + if (!ForceCloseHandle1 (get_output_handle (), to_pty)) + termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ()); + + inuse = NULL; + set_io_handle (NULL); + return 0; +} + +int +fhandler_pty_master::close () +{ +#if 0 + while (accept_input () > 0) + continue; +#endif + fhandler_tty_common::close (); + + if (!get_ttyp ()->master_alive ()) + { + termios_printf ("freeing tty%d (%d)", get_unit (), get_ttyp ()->ntty); +#if 0 + if (get_ttyp ()->to_slave) + ForceCloseHandle1 (get_ttyp ()->to_slave, to_slave); + if (get_ttyp ()->from_slave) + ForceCloseHandle1 (get_ttyp ()->from_slave, from_slave); +#endif + if (get_ttyp ()->from_master) + CloseHandle (get_ttyp ()->from_master); + if (get_ttyp ()->to_master) + CloseHandle (get_ttyp ()->to_master); + get_ttyp ()->init (); + } + + return 0; +} + +int +fhandler_pty_master::write (const void *ptr, size_t len) +{ + int i; + char *p = (char *) ptr; + termios ti = tc->ti; + + for (i = 0; i < (int) len; i++) + { + line_edit_status status = line_edit (p++, 1, ti); + if (status > line_edit_signalled) + { + if (status != line_edit_pipe_full) + i = -1; + break; + } + } + return i; +} + +void __stdcall +fhandler_pty_master::read (void *ptr, size_t& len) +{ + len = (size_t) process_slave_output ((char *) ptr, len, pktmode); + return; +} + +int +fhandler_pty_master::tcgetattr (struct termios *t) +{ + *t = cygwin_shared->tty[get_unit ()]->ti; + return 0; +} + +int +fhandler_pty_master::tcsetattr (int, const struct termios *t) +{ + cygwin_shared->tty[get_unit ()]->ti = *t; + return 0; +} + +int +fhandler_pty_master::tcflush (int queue) +{ + int ret = 0; + + termios_printf ("tcflush(%d) handle %p", queue, get_handle ()); + + if (queue == TCIFLUSH || queue == TCIOFLUSH) + ret = process_slave_output (NULL, OUT_BUFFER_SIZE, 0); + else if (queue == TCIFLUSH || queue == TCIOFLUSH) + { + /* do nothing for now. */ + } + + termios_printf ("%d=tcflush(%d)", ret, queue); + return ret; +} + +int +fhandler_pty_master::ioctl (unsigned int cmd, void *arg) +{ + switch (cmd) + { + case TIOCPKT: + pktmode = *(int *) arg; + break; + case TIOCGWINSZ: + *(struct winsize *) arg = get_ttyp ()->winsize; + break; + case TIOCSWINSZ: + if (get_ttyp ()->winsize.ws_row != ((struct winsize *) arg)->ws_row + || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) + { + get_ttyp ()->winsize = *(struct winsize *) arg; + killsys (-get_ttyp ()->getpgid (), SIGWINCH); + } + break; + case FIONBIO: + set_nonblocking (*(int *) arg); + break; + default: + set_errno (EINVAL); + return -1; + } + return 0; +} + +char * +fhandler_pty_master::ptsname () +{ + static char buf[32]; + + __small_sprintf (buf, "/dev/tty%d", get_unit ()); + return buf; +} + +void +fhandler_tty_common::set_close_on_exec (int val) +{ + if (archetype) + set_close_on_exec_flag (val); + else + { + if (output_done_event) + set_inheritance (output_done_event, val); + if (ioctl_request_event) + set_inheritance (ioctl_request_event, val); + if (ioctl_done_event) + set_inheritance (ioctl_done_event, val); + if (inuse) + set_inheritance (inuse, val); + set_inheritance (output_mutex, val); + set_inheritance (input_mutex, val); + set_inheritance (input_available_event, val); + set_inheritance (output_handle, val); +#ifndef DEBUGGING + fhandler_base::set_close_on_exec (val); +#else + /* FIXME: This is a duplication from fhandler_base::set_close_on_exec. + It is here because we need to specify the "from_pty" stuff here or + we'll get warnings from ForceCloseHandle when debugging. */ + set_inheritance (get_io_handle (), val); + set_close_on_exec_flag (val); +#endif + } +} + +void +fhandler_tty_slave::fixup_after_fork (HANDLE parent) +{ + // fhandler_tty_common::fixup_after_fork (parent); + report_tty_counts (this, "inherited", "", ""); +} + +void +fhandler_tty_common::fixup_after_fork (HANDLE parent) +{ + fhandler_termios::fixup_after_fork (parent); + if (output_done_event) + fork_fixup (parent, output_done_event, "output_done_event"); + if (ioctl_request_event) + fork_fixup (parent, ioctl_request_event, "ioctl_request_event"); + if (ioctl_done_event) + fork_fixup (parent, ioctl_done_event, "ioctl_done_event"); + if (output_mutex) + fork_fixup (parent, output_mutex, "output_mutex"); + if (input_mutex) + fork_fixup (parent, input_mutex, "input_mutex"); + if (input_available_event) + fork_fixup (parent, input_available_event, "input_available_event"); + fork_fixup (parent, inuse, "inuse"); +} + +void +fhandler_pty_master::set_close_on_exec (int val) +{ + fhandler_tty_common::set_close_on_exec (val); + + /* FIXME: There is a console handle leak here. */ + if (get_ttyp ()->master_pid == GetCurrentProcessId ()) + { + get_ttyp ()->from_slave = get_handle (); + get_ttyp ()->to_slave = get_output_handle (); + termios_printf ("from_slave %p, to_slave %p", get_handle (), + get_output_handle ()); + } +} + +int +fhandler_tty_master::init_console () +{ + console = (fhandler_console *) build_fh_dev (*console_dev, "/dev/ttym"); + if (console == NULL) + return -1; + + console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY); + cygheap->open_fhs--; /* handled when individual fds are opened */ + console->set_r_no_interrupt (1); + return 0; +} diff --git a/winsup/cygwin/gentls_offsets b/winsup/cygwin/gentls_offsets new file mode 100755 index 00000000000..375b668408f --- /dev/null +++ b/winsup/cygwin/gentls_offsets @@ -0,0 +1,79 @@ +#!/usr/bin/perl -s +my $tls = shift; +my $tls_out = shift; +open(TLS, $tls) or die "$0: couldn't open tls file \"$tls\" - $!\n"; +my $struct = ''; +my @fields = (); +my $def = ''; +$tls = join('', <TLS>); +$tls =~ s/\n[^\n]*gentls_offsets[^\n]*\n(.+)\Z/$1/os; +my $pre = $`; +substr($tls, 0, length($pre)) = ''; +$pre =~ s/\n#ifndef _[^\n]+\n/\n/os; +$pre .= "\n//*/"; +$tls =~ s%/\*\s*gentls_offsets.*?/\*\s*gentls_offsets\s*\*/%%ogs; +foreach ($tls =~ /^.*\n/mg) { + $def .= $_ if $struct; + last if /^};/o; + /^\s*typedef/o and do { + $def .= $_ ; + next; + }; + if (!s/;.*$//o) { + if (!$struct && /^\s*(?:struct|class)\s*([a-z_0-9]+)/o) { + $def .= $_; + $struct = $1 + } + next; + } + s/(?:\[[^\]]*\]|struct|class)//o; + s/^\s+\S+\s+//o; + s/[\*\s()]+//go; + for my $f (split(/,/)) { + push(@fields, $f); + } +} +close TLS; +open(TMP, '>', "/tmp/$$.cc") or die "$0: couldn't open temporary index file \"/tmp/$$.c\" - $!\n"; +print TMP <<EOF; +#define __INSIDE_CYGWIN__ +#define __attribute__(X) +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +typedef void *HANDLE; +$pre +$def +int +main(int argc, char **argv) +{ + $struct foo[1]; +# define foo_end ((char *) (foo + 1)) +# define offset(f) (((char *) &(foo->f)) - foo_end) +EOF + print TMP 'puts ("//;# autogenerated: Do not edit.\n");', "\n\n"; + for my $f (@fields) { + print TMP ' printf ("//; $tls::', $f, ' = %d;\n", ', "offset($f));\n"; + } + print TMP ' puts ("//; __DATA__\n");', "\n"; + for my $f (@fields) { + print TMP ' printf ("#define tls_', $f, ' (%d)\n", ', "offset($f));\n"; + } + + print TMP <<EOF; + + exit (0); +} +EOF +close TMP; +system @ARGV, '-o', "/tmp/$$-1.cc", '-E', "/tmp/$$.cc"; +system 'g++', '-o', "/tmp/$$.a.out", "/tmp/$$-1.cc" and +($? == 127 && system 'c++', '-o', "/tmp/$$.a.out", "/tmp/$$-1.cc") and +die "$0: couldn't generate executable for offset calculation \"/tmp/$$.a.out\" - $!\n"; +open(TLS_OUT, '>', $tls_out) or die "$0: couldn't open tls index file \"tls_out\" - $!\n"; +open(OFFS, "/tmp/$$.a.out|") or die "$0: couldn't run \"/tmp/$$.a.out\" - $!\n"; +print TLS_OUT <OFFS>; +close OFFS; +close TLS_OUT; +unlink "/tmp/$$.cc", "/tmp/$$.a.out"; +exit(0); diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h new file mode 100644 index 00000000000..5e26bf42ff3 --- /dev/null +++ b/winsup/cygwin/include/cygwin/signal.h @@ -0,0 +1,187 @@ +#ifndef _CYGWIN_SIGNAL_H +#define _CYGWIN_SIGNAL_H + +#if 0 +struct ucontext +{ + unsigned long uc_flags; + void *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; +}; +#endif + +typedef union sigval +{ + int sival_int; /* integer signal value */ + void *sival_ptr; /* pointer signal value */ +} sigval_t; + +#pragma pack(push,4) +typedef struct +{ + int si_signo; /* signal number */ + int si_code; /* signal code */ + pid_t si_pid; /* sender's pid */ + uid_t si_uid; /* sender's uid */ + int si_errno; /* errno associated with signal */ + + union + { + __uint32_t __pad[120]; /* plan for future growth */ + union + { + /* timers */ + struct + { + union + { + struct + { + unsigned int si_tid; /* timer id */ + unsigned int si_overrun; /* overrun count */ + }; + }; + sigval_t si_sigval; /* signal value */ + }; + }; + + /* SIGCHLD */ + struct + { + int si_status; /* exit code */ + clock_t si_utime; /* user time */ + clock_t si_stime; /* system time */ + }; + + /* core dumping signals */ + void *si_addr; /* faulting address */ + }; +} siginfo_t; +#pragma pack(pop) + +enum +{ + SI_USER = 1, /* sent by kill, raise, pthread_kill */ + SI_ASYNCIO, /* sent by AIO completion (currently + unimplemented) */ + SI_MESGQ, /* sent by real time mesq state change + (currently unimplemented) */ + SI_TIMER, /* sent by timer expiration */ + SI_QUEUE, /* sent by sigqueue (currently + unimplemented) */ + SI_KERNEL, /* sent by system */ + + ILL_ILLOPC, /* illegal opcode */ + ILL_ILLOPN, /* illegal operand */ + ILL_ILLADR, /* illegal addressing mode */ + ILL_ILLTRP, /* illegal trap*/ + ILL_PRVOPC, /* privileged opcode */ + ILL_PRVREG, /* privileged register */ + ILL_COPROC, /* coprocessor error */ + ILL_BADSTK, /* internal stack error */ + + FPE_INTDIV, /* integer divide by zero */ + FPE_INTOVF, /* integer overflow */ + FPE_FLTDIV, /* floating point divide by zero */ + FPE_FLTOVF, /* floating point overflow */ + FPE_FLTUND, /* floating point underflow */ + FPE_FLTRES, /* floating point inexact result */ + FPE_FLTINV, /* floating point invalid operation */ + FPE_FLTSUB, /* subscript out of range */ + + SEGV_MAPERR, /* address not mapped to object */ + SEGV_ACCERR, /* invalid permissions for mapped object */ + + BUS_ADRALN, /* invalid address alignment. */ + BUS_ADRERR, /* non-existant physical address. */ + BUS_OBJERR, /* object specific hardware error. */ + + CLD_EXITED, /* child has exited */ + CLD_KILLED, /* child was killed */ + CLD_DUMPED, /* child terminated abnormally */ + CLD_TRAPPED, /* traced child has trapped */ + CLD_STOPPED, /* child has stopped */ + CLD_CONTINUED /* stopped child has continued */ +}; + +typedef struct sigevent +{ + sigval_t sigev_value; /* signal value */ + int sigev_signo; /* signal number */ + int sigev_notify; /* notification type */ + void (*sigev_notify_function) (sigval_t); /* notification function */ + pthread_attr_t *sigev_notify_attributes; /* notification attributes */ +} sigevent_t; + +enum +{ + SIGEV_SIGNAL = 0, /* a queued signal, with an application + defined value, is generated when the + event of interest occurs */ + SIGEV_NONE, /* no asynchronous notification is + delivered when the event of interest + occurs */ + SIGEV_THREAD /* a notification function is called to + perform notification */ +}; + +typedef void (*_sig_func_ptr)(int); + +struct sigaction +{ + union + { + _sig_func_ptr sa_handler; /* SIG_DFL, SIG_IGN, or pointer to a function */ + void (*sa_sigaction) ( int, siginfo_t *, void * ); + }; + sigset_t sa_mask; + int sa_flags; +}; + +#define SA_NOCLDSTOP 1 /* Do not generate SIGCHLD when children + stop */ +#define SA_SIGINFO 2 /* Invoke the signal catching function + with three arguments instead of one + */ +#define SA_RESTART 0x10000000 /* Restart syscall on signal return */ +#define SA_NODEFER 0x40000000 /* Don't automatically block the signal + when its handler is being executed */ +#define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler */ + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt */ +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 /* illegal instruction (not reset when caught) */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGABRT 6 /* used by abort */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 /* segmentation violation */ +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ +#define SIGURG 16 /* urgent condition on IO channel */ +#define SIGSTOP 17 /* sendable stop signal not from tty */ +#define SIGTSTP 18 /* stop signal from tty */ +#define SIGCONT 19 /* continue a stopped process */ +#define SIGCHLD 20 /* to parent on child stop or exit */ +#define SIGCLD 20 /* System V name for SIGCHLD */ +#define SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */ +#define SIGIO 23 /* input/output possible signal */ +#define SIGPOLL SIGIO /* System V name for SIGIO */ +#define SIGXCPU 24 /* exceeded CPU time limit */ +#define SIGXFSZ 25 /* exceeded file size limit */ +#define SIGVTALRM 26 /* virtual time alarm */ +#define SIGPROF 27 /* profiling time alarm */ +#define SIGWINCH 28 /* window changed */ +#define SIGLOST 29 /* resource lost (eg, record-lock lost) */ +#define SIGUSR1 30 /* user defined signal 1 */ +#define SIGUSR2 31 /* user defined signal 2 */ +#define NSIG 32 /* signal 0 implied */ +#endif /*_CYGWIN_SIGNAL_H*/ diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc new file mode 100644 index 00000000000..492ca3b24da --- /dev/null +++ b/winsup/cygwin/signal.cc @@ -0,0 +1,507 @@ +/* signal.cc + + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. + + Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com + Significant changes by Sergey Okhapkin <sos@prospect.com.ru> + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include <stdlib.h> +#include "cygerrno.h" +#include <sys/cygwin.h> +#include "pinfo.h" +#include "sigproc.h" +#include "hires.h" +#include "security.h" +#include "cygtls.h" + +int sigcatchers; /* FIXME: Not thread safe. */ + +#define sigtrapped(func) ((func) != SIG_IGN && (func) != SIG_DFL) + +static inline void +set_sigcatchers (void (*oldsig) (int), void (*cursig) (int)) +{ +#ifdef DEBUGGING + int last_sigcatchers = sigcatchers; +#endif + if (!sigtrapped (oldsig) && sigtrapped (cursig)) + sigcatchers++; + else if (sigtrapped (oldsig) && !sigtrapped (cursig)) + sigcatchers--; +#ifdef DEBUGGING + if (last_sigcatchers != sigcatchers) + sigproc_printf ("last %d, old %d, cur %p, cur %p", last_sigcatchers, + sigcatchers, oldsig, cursig); +#endif +} + +extern "C" _sig_func_ptr +signal (int sig, _sig_func_ptr func) +{ + sig_dispatch_pending (); + _sig_func_ptr prev; + + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func); + return (_sig_func_ptr) SIG_ERR; + } + + prev = global_sigs[sig].sa_handler; + global_sigs[sig].sa_handler = func; + global_sigs[sig].sa_mask = 0; + /* SA_RESTART is set to maintain BSD compatible signal behaviour by default. + This is also compatible with the behaviour of signal(2) in Linux. */ + global_sigs[sig].sa_flags |= SA_RESTART; + set_sigcatchers (prev, func); + + syscall_printf ("%p = signal (%d, %p)", prev, sig, func); + return prev; +} + +extern "C" int +nanosleep (const struct timespec *rqtp, struct timespec *rmtp) +{ + int res = 0; + sig_dispatch_pending (); + pthread_testcancel (); + + if ((unsigned int) rqtp->tv_sec > (HIRES_DELAY_MAX / 1000 - 1) + || (unsigned int) rqtp->tv_nsec > 999999999) + { + set_errno (EINVAL); + return -1; + } + DWORD resolution = gtod.resolution (); + DWORD req = ((rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000 + + resolution - 1) / resolution) * resolution; + DWORD end_time = gtod.dmsecs () + req; + syscall_printf ("nanosleep (%ld)", req); + + int rc = pthread::cancelable_wait (signal_arrived, req); + DWORD rem; + if ((rem = end_time - gtod.dmsecs ()) > HIRES_DELAY_MAX) + rem = 0; + if (rc == WAIT_OBJECT_0) + { + (void) call_signal_handler_now (); + set_errno (EINTR); + res = -1; + } + + if (rmtp) + { + rmtp->tv_sec = rem / 1000; + rmtp->tv_nsec = (rem % 1000) * 1000000; + } + + syscall_printf ("%d = nanosleep (%ld, %ld)", res, req, rem); + return res; +} + +extern "C" unsigned int +sleep (unsigned int seconds) +{ + struct timespec req, rem; + req.tv_sec = seconds; + req.tv_nsec = 0; + nanosleep (&req, &rem); + return rem.tv_sec + (rem.tv_nsec > 0); +} + +extern "C" unsigned int +usleep (unsigned int useconds) +{ + struct timespec req; + req.tv_sec = useconds / 1000000; + req.tv_nsec = (useconds % 1000000) * 1000; + int res = nanosleep (&req, 0); + return res; +} + +extern "C" int +sigprocmask (int sig, const sigset_t *set, sigset_t *oldset) +{ + return handle_sigprocmask (sig, set, oldset, myself->getsigmask ()); +} + +int __stdcall +handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& opmask) +{ + sig_dispatch_pending (); + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (ESRCH); + syscall_printf ("SIG_ERR = sigprocmask signal %d out of range", sig); + return -1; + } + + if (oldset) + { + if (check_null_invalid_struct_errno (oldset)) + return -1; + *oldset = opmask; + } + + if (set) + { + if (check_invalid_read_struct_errno (set)) + return -1; + sigset_t newmask = opmask; + switch (sig) + { + case SIG_BLOCK: + /* add set to current mask */ + newmask |= *set; + break; + case SIG_UNBLOCK: + /* remove set from current mask */ + newmask &= ~*set; + break; + case SIG_SETMASK: + /* just set it */ + newmask = *set; + break; + default: + set_errno (EINVAL); + return -1; + } + (void) set_signal_mask (newmask, opmask); + } + return 0; +} + +static int +kill_worker (pid_t pid, siginfo_t& si) +{ + sig_dispatch_pending (); + + int res = 0; + pinfo dest (pid); + bool sendSIGCONT; + + if (!dest) + { + set_errno (ESRCH); + return -1; + } + + if ((sendSIGCONT = (si.si_signo < 0))) + si.si_signo = -si.si_signo; + + DWORD process_state = dest->process_state; + if (si.si_signo == 0) + { + res = proc_exists (dest) ? 0 : -1; + if (res < 0) + set_errno (ESRCH); + } + else if ((res = sig_send (dest, si))) + { + sigproc_printf ("%d = sig_send, %E ", res); + res = -1; + } + else if (sendSIGCONT) + { + siginfo_t si2; + si2.si_signo = SIGCONT; + si2.si_code = SI_KERNEL; + si2.si_pid = si2.si_uid = si2.si_errno = 0; + (void) sig_send (dest, si2); + } + + syscall_printf ("%d = kill_worker (%d, %d), process_state %p", res, pid, + si.si_signo, process_state); + return res; +} + +int +raise (int sig) +{ + return kill (myself->pid, sig); +} + +static int +kill0 (pid_t pid, siginfo_t& si) +{ + syscall_printf ("kill (%d, %d)", pid, si.si_signo); + /* check that sig is in right range */ + if (si.si_signo < 0 || si.si_signo >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("signal %d out of range", si.si_signo); + return -1; + } + + /* Silently ignore stop signals from a member of orphaned process group. + FIXME: Why??? */ + if (ISSTATE (myself, PID_ORPHANED) && + (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)) + si.si_signo = 0; + + return (pid > 0) ? kill_worker (pid, si) : kill_pgrp (-pid, si); +} + +int +killsys (pid_t pid, int sig) +{ + siginfo_t si; + si.si_signo = sig; + si.si_code = SI_KERNEL; + si.si_pid = si.si_uid = si.si_errno = 0; + return kill0 (pid, si); +} +int +kill (pid_t pid, int sig) +{ + siginfo_t si; + si.si_signo = sig; + si.si_code = SI_USER; + si.si_pid = si.si_uid = si.si_errno = 0; + return kill0 (pid, si); +} + +int +kill_pgrp (pid_t pid, siginfo_t& si) +{ + int res = 0; + int found = 0; + int killself = 0; + + sigproc_printf ("pid %d, signal %d", pid, si.si_signo); + + winpids pids ((DWORD) PID_MAP_RW); + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + + if (!proc_exists (p)) + continue; + + /* Is it a process we want to kill? */ + if ((pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) || + (pid > 1 && p->pgid != pid) || + (si.si_signo < 0 && NOTSTATE (p, PID_STOPPED))) + continue; + sigproc_printf ("killing pid %d, pgrp %d, p->ctty %d, myself->ctty %d", + p->pid, p->pgid, p->ctty, myself->ctty); + if (p == myself) + killself++; + else if (kill_worker (p->pid, si)) + res = -1; + found++; + } + + if (killself && kill_worker (myself->pid, si)) + res = -1; + + if (!found) + { + set_errno (ESRCH); + res = -1; + } + syscall_printf ("%d = kill (%d, %d)", res, pid, si.si_signo); + return res; +} + +extern "C" int +killpg (pid_t pgrp, int sig) +{ + return kill (-pgrp, sig); +} + +extern "C" void +abort (void) +{ + sig_dispatch_pending (); + /* Flush all streams as per SUSv2. + From my reading of this document, this isn't strictly correct. + The streams are supposed to be flushed prior to exit. However, + if there is I/O in any signal handler that will not necessarily + be flushed. + However this is the way FreeBSD does it, and it is much easier to + do things this way, so... */ + if (_REENT->__cleanup) + _REENT->__cleanup (_REENT); + + /* Ensure that SIGABRT can be caught regardless of blockage. */ + sigset_t sig_mask; + sigfillset (&sig_mask); + sigdelset (&sig_mask, SIGABRT); + set_signal_mask (sig_mask); + + raise (SIGABRT); + (void) call_signal_handler_now (); /* Call any signal handler */ + do_exit (1); /* signal handler didn't exit. Goodbye. */ +} + +extern "C" int +sigaction (int sig, const struct sigaction *newact, struct sigaction *oldact) +{ + sig_dispatch_pending (); + sigproc_printf ("signal %d, newact %p, oldact %p", sig, newact, oldact); + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigaction signal %d out of range", sig); + return -1; + } + + struct sigaction oa = global_sigs[sig]; + + if (newact) + { + if (sig == SIGKILL || sig == SIGSTOP) + { + set_errno (EINVAL); + return -1; + } + global_sigs[sig] = *newact; + if (newact->sa_handler == SIG_IGN) + sig_clear (sig); + if (newact->sa_handler == SIG_DFL && sig == SIGCHLD) + sig_clear (sig); + set_sigcatchers (oa.sa_handler, newact->sa_handler); + if (sig == SIGCHLD) + { + myself->process_state &= ~PID_NOCLDSTOP; + if (newact->sa_flags & SA_NOCLDSTOP); + myself->process_state |= PID_NOCLDSTOP; + } + } + + if (oldact) + *oldact = oa; + + return 0; +} + +extern "C" int +sigaddset (sigset_t *set, const int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigaddset signal %d out of range", sig); + return -1; + } + + *set |= SIGTOMASK (sig); + return 0; +} + +extern "C" int +sigdelset (sigset_t *set, const int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig); + return -1; + } + + *set &= ~SIGTOMASK (sig); + return 0; +} + +extern "C" int +sigismember (const sigset_t *set, int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigdelset signal %d out of range", sig); + return -1; + } + + if (*set & SIGTOMASK (sig)) + return 1; + else + return 0; +} + +extern "C" int +sigemptyset (sigset_t *set) +{ + *set = (sigset_t) 0; + return 0; +} + +extern "C" int +sigfillset (sigset_t *set) +{ + *set = ~((sigset_t) 0); + return 0; +} + +extern "C" int +sigsuspend (const sigset_t *set) +{ + return handle_sigsuspend (*set); +} + +extern "C" int +sigpause (int signal_mask) +{ + return handle_sigsuspend ((sigset_t) signal_mask); +} + +extern "C" int +pause (void) +{ + return handle_sigsuspend (myself->getsigmask ()); +} + +extern "C" int +siginterrupt (int sig, int flag) +{ + struct sigaction act; + (void) sigaction(sig, NULL, &act); + if (flag) + act.sa_flags &= ~SA_RESTART; + else + act.sa_flags |= SA_RESTART; + return sigaction (sig, &act, NULL); +} + + +extern "C" int +sigwait (const sigset_t *set, int *sig) +{ + pthread_testcancel (); + _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + if (!_my_tls.event) + { + __seterrno (); + return -1; + } + + _my_tls.sigwait_mask = *set; + + switch (WaitForSingleObject (_my_tls.event, INFINITE)) + { + case WAIT_OBJECT_0: + CloseHandle (_my_tls.event); + _my_tls.event = NULL; + *sig = InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0); + break; + default: + __seterrno (); + return -1; + } + return 0; +} diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index e143a823963..70129f6c289 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -48,41 +48,22 @@ details. */ #define NZOMBIES 256 -struct sigelem -{ - int sig; - int pid; - _threadinfo *tls; - class sigelem *next; - friend class pending_signals; - friend int __stdcall sig_dispatch_pending (); -}; - class pending_signals { - sigelem sigs[NSIG + 1]; - sigelem start; - sigelem *end; - sigelem *prev; - sigelem *curr; + sigpacket sigs[NSIG + 1]; + sigpacket start; + sigpacket *end; + sigpacket *prev; + sigpacket *curr; int empty; public: void reset () {curr = &start; prev = &start;} - void add (int sig, int pid, _threadinfo *tls); + void add (sigpacket&); void del (); - sigelem *next (); + sigpacket *next (); friend int __stdcall sig_dispatch_pending (); }; -struct sigpacket -{ - int sig; - pid_t pid; - HANDLE wakeup; - sigset_t *mask; - _threadinfo *tls; -}; - static pending_signals sigqueue; struct sigaction *global_sigs; @@ -563,9 +544,9 @@ sig_clear (int target_sig) else { sigqueue.reset (); - sigelem *q; + sigpacket *q; while ((q = sigqueue.next ())) - if (q->sig == target_sig) + if (q->si.si_signo == target_sig) { sigqueue.del (); break; @@ -670,13 +651,22 @@ sigproc_terminate (void) return; } +int __stdcall +sig_send (_pinfo *p, int sig) +{ + siginfo_t si; + si.si_signo = sig; + si.si_code = SI_KERNEL; + si.si_pid = si.si_uid = si.si_errno = 0; + return sig_send (p, si); +} + /* Send a signal to another process by raising its signal semaphore. - * If pinfo *p == NULL, send to the current process. - * If sending to this process, wait for notification that a signal has - * completed before returning. - */ + If pinfo *p == NULL, send to the current process. + If sending to this process, wait for notification that a signal has + completed before returning. */ int __stdcall -sig_send (_pinfo *p, int sig, void *tls) +sig_send (_pinfo *p, siginfo_t& si, _threadinfo *tls) { int rc = 1; bool its_me; @@ -703,11 +693,11 @@ sig_send (_pinfo *p, int sig, void *tls) if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */ { sigproc_printf ("invalid pid %d(%x), signal %d", - p->pid, p->process_state, sig); + p->pid, p->process_state, si.si_signo); goto out; } - sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me); + sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, si.si_signo, its_me); if (its_me) { @@ -740,14 +730,18 @@ sig_send (_pinfo *p, int sig, void *tls) sigset_t pending; if (!its_me) pack.mask = NULL; - else if (sig == __SIGPENDING) + else if (si.si_signo == __SIGPENDING) pack.mask = &pending; - else if (sig == __SIGFLUSH || sig > 0) + else if (si.si_signo == __SIGFLUSH || si.si_signo > 0) pack.mask = &myself->getsigmask (); else pack.mask = NULL; - pack.sig = sig; + pack.si = si; + if (!pack.si.si_pid) + pack.si.si_pid = myself->pid; + if (!pack.si.si_uid) + pack.si.si_uid = myself->uid; pack.pid = myself->pid; pack.tls = (_threadinfo *) tls; DWORD nb; @@ -767,7 +761,7 @@ sig_send (_pinfo *p, int sig, void *tls) sigproc_printf ("I'm going away now"); else system_printf ("error sending signal %d to pid %d, pipe handle %p, %E", - sig, p->pid, sendsig); + si.si_signo, p->pid, sendsig); } goto out; } @@ -787,7 +781,8 @@ sig_send (_pinfo *p, int sig, void *tls) else { rc = WAIT_OBJECT_0; - sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig); + sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", + its_me, si.si_signo); if (!its_me) ForceCloseHandle (sendsig); } @@ -798,7 +793,7 @@ sig_send (_pinfo *p, int sig, void *tls) { if (!no_signals_available ()) system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E", - sig, rc); + si.si_signo, rc); set_errno (ENOSYS); rc = -1; } @@ -807,13 +802,13 @@ sig_send (_pinfo *p, int sig, void *tls) call_signal_handler_now (); out: - if (sig != __SIGPENDING) + if (si.si_signo != __SIGPENDING) /* nothing */; else if (!rc) rc = (int) pending; else rc = SIG_BAD_MASK; - sigproc_printf ("returning %p from sending signal %d", rc, sig); + sigproc_printf ("returning %p from sending signal %d", rc, si.si_signo); return rc; } @@ -1009,20 +1004,20 @@ talktome () has been handled, as per POSIX. */ void -pending_signals::add (int sig, int pid, _threadinfo *tls) +pending_signals::add (sigpacket& pack) { - sigelem *se; + sigpacket *se; for (se = start.next; se; se = se->next) - if (se->sig == sig) + if (se->si.si_signo == pack.si.si_signo) return; - while (sigs[empty].sig) + while (sigs[empty].si.si_signo) if (++empty == NSIG) empty = 0; se = sigs + empty; - se->sig = sig; + *se = pack; + se->mask_storage = *(pack.mask); + se->mask = &se->mask_storage; se->next = NULL; - se->tls = tls; - se->pid = pid; if (end) end->next = se; end = se; @@ -1034,9 +1029,9 @@ pending_signals::add (int sig, int pid, _threadinfo *tls) void pending_signals::del () { - sigelem *next = curr->next; + sigpacket *next = curr->next; prev->next = next; - curr->sig = 0; + curr->si.si_signo = 0; #ifdef DEBUGGING curr->next = NULL; #endif @@ -1046,10 +1041,10 @@ pending_signals::del () curr = next; } -sigelem * +sigpacket * pending_signals::next () { - sigelem *res; + sigpacket *res; prev = curr; if (!curr || !(curr = curr->next)) res = NULL; @@ -1125,7 +1120,7 @@ wait_sig (VOID *self) continue; } - if (!pack.sig) + if (!pack.si.si_signo) { #ifdef DEBUGGING system_printf ("zero signal?"); @@ -1140,8 +1135,8 @@ wait_sig (VOID *self) pack.mask = &dummy_mask; } - sigelem *q; - switch (pack.sig) + sigpacket *q; + switch (pack.si.si_signo) { case __SIGCOMMUNE: talktome (); @@ -1154,30 +1149,30 @@ wait_sig (VOID *self) unsigned bit; sigqueue.reset (); while ((q = sigqueue.next ())) - if (myself->getsigmask () & (bit = SIGTOMASK (q->sig))) + if (myself->getsigmask () & (bit = SIGTOMASK (q->si.si_signo))) *pack.mask |= bit; break; case __SIGFLUSH: sigqueue.reset (); while ((q = sigqueue.next ())) - if (sig_handle (q->sig, *pack.mask, q->pid, q->tls) > 0) + if (q->process () > 0) sigqueue.del (); break; default: - if (pack.sig < 0) - sig_clear (-pack.sig); + if (pack.si.si_signo < 0) + sig_clear (-pack.si.si_signo); else { - int sigres = sig_handle (pack.sig, *pack.mask, pack.pid, pack.tls); + int sigres = pack.process (); if (sigres <= 0) { #ifdef DEBUGGING2 if (!sigres) system_printf ("Failed to arm signal %d from pid %d", pack.sig, pack.pid); #endif - sigqueue.add (pack.sig, pack.pid, pack.tls);// FIXME: Shouldn't add this in !sh condition + sigqueue.add (pack); // FIXME: Shouldn't add this in !sh condition } - if (pack.sig == SIGCHLD) + if (pack.si.si_signo == SIGCHLD) proc_subproc (PROC_CLEARWAIT, 0); } break; @@ -1245,6 +1240,13 @@ wait_subproc (VOID *) rc -= WAIT_OBJECT_0; if (rc-- != 0) { + siginfo_t si; + si.si_signo = SIGCHLD; + si.si_code = SI_KERNEL; + si.si_pid = pchildren[rc]->pid; + si.si_uid = pchildren[rc]->uid; + si.si_errno = 0; + si.si_status = si.si_utime = si.si_stime = 0; // FIXME fill these in someday rc = proc_subproc (PROC_CHILDTERMINATED, rc); if (!proc_loop_wait) // Don't bother if wait_subproc is break; // exiting @@ -1253,7 +1255,7 @@ wait_subproc (VOID *) to avoid the proc_subproc lock since the signal thread will eventually be calling proc_subproc and could unnecessarily block. */ if (rc) - sig_send (myself_nowait, SIGCHLD); + sig_send (myself_nowait, si); } sigproc_printf ("looping"); } diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h new file mode 100644 index 00000000000..03ee1b89b1f --- /dev/null +++ b/winsup/cygwin/sigproc.h @@ -0,0 +1,110 @@ +/* sigproc.h + + Copyright 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _SIGPROC_H +#define _SIGPROC_H +#include <signal.h> + +#define EXIT_SIGNAL 0x010000 +#define EXIT_REPARENTING 0x020000 +#define EXIT_NOCLOSEALL 0x040000 + +#ifdef NSIG +enum +{ + __SIGFLUSH = -(NSIG + 1), + __SIGSTRACE = -(NSIG + 2), + __SIGCOMMUNE = -(NSIG + 3), + __SIGPENDING = -(NSIG + 4) +}; +#endif + +#define SIG_BAD_MASK (1 << (SIGKILL - 1)) + +enum procstuff +{ + PROC_ADDCHILD = 1, // add a new subprocess to list + PROC_CHILDTERMINATED = 2, // a child died + PROC_CLEARWAIT = 3, // clear all waits - signal arrived + PROC_WAIT = 4, // setup for wait() for subproc + PROC_NOTHING = 5 // nothing, really +}; + +typedef struct struct_waitq +{ + int pid; + int options; + int status; + HANDLE ev; + void *rusage; /* pointer to potential rusage */ + struct struct_waitq *next; + HANDLE thread_ev; +} waitq; + +struct sigpacket +{ + siginfo_t si; + pid_t pid; + class _threadinfo *tls; + sigset_t *mask; + sigset_t mask_storage; + union + { + HANDLE wakeup; + struct sigpacket *next; + }; + int __stdcall process () __attribute__ ((regparm (1))); +}; + +extern HANDLE signal_arrived; +extern HANDLE sigCONT; + +bool __stdcall my_parent_is_alive (); +int __stdcall sig_dispatch_pending (); +#ifdef _PINFO_H +extern "C" void __stdcall set_signal_mask (sigset_t newmask, sigset_t = myself->getsigmask ()); +#endif +int __stdcall handle_sigprocmask (int sig, const sigset_t *set, + sigset_t *oldset, sigset_t& opmask) + __attribute__ ((regparm (3))); + +extern "C" void __stdcall reset_signal_arrived (); +extern "C" int __stdcall call_signal_handler_now (); +void __stdcall sig_clear (int) __attribute__ ((regparm (1))); +void __stdcall sig_set_pending (int) __attribute__ ((regparm (1))); +int __stdcall handle_sigsuspend (sigset_t); + +int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2))); + +class _pinfo; +void __stdcall proc_terminate (); +void __stdcall sigproc_init (); +void __stdcall subproc_init (); +void __stdcall sigproc_terminate (); +bool __stdcall proc_exists (_pinfo *) __attribute__ ((regparm(1))); +bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1))); +int __stdcall sig_send (_pinfo *, siginfo_t&, class _threadinfo *tls = NULL) __attribute__ ((regparm (3))); +int __stdcall sig_send (_pinfo *, int) __attribute__ ((regparm (2))); +void __stdcall signal_fixup_after_fork (); +void __stdcall signal_fixup_after_exec (); +void __stdcall wait_for_sigthread (); +void __stdcall sigalloc (); + +int kill_pgrp (pid_t, siginfo_t&); +int killsys (pid_t, int); + +extern char myself_nowait_dummy[]; + +extern struct sigaction *global_sigs; + +#define WAIT_SIG_PRIORITY THREAD_PRIORITY_TIME_CRITICAL + +#define myself_nowait ((_pinfo *)myself_nowait_dummy) +#endif /*_SIGPROC_H*/ diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index ae03dc6266b..0b1782530fb 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -2736,7 +2736,11 @@ pthread_kill (pthread_t thread, int sig) if (!pthread::is_good_object (&thread)) return EINVAL; - int rval = sig ? sig_send (NULL, sig, thread->cygtls) : 0; + siginfo_t si; + si.si_signo = sig; + si.si_code = SI_USER; + si.si_pid = si.si_uid = si.si_errno = 0; + int rval = sig ? sig_send (NULL, si, thread->cygtls) : 0; // unlock myself return rval; diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 6c2e58fafa6..f8bb9ec94be 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -318,10 +318,6 @@ int cygwin_select (int , fd_set *, fd_set *, fd_set *, struct timeval *to); int cygwin_gethostname (char *__name, size_t __len); -int kill_pgrp (pid_t, int); -int _kill (int, int); -int _raise (int sig); - extern DWORD binmode; extern char _data_start__, _data_end__, _bss_start__, _bss_end__; extern void (*__CTOR_LIST__) (void); |