|
From: <sv...@va...> - 2006-10-17 01:30:50
|
Author: sewardj
Date: 2006-10-17 02:30:47 +0100 (Tue, 17 Oct 2006)
New Revision: 6259
Log:
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.
Modified:
trunk/coregrind/m_libcsignal.c
trunk/coregrind/pub_core_libcsignal.h
Modified: trunk/coregrind/m_libcsignal.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_libcsignal.c 2006-10-17 01:30:07 UTC (rev 6258)
+++ trunk/coregrind/m_libcsignal.c 2006-10-17 01:30:47 UTC (rev 6259)
@@ -29,15 +29,18 @@
*/
=20
#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 */
=20
/* 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). */
=20
Int VG_(sigfillset)( vki_sigset_t* set )
{
@@ -122,7 +125,6 @@
return 0;
}
=20
-
/* Add all signals in src to dst. */
void VG_(sigaddset_from_set)( vki_sigset_t* dst, vki_sigset_t* src )
{
@@ -164,55 +166,144 @@
}
=20
=20
-Int VG_(sigtimedwait)( const vki_sigset_t *set, vki_siginfo_t *info,=20
- const struct vki_timespec *timeout )
+Int VG_(kill)( Int pid, Int signo )
{
- SysRes res =3D VG_(do_syscall4)(__NR_rt_sigtimedwait, (UWord)set, (UW=
ord)info,=20
- (UWord)timeout, sizeof(*set));
- return res.isError ? -1 : res.val;
+ SysRes res =3D VG_(do_syscall2)(__NR_kill, pid, signo);
+ return res.isError ? -1 : 0;
}
-=20
-Int VG_(signal)(Int signum, void (*sighandler)(Int))
+
+
+Int VG_(tkill)( ThreadId tid, Int signo )
{
- SysRes res;
- Int n;
- struct vki_sigaction sa;
- sa.ksa_handler =3D sighandler;
- sa.sa_flags =3D VKI_SA_ONSTACK | VKI_SA_RESTART;
- sa.sa_restorer =3D NULL;
- n =3D VG_(sigemptyset)( &sa.sa_mask );
- vg_assert(n =3D=3D 0);
- res =3D VG_(do_syscall4)(__NR_rt_sigaction, signum, (UWord)&sa, (UWor=
d)NULL,
- _VKI_NSIG_WORDS * sizeof(UWord));
+ SysRes res =3D VG_(mk_SysRes_Error)(VKI_ENOSYS);
+ res =3D VG_(do_syscall2)(__NR_tkill, tid, signo);
+ if (res.isError && res.err =3D=3D VKI_ENOSYS)
+ res =3D VG_(do_syscall2)(__NR_kill, tid, signo);
return res.isError ? -1 : 0;
}
=20
=20
-Int VG_(kill)( Int pid, 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.=20
+
+ The Linux implementation is trivial: do the corresponding syscall.
+
+ 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,=20
+ vki_siginfo_t *info )
{
- SysRes res =3D VG_(do_syscall2)(__NR_kill, pid, signo);
- return res.isError ? -1 : 0;
+ static const struct vki_timespec zero =3D { 0, 0 };
+ SysRes res =3D VG_(do_syscall4)(__NR_rt_sigtimedwait, (UWord)set, (UW=
ord)info,=20
+ (UWord)&zero, sizeof(*set));
+ return res.isError ? -1 : res.res;
}
=20
+#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.
+*/
=20
-Int VG_(tkill)( ThreadId tid, Int signo )
+/* 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 )=20
+{=20
+ vg_assert(sig !=3D VKI_SIGILL);
+ vg_assert(sig !=3D VKI_SIGSEGV);
+ vg_assert(sig !=3D VKI_SIGBUS);
+ vg_assert(sig !=3D VKI_SIGTRAP);
+ /* do nothing */=20
+}
+
+Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,=20
+ vki_siginfo_t *info )
{
- SysRes res =3D VG_(mk_SysRes_Error)(VKI_ENOSYS);
+ Int i, ir;
+ SysRes sr;
+ vki_sigset_t pending, blocked, allbutone;
+ struct vki_sigaction sa, saved_sa;
=20
-#if 0
- /* This isn't right because the client may create a process
- structure with multiple thread groups */
- res =3D VG_(do_syscall3)(__NR_tgkill, VG_(getpid)(), tid, signo);
-#endif
+ /* Find out what's pending: AIX _sigpending */
+ sr =3D VG_(do_syscall1)(__NR__sigpending, (UWord)&pending);
+ vg_assert(!sr.isError);
=20
- res =3D VG_(do_syscall2)(__NR_tkill, tid, signo);
+ /* don't try for signals not in 'set' */
+ /* pending =3D pending `intersect` set */
+ for (i =3D 0; i < _VKI_NSIG_WORDS; i++)
+ pending.sig[i] &=3D set->sig[i];
=20
- if (res.isError && res.val =3D=3D VKI_ENOSYS)
- res =3D VG_(do_syscall2)(__NR_kill, tid, signo);
+ /* don't try for signals not blocked at the moment */
+ ir =3D VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &blocked);
+ vg_assert(ir =3D=3D 0);
=20
- return res.isError ? -1 : 0;
+ /* pending =3D pending `intersect` blocked */
+ for (i =3D 0; i < _VKI_NSIG_WORDS; i++)
+ pending.sig[i] &=3D blocked.sig[i];
+
+ /* decide which signal we're going to snarf */
+ for (i =3D 1; i < _VKI_NSIG; i++)
+ if (VG_(sigismember)(&pending,i))
+ break;
+
+ if (i =3D=3D _VKI_NSIG)
+ return 0;
+
+ /* fetch signal i.
+ pre: i is blocked and pending
+ pre: we are the only thread running=20
+ */
+ /* Set up alternative signal handler */
+ VG_(sigfillset)(&allbutone);
+ VG_(sigdelset)(&allbutone, i);
+ sa.sa_mask =3D allbutone;
+ sa.ksa_handler =3D &sigtimedwait_zero_handler;
+ sa.sa_flags =3D 0;
+ ir =3D VG_(sigaction)(i, &sa, &saved_sa);
+ vg_assert(ir =3D=3D 0);
+
+ /* Switch signal masks and wait for the signal. This should happen
+ immediately, since we've already established it is pending and
+ blocked. */
+ sr =3D 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",=20
+ sr.res, sr.err);
+ vg_assert(sr.res =3D=3D (UWord)-1);
+
+ /* Restore signal's handler to whatever it was before */
+ ir =3D VG_(sigaction)(i, &saved_sa, NULL);
+ vg_assert(ir =3D=3D 0);
+
+ /* This is bogus - we could get more info from the sighandler. */
+ VG_(memset)( info, 0, sizeof(*info) );
+ info->si_signo =3D i;
+
+ return i;
}
=20
+#else
+# error Unknown OS
+#endif
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
Modified: trunk/coregrind/pub_core_libcsignal.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_libcsignal.h 2006-10-17 01:30:07 UTC (rev 62=
58)
+++ trunk/coregrind/pub_core_libcsignal.h 2006-10-17 01:30:47 UTC (rev 62=
59)
@@ -65,14 +65,19 @@
const struct vki_sigaction* act,
struct vki_sigaction* oldact );
=20
-extern Int VG_(sigtimedwait)( const vki_sigset_t *, vki_siginfo_t *,=20
- 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 );
=20
+/* 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 *=
);
=20
#endif // __PUB_CORE_LIBCSIGNAL_H
=20
|