*/
#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 )
{
return 0;
}
-
/* Add all signals in src to dst. */
void VG_(sigaddset_from_set)( vki_sigset_t* dst, vki_sigset_t* src )
{
}
-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);
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 ---*/
/*--------------------------------------------------------------------*/