popen() ( , API) clone(2), issue vfork(2) posix_spawn() . , Linux clone(2). , , , - : , , .
, .
- , Unix, , fork(2) fork-exec , Windows , exec*() _spawn*(), .
, fork(2) . vfork(2)
, , . vfork(2)
, , ( ).
, .
, fork(2) - , , . vfork(2)
. vfork(2)
fork(2)
, , , , , . , vfork(2)
! , , : exec*(2)
, _exit(2)
.
3BSD vfork(2)
, 4.4BSD , . . 4.4BSD . : vfork(2)
, fork(2)
- , . , fork(2)
, ( , ). , , . . , , seed’ , (, JVM), RSS . , fork(2)
, (, shell).
, , fork(2)
- . , fork-safety! fork-safety thread-safety (), fork-safe , thread-safe. fork-safety: .
( , : , fork(2)
, , , . , fork-unsafe , , fork(2)
. vfork(2)
. Windows CreateProcess()
_spawn()
, .)
, fork(2)
? , : CreateProcess*()
, _spawn()
posix_spawn()
, , , , fork()
exec()
, , shell. fork()
exec()
API, : ! fork(2)
Unix kernel-land user-land, - , , . , Unix , . , . , .
vfork()
fork()
!
vfork()
: ( , , vfork()
) , () , exec()
_exit()
. ( - , vfork(2)
- , . - main()- .) - , , , . vfork()
/ . afork()
avfork()
. afork()
pthread_create()
: , .
, vfork()
, , , , exit/exec, . Linux, , - vfork()
, . , , IIRC ( , IMO).
afork()
API popen()
I/O . - , , ( ) EOF, / EPIPE / SIGPIPE, popen()
.
forkx()/vforkx() Illumos , afork()
- :
pid_t afork(int (*start_routine)(void *), void *arg);
pid_t aforkx(int flags /* FORK_NOSIGCHLD / FORK_WAITPID */, int (*fn)(void *), void *arg);
, afork()
Linux: clone(<function>
, <stack>
, CLONE_VM | CLONE_SETTLS
, <argument>
). ( , SIGCHLD , , popen()
, , pclose()
. Illumos.)
- afork ()
( Illumos forkx()
) POSIX, pthread_create()
, vfork()
, afork()
. taskq, , , afork()
. afork()
, , PID, taskq pre-vfork ( !), , - :
int emulated_afork(int (*start_routine)(void *), void *arg, void (*cb)(pid_t) /* NULL */);
pre-vfork, PID afork()
, pre-vfork
: pthread_cond_wait()
, , . ( vfork()
. , read()
write()
vfork()
) :
// , vfork() , vfork(), . , Linux.
// , avfork() . , Linux clone(2).
static struct avfork_taskq_s { /* */ ... } *avfork_taskq;
static void
avfork_taskq_init(void)
{
// ,
...
}
// taskq , ,
// taskq
static void *
worker_start_routine(void *arg)
{
struct worker_s *me = arg;
struct job_s *job;
// pthread_cond_signal() , .
avfork_taskq_add_worker(avfork_taskq, me);
do {
if ((job = calloc(1, sizeof(*job))) == NULL ||
pipe2(job->dispatch_pipe, O_CLOEXEC) == -1 ||
pipe2(job->ready_pipe, O_CLOEXEC) == -1 ||
(pid = vfork()) == -1) {
avfork_taskq_remove(avfork_taskq, me, errno); // !
break;
}
if (pid != 0) {
// exit exec
if (job->errno)
//
reap_child(pid);
else
// ; , .
// , .
avfork_taskq_record_child(avfork_taskq, me, job, pid);
if (avfork_taskq_too_big_p(avfork_taskq))
break; // taskq
continue;
}
//
// , read(2), write(2), _exit(2) start_routine avfork(). avfork() start_routine() , , , vfork(). C - : , , , RTLD .. , dup2(2), close(2), sigaction(2), , exec(2) _exit(2) start_routine(), posix_spawn(), popen(), system () ..
// , taskq.
//
if (net_read(me->dispatch_pipe[0], &job->descr, sizeof(job->descr)) != sizeof(job->descr)) {
job->errno = errno ? errno : EINVAL;
_exit(1);
}
job->descr->pid = getpid(); // pid,
if(net_write(me->ready_pipe[1], "", sizeof("")) != sizeof("")) {
job->errno = errno;
_exit(1);
}
//
_exit(job->descr->start_routine(job->descr->arg));
} while(!avfork_taskq->terminated); // , atexit()
return NULL;
}
pid_t
avfork(int (*start_routine)(void *), void *arg)
{
static pthread_once_t once = PTHREAD_ONCE_INIT;
struct worker_s *worker;
struct job_descr_s job;
struct job_descr_s *jobp = &job;
char c;
// avfork_taskq_init() , , . N , , , taskq.get_worker() pthread_cond_wait(), .
pthread_once(&once, avfork_taskq_init);
//
memset(&job, 0, sizeof(job));
job.start_routine = start_routine;
job.arg = arg;
worker = avfork_taskq_get_worker(avfork_taskq); // , ;
// . , , pre-vfork() . , vfork(). , .
//
// taskq , , , .
// , , , , ( worker_start_routine()).
if (net_write(worker->dispatch_pipe[1], &jobp, sizeof(jobp)) != sizeof(jobp) ||
net_read(worker->ready_pipe[0], &c, sizeof(c)) != sizeof(c))
job.errno = errno ? errno : EINVAL;
//
(void) close(worker->dispatch_pipe[0]);
(void) close(worker->dispatch_pipe[1]);
(void) close(worker->ready_pipe[0]);
(void) close(worker->ready_pipe[1]);
if (job.errno)
return -1;
return job.pid; // , PID pid
}
, clone(2) - . . clone (2) POSIX, POSIX. , fork()
, , , , avfork()
! avfork()
. NPTL .
Linux - , pthread
Linux. Linux Solaris/SVR4, BSD libsocket STREAMS . API API .
clone()
- , /jail’, : Linux /jail’, clone(2)
, . clone(2)
, ... clone(2)
, .
Linux fork()
, vfork()
, avfork()
, thread_create()
container_create()
. , ( minder/init). , , /// , . clone(2)
, , .
, , «, - /jail’, », . /jail’, Linux /jail’. , . /jail’ , . - , , , clone(2) . , « » ( Linux : , C, , shell’, , - ). .
. . , fork()
, vfork()
, afork()
( ) clone()
( !). , 4.4BSD vfork()
( ). , , , , .
« ».