From f6936c48f382a12b7b67fda40352b8e377662743 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Mon, 19 Jan 2004 05:46:54 +0000 Subject: [PATCH] * cygwin/include/signal.h: Add copyright notice. * cygwin.din: Make clock SIGFE. Add clock_gettime, sigwaitinfo, timer_create, timer_delete, timer_settime. * include/cygwin/version.h: Reflect above additions. * fork.cc (fork_child): Call fixup_timers_after_fork. * signal.cc (sigwait): Remove unused variable. * timer.cc: New file. (clock_gettime): Define new function. (timer_tracker): Define new struct used by timer functions. (timer_tracker::timer_tracker): New function. (to_us): New function. (timer_thread): New function. (timer_tracker::settime): New function. (timer_create): New function. (timer_settime): New function. (timer_delete): New function. (fixup_timers_after_fork): New function. * cygthread.cc: Bump thread count. * signal.cc (sigwaitinfo): Define new function. (sigwait): Redefine based on sigwaitinfo. * include/cygwin/signal.h (sigwaitinfo): Declare. (sigwait): Ditto. * dtable.cc (dtable::vfork_parent_restore): Avoid double close of ctty when ctty == ctty_on_hold. * cygtls.h (_threadinfo::threadkill): New element. (_threadinfo::set_threadkill): Declare new function. (_threadinfo::reset_threadkill): Declare new function. * dcrt0.cc (dcrt0_1): Call here so that it will be possible to attach to running process with #(*& Windows Me/9x. (initial_env): Try to initialize strace if uninitialized. * gendef: Don't zero signal if threadkill is set since that will happen in the called function. * signal.cc (sigwait): Ensure cleanup in error conditions. * sigproc.cc (sig_send): Clear packet mask storage. (wait_subproc): Fill in child exit code in siginfo_t structure. * thread.cc (pthread_kill): Set threadkill flag. * tlsoffsets.h: Regenerate. Throughout, use siginfo_t to fill out all signal information for "kernel" signals. * cygtls.h (_threadinfo::set_siginfo): Declare new function. * cygtls.cc (_threadinfo::set_siginfo): Define new function. * dcrt0.cc (do_exit): Accommodate siginfo_t considerations. * exceptions.cc (handle_exceptions): Ditto. (sig_handle_tty_stop): Ditto. (ctrl_c_handler): Use killsys() to send signal. (sigpacket::process): Rename from sig_handle. Use siginfo_t field from sigpacket for everything. (tty_min::kill_pgrp): Accommodate siginfo_t considerations. (fhandler_termios::bg_check): Ditto. * fhandler_tty.cc (fhandler_tty_slave::ioctl): Use killsys() to send signal. * signal.cc (kill_worker): Rewrite to use siginfo_t second argument. (kill_pgrp): Ditto. (kill0): Define new function pulled from kill(). (kill): Rewrite as frontend to kill0. (killsys): Define new function. * sigproc.cc (sigelem): Eliminate. (sigpacket): Move to sigproc.h. Subsume sigelem. (pending_signals): Use sigpacket rather than sigelem for everything. (sig_clear): Ditto. (wait_sig): Ditto. (sig_send): Rewrite to use siginfo_t argument. (sig_send): New function wratpper to sig_send with siginfo_t argument. (wait_subproc): Accommodate siginfo_t considerations. * thread.cc (pthread_kill): Ditto. * sigproc.h (sigpacket): Move here. (sigpacket::process): Declare "new" function. (sig_handle): Eliminate declaration. (sig_send): Declare with new paramaters. (killsys): Declare new function. (kill_pgrp): Declare. * winsup.h: Move some signal-specific stuff to sigproc.h. * include/cygwin/signal.h: Tweak some siginfo_t stuff. --- winsup/cygwin/ChangeLog | 88 ++++++++ winsup/cygwin/Makefile.in | 2 +- winsup/cygwin/cygthread.cc | 2 +- winsup/cygwin/cygthread.h | 2 +- winsup/cygwin/cygtls.cc | 7 + winsup/cygwin/cygtls.h | 6 +- winsup/cygwin/cygwin.din | 9 +- winsup/cygwin/dcrt0.cc | 16 +- winsup/cygwin/dtable.h | 2 +- winsup/cygwin/exceptions.cc | 193 ++++++++++------- winsup/cygwin/fhandler_termios.cc | 16 +- winsup/cygwin/fhandler_tty.cc | 4 +- winsup/cygwin/fork.cc | 2 + winsup/cygwin/gendef | 4 +- winsup/cygwin/include/cygwin/signal.h | 83 +++++--- winsup/cygwin/include/cygwin/version.h | 4 +- winsup/cygwin/signal.cc | 99 ++++++--- winsup/cygwin/sigproc.cc | 142 +++++++------ winsup/cygwin/sigproc.h | 24 ++- winsup/cygwin/syscalls.cc | 2 +- winsup/cygwin/thread.cc | 7 +- winsup/cygwin/timer.cc | 275 +++++++++++++++++++++++++ winsup/cygwin/times.cc | 27 ++- winsup/cygwin/tlsoffsets.h | 50 ++--- winsup/cygwin/winsup.h | 6 +- 25 files changed, 819 insertions(+), 253 deletions(-) create mode 100644 winsup/cygwin/timer.cc diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 746730b15..b8100186a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,91 @@ +2004-01-19 Christopher Faylor + + * cygwin/include/signal.h: Add copyright notice. + + * cygwin.din: Make clock SIGFE. Add clock_gettime, sigwaitinfo, + timer_create, timer_delete, timer_settime. + * include/cygwin/version.h: Reflect above additions. + * fork.cc (fork_child): Call fixup_timers_after_fork. + * signal.cc (sigwait): Remove unused variable. + * timer.cc: New file. + (clock_gettime): Define new function. + (timer_tracker): Define new struct used by timer functions. + (timer_tracker::timer_tracker): New function. + (to_us): New function. + (timer_thread): New function. + (timer_tracker::settime): New function. + (timer_create): New function. + (timer_settime): New function. + (timer_delete): New function. + (fixup_timers_after_fork): New function. + * cygthread.cc: Bump thread count. + +2004-01-17 Christopher Faylor + + * signal.cc (sigwaitinfo): Define new function. + (sigwait): Redefine based on sigwaitinfo. + * include/cygwin/signal.h (sigwaitinfo): Declare. + (sigwait): Ditto. + +2004-01-17 Christopher Faylor + + * dtable.cc (dtable::vfork_parent_restore): Avoid double close of ctty + when ctty == ctty_on_hold. + +2004-01-16 Christopher Faylor + + * cygtls.h (_threadinfo::threadkill): New element. + (_threadinfo::set_threadkill): Declare new function. + (_threadinfo::reset_threadkill): Declare new function. + * dcrt0.cc (dcrt0_1): Call here so that it will be possible to attach + to running process with #(*& Windows Me/9x. + (initial_env): Try to initialize strace if uninitialized. + * gendef: Don't zero signal if threadkill is set since that will happen + in the called function. + * signal.cc (sigwait): Ensure cleanup in error conditions. + * sigproc.cc (sig_send): Clear packet mask storage. + (wait_subproc): Fill in child exit code in siginfo_t structure. + * thread.cc (pthread_kill): Set threadkill flag. + * tlsoffsets.h: Regenerate. + +2004-01-16 Christopher Faylor + + Throughout, use siginfo_t to fill out all signal information for + "kernel" signals. + * cygtls.h (_threadinfo::set_siginfo): Declare new function. + * cygtls.cc (_threadinfo::set_siginfo): Define new function. + * dcrt0.cc (do_exit): Accommodate siginfo_t considerations. + * exceptions.cc (handle_exceptions): Ditto. + (sig_handle_tty_stop): Ditto. + (ctrl_c_handler): Use killsys() to send signal. + (sigpacket::process): Rename from sig_handle. Use siginfo_t field from + sigpacket for everything. + (tty_min::kill_pgrp): Accommodate siginfo_t considerations. + (fhandler_termios::bg_check): Ditto. + * fhandler_tty.cc (fhandler_tty_slave::ioctl): Use killsys() to send signal. + * signal.cc (kill_worker): Rewrite to use siginfo_t second argument. + (kill_pgrp): Ditto. + (kill0): Define new function pulled from kill(). + (kill): Rewrite as frontend to kill0. + (killsys): Define new function. + * sigproc.cc (sigelem): Eliminate. + (sigpacket): Move to sigproc.h. Subsume sigelem. + (pending_signals): Use sigpacket rather than sigelem for everything. + (sig_clear): Ditto. + (wait_sig): Ditto. + (sig_send): Rewrite to use siginfo_t argument. + (sig_send): New function wratpper to sig_send with siginfo_t argument. + (wait_subproc): Accommodate siginfo_t considerations. + * thread.cc (pthread_kill): Ditto. + * sigproc.h (sigpacket): Move here. + (sigpacket::process): Declare "new" function. + (sig_handle): Eliminate declaration. + (sig_send): Declare with new paramaters. + (killsys): Declare new function. + (kill_pgrp): Declare. + * winsup.h: Move some signal-specific stuff to sigproc.h. + * include/cygwin/signal.h: Tweak some siginfo_t stuff. + 2004-01-16 Christopher Faylor * fhandler_console.cc (fhandler_console::close): Remove obsolete test diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index cf15b320d..5cd0938f4 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -134,7 +134,7 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o cxx.o cygheap.o cygthread.o cygtls.o \ resource.o scandir.o sched.o sec_acl.o sec_helper.o security.o \ select.o sem.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o \ spawn.o strace.o strsep.o sync.o syscalls.o sysconf.o syslog.o \ - termios.o thread.o times.o tty.o uinfo.o uname.o v8_regexp.o \ + termios.o thread.o timer.o times.o tty.o uinfo.o uname.o v8_regexp.o \ v8_regerror.o v8_regsub.o wait.o wincap.o window.o \ $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS) diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index e83019663..309bd51ed 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -20,7 +20,7 @@ details. */ #undef CloseHandle -static cygthread NO_COPY threads[18]; +static cygthread NO_COPY threads[32]; #define NTHREADS (sizeof (threads) / sizeof (threads[0])) DWORD NO_COPY cygthread::main_thread_id; diff --git a/winsup/cygwin/cygthread.h b/winsup/cygwin/cygthread.h index 76604b471..9d10bb266 100644 --- a/winsup/cygwin/cygthread.h +++ b/winsup/cygwin/cygthread.h @@ -1,6 +1,6 @@ /* cygthread.h - Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 5c9fa615f..ecec3f52b 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 779e42b89..0fa1b1b4c 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -102,6 +102,7 @@ struct _threadinfo sigset_t sigmask; sigset_t sigwait_mask; siginfo_t *sigwait_info; + unsigned threadkill; siginfo_t infodata; struct pthread *tid; struct _reent local_clib; @@ -120,7 +121,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 +132,9 @@ 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))); + void set_threadkill () {threadkill = true;} + void reset_threadkill () {threadkill = false;} /*gentls_offsets*/ }; #pragma pack(pop) diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 1f3fe08c9..7d4c352d1 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -246,8 +246,9 @@ _chroot = chroot SIGFE cleanup_glue NOSIGFE clearerr NOSIGFE _clearerr = clearerr NOSIGFE -clock NOSIGFE -_clock = clock NOSIGFE +clock SIGFE +_clock = clock SIGFE +clock_gettime SIGFE close SIGFE _close = close SIGFE closedir SIGFE @@ -1234,6 +1235,7 @@ sigpending SIGFE sigprocmask SIGFE sigsuspend SIGFE sigwait SIGFE +sigwaitinfo SIGFE sin NOSIGFE _sin = sin NOSIGFE sincos NOSIGFE @@ -1407,6 +1409,9 @@ tgamma NOSIGFE tgammaf NOSIGFE time SIGFE _time = time SIGFE +timer_create SIGFE +timer_delete SIGFE +timer_settime SIGFE times SIGFE _times = times SIGFE timezone SIGFE diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 3d6b7a89b..29d11f8e4 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -542,8 +542,12 @@ initial_env () buf[0] = '\0'; len = GetModuleFileName (NULL, buf, CYG_MAX_PATH); console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf); - while (ms--) - Sleep (1); + Sleep (ms); + if (!strace.active) + { + strace.inited = 0; + strace.hello (); + } } if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1)) { @@ -573,7 +577,6 @@ void __stdcall dll_crt0_0 () { wincap.init (); - initial_env (); char zeros[sizeof (child_proc_info->zero)] = {0}; @@ -719,6 +722,7 @@ dll_crt0_1 (char *) /* FIXME: Verify forked children get their exception handler set up ok. */ exception_list cygwin_except_entry; + initial_env (); check_sanity_and_sync (user_data); malloc_init (); @@ -1042,9 +1046,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/dtable.h b/winsup/cygwin/dtable.h index 573467d01..8f3cbea40 100644 --- a/winsup/cygwin/dtable.h +++ b/winsup/cygwin/dtable.h @@ -1,6 +1,6 @@ /* dtable.h: fd table definition. - Copyright 2000, 2001, 2003 Red Hat, Inc. + Copyright 2000, 2001, 2003, 2004 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 597c58e47..1e9745b22 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,14 @@ 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 } + si.si_addr = ebp; + si.si_code = SI_KERNEL; + si.si_errno = si.si_pid = si.si_uid = 0; _my_tls.push ((__stack_t) ebp, true); - sig_send (NULL, sig, &_my_tls); // Signal myself + sig_send (NULL, si, &_my_tls); // Signal myself return 1; } #endif /* __i386__ */ @@ -605,7 +632,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 +848,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 +883,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 +918,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 +935,56 @@ 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 special_case = ISSTATE (myself, PID_STOPPED) || main_vfork->pid; - bool masked = sigismember (&mask, sig); - if (sig != SIGKILL && sig != SIGSTOP - && (special_case || main_vfork->pid || masked || insigwait_mask - || (tls && sigismember (&tls->sigmask, sig)))) + + sigproc_printf ("signal %d processing", si.si_signo); + struct sigaction thissig = global_sigs[si.si_signo]; + + myself->rusage_self.ru_nsignals++; + + if (si.si_signo == SIGKILL) + goto exit_sig; + if ( si.si_signo == SIGSTOP) { - sigproc_printf ("signal %d blocked", sig); - if ((!special_case && !masked) - && (insigwait_mask || (tls = _threadinfo::find_tls (sig)) != NULL)) - goto thread_specific; + sig_clear (SIGCONT); + goto stop; + } + + bool masked; + bool special_case; + bool insigwait_mask; + insigwait_mask = masked = false; + if (special_case = (main_vfork->pid || ISSTATE (myself, PID_STOPPED))) + /* nothing to do */; + else if (tls && sigismember (&tls->sigwait_mask, si.si_signo)) + insigwait_mask = true; + else if (!tls && (tls = _threadinfo::find_tls (si.si_signo))) + insigwait_mask = true; + else if (!(masked = sigismember (mask, si.si_signo)) && tls) + masked = sigismember (&tls->sigmask, si.si_signo); + + if (insigwait_mask) + goto thread_specific; + + if (!tls) + tls = _main_tls; + + if (special_case || masked) + { + sigproc_printf ("signal %d blocked", si.si_signo); rc = -1; goto done; } - /* Clear pending SIGCONT on stop signals */ - if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) - sig_clear (SIGCONT); - - sigproc_printf ("signal %d processing", sig); - struct sigaction thissig = global_sigs[sig]; void *handler; handler = (void *) thissig.sa_handler; - myself->rusage_self.ru_nsignals++; - - if (sig == SIGKILL) - goto exit_sig; - - if (sig == SIGSTOP) - goto stop; + /* Clear pending SIGCONT on stop signals */ + if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) + sig_clear (SIGCONT); #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 +992,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 +1007,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 +1022,38 @@ 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; + tls->set_siginfo (this); 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 index edb8354ef..398dabd9e 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -87,6 +87,10 @@ 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]; @@ -95,10 +99,10 @@ tty_min::kill_pgrp (int sig) if (p == myself) killself++; else - (void) sig_send (p, sig); + (void) sig_send (p, si); } if (killself) - sig_send (myself, sig); + sig_send (myself, si); } bg_check_types @@ -144,7 +148,13 @@ fhandler_termios::bg_check (int sig) /* Don't raise a SIGTT* signal if we have already been interrupted by another signal. */ if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0) - kill_pgrp (myself->pgid, sig); + { + 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: diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index ef308b09a..33c7f379d 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -1109,7 +1109,7 @@ fhandler_tty_slave::ioctl (unsigned int cmd, void *arg) get_ttyp ()->arg.winsize = *(struct winsize *) arg; SetEvent (ioctl_request_event); get_ttyp ()->winsize = *(struct winsize *) arg; - kill (-get_ttyp ()->getpgid (), SIGWINCH); + killsys (-get_ttyp ()->getpgid (), SIGWINCH); if (ioctl_done_event) WaitForSingleObject (ioctl_done_event, INFINITE); } @@ -1307,7 +1307,7 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg) || get_ttyp ()->winsize.ws_col != ((struct winsize *) arg)->ws_col) { get_ttyp ()->winsize = *(struct winsize *) arg; - kill (-get_ttyp ()->getpgid (), SIGWINCH); + killsys (-get_ttyp ()->getpgid (), SIGWINCH); } break; case FIONBIO: diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 407a47ddd..2471ad225 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -231,6 +231,7 @@ sync_with_parent (const char *s, bool hang_self) static int __stdcall fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) { + extern void fixup_timers_after_fork (); debug_printf ("child is running. pid %d, ppid %d, stack here %p", myself->pid, myself->ppid, __builtin_frame_address (0)); @@ -316,6 +317,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) (*t)->set (); pthread::atforkchild (); + fixup_timers_after_fork (); wait_for_sigthread (); cygbench ("fork-child"); return 0; diff --git a/winsup/cygwin/gendef b/winsup/cygwin/gendef index df810cb06..5addf91e2 100755 --- a/winsup/cygwin/gendef +++ b/winsup/cygwin/gendef @@ -169,10 +169,12 @@ _sigdelayed: pushl $tls::newmask(%ebx) # newmask - eaten by set_process_mask call _set_process_mask\@4 + cmpl \$0,$tls::threadkill(%ebx)#pthread_kill signal? + jnz 4f #yes. Callee clears signal number movl \$0,$tls::sig(%ebx) # zero the signal number as a # flag to the signal handler thread # that it is ok to set up sigsave - popl %ebx +4: popl %ebx jmp *%ebx EOF diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h index 1e2863404..87af7c883 100644 --- a/winsup/cygwin/include/cygwin/signal.h +++ b/winsup/cygwin/include/cygwin/signal.h @@ -1,6 +1,20 @@ +/* signal.h + + Copyright 2004 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 _CYGWIN_SIGNAL_H #define _CYGWIN_SIGNAL_H +#ifdef __cplusplus +extern "C" { +#endif + #if 0 struct ucontext { @@ -8,7 +22,7 @@ struct ucontext void *uc_link; stack_t uc_stack; struct sigcontext uc_mcontext; - sigset_t uc_sigmask; + sigset_t uc_sigmask; }; #endif @@ -18,49 +32,55 @@ typedef union sigval void *sival_ptr; /* pointer signal value */ } sigval_t; +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; + #pragma pack(push,4) typedef struct { int si_signo; /* signal number */ - int si_errno; /* errno associated with signal */ 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 { - int __pad[128]; /* plan for future growth */ - + __uint32_t __pad[32]; /* plan for future growth */ union { - /* timers */ + /* timers */ struct { - unsigned int si_tid; /* timer id */ - unsigned int si_overrun; /* overrun count */ + union + { + struct + { + timer_t si_tid; /* timer id */ + unsigned int si_overrun; /* overrun count */ + }; + sigval_t si_sigval; /* signal value */ + sigval_t si_value; /* signal value */ + }; }; - - /* POSIX signals or signals invoked by kill() */ - struct - { - pid_t si_pid; /* sender's pid */ - uid_t si_uid; /* sender's uid */ - }; - sigval_t si_sigval; /* signal value */ }; + /* SIGCHLD */ struct { - pid_t si_pid2; /* which child */ - uid_t si_uid2; /* sender's uid */ - int si_status; /* exit code */ + int si_status; /* exit code */ clock_t si_utime; /* user time */ clock_t si_stime; /* system time */ }; /* core dumping signals */ - struct - { - void *si_addr; /* faulting address */ - }; + void *si_addr; /* faulting address */ }; } siginfo_t; #pragma pack(pop) @@ -77,7 +97,7 @@ enum unimplemented) */ SI_KERNEL, /* sent by system */ - ILL_ILLOP, /* illegal opcode */ + ILL_ILLOPC, /* illegal opcode */ ILL_ILLOPN, /* illegal operand */ ILL_ILLADR, /* illegal addressing mode */ ILL_ILLTRP, /* illegal trap*/ @@ -110,15 +130,6 @@ enum 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 @@ -133,7 +144,7 @@ enum typedef void (*_sig_func_ptr)(int); -struct sigaction +struct sigaction { union { @@ -188,4 +199,10 @@ struct sigaction #define SIGUSR1 30 /* user defined signal 1 */ #define SIGUSR2 31 /* user defined signal 2 */ #define NSIG 32 /* signal 0 implied */ + +int sigwait (const sigset_t *, int *); +int sigwaitinfo (const sigset_t *, siginfo_t *); +#ifdef __cplusplus +} +#endif #endif /*_CYGWIN_SIGNAL_H*/ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 1a91721ef..e8b557797 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -233,12 +233,14 @@ details. */ 106: Export flock. 107: Export fcntl64. 108: Remove unused (hopefully) reent_data export. + 109: Export clock_gettime, sigwaitinfo, timer_create, timer_delete, + timer_settime */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 108 +#define CYGWIN_VERSION_API_MINOR 109 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 311e7303b..d442b17f3 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -182,13 +182,13 @@ handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& op } static int -kill_worker (pid_t pid, int sig) +kill_worker (pid_t pid, siginfo_t& si) { sig_dispatch_pending (); int res = 0; pinfo dest (pid); - BOOL sendSIGCONT; + bool sendSIGCONT; if (!dest) { @@ -196,25 +196,32 @@ kill_worker (pid_t pid, int sig) return -1; } - if ((sendSIGCONT = (sig < 0))) - sig = -sig; + if ((sendSIGCONT = (si.si_signo < 0))) + si.si_signo = -si.si_signo; DWORD process_state = dest->process_state; - if (sig == 0) + if (si.si_signo == 0) { res = proc_exists (dest) ? 0 : -1; if (res < 0) set_errno (ESRCH); } - else if ((res = sig_send (dest, sig))) + else if ((res = sig_send (dest, si))) { sigproc_printf ("%d = sig_send, %E ", res); res = -1; } else if (sendSIGCONT) - (void) sig_send (dest, SIGCONT); + { + 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, sig, process_state); + syscall_printf ("%d = kill_worker (%d, %d), process_state %p", res, pid, + si.si_signo, process_state); return res; } @@ -224,35 +231,54 @@ raise (int sig) return kill (myself->pid, sig); } -int -kill (pid_t pid, int sig) +static int +kill0 (pid_t pid, siginfo_t& si) { - syscall_printf ("kill (%d, %d)", pid, sig); + syscall_printf ("kill (%d, %d)", pid, si.si_signo); /* check that sig is in right range */ - if (sig < 0 || sig >= NSIG) + if (si.si_signo < 0 || si.si_signo >= NSIG) { set_errno (EINVAL); - syscall_printf ("signal %d out of range", sig); + 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) && - (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)) - sig = 0; + (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)) + si.si_signo = 0; - return (pid > 0) ? kill_worker (pid, sig) : kill_pgrp (-pid, sig); + return (pid > 0) ? kill_worker (pid, si) : kill_pgrp (-pid, si); } int -kill_pgrp (pid_t pid, int sig) +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, sig); + sigproc_printf ("pid %d, signal %d", pid, si.si_signo); winpids pids ((DWORD) PID_MAP_RW); for (unsigned i = 0; i < pids.npids; i++) @@ -265,18 +291,18 @@ kill_pgrp (pid_t pid, int sig) /* Is it a process we want to kill? */ if ((pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) || (pid > 1 && p->pgid != pid) || - (sig < 0 && NOTSTATE (p, PID_STOPPED))) + (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, sig)) + else if (kill_worker (p->pid, si)) res = -1; found++; } - if (killself && kill_worker (myself->pid, sig)) + if (killself && kill_worker (myself->pid, si)) res = -1; if (!found) @@ -284,7 +310,7 @@ kill_pgrp (pid_t pid, int sig) set_errno (ESRCH); res = -1; } - syscall_printf ("%d = kill (%d, %d)", res, pid, sig); + syscall_printf ("%d = kill (%d, %d)", res, pid, si.si_signo); return res; } @@ -452,12 +478,21 @@ siginterrupt (int sig, int flag) return sigaction (sig, &act, NULL); } +extern "C" int +sigwait (const sigset_t *set, int *sig_ptr) +{ + int sig = sigwaitinfo (set, NULL); + if (sig > 0) + *sig_ptr = sig; + return sig > 0 ? 0 : -1; +} extern "C" int -sigwait (const sigset_t *set, int *sig) +sigwaitinfo (const sigset_t *set, siginfo_t *info) { pthread_testcancel (); - _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + HANDLE h; + h = _my_tls.event = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); if (!_my_tls.event) { __seterrno (); @@ -466,16 +501,22 @@ sigwait (const sigset_t *set, int *sig) _my_tls.sigwait_mask = *set; + int res; 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); + res = _my_tls.infodata.si_signo; + sigproc_printf ("returning sig %d", res); + if (info) + *info = _my_tls.infodata; break; default: __seterrno (); - return -1; + res = -1; } - return 0; + _my_tls.event = NULL; + InterlockedExchange ((LONG *) &_my_tls.sig, (LONG) 0); + CloseHandle (h); + sig_dispatch_pending (); + return res; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index e143a8239..a1c2d305d 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; } -/* 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. - */ int __stdcall -sig_send (_pinfo *p, int sig, void *tls) +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. */ +int __stdcall +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,16 +730,21 @@ 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; + pack.mask_storage = 0; DWORD nb; if (!WriteFile (sendsig, &pack, sizeof (pack), &nb, NULL) || nb != sizeof (pack)) { @@ -767,7 +762,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 +782,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 +794,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 +803,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 +1005,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 +1030,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 +1042,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 +1121,7 @@ wait_sig (VOID *self) continue; } - if (!pack.sig) + if (!pack.si.si_signo) { #ifdef DEBUGGING system_printf ("zero signal?"); @@ -1140,8 +1136,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 +1150,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 +1241,20 @@ 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; + GetExitCodeProcess (hchildren[rc], (DWORD *) &si.si_status); +#if 0 // FIXME: This is tricky to get right + si.si_utime = pchildren[rc]->rusage_self.ru_utime; + si.si_stime = pchildren[rc].rusage_self.ru_stime; +#else + si.si_utime = 0; + si.si_stime = 0; +#endif rc = proc_subproc (PROC_CHILDTERMINATED, rc); if (!proc_loop_wait) // Don't bother if wait_subproc is break; // exiting @@ -1253,7 +1263,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 index f34dfa208..03ee1b89b 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -48,6 +48,21 @@ typedef struct struct_waitq 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; @@ -62,9 +77,6 @@ int __stdcall handle_sigprocmask (int sig, const sigset_t *set, extern "C" void __stdcall reset_signal_arrived (); extern "C" int __stdcall call_signal_handler_now (); -#ifdef _CYGTLS_H -int __stdcall sig_handle (int, sigset_t, int, _threadinfo *) __attribute__ ((regparm (3))); -#endif void __stdcall sig_clear (int) __attribute__ ((regparm (1))); void __stdcall sig_set_pending (int) __attribute__ ((regparm (1))); int __stdcall handle_sigsuspend (sigset_t); @@ -78,12 +90,16 @@ 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 *, int, void * = NULL) __attribute__ ((regparm(3))); +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; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 5abe0caf9..e704d1451 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -85,7 +85,7 @@ static int __stdcall stat_worker (const char *name, struct __stat64 *buf, ensure we don't leave any such files lying around. */ void __stdcall -close_all_files (void) +close_all_files () { cygheap->fdtab.lock (); diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index ae03dc626..b04dfa116 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -2736,7 +2736,12 @@ 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; + thread->cygtls->set_threadkill (); + int rval = sig ? sig_send (NULL, si, thread->cygtls) : 0; // unlock myself return rval; diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc new file mode 100644 index 000000000..8e836e9d4 --- /dev/null +++ b/winsup/cygwin/timer.cc @@ -0,0 +1,275 @@ +/* timer.cc + + Copyright 2004 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 +#include +#include "cygerrno.h" +#include "security.h" +#include "hires.h" +#include "thread.h" +#include "cygtls.h" +#include "cygthread.h" +#include "sigproc.h" +#include "sync.h" + +#define TT_MAGIC 0x513e4a1c +struct timer_tracker +{ + static muto *protect; + unsigned magic; + clockid_t clock_id; + sigevent evp; + itimerspec it; + HANDLE cancel; + int flags; + cygthread *th; + struct timer_tracker *next; + int settime (int, const itimerspec *, itimerspec *); + timer_tracker (clockid_t, const sigevent *); + timer_tracker (); +}; + +timer_tracker ttstart; + +muto *timer_tracker::protect; + +timer_tracker::timer_tracker () +{ + new_muto (protect); +} + +timer_tracker::timer_tracker (clockid_t c, const sigevent *e) +{ + if (e != NULL) + evp = *e; + else + { + evp.sigev_notify = SIGEV_SIGNAL; + evp.sigev_signo = SIGALRM; + evp.sigev_value.sival_ptr = this; + } + clock_id = c; + cancel = NULL; + flags = 0; + memset (&it, 0, sizeof (it)); + protect->acquire (); + next = ttstart.next; + ttstart.next = this; + protect->release (); + magic = TT_MAGIC; +} + +static long long +to_us (timespec& ts) +{ + long long res = ts.tv_sec; + res *= 1000000; + res += ts.tv_nsec / 1000 + ((ts.tv_nsec % 1000) >= 500 ? 1 : 0); + return res; +} + +static NO_COPY itimerspec itzero; +static NO_COPY timespec tzero; + +static DWORD WINAPI +timer_thread (VOID *x) +{ + timer_tracker *tp = ((timer_tracker *) x); + timer_tracker tt = *tp; + for (bool first = true; ; first = false) + { + long long sleep_us = to_us (first ? tt.it.it_value : tt.it.it_interval); + long long sleep_to = sleep_us; + long long now = gtod.usecs (false); + if (tt.flags & TIMER_ABSTIME) + sleep_us -= now; + else + sleep_to += now; + + DWORD sleep_ms = (sleep_us < 0) ? 0 : (sleep_us / 1000); + debug_printf ("%p waiting for %u ms, first %d", x, sleep_ms, first); + tp->it.it_value = tzero; + switch (WaitForSingleObject (tt.cancel, sleep_ms)) + { + case WAIT_TIMEOUT: + debug_printf ("timed out"); + break; + case WAIT_OBJECT_0: + now = gtod.usecs (false); + sleep_us = sleep_to - now; + if (sleep_us < 0) + sleep_us = 0; + tp->it.it_value.tv_sec = sleep_us / 1000000; + tp->it.it_value.tv_nsec = (sleep_us % 1000000) * 1000; + debug_printf ("%p cancelled, elapsed %D", x, sleep_us); + goto out; + default: + debug_printf ("%p timer wait failed, %E", x); + goto out; + } + + switch (tt.evp.sigev_notify) + { + case SIGEV_SIGNAL: + { + siginfo_t si; + memset (&si, 0, sizeof (si)); + si.si_signo = tt.evp.sigev_signo; + si.si_sigval.sival_ptr = tt.evp.sigev_value.sival_ptr; + debug_printf ("%p sending sig %d", x, tt.evp.sigev_signo); + sig_send (NULL, si); + break; + } + case SIGEV_THREAD: + { + pthread_t notify_thread; + debug_printf ("%p starting thread", x); + int rc = pthread_create (¬ify_thread, tt.evp.sigev_notify_attributes, + (void * (*) (void *)) tt.evp.sigev_notify_function, + &tt.evp.sigev_value); + if (rc) + { + debug_printf ("thread creation failed, %E"); + return 0; + } + // FIXME: pthread_join? + break; + } + } + if (!tt.it.it_interval.tv_sec && !tt.it.it_interval.tv_nsec) + break; + tt.flags = 0; + debug_printf ("looping"); + } + +out: + CloseHandle (tt.cancel); + // FIXME: race here but is it inevitable? + if (tt.cancel == tp->cancel) + tp->cancel = NULL; + return 0; +} + +static bool +it_bad (const timespec& t) +{ + if (t.tv_nsec < 0 || t.tv_nsec >= 1000000000 || t.tv_sec < 0) + { + set_errno (EINVAL); + return true; + } + return false; +} + +int +timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalue) +{ + if (!value) + { + set_errno (EINVAL); + return -1; + } + + if (__check_invalid_read_ptr_errno (value, sizeof (*value))) + return -1; + + if (ovalue && check_null_invalid_struct_errno (ovalue)) + return -1; + + itimerspec *elapsed; + if (!cancel) + elapsed = &itzero; + else + { + SetEvent (cancel); // should be closed when the thread exits + th->detach (); + elapsed = ⁢ + } + + if (ovalue) + *ovalue = *elapsed; + + if (value->it_value.tv_sec || value->it_value.tv_nsec) + { + if (it_bad (value->it_value)) + return -1; + if (it_bad (value->it_interval)) + return -1; + flags = in_flags; + cancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + it = *value; + th = new cygthread (timer_thread, this, "itimer"); + } + + return 0; +} + +extern "C" int +timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) +{ + if (evp && check_null_invalid_struct_errno (evp)) + return -1; + if (check_null_invalid_struct_errno (timerid)) + return -1; + + if (clock_id != CLOCK_REALTIME) + { + set_errno (EINVAL); + return -1; + } + + *timerid = (timer_t) new timer_tracker (clock_id, evp); + return 0; +} + +extern "C" int +timer_settime (timer_t timerid, int flags, const struct itimerspec *value, + struct itimerspec *ovalue) +{ + timer_tracker *tt = (timer_tracker *) timerid; + if (check_null_invalid_struct_errno (tt) || tt->magic != TT_MAGIC) + return -1; + return tt->settime (flags, value, ovalue); +} + +extern "C" int +timer_delete (timer_t timerid) +{ + timer_tracker *in_tt = (timer_tracker *) timerid; + if (check_null_invalid_struct_errno (in_tt) || in_tt->magic != TT_MAGIC) + return -1; + + timer_tracker::protect->acquire (); + for (timer_tracker *tt = &ttstart; tt->next != NULL; tt = tt->next) + if (tt->next == in_tt) + { + timer_tracker *deleteme = tt->next; + tt->next = deleteme->next; + delete deleteme; + timer_tracker::protect->release (); + return 0; + } + timer_tracker::protect->release (); + + set_errno (EINVAL); + return 0; +} + +void +fixup_timers_after_fork () +{ + for (timer_tracker *tt = &ttstart; tt->next != NULL; /* nothing */) + { + timer_tracker *deleteme = tt->next; + tt->next = deleteme->next; + delete deleteme; + } +} diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 46e02436b..635d05a37 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -1,6 +1,6 @@ /* times.cc - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. This file is part of Cygwin. @@ -15,6 +15,7 @@ details. */ #include #include #include +#include #include "cygerrno.h" #include "security.h" #include "path.h" @@ -22,6 +23,9 @@ details. */ #include "pinfo.h" #include "hires.h" #include "cygtls.h" +#include "cygthread.h" +#include "sigproc.h" +#include "sync.h" #define FACTOR (0x19db1ded53e8000LL) #define NSPERSEC 10000000LL @@ -612,7 +616,8 @@ hires_us::usecs (bool justdelta) // FIXME: Use round() here? now.QuadPart = (LONGLONG) (freq * (double) (now.QuadPart - primed_pc.QuadPart)); - return justdelta ? now.QuadPart : primed_ft.QuadPart + now.QuadPart; + LONGLONG res = justdelta ? now.QuadPart : primed_ft.QuadPart + now.QuadPart; + return res; } UINT @@ -657,3 +662,21 @@ hires_ms::usecs (bool justdelta) LONGLONG res = initime_us.QuadPart + ((LONGLONG) (now - initime_ms) * 1000); return res; } + +extern "C" int +clock_gettime (clockid_t clk_id, struct timespec *tp) +{ + if (clk_id != CLOCK_REALTIME) + { + set_errno (ENOSYS); + return -1; + } + + LONGLONG now = gtod.usecs (false); + if (now == (LONGLONG) -1) + return -1; + + tp->tv_sec = now / 1000000; + tp->tv_nsec = (now % 1000000) * 1000; + return 0; +} diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h index 6aeea68d5..51c79561e 100644 --- a/winsup/cygwin/tlsoffsets.h +++ b/winsup/cygwin/tlsoffsets.h @@ -1,17 +1,18 @@ //;# autogenerated: Do not edit. -//; $tls::func = -4076; -//; $tls::saved_errno = -4072; -//; $tls::sa_flags = -4068; -//; $tls::oldmask = -4064; -//; $tls::newmask = -4060; -//; $tls::event = -4056; -//; $tls::errno_addr = -4052; -//; $tls::initialized = -4048; -//; $tls::sigmask = -4044; -//; $tls::sigwait_mask = -4040; -//; $tls::sigwait_info = -4036; -//; $tls::infodata = -4032; +//; $tls::func = -3704; +//; $tls::saved_errno = -3700; +//; $tls::sa_flags = -3696; +//; $tls::oldmask = -3692; +//; $tls::newmask = -3688; +//; $tls::event = -3684; +//; $tls::errno_addr = -3680; +//; $tls::initialized = -3676; +//; $tls::sigmask = -3672; +//; $tls::sigwait_mask = -3668; +//; $tls::sigwait_info = -3664; +//; $tls::threadkill = -3660; +//; $tls::infodata = -3656; //; $tls::tid = -3508; //; $tls::local_clib = -3504; //; $tls::locals = -2576; @@ -23,18 +24,19 @@ //; $tls::padding = 0; //; __DATA__ -#define tls_func (-4076) -#define tls_saved_errno (-4072) -#define tls_sa_flags (-4068) -#define tls_oldmask (-4064) -#define tls_newmask (-4060) -#define tls_event (-4056) -#define tls_errno_addr (-4052) -#define tls_initialized (-4048) -#define tls_sigmask (-4044) -#define tls_sigwait_mask (-4040) -#define tls_sigwait_info (-4036) -#define tls_infodata (-4032) +#define tls_func (-3704) +#define tls_saved_errno (-3700) +#define tls_sa_flags (-3696) +#define tls_oldmask (-3692) +#define tls_newmask (-3688) +#define tls_event (-3684) +#define tls_errno_addr (-3680) +#define tls_initialized (-3676) +#define tls_sigmask (-3672) +#define tls_sigwait_mask (-3668) +#define tls_sigwait_info (-3664) +#define tls_threadkill (-3660) +#define tls_infodata (-3656) #define tls_tid (-3508) #define tls_local_clib (-3504) #define tls_locals (-2576) diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 6c2e58faf..980f661e7 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -219,7 +219,7 @@ void uinfo_init (void); void events_init (void); void events_terminate (void); -void __stdcall close_all_files (void); +void __stdcall close_all_files (); /* Invisible window initialization/termination. */ HWND __stdcall gethwnd (void); @@ -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);