|
From: Jeremy F. <je...@go...> - 2005-01-17 03:16:30
|
CVS commit by fitzhardinge:
When the client uses clone() to do a fork, use the clone syscall to
implement it rather than fork, so that all the CHILD/PARENT_SET/CLEARTID
flags are obeyed.
M +5 -0 core.h 1.66
M +6 -6 vg_syscalls.c 1.232
M +50 -5 x86-linux/syscalls.c 1.15
--- valgrind/coregrind/core.h #1.65:1.66
@@ -1250,4 +1250,9 @@ extern const Char *VG_(prot_str)(UInt pr
------------------------------------------------------------------ */
+/* Simple Valgrind-internal atfork mechanism */
+extern void VG_(do_atfork_pre) (ThreadId tid);
+extern void VG_(do_atfork_parent)(ThreadId tid);
+extern void VG_(do_atfork_child) (ThreadId tid);
+
extern Char *VG_(resolve_filename)(Int fd);
--- valgrind/coregrind/vg_syscalls.c #1.231:1.232
@@ -79,5 +79,5 @@ void VG_(atfork)(vg_atfork_t pre, vg_atf
}
-static void do_atfork_pre(ThreadId tid)
+void VG_(do_atfork_pre)(ThreadId tid)
{
Int i;
@@ -88,5 +88,5 @@ static void do_atfork_pre(ThreadId tid)
}
-static void do_atfork_parent(ThreadId tid)
+void VG_(do_atfork_parent)(ThreadId tid)
{
Int i;
@@ -97,5 +97,5 @@ static void do_atfork_parent(ThreadId ti
}
-static void do_atfork_child(ThreadId tid)
+void VG_(do_atfork_child)(ThreadId tid)
{
Int i;
@@ -2073,10 +2073,10 @@ PRE(sys_fork, Special)
VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask);
- do_atfork_pre(tid);
+ VG_(do_atfork_pre)(tid);
set_result(VG_(do_syscall)(__NR_fork));
if (SYSRES == 0) {
- do_atfork_child(tid);
+ VG_(do_atfork_child)(tid);
/* restore signal mask */
@@ -2085,5 +2085,5 @@ PRE(sys_fork, Special)
PRINT(" fork: process %d created child %d\n", VG_(getpid)(), SYSRES);
- do_atfork_parent(tid);
+ VG_(do_atfork_parent)(tid);
/* restore signal mask */
--- valgrind/coregrind/x86-linux/syscalls.c #1.14:1.15
@@ -357,4 +357,45 @@ static Int do_clone(ThreadId ptid,
}
+/* Do a clone which is really a fork() */
+static Int do_fork_clone(ThreadId tid, UInt flags, Addr esp, Int *parent_tidptr, Int *child_tidptr)
+{
+ vki_sigset_t fork_saved_mask;
+ vki_sigset_t mask;
+ Int ret;
+
+ if (flags & (VKI_CLONE_SETTLS | VKI_CLONE_FS | VKI_CLONE_VM | VKI_CLONE_FILES | VKI_CLONE_VFORK))
+ return -VKI_EINVAL;
+
+ /* Block all signals during fork, so that we can fix things up in
+ the child without being interrupted. */
+ VG_(sigfillset)(&mask);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask);
+
+ VG_(do_atfork_pre)(tid);
+
+ /* Since this is the fork() form of clone, we don't need all that
+ VG_(clone) stuff */
+ ret = VG_(do_syscall)(__NR_clone, flags, NULL, parent_tidptr, NULL, child_tidptr);
+
+ if (ret == 0) {
+ /* child */
+ VG_(do_atfork_child)(tid);
+
+ /* restore signal mask */
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
+ } else if (ret > 0) {
+ /* parent */
+ if (VG_(clo_trace_syscalls))
+ VG_(printf)(" clone(fork): process %d created child %d\n", VG_(getpid)(), ret);
+
+ VG_(do_atfork_parent)(tid);
+
+ /* restore signal mask */
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
+ }
+
+ return ret;
+}
+
/* ---------------------------------------------------------------------
PRE/POST wrappers for x86/Linux-specific syscalls
@@ -451,6 +492,5 @@ PRE(sys_clone, Special)
}
- /* Only look at the flags we really care about */
- cloneflags = arg1 & (VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES | VKI_CLONE_VFORK);
+ cloneflags = arg1;
if (!VG_(client_signal_OK)(arg1 & VKI_CSIGNAL)) {
@@ -459,5 +499,6 @@ PRE(sys_clone, Special)
}
- switch(cloneflags) {
+ /* Only look at the flags we really care about */
+ switch(cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
/* thread creation */
@@ -472,8 +513,12 @@ PRE(sys_clone, Special)
case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
/* FALLTHROUGH - assume vfork == fork */
+ cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
case 0: /* plain fork */
- vg_assert(VGA_(gen_sys_fork_flags) & Special);
- VGA_(gen_sys_fork_before)(tid, tst, &VGA_(gen_sys_fork_flags));
+ set_result(do_fork_clone(tid,
+ cloneflags, /* flags */
+ (Addr)arg2, /* child ESP */
+ (Int *)arg3, /* parent_tidptr */
+ (Int *)arg5)); /* child_tidptr */
break;
|