@@ -95,25 +95,27 @@ struct child_args {
9595 const char * path ;
9696 struct mp_subprocess_opts * opts ;
9797 int * src_fds ;
98+ void * child_stack ;
9899 int pipe_end ;
99100 bool detach ;
100101};
101102
102103static pid_t spawn_process_inner (const char * path , struct mp_subprocess_opts * opts ,
103- int src_fds [], bool detach );
104+ int src_fds [], bool detach , void * stacks [] );
104105
105106static int child_main (void * args )
106107{
107108 struct child_args * child_args = args ;
108109 const char * path = child_args -> path ;
109110 struct mp_subprocess_opts * opts = child_args -> opts ;
110111 int * src_fds = child_args -> src_fds ;
112+ void * child_stack = child_args -> child_stack ;
111113 int * pipe_end = & child_args -> pipe_end ;
112114 bool detach = child_args -> detach ;
113115
114116 if (detach ) {
115117 setsid ();
116- if (!spawn_process_inner (path , opts , src_fds , false))
118+ if (!spawn_process_inner (path , opts , src_fds , false, & child_stack ))
117119 goto child_failed ;
118120 return 0 ;
119121 }
@@ -148,7 +150,7 @@ static int child_main(void* args)
148150}
149151
150152static pid_t spawn_process_inner (const char * path , struct mp_subprocess_opts * opts ,
151- int src_fds [], bool detach )
153+ int src_fds [], bool detach , void * stacks [] )
152154{
153155 pid_t fres = 0 ;
154156 int r ;
@@ -157,21 +159,15 @@ static pid_t spawn_process_inner(const char *path, struct mp_subprocess_opts *op
157159 .path = path ,
158160 .opts = opts ,
159161 .src_fds = src_fds ,
162+ .child_stack = stacks [1 ],
160163 .pipe_end = 0 ,
161164 .detach = detach ,
162165 };
163166
164- #if HAVE_CLONE || HAVE_RFORK
165- const size_t stack_size = 0x8000 ;
166- void * stack = mmap (NULL , stack_size , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK , -1 , 0 );
167- if (stack == MAP_FAILED )
168- goto done ;
169- #endif
170-
171167#if HAVE_RFORK
172- fres = rfork_thread (RFSPAWN , ( int8_t * ) stack + stack_size , child_main , & child_args );
168+ fres = rfork_thread (RFSPAWN , stacks [ 0 ] , child_main , & child_args );
173169#elif HAVE_CLONE
174- fres = clone (child_main , ( int8_t * ) stack + stack_size , CLONE_VM | CLONE_VFORK | SIGCHLD , & child_args );
170+ fres = clone (child_main , stacks [ 0 ] , CLONE_VM | CLONE_VFORK | SIGCHLD , & child_args );
175171#else
176172 int p [2 ] = {-1 , -1 };
177173 // We setup a communication pipe to signal failure. Since the child calls
@@ -219,9 +215,7 @@ static pid_t spawn_process_inner(const char *path, struct mp_subprocess_opts *op
219215 }
220216
221217done :
222- #if HAVE_CLONE || HAVE_RFORK
223- munmap (stack , stack_size );
224- #else
218+ #if !HAVE_CLONE && !HAVE_RFORK
225219 SAFE_CLOSE (p [0 ]);
226220 SAFE_CLOSE (p [1 ]);
227221#endif
@@ -234,19 +228,35 @@ static pid_t spawn_process_inner(const char *path, struct mp_subprocess_opts *op
234228static pid_t spawn_process (const char * path , struct mp_subprocess_opts * opts ,
235229 int src_fds [])
236230{
231+ bool detach = opts -> detach ;
232+ void * stacks [2 ];
233+
234+ #if HAVE_CLONE || HAVE_RFORK
235+ // pre-allocate stacks so we can be async-signal-safe in spawn_process_inner()
236+ const size_t stack_size = 0x8000 ;
237+ void * ctx = talloc_new (NULL );
238+ // stack should be aligned to 16 bytes, which is guaranteed by malloc
239+ stacks [0 ] = (int8_t * )talloc_size (ctx , stack_size ) + stack_size ;
240+ if (detach ) stacks [1 ] = (int8_t * )talloc_size (ctx , stack_size ) + stack_size ;
241+ #endif
242+
237243#if !HAVE_RFORK
238244 sigset_t sigmask , oldmask ;
239245
240246 sigfillset (& sigmask );
241247 pthread_sigmask (SIG_BLOCK , & sigmask , & oldmask );
242248#endif
243249
244- pid_t fres = spawn_process_inner (path , opts , src_fds , opts -> detach );
250+ pid_t fres = spawn_process_inner (path , opts , src_fds , detach , stacks );
245251
246252#if !HAVE_RFORK
247253 pthread_sigmask (SIG_SETMASK , & oldmask , NULL );
248254#endif
249255
256+ #if HAVE_CLONE || HAVE_RFORK
257+ talloc_free (ctx );
258+ #endif
259+
250260 return fres ;
251261}
252262
0 commit comments