Merge patch from Jeremy Fitzhardinge:
02-sysv-msg
Support for threaded programs using msgsnd/msgrcv.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1264 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index 42e289f..771ed74 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -2180,6 +2180,22 @@
return __res;
}
+static inline
+int my_do_syscall5 ( int syscallno,
+ int arg1, int arg2, int arg3, int arg4, int arg5 )
+{
+ int __res;
+ __asm__ volatile ("int $0x80"
+ : "=a" (__res)
+ : "0" (syscallno),
+ "b" (arg1),
+ "c" (arg2),
+ "d" (arg3),
+ "S" (arg4),
+ "D" (arg5));
+ return __res;
+}
+
static
int do_syscall_select( int n,
vki_fd_set* readfds,
@@ -3037,6 +3053,96 @@
/* ---------------------------------------------------------------------
+ Make SYSV IPC not block everything
+ ------------------------------------------------------------------ */
+
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <asm/ipc.h> /* for ipc_kludge */
+
+static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
+{
+ return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
+}
+
+/* Turn a blocking msgsnd() into a polling non-blocking one, so that
+ other threads make progress */
+int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
+{
+ struct vki_timespec nanosleep_interval;
+ int err;
+
+ ensure_valgrind("msgsnd");
+
+ nanosleep_interval.tv_sec = 0;
+ nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+
+ if (msgflg & IPC_NOWAIT) {
+ /* If we aren't blocking anyway, just do it */
+ err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
+ } else {
+ /* Otherwise poll on the queue to let other things run */
+ for(;;) {
+ err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
+
+ if (err != -EAGAIN)
+ break;
+
+ (void)my_do_syscall2(__NR_nanosleep,
+ (int)(&nanosleep_interval), (int)NULL);
+ }
+ }
+
+ if (is_kerror(err)) {
+ *(__errno_location()) = -err;
+ return -1;
+ }
+ return 0;
+}
+
+/* Turn a blocking msgrcv() into a polling non-blocking one, so that
+ other threads make progress */
+int msgrcv( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg )
+{
+ struct vki_timespec nanosleep_interval;
+ int err;
+ struct ipc_kludge tmp;
+
+ ensure_valgrind("msgrcv");
+
+ nanosleep_interval.tv_sec = 0;
+ nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+
+ tmp.msgp = msgp;
+ tmp.msgtyp = msgtyp;
+
+ if (msgflg & IPC_NOWAIT) {
+ /* If we aren't blocking anyway, just do it */
+ err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
+ } else {
+ /* Otherwise poll on the queue to let other things run */
+ for(;;) {
+ err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
+
+ if (err != -ENOMSG)
+ break;
+
+ (void)my_do_syscall2(__NR_nanosleep,
+ (int)(&nanosleep_interval), (int)NULL);
+ }
+ }
+
+ if (is_kerror(err)) {
+ *(__errno_location()) = -err;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/* ---------------------------------------------------------------------
B'stard.
------------------------------------------------------------------ */
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index 42e289f..771ed74 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -2180,6 +2180,22 @@
return __res;
}
+static inline
+int my_do_syscall5 ( int syscallno,
+ int arg1, int arg2, int arg3, int arg4, int arg5 )
+{
+ int __res;
+ __asm__ volatile ("int $0x80"
+ : "=a" (__res)
+ : "0" (syscallno),
+ "b" (arg1),
+ "c" (arg2),
+ "d" (arg3),
+ "S" (arg4),
+ "D" (arg5));
+ return __res;
+}
+
static
int do_syscall_select( int n,
vki_fd_set* readfds,
@@ -3037,6 +3053,96 @@
/* ---------------------------------------------------------------------
+ Make SYSV IPC not block everything
+ ------------------------------------------------------------------ */
+
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <asm/ipc.h> /* for ipc_kludge */
+
+static inline int sys_ipc(unsigned call, int first, int second, int third, void *ptr)
+{
+ return my_do_syscall5(__NR_ipc, call, first, second, third, (int)ptr);
+}
+
+/* Turn a blocking msgsnd() into a polling non-blocking one, so that
+ other threads make progress */
+int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
+{
+ struct vki_timespec nanosleep_interval;
+ int err;
+
+ ensure_valgrind("msgsnd");
+
+ nanosleep_interval.tv_sec = 0;
+ nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+
+ if (msgflg & IPC_NOWAIT) {
+ /* If we aren't blocking anyway, just do it */
+ err = sys_ipc(11, msgid, msgsz, msgflg, (void *)msgp);
+ } else {
+ /* Otherwise poll on the queue to let other things run */
+ for(;;) {
+ err = sys_ipc(11, msgid, msgsz, msgflg | IPC_NOWAIT, (void *)msgp);
+
+ if (err != -EAGAIN)
+ break;
+
+ (void)my_do_syscall2(__NR_nanosleep,
+ (int)(&nanosleep_interval), (int)NULL);
+ }
+ }
+
+ if (is_kerror(err)) {
+ *(__errno_location()) = -err;
+ return -1;
+ }
+ return 0;
+}
+
+/* Turn a blocking msgrcv() into a polling non-blocking one, so that
+ other threads make progress */
+int msgrcv( int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg )
+{
+ struct vki_timespec nanosleep_interval;
+ int err;
+ struct ipc_kludge tmp;
+
+ ensure_valgrind("msgrcv");
+
+ nanosleep_interval.tv_sec = 0;
+ nanosleep_interval.tv_nsec = 13 * 1000 * 1000; /* 13 milliseconds */
+
+ tmp.msgp = msgp;
+ tmp.msgtyp = msgtyp;
+
+ if (msgflg & IPC_NOWAIT) {
+ /* If we aren't blocking anyway, just do it */
+ err = sys_ipc(12, msqid, msgsz, msgflg, &tmp );
+ } else {
+ /* Otherwise poll on the queue to let other things run */
+ for(;;) {
+ err = sys_ipc(12, msqid, msgsz, msgflg | IPC_NOWAIT, &tmp );
+
+ if (err != -ENOMSG)
+ break;
+
+ (void)my_do_syscall2(__NR_nanosleep,
+ (int)(&nanosleep_interval), (int)NULL);
+ }
+ }
+
+ if (is_kerror(err)) {
+ *(__errno_location()) = -err;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/* ---------------------------------------------------------------------
B'stard.
------------------------------------------------------------------ */