diff options
author | njn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2008-10-13 04:19:15 +0000 |
---|---|---|
committer | njn <njn@a5019735-40e9-0310-863c-91ae7b9d1cf9> | 2008-10-13 04:19:15 +0000 |
commit | e9ba34af88cd1b397957018e3e122869c76c1652 (patch) | |
tree | ebc1bfa5213e6ed7cf4b3364d7f624a82e276d83 | |
parent | fad9837bc7439202a0f1db8d640f0b5990f6ae19 (diff) | |
download | valgrind-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.c | 104 | ||||
-rw-r--r-- | coregrind/m_scheduler/scheduler.c | 2 | ||||
-rw-r--r-- | coregrind/m_syswrap/syswrap-aix5.c | 4 | ||||
-rw-r--r-- | coregrind/m_syswrap/syswrap-generic.c | 4 | ||||
-rw-r--r-- | coregrind/m_syswrap/syswrap-linux.c | 4 | ||||
-rw-r--r-- | coregrind/pub_core_libcproc.h | 7 | ||||
-rw-r--r-- | include/pub_tool_libcproc.h | 14 |
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 /*--------------------------------------------------------------------*/ |