aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornjn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9>2008-10-13 04:19:15 +0000
committernjn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9>2008-10-13 04:19:15 +0000
commite9ba34af88cd1b397957018e3e122869c76c1652 (patch)
treeebc1bfa5213e6ed7cf4b3364d7f624a82e276d83
parentfad9837bc7439202a0f1db8d640f0b5990f6ae19 (diff)
downloadvalgrind-e9ba34af88cd1b397957018e3e122869c76c1652.tar.gz
- Reinstate the 'atfork' from 2.4.0, which was more powerful, and expose it to
tools. - Factor out 'execv' from 'system' and expose it to tools. Partly based on a patch from Robert O'Callahan. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8669 a5019735-40e9-0310-863c-91ae7b9d1cf9
-rw-r--r--coregrind/m_libcproc.c104
-rw-r--r--coregrind/m_scheduler/scheduler.c2
-rw-r--r--coregrind/m_syswrap/syswrap-aix5.c4
-rw-r--r--coregrind/m_syswrap/syswrap-generic.c4
-rw-r--r--coregrind/m_syswrap/syswrap-linux.c4
-rw-r--r--coregrind/pub_core_libcproc.h7
-rw-r--r--include/pub_tool_libcproc.h14
7 files changed, 101 insertions, 38 deletions
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 4ea181ad6..e24ad2cfb 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -271,36 +271,37 @@ Char **VG_(env_clone) ( Char **oldenv )
return newenv;
}
+void VG_(execv) ( Char* filename, Char** argv )
+{
+ Char** envp;
+ SysRes res;
+
+ /* restore the DATA rlimit for the child */
+ VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+
+ envp = VG_(env_clone)(VG_(client_envp));
+ VG_(env_remove_valgrind_env_stuff)( envp );
+
+ res = VG_(do_syscall3)(__NR_execve,
+ (UWord)filename, (UWord)argv, (UWord)envp);
+
+ VG_(printf)("EXEC failed, errno = %ld\n", res.res);
+}
+
/* Return -1 if error, else 0. NOTE does not indicate return code of
child! */
Int VG_(system) ( Char* cmd )
{
- Int pid;
- SysRes res;
+ Int pid;
if (cmd == NULL)
return 1;
- res = VG_(do_syscall0)(__NR_fork);
- if (res.isError)
+ pid = VG_(fork)();
+ if (pid < 0)
return -1;
- pid = res.res;
if (pid == 0) {
/* child */
- static Char** envp = NULL;
- Char* argv[4];
-
- /* restore the DATA rlimit for the child */
- VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
-
- envp = VG_(env_clone)(VG_(client_envp));
- VG_(env_remove_valgrind_env_stuff)( envp );
-
- argv[0] = "/bin/sh";
- argv[1] = "-c";
- argv[2] = cmd;
- argv[3] = 0;
-
- (void)VG_(do_syscall3)(__NR_execve,
- (UWord)"/bin/sh", (UWord)argv, (UWord)envp);
+ Char* argv[4] = { "/bin/sh", "-c", cmd, 0 };
+ VG_(execv)(argv[0], argv);
/* If we're still alive here, execve failed. */
VG_(exit)(1);
@@ -569,26 +570,67 @@ UInt VG_(read_millisecond_timer) ( void )
}
/* ---------------------------------------------------------------------
- A trivial atfork() facility for Valgrind's internal use
+ atfork()
------------------------------------------------------------------ */
-// Trivial because it only supports a single post-fork child action, which
-// is all we need.
+struct atfork {
+ vg_atfork_t pre;
+ vg_atfork_t parent;
+ vg_atfork_t child;
+};
-static vg_atfork_t atfork_child = NULL;
+#define VG_MAX_ATFORK 10
-void VG_(atfork_child)(vg_atfork_t child)
+static struct atfork atforks[VG_MAX_ATFORK];
+static Int n_atfork = 0;
+
+void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child)
{
- if (NULL != atfork_child)
- VG_(core_panic)("More than one atfork_child handler requested");
+ Int i;
- atfork_child = child;
+ for (i = 0; i < n_atfork; i++) {
+ if (atforks[i].pre == pre &&
+ atforks[i].parent == parent &&
+ atforks[i].child == child)
+ return;
+ }
+
+ if (n_atfork >= VG_MAX_ATFORK)
+ VG_(core_panic)(
+ "Too many VG_(atfork) handlers requested: raise VG_MAX_ATFORK");
+
+ atforks[n_atfork].pre = pre;
+ atforks[n_atfork].parent = parent;
+ atforks[n_atfork].child = child;
+
+ n_atfork++;
+}
+
+void VG_(do_atfork_pre)(ThreadId tid)
+{
+ Int i;
+
+ for (i = 0; i < n_atfork; i++)
+ if (atforks[i].pre != NULL)
+ (*atforks[i].pre)(tid);
+}
+
+void VG_(do_atfork_parent)(ThreadId tid)
+{
+ Int i;
+
+ for (i = 0; i < n_atfork; i++)
+ if (atforks[i].parent != NULL)
+ (*atforks[i].parent)(tid);
}
void VG_(do_atfork_child)(ThreadId tid)
{
- if (NULL != atfork_child)
- (*atfork_child)(tid);
+ Int i;
+
+ for (i = 0; i < n_atfork; i++)
+ if (atforks[i].child != NULL)
+ (*atforks[i].child)(tid);
}
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index 6d6e59341..d8bc44d45 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -502,7 +502,7 @@ void VG_(scheduler_init_phase2) ( ThreadId tid_main,
VG_(threads)[tid_main].client_stack_szB
= clstack_size;
- VG_(atfork_child)(sched_fork_cleanup);
+ VG_(atfork)(NULL, NULL, sched_fork_cleanup);
}
diff --git a/coregrind/m_syswrap/syswrap-aix5.c b/coregrind/m_syswrap/syswrap-aix5.c
index 9d4db5c56..3a54ec631 100644
--- a/coregrind/m_syswrap/syswrap-aix5.c
+++ b/coregrind/m_syswrap/syswrap-aix5.c
@@ -1332,6 +1332,8 @@ PRE(sys_kfork) /* COPY OF GENERIC */
VG_(sigfillset)(&mask);
VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask);
+ VG_(do_atfork_pre)(tid);
+
SET_STATUS_from_SysRes( VG_(do_syscall0)(__NR_fork) );
if (SUCCESS && RES == 0) {
@@ -1351,6 +1353,8 @@ PRE(sys_kfork) /* COPY OF GENERIC */
else
if (SUCCESS && RES > 0) {
/* parent */
+ VG_(do_atfork_parent)(tid);
+
PRINT(" fork: process %d created child %lu\n", VG_(getpid)(), RES);
/* restore signal mask */
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 0d3674739..ba0eaa7d4 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -2977,6 +2977,8 @@ PRE(sys_fork)
SET_STATUS_from_SysRes( VG_(do_syscall0)(__NR_fork) );
+ VG_(do_atfork_pre)(tid);
+
if (SUCCESS && RES == 0) {
/* child */
VG_(do_atfork_child)(tid);
@@ -2994,6 +2996,8 @@ PRE(sys_fork)
else
if (SUCCESS && RES > 0) {
/* parent */
+ VG_(do_atfork_parent)(tid);
+
PRINT(" fork: process %d created child %ld\n", VG_(getpid)(), RES);
/* restore signal mask */
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index f1950dd2f..dc54ca10d 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -313,6 +313,8 @@ SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
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 */
#if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
@@ -346,6 +348,8 @@ SysRes ML_(do_fork_clone) ( ThreadId tid, UInt flags,
else
if (!res.isError && res.res > 0) {
/* parent */
+ VG_(do_atfork_parent)(tid);
+
if (VG_(clo_trace_syscalls))
VG_(printf)(" clone(fork): process %d created child %ld\n",
VG_(getpid)(), res.res);
diff --git a/coregrind/pub_core_libcproc.h b/coregrind/pub_core_libcproc.h
index 23e5b5abb..13aea944e 100644
--- a/coregrind/pub_core_libcproc.h
+++ b/coregrind/pub_core_libcproc.h
@@ -78,12 +78,11 @@ extern Char **VG_(env_clone) ( Char **env_clone );
// misc
extern Int VG_(getgroups)( Int size, UInt* list );
extern Int VG_(ptrace)( Int request, Int pid, void *addr, void *data );
-extern Int VG_(fork)( void );
// atfork
-typedef void (*vg_atfork_t)(ThreadId);
-extern void VG_(atfork_child) ( vg_atfork_t child_action );
-extern void VG_(do_atfork_child) ( ThreadId tid );
+extern void VG_(do_atfork_pre) ( ThreadId tid );
+extern void VG_(do_atfork_parent) ( ThreadId tid );
+extern void VG_(do_atfork_child) ( ThreadId tid );
#endif // __PUB_CORE_LIBCPROC_H
diff --git a/include/pub_tool_libcproc.h b/include/pub_tool_libcproc.h
index ddf91b4e3..f0f7cfca7 100644
--- a/include/pub_tool_libcproc.h
+++ b/include/pub_tool_libcproc.h
@@ -50,8 +50,10 @@ extern const Char *VG_(libdir);
Important syscalls
------------------------------------------------------------------ */
-extern Int VG_(waitpid)( Int pid, Int *status, Int options );
-extern Int VG_(system) ( Char* cmd );
+extern Int VG_(waitpid)( Int pid, Int *status, Int options );
+extern Int VG_(system) ( Char* cmd );
+extern Int VG_(fork) ( void);
+extern void VG_(execv) ( Char* filename, Char** argv );
/* ---------------------------------------------------------------------
Resource limits
@@ -80,6 +82,14 @@ extern Int VG_(getegid) ( void );
// steps).
extern UInt VG_(read_millisecond_timer) ( void );
+/* ---------------------------------------------------------------------
+ atfork
+ ------------------------------------------------------------------ */
+
+typedef void (*vg_atfork_t)(ThreadId);
+extern void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child);
+
+
#endif // __PUB_TOOL_LIBCPROC_H
/*--------------------------------------------------------------------*/