]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
- Reinstate the 'atfork' from 2.4.0, which was more powerful, and expose it to
authorNicholas Nethercote <njn@valgrind.org>
Mon, 13 Oct 2008 04:19:15 +0000 (04:19 +0000)
committerNicholas Nethercote <njn@valgrind.org>
Mon, 13 Oct 2008 04:19:15 +0000 (04:19 +0000)
  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

coregrind/m_libcproc.c
coregrind/m_scheduler/scheduler.c
coregrind/m_syswrap/syswrap-aix5.c
coregrind/m_syswrap/syswrap-generic.c
coregrind/m_syswrap/syswrap-linux.c
coregrind/pub_core_libcproc.h
include/pub_tool_libcproc.h

index 4ea181ad6a9d821162b621219200f4f6f870b509..e24ad2cfb9fd3a5b490ee040d7ccae1a62d0fda8 100644 (file)
@@ -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);
 }
 
 /*--------------------------------------------------------------------*/
index 6d6e593419be58c386788bfc96f9086fd224aee2..d8bc44d45e5cc8dea58fc000e3da8ab4dfd952d7 100644 (file)
@@ -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);
 }
 
 
index 9d4db5c56c6adcc3ee4713774992f2140221e766..3a54ec6311559f4514c346854f1953db6d47a113 100644 (file)
@@ -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 */
index 0d36747396583f2ab70379899c56c642d5086c36..ba0eaa7d469445fab06901b9ba2817965c3dbd44 100644 (file)
@@ -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 */
index f1950dd2ffe06b807a53600300fb99e28eea1a23..dc54ca10de29da7e06f6fdb09a6ba53eed20396c 100644 (file)
@@ -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);
index 23e5b5abb79582dec9867e13c3a52d0ee1af4bbd..13aea944e0b60df93348fdc7a29c6599fe819185 100644 (file)
@@ -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
 
index ddf91b4e30350e56ecc4aafebf96b646c460aa31..f0f7cfca75f2ae7ac9312ca9f33a181d2eec85f1 100644 (file)
@@ -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
 
 /*--------------------------------------------------------------------*/