Mail Archives: cygwin/2004/10/24/22:11:43
--=====================_1098684400==_
Content-Type: text/plain; charset="us-ascii"
Attached is a "simpler & better" patch to bash, replacing
the one in
<http://cygwin.com/ml/cygwin/2004-09/msg00882.html>
It's simpler because it slightly changes how bash works to
prevent the pid reuse problem, instead of adding a layer to
fix it. It's better because it also fixes the bug reported
in <http://cygwin.com/ml/cygwin/2004-09/msg01503.html>
and some other potential issues.
To build bash, follow the following steps:
Download the bash source package, using setup, and put
the attached pids3.diff file under /usr/src/bash-2.05b
$ cd /usr/src
$ ./bash-2.05b-16.sh prep
$ cd bash-2.05b
$ patch < pids3.diff
$ cd ..
$ ./bash-2.05b-16.sh conf
$ ./bash-2.05b-16.sh build
This produces /usr/src/bash-2.05b/.build/bash.exe,
which you can copy to /bin, preferably after having saved
the original bash.
Pierre
Note: This patch does not modify configure. If you have
applied the previous patch, make sure to run prep again.
--=====================_1098684400==_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="pids3.diff"
--- execute_cmd.c.orig 2002-03-18 13:24:22.000000000 -0500
+++ execute_cmd.c 2004-10-23 21:45:10.000000000 -0400
@@ -619,6 +619,9 @@ execute_command_internal (command, async
/* We can't rely on this variable retaining its value across a
call to execute_simple_command if a longjmp occurs as the
result of a `return' builtin. This is true for sure with gcc. */
+#if defined (RECYCLES_PIDS)
+ last_made_pid =3D NO_PID;
+#endif
last_pid =3D last_made_pid;
was_error_trap =3D signal_is_trapped (ERROR_TRAP) && signal_is_ignored (E=
RROR_TRAP) =3D=3D 0;
@@ -664,13 +667,6 @@ execute_command_internal (command, async
commands, this causes the last simple command in
the function to be waited for twice. */
exec_result =3D wait_for (last_made_pid);
-#if defined (RECYCLES_PIDS)
- /* LynxOS, for one, recycles pids very quickly -- so quickly
- that a new process may have the same pid as the last one
- created. This has been reported to fix the problem. */
- if (exec_result =3D=3D 0)
- last_made_pid =3D NO_PID;
-#endif
}
}
@@ -2485,6 +2481,9 @@ execute_simple_command (simple_command,
first_word_quoted =3D
simple_command->words ? (simple_command->words->word->flags & W_QUOTED=
): 0;
+#if defined (RECYCLES_PIDS)
+ last_command_subst_pid =3D NO_PID;
+#endif
old_last_command_subst_pid =3D last_command_subst_pid;
old_last_async_pid =3D last_asynchronous_pid;
@@ -2518,9 +2517,11 @@ execute_simple_command (simple_command,
already_forked =3D 1;
simple_command->flags |=3D CMD_NO_FORK;
- subshell_environment =3D (pipe_in !=3D NO_PIPE || pipe_out !=3D NO_PIPE)
- ? (SUBSHELL_PIPE|SUBSHELL_FORK)
- : (SUBSHELL_ASYNC|SUBSHELL_FORK);
+ subshell_environment =3D SUBSHELL_FORK;
+ if (async)
+ subshell_environment |=3D SUBSHELL_ASYNC;
+ if (pipe_in !=3D NO_PIPE || pipe_out !=3D NO_PIPE)
+ subshell_environment |=3D SUBSHELL_PIPE;
/* We need to do this before piping to handle some really
pathological cases where one of the pipe file descriptors
--- jobs.c.orig 2004-09-22 22:52:44.000000000 -0400
+++ jobs.c 2004-10-23 22:05:02.000000000 -0400
@@ -232,7 +232,7 @@ static int map_over_jobs __P((sh_job_map
static int job_last_stopped __P((int));
static int job_last_running __P((int));
static int most_recent_job_in_state __P((int, JOB_STATE));
-static int find_job __P((pid_t, int));
+static int find_job __P((pid_t, int, PROCESS **));
static int print_job __P((JOB *, int, int, int));
static int process_exit_status __P((WAIT));
static int job_exit_status __P((int));
@@ -504,7 +504,7 @@ stop_pipeline (async, deferred)
if (the_pipeline)
{
register PROCESS *p;
- int any_alive, any_stopped;
+ int any_running, any_stopped;
newjob =3D (JOB *)xmalloc (sizeof (JOB));
@@ -528,16 +528,16 @@ stop_pipeline (async, deferred)
/* Set the state of this pipeline. */
p =3D newjob->pipe;
- any_alive =3D any_stopped =3D 0;
+ any_running =3D any_stopped =3D 0;
do
{
- any_alive |=3D p->running;
- any_stopped |=3D WIFSTOPPED (p->status);
+ any_running |=3D PRUNNING (p);
+ any_stopped |=3D PSTOPPED (p);
p =3D p->next;
}
while (p !=3D newjob->pipe);
- newjob->state =3D any_alive ? JRUNNING : (any_stopped ? JSTOPPED : J=
DEAD);
+ newjob->state =3D any_running ? JRUNNING : (any_stopped ? JSTOPPED :=
JDEAD);
newjob->wd =3D job_working_directory ();
newjob->deferred =3D deferred;
@@ -739,6 +739,28 @@ add_process (name, pid)
{
PROCESS *t, *p;
+#if defined (RECYCLES_PIDS)
+ int job;
+ p =3D find_pipeline (pid, 0, &job);
+ if (p)
+ {
+ /* As I understand it, job should never be "NO_JOB" because processes
+ in the current pipeline have not been reaped.
+ If that's true (the printf below never kicks in), replace the above by
+ job =3D find_job (pid, 0, &p)
+ if (job !=3D NO_JOB)
+ and remove the test and printf below.
+ */
+ if (job =3D=3D NO_JOB)
+ fprintf(stderr, "add_process: process pid %5ld (%s) in the_pipeline",
+ (long) p->pid, p->command);
+ if (PALIVE (p))
+ internal_error ("add_process: pid %5ld (%s) is still alive",
+ (long) p->pid, p->command);
+ p->running =3D PS_RECYCLED;
+ }
+#endif
+
t =3D (PROCESS *)xmalloc (sizeof (PROCESS));
t->next =3D the_pipeline;
t->pid =3D pid;
@@ -885,13 +907,13 @@ kill_current_pipeline ()
/* Return the pipeline that PID belongs to. Note that the pipeline
doesn't have to belong to a job. Must be called with SIGCHLD blocked. =
*/
static PROCESS *
-find_pipeline (pid, running_only, jobp)
+find_pipeline (pid, alive_only, jobp)
pid_t pid;
- int running_only;
+ int alive_only;
int *jobp; /* index into jobs list or NO_JOB */
{
int job;
- register PROCESS *p;
+ PROCESS *p;
/* See if this process is in the pipeline that we are building. */
if (jobp)
@@ -902,32 +924,31 @@ find_pipeline (pid, running_only, jobp)
do
{
/* Return it if we found it. */
- if (p->pid =3D=3D pid)
- {
- if ((running_only && PRUNNING(p)) || (running_only =3D=3D 0))
- return (p);
- }
+ if (p->pid =3D=3D pid
+ && (PALIVE (p) || ((alive_only =3D=3D 0) && !PRECYCLED (p))))
+ return (p);
p =3D p->next;
}
while (p !=3D the_pipeline);
}
- job =3D find_job (pid, running_only);
+ job =3D find_job (pid, alive_only, &p);
if (jobp)
*jobp =3D job;
- return (job =3D=3D NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe;
+ return (job =3D=3D NO_JOB) ? (PROCESS *)NULL : p;
}
/* Return the job index that PID belongs to, or NO_JOB if it doesn't
belong to any job. Must be called with SIGCHLD blocked. */
static int
-find_job (pid, running_only)
+find_job (pid, alive_only, pp)
pid_t pid;
- int running_only;
+ int alive_only;
+ PROCESS ** pp;
{
register int i;
- register PROCESS *p;
+ PROCESS *p;
for (i =3D 0; i < job_slots; i++)
{
@@ -937,10 +958,12 @@ find_job (pid, running_only)
do
{
- if (p->pid =3D=3D pid)
+ if (p->pid =3D=3D pid
+ && (PALIVE (p) || ((alive_only =3D=3D 0) && !PRECYCLED (p))))
{
- if ((running_only && PRUNNING(p)) || (running_only =3D=3D 0))
- return (i);
+ if (pp)
+ *pp =3D p;
+ return (i);
}
p =3D p->next;
@@ -965,7 +988,7 @@ get_job_by_pid (pid, block)
if (block)
BLOCK_CHILD (set, oset);
- job =3D find_job (pid, 0);
+ job =3D find_job (pid, 0, NULL);
if (block)
UNBLOCK_CHILD (oset);
@@ -983,7 +1006,7 @@ describe_pid (pid)
BLOCK_CHILD (set, oset);
- job =3D find_job (pid, 0);
+ job =3D find_job (pid, 0, NULL);
if (job !=3D NO_JOB)
printf ("[%d] %ld\n", job + 1, (long)pid);
@@ -1099,7 +1122,7 @@ print_pipeline (p, job_index, format, st
{
if (format)
{
- if (show->running =3D=3D first->running &&
+ if (PRUNNING (show) =3D=3D PRUNNING (first) &&
WSTATUS (show->status) =3D=3D WSTATUS (first->status))
temp =3D "";
}
@@ -1374,6 +1397,13 @@ make_child (command, async_p)
if (async_p)
last_asynchronous_pid =3D getpid ();
+#if defined (RECYCLES_PIDS)
+ /* Avoid aliasing by setting the pid to an unusual value.
+ Setting to NO_PID might cause an error when evaluating $!
+ Using 1 seems safe as that process cannot be killed accidentally =
*/
+ else if (last_asynchronous_pid =3D=3D getpid ())
+ last_asynchronous_pid =3D 1;
+#endif
}
else
{
@@ -1407,7 +1437,11 @@ make_child (command, async_p)
if (async_p)
last_asynchronous_pid =3D pid;
-
+#if defined (RECYCLES_PIDS)
+ /* See comment in child code */
+ else if (last_asynchronous_pid =3D=3D pid)
+ last_asynchronous_pid =3D 1;
+#endif
last_made_pid =3D pid;
/* Unblock SIGINT and SIGCHLD. */
@@ -1616,7 +1650,7 @@ wait_for_single_pid (pid)
/* POSIX.2: if we just waited for a job, we can remove it from the jobs
table. */
BLOCK_CHILD (set, oset);
- job =3D find_job (pid, 0);
+ job =3D find_job (pid, 0, NULL);
if (job !=3D NO_JOB && jobs[job] && DEADJOB (job))
jobs[job]->flags |=3D J_NOTIFIED;
UNBLOCK_CHILD (oset);
@@ -1821,13 +1855,13 @@ wait_for (pid)
We check for JDEAD in case the job state has been set by waitchld
after receipt of a SIGCHLD. */
if (job =3D=3D NO_JOB)
- job =3D find_job (pid, 0);
+ job =3D find_job (pid, 0, NULL);
/* waitchld() takes care of setting the state of the job. If the job
has already exited before this is called, sigchld_handler will have
called waitchld and the state will be set to JDEAD. */
- if (child->running || (job !=3D NO_JOB && RUNNING (job)))
+ if (PRUNNING (child) || (job !=3D NO_JOB && RUNNING (job)))
{
#if defined (WAITPID_BROKEN) /* SCOv4 */
sigset_t suspend_set;
@@ -1881,7 +1915,7 @@ wait_for (pid)
if (interactive && job_control =3D=3D 0)
QUIT;
}
- while (child->running || (job !=3D NO_JOB && RUNNING (job)));
+ while (PRUNNING (child) || (job !=3D NO_JOB && RUNNING (job)));
/* The exit state of the command is either the termination state of the
child, or the termination state of the job. If a job, the status
@@ -2356,6 +2390,10 @@ kill_pid (pid, sig, group)
do
{
+#if defined (RECYCLES_PIDS)
+ if (!PALIVE (p)) /* The pid may have been recycled */
+ continue;
+#endif
kill (p->pid, sig);
if (p->running =3D=3D PS_DONE && (sig =3D=3D SIGTERM || sig =3D=3D SIG=
HUP))
kill (p->pid, SIGCONT);
@@ -2473,9 +2511,6 @@ waitchld (wpid, block)
if (child =3D=3D 0)
continue;
- while (child->pid !=3D pid)
- child =3D child->next;
-
/* Remember status, and whether or not the process is running. */
child->status =3D status;
child->running =3D WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
@@ -2544,8 +2579,8 @@ set_job_status_and_cleanup (job)
job_state =3D any_stopped =3D any_tstped =3D 0;
do
{
- job_state |=3D child->running;
- if (child->running =3D=3D PS_DONE && (WIFSTOPPED (child->status)))
+ job_state |=3D PRUNNING (child);
+ if (PSTOPPED (child))
{
any_stopped =3D 1;
any_tstped |=3D interactive && job_control &&
--- jobs.h.orig 2002-01-17 12:35:12.000000000 -0500
+++ jobs.h 2004-10-23 21:40:00.000000000 -0400
@@ -45,7 +45,7 @@
/* Values for the `running' field of a struct process. */
#define PS_DONE 0
#define PS_RUNNING 1
-#define PS_STOPPED 2
+#define PS_RECYCLED 2
/* Each child of the shell is remembered in a STRUCT PROCESS. A chain of
such structures is a pipeline. The chain is circular. */
@@ -57,10 +57,14 @@ typedef struct process {
char *command; /* The particular program that is running. */
} PROCESS;
-/* PRUNNING really means `not exited' */
-#define PRUNNING(p) ((p)->running || WIFSTOPPED((p)->status))
+#define PRUNNING(p) ((p)->running =3D=3D PS_RUNNING)
+#define PALIVE(p) ((p)->running =3D=3D PS_RUNNING || WIFSTOPPED((p)->statu=
s))
#define PSTOPPED(p) (WIFSTOPPED((p)->status))
-#define PDEADPROC(p) ((p)->running =3D=3D PS_DONE)
+#if defined (RECYCLES_PIDS)
+# define PRECYCLED(p) ((p)->running =3D=3D PS_RECYCLED)
+#else
+# define PRECYCLED(p) 0
+#endif
/* A description of a pipeline's state. */
typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
--- subst.c.orig 2004-09-17 21:03:52.000000000 -0400
+++ subst.c 2004-10-23 21:48:06.000000000 -0400
@@ -3773,7 +3773,7 @@ command_substitute (string, quoted)
cleanup_the_pipeline ();
#endif
- pid =3D make_child ((char *)NULL, 0);
+ pid =3D make_child ((char *)NULL, subshell_environment & SUBSHELL_ASYNC);
if (pid =3D=3D 0)
/* Reset the signal handlers in the child, but don't free the
trap strings. */
--=====================_1098684400==_
Content-Type: text/plain; charset=us-ascii
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Problem reports: http://cygwin.com/problems.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
--=====================_1098684400==_--
- Raw text -