Created
October 24, 2011 21:12
-
-
Save Ludo6431/1310338 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Fork, handling errors. Returns the pid of the newly made child, or 0. | |
COMMAND is just for remembering the name of the command; we don't do | |
anything else with it. ASYNC_P says what to do with the tty. If | |
non-zero, then don't give it away. */ | |
pid_t | |
make_child (command, async_p) | |
char *command; | |
int async_p; | |
{ | |
int forksleep; | |
sigset_t set, oset; | |
pid_t pid; | |
sigemptyset (&set); | |
sigaddset (&set, SIGCHLD); | |
sigaddset (&set, SIGINT); | |
sigemptyset (&oset); | |
sigprocmask (SIG_BLOCK, &set, &oset); | |
making_children (); | |
forksleep = 1; | |
#if defined (BUFFERED_INPUT) | |
/* If default_buffered_input is active, we are reading a script. If | |
the command is asynchronous, we have already duplicated /dev/null | |
as fd 0, but have not changed the buffered stream corresponding to | |
the old fd 0. We don't want to sync the stream in this case. */ | |
if (default_buffered_input != -1 && | |
(!async_p || default_buffered_input > 0)) | |
sync_buffered_stream (default_buffered_input); | |
#endif /* BUFFERED_INPUT */ | |
/* Create the child, handle severe errors. Retry on EAGAIN. */ | |
while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX) | |
{ | |
/* bash-4.2 */ | |
/* If we can't create any children, try to reap some dead ones. */ | |
waitchld (-1, 0); | |
sys_error ("fork: retry"); | |
if (sleep (forksleep) != 0) | |
break; | |
forksleep <<= 1; | |
} | |
if (pid < 0) | |
{ | |
sys_error ("fork"); | |
/* Kill all of the processes in the current pipeline. */ | |
terminate_current_pipeline (); | |
/* Discard the current pipeline, if any. */ | |
if (the_pipeline) | |
kill_current_pipeline (); | |
last_command_exit_value = EX_NOEXEC; | |
throw_to_top_level (); /* Reset signals, etc. */ | |
} | |
if (pid == 0) | |
{ | |
/* In the child. Give this child the right process group, set the | |
signals to the default state for a new process. */ | |
pid_t mypid; | |
mypid = getpid (); | |
#if defined (BUFFERED_INPUT) | |
/* Close default_buffered_input if it's > 0. We don't close it if it's | |
0 because that's the file descriptor used when redirecting input, | |
and it's wrong to close the file in that case. */ | |
unset_bash_input (0); | |
#endif /* BUFFERED_INPUT */ | |
/* Restore top-level signal mask. */ | |
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); | |
if (job_control) | |
{ | |
/* All processes in this pipeline belong in the same | |
process group. */ | |
if (pipeline_pgrp == 0) /* This is the first child. */ | |
pipeline_pgrp = mypid; | |
/* Check for running command in backquotes. */ | |
if (pipeline_pgrp == shell_pgrp) | |
ignore_tty_job_signals (); | |
else | |
default_tty_job_signals (); | |
/* Set the process group before trying to mess with the terminal's | |
process group. This is mandated by POSIX. */ | |
/* This is in accordance with the Posix 1003.1 standard, | |
section B.7.2.4, which says that trying to set the terminal | |
process group with tcsetpgrp() to an unused pgrp value (like | |
this would have for the first child) is an error. Section | |
B.4.3.3, p. 237 also covers this, in the context of job control | |
shells. */ | |
if (setpgid (mypid, pipeline_pgrp) < 0) | |
sys_error (_("child setpgid (%ld to %ld)"), (long)mypid, (long)pipeline_pgrp); | |
/* By convention (and assumption above), if | |
pipeline_pgrp == shell_pgrp, we are making a child for | |
command substitution. | |
In this case, we don't want to give the terminal to the | |
shell's process group (we could be in the middle of a | |
pipeline, for example). */ | |
if (async_p == 0 && pipeline_pgrp != shell_pgrp && ((subshell_environment&SUBSHELL_ASYNC) == 0)) | |
give_terminal_to (pipeline_pgrp, 0); | |
#if defined (PGRP_PIPE) | |
if (pipeline_pgrp == mypid) | |
pipe_read (pgrp_pipe); | |
#endif | |
} | |
else /* Without job control... */ | |
{ | |
if (pipeline_pgrp == 0) | |
pipeline_pgrp = shell_pgrp; | |
/* If these signals are set to SIG_DFL, we encounter the curious | |
situation of an interactive ^Z to a running process *working* | |
and stopping the process, but being unable to do anything with | |
that process to change its state. On the other hand, if they | |
are set to SIG_IGN, jobs started from scripts do not stop when | |
the shell running the script gets a SIGTSTP and stops. */ | |
default_tty_job_signals (); | |
} | |
#if defined (PGRP_PIPE) | |
/* Release the process group pipe, since our call to setpgid () | |
is done. The last call to sh_closepipe is done in stop_pipeline. */ | |
sh_closepipe (pgrp_pipe); | |
#endif /* PGRP_PIPE */ | |
#if 0 | |
/* Don't set last_asynchronous_pid in the child */ | |
if (async_p) | |
last_asynchronous_pid = mypid; /* XXX */ | |
else | |
#endif | |
#if defined (RECYCLES_PIDS) | |
if (last_asynchronous_pid == mypid) | |
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */ | |
last_asynchronous_pid = 1; | |
#endif | |
} | |
else | |
{ | |
/* In the parent. Remember the pid of the child just created | |
as the proper pgrp if this is the first child. */ | |
if (first_pid == NO_PID) | |
first_pid = pid; | |
else if (pid_wrap == -1 && pid < first_pid) | |
pid_wrap = 0; | |
else if (pid_wrap == 0 && pid >= first_pid) | |
pid_wrap = 1; | |
if (job_control) | |
{ | |
if (pipeline_pgrp == 0) | |
{ | |
pipeline_pgrp = pid; | |
/* Don't twiddle terminal pgrps in the parent! This is the bug, | |
not the good thing of twiddling them in the child! */ | |
/* give_terminal_to (pipeline_pgrp, 0); */ | |
} | |
/* This is done on the recommendation of the Rationale section of | |
the POSIX 1003.1 standard, where it discusses job control and | |
shells. It is done to avoid possible race conditions. (Ref. | |
1003.1 Rationale, section B.4.3.3, page 236). */ | |
setpgid (pid, pipeline_pgrp); | |
} | |
else | |
{ | |
if (pipeline_pgrp == 0) | |
pipeline_pgrp = shell_pgrp; | |
} | |
/* Place all processes into the jobs array regardless of the | |
state of job_control. */ | |
add_process (command, pid); | |
if (async_p) | |
last_asynchronous_pid = pid; | |
#if defined (RECYCLES_PIDS) | |
else if (last_asynchronous_pid == pid) | |
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */ | |
last_asynchronous_pid = 1; | |
#endif | |
if (pid_wrap > 0) | |
delete_old_job (pid); | |
#if !defined (RECYCLES_PIDS) | |
/* Only check for saved status if we've saved more than CHILD_MAX | |
statuses, unless the system recycles pids. */ | |
if ((js.c_reaped + bgpids.npid) >= js.c_childmax) | |
#endif | |
bgp_delete (pid); /* new process, discard any saved status */ | |
last_made_pid = pid; | |
/* keep stats */ | |
js.c_totforked++; | |
js.c_living++; | |
/* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case | |
SIGCHLD remains blocked until all commands in the pipeline have been | |
created. */ | |
sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); | |
} | |
return (pid); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment