From: Julian Seward Date: Tue, 17 Oct 2006 01:30:47 +0000 (+0000) Subject: Merge r6120: X-Git-Tag: svn/VALGRIND_3_3_0~617 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e7f6fcf8d9d5f5d3561ea5bb0feb49cc90bdc368;p=thirdparty%2Fvalgrind.git Merge r6120: Get rid of VG_(sigtimedwait) and replace it a simpler version, VG_(sigtimedwait_zero), which polls for signals and returns immediately. AIX doesn't have a sigtimedwait syscall, so in that case try and implement VG_(sigtimedwait_zero) using various other signal syscalls. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@6259 --- diff --git a/coregrind/m_libcsignal.c b/coregrind/m_libcsignal.c index 9e11ed0457..7dd14267cc 100644 --- a/coregrind/m_libcsignal.c +++ b/coregrind/m_libcsignal.c @@ -29,15 +29,18 @@ */ #include "pub_core_basics.h" +#include "pub_core_debuglog.h" #include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" #include "pub_core_libcbase.h" #include "pub_core_libcassert.h" -#include "pub_core_libcsignal.h" #include "pub_core_syscall.h" -#include "pub_core_vkiscnums.h" +#include "pub_core_libcsignal.h" /* self */ /* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on success and -1 on error. */ +/* I believe the indexing scheme in ->sig[] is also correct for + 32- and 64-bit AIX (verified 27 July 06). */ Int VG_(sigfillset)( vki_sigset_t* set ) { @@ -122,7 +125,6 @@ Int VG_(sigismember) ( const vki_sigset_t* set, Int signum ) return 0; } - /* Add all signals in src to dst. */ void VG_(sigaddset_from_set)( vki_sigset_t* dst, vki_sigset_t* src ) { @@ -164,30 +166,6 @@ Int VG_(sigaction) ( Int signum, const struct vki_sigaction* act, } -Int VG_(sigtimedwait)( const vki_sigset_t *set, vki_siginfo_t *info, - const struct vki_timespec *timeout ) -{ - SysRes res = VG_(do_syscall4)(__NR_rt_sigtimedwait, (UWord)set, (UWord)info, - (UWord)timeout, sizeof(*set)); - return res.isError ? -1 : res.val; -} - -Int VG_(signal)(Int signum, void (*sighandler)(Int)) -{ - SysRes res; - Int n; - struct vki_sigaction sa; - sa.ksa_handler = sighandler; - sa.sa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART; - sa.sa_restorer = NULL; - n = VG_(sigemptyset)( &sa.sa_mask ); - vg_assert(n == 0); - res = VG_(do_syscall4)(__NR_rt_sigaction, signum, (UWord)&sa, (UWord)NULL, - _VKI_NSIG_WORDS * sizeof(UWord)); - return res.isError ? -1 : 0; -} - - Int VG_(kill)( Int pid, Int signo ) { SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo); @@ -198,21 +176,134 @@ Int VG_(kill)( Int pid, Int signo ) Int VG_(tkill)( ThreadId tid, Int signo ) { SysRes res = VG_(mk_SysRes_Error)(VKI_ENOSYS); + res = VG_(do_syscall2)(__NR_tkill, tid, signo); + if (res.isError && res.err == VKI_ENOSYS) + res = VG_(do_syscall2)(__NR_kill, tid, signo); + return res.isError ? -1 : 0; +} -#if 0 - /* This isn't right because the client may create a process - structure with multiple thread groups */ - res = VG_(do_syscall3)(__NR_tgkill, VG_(getpid)(), tid, signo); -#endif - res = VG_(do_syscall2)(__NR_tkill, tid, signo); +/* A cut-down version of POSIX sigtimedwait: poll for pending signals + mentioned in the sigset_t, and if any are present, select one + arbitrarily, return its number (which must be > 0), and put + auxiliary info about it in the siginfo_t, and make it + not-pending-any-more. If none are pending, return zero. The _zero + refers to the fact that there is zero timeout, so if no signals are + pending it returns immediately. Perhaps a better name would be + 'sigpoll'. Returns -1 on error, 0 if no signals pending, and n > 0 + if signal n was selected. - if (res.isError && res.val == VKI_ENOSYS) - res = VG_(do_syscall2)(__NR_kill, tid, signo); + The Linux implementation is trivial: do the corresponding syscall. - return res.isError ? -1 : 0; + The AIX implementation is horrible and probably broken in a dozen + obscure ways. I suspect it's only thread-safe because V forces + single-threadedness. */ + +#if defined(VGO_linux) +Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, + vki_siginfo_t *info ) +{ + static const struct vki_timespec zero = { 0, 0 }; + SysRes res = VG_(do_syscall4)(__NR_rt_sigtimedwait, (UWord)set, (UWord)info, + (UWord)&zero, sizeof(*set)); + return res.isError ? -1 : res.res; } +#elif defined(VGO_aix5) +/* The general idea is: + - use sigpending to find out which signals are pending + - choose one + - temporarily set its handler to sigtimedwait_zero_handler + - use sigsuspend atomically unblock it and wait for the signal. + Upon return, sigsuspend restores the signal mask to what it + was to start with. + - Restore the handler for the signal to whatever it was before. +*/ + +/* A signal handler which does nothing (it doesn't need to). It does + however check that it's not handing a sync signal for which + returning is meaningless. */ +static void sigtimedwait_zero_handler ( Int sig ) +{ + vg_assert(sig != VKI_SIGILL); + vg_assert(sig != VKI_SIGSEGV); + vg_assert(sig != VKI_SIGBUS); + vg_assert(sig != VKI_SIGTRAP); + /* do nothing */ +} + +Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, + vki_siginfo_t *info ) +{ + Int i, ir; + SysRes sr; + vki_sigset_t pending, blocked, allbutone; + struct vki_sigaction sa, saved_sa; + + /* Find out what's pending: AIX _sigpending */ + sr = VG_(do_syscall1)(__NR__sigpending, (UWord)&pending); + vg_assert(!sr.isError); + + /* don't try for signals not in 'set' */ + /* pending = pending `intersect` set */ + for (i = 0; i < _VKI_NSIG_WORDS; i++) + pending.sig[i] &= set->sig[i]; + + /* don't try for signals not blocked at the moment */ + ir = VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &blocked); + vg_assert(ir == 0); + + /* pending = pending `intersect` blocked */ + for (i = 0; i < _VKI_NSIG_WORDS; i++) + pending.sig[i] &= blocked.sig[i]; + + /* decide which signal we're going to snarf */ + for (i = 1; i < _VKI_NSIG; i++) + if (VG_(sigismember)(&pending,i)) + break; + + if (i == _VKI_NSIG) + return 0; + + /* fetch signal i. + pre: i is blocked and pending + pre: we are the only thread running + */ + /* Set up alternative signal handler */ + VG_(sigfillset)(&allbutone); + VG_(sigdelset)(&allbutone, i); + sa.sa_mask = allbutone; + sa.ksa_handler = &sigtimedwait_zero_handler; + sa.sa_flags = 0; + ir = VG_(sigaction)(i, &sa, &saved_sa); + vg_assert(ir == 0); + + /* Switch signal masks and wait for the signal. This should happen + immediately, since we've already established it is pending and + blocked. */ + sr = VG_(do_syscall1)(__NR__sigsuspend, (UWord)&allbutone); + vg_assert(sr.isError); + if (0) + VG_(debugLog)(0, "libcsignal", + "sigtimedwait_zero: sigsuspend got res %ld err %ld\n", + sr.res, sr.err); + vg_assert(sr.res == (UWord)-1); + + /* Restore signal's handler to whatever it was before */ + ir = VG_(sigaction)(i, &saved_sa, NULL); + vg_assert(ir == 0); + + /* This is bogus - we could get more info from the sighandler. */ + VG_(memset)( info, 0, sizeof(*info) ); + info->si_signo = i; + + return i; +} + +#else +# error Unknown OS +#endif + /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/pub_core_libcsignal.h b/coregrind/pub_core_libcsignal.h index 32bd849780..db364d387d 100644 --- a/coregrind/pub_core_libcsignal.h +++ b/coregrind/pub_core_libcsignal.h @@ -65,14 +65,19 @@ extern Int VG_(sigaction) ( Int signum, const struct vki_sigaction* act, struct vki_sigaction* oldact ); -extern Int VG_(sigtimedwait)( const vki_sigset_t *, vki_siginfo_t *, - const struct vki_timespec * ); - -extern Int VG_(signal) ( Int signum, void (*sighandler)(Int) ); - extern Int VG_(kill) ( Int pid, Int signo ); extern Int VG_(tkill) ( ThreadId tid, Int signo ); +/* A cut-down version of POSIX sigtimedwait: poll for pending signals + mentioned in the sigset_t, and if any are present, select one + arbitrarily, return its number (which must be > 0), and put + auxiliary info about it in the siginfo_t, and make it + not-pending-any-more. If none are pending, return zero. The _zero + refers to the fact that there is zero timeout, so if no signals are + pending it returns immediately. Perhaps a better name would be + 'sigpoll'. Returns -1 on error, 0 if no signals pending, and n > 0 + if signal n was selected. */ +extern Int VG_(sigtimedwait_zero)( const vki_sigset_t *, vki_siginfo_t * ); #endif // __PUB_CORE_LIBCSIGNAL_H