📄 jobs.c
字号:
else if (temp == js.j_lastasync) js.j_lastasync = 0; free (temp->wd); ndel = discard_pipeline (temp->pipe); js.c_injobs -= ndel; if (temp->state == JDEAD) { js.c_reaped -= ndel; js.j_ndead--; if (js.c_reaped < 0) {#ifdef DEBUG itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead);#endif js.c_reaped = 0; } } if (temp->deferred) dispose_command (temp->deferred); free (temp); js.j_njobs--; if (js.j_njobs == 0) js.j_firstj = js.j_lastj = 0; else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0) reset_job_indices (); if (job_index == js.j_current || job_index == js.j_previous) reset_current ();}/* Must be called with SIGCHLD blocked. */voidnohup_job (job_index) int job_index;{ register JOB *temp; if (js.j_jobslots == 0) return; if (temp = jobs[job_index]) temp->flags |= J_NOHUP;}/* Get rid of the data structure associated with a process chain. */static intdiscard_pipeline (chain) register PROCESS *chain;{ register PROCESS *this, *next; int n; this = chain; n = 0; do { next = this->next; FREE (this->command); free (this); n++; this = next; } while (this != chain); return n;}/* Add this process to the chain being built in the_pipeline. NAME is the command string that will be exec'ed later. PID is the process id of the child. */static voidadd_process (name, pid) char *name; pid_t pid;{ PROCESS *t, *p;#if defined (RECYCLES_PIDS) int j; p = find_process (pid, 0, &j); if (p) {# ifdef DEBUG if (j == NO_JOB) internal_warning (_("add_process: process %5ld (%s) in the_pipeline"), (long)p->pid, p->command);# endif if (PALIVE (p)) internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command); p->running = PS_RECYCLED; /* mark as recycled */ }#endif t = (PROCESS *)xmalloc (sizeof (PROCESS)); t->next = the_pipeline; t->pid = pid; WSTATUS (t->status) = 0; t->running = PS_RUNNING; t->command = name; the_pipeline = t; if (t->next == 0) t->next = t; else { p = t->next; while (p->next != t->next) p = p->next; p->next = t; }}/* Create a (dummy) PROCESS with NAME, PID, and STATUS, and make it the last process in jobs[JID]->pipe. Used by the lastpipe code. */voidappend_process (name, pid, status, jid) char *name; pid_t pid; int status; int jid;{ PROCESS *t, *p; t = (PROCESS *)xmalloc (sizeof (PROCESS)); t->next = (PROCESS *)NULL; t->pid = pid; /* set process exit status using offset discovered by configure */ t->status = (status & 0xff) << WEXITSTATUS_OFFSET; t->running = PS_DONE; t->command = name; js.c_reaped++; /* XXX */ for (p = jobs[jid]->pipe; p->next != jobs[jid]->pipe; p = p->next) ; p->next = t; t->next = jobs[jid]->pipe;}#if 0/* Take the last job and make it the first job. Must be called with SIGCHLD blocked. */introtate_the_pipeline (){ PROCESS *p; if (the_pipeline->next == the_pipeline) return; for (p = the_pipeline; p->next != the_pipeline; p = p->next) ; the_pipeline = p;}/* Reverse the order of the processes in the_pipeline. Must be called with SIGCHLD blocked. */intreverse_the_pipeline (){ PROCESS *p, *n; if (the_pipeline->next == the_pipeline) return; for (p = the_pipeline; p->next != the_pipeline; p = p->next) ; p->next = (PROCESS *)NULL; n = REVERSE_LIST (the_pipeline, PROCESS *); the_pipeline = n; for (p = the_pipeline; p->next; p = p->next) ; p->next = the_pipeline;}#endif/* Map FUNC over the list of jobs. If FUNC returns non-zero, then it is time to stop mapping, and that is the return value for map_over_jobs. FUNC is called with a JOB, arg1, arg2, and INDEX. */static intmap_over_jobs (func, arg1, arg2) sh_job_map_func_t *func; int arg1, arg2;{ register int i; int result; sigset_t set, oset; if (js.j_jobslots == 0) return 0; BLOCK_CHILD (set, oset); /* XXX could use js.j_firstj here */ for (i = result = 0; i < js.j_jobslots; i++) {#if defined (DEBUG) if (i < js.j_firstj && jobs[i]) itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); if (i > js.j_lastj && jobs[i]) itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);#endif if (jobs[i]) { result = (*func)(jobs[i], arg1, arg2, i); if (result) break; } } UNBLOCK_CHILD (oset); return (result);}/* Cause all the jobs in the current pipeline to exit. */voidterminate_current_pipeline (){ if (pipeline_pgrp && pipeline_pgrp != shell_pgrp) { killpg (pipeline_pgrp, SIGTERM); killpg (pipeline_pgrp, SIGCONT); }}/* Cause all stopped jobs to exit. */voidterminate_stopped_jobs (){ register int i; /* XXX could use js.j_firstj here */ for (i = 0; i < js.j_jobslots; i++) { if (jobs[i] && STOPPED (i)) { killpg (jobs[i]->pgrp, SIGTERM); killpg (jobs[i]->pgrp, SIGCONT); } }}/* Cause all jobs, running or stopped, to receive a hangup signal. If a job is marked J_NOHUP, don't send the SIGHUP. */voidhangup_all_jobs (){ register int i; /* XXX could use js.j_firstj here */ for (i = 0; i < js.j_jobslots; i++) { if (jobs[i]) { if (jobs[i]->flags & J_NOHUP) continue; killpg (jobs[i]->pgrp, SIGHUP); if (STOPPED (i)) killpg (jobs[i]->pgrp, SIGCONT); } }}voidkill_current_pipeline (){ stop_making_children (); start_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. If JOBP is non-null, return the index of the job containing PID. */static PROCESS *find_pipeline (pid, alive_only, jobp) pid_t pid; int alive_only; int *jobp; /* index into jobs list or NO_JOB */{ int job; PROCESS *p; /* See if this process is in the pipeline that we are building. */ if (jobp) *jobp = NO_JOB; if (the_pipeline) { p = the_pipeline; do { /* Return it if we found it. Don't ever return a recycled pid. */ if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p))) return (p); p = p->next; } while (p != the_pipeline); } job = find_job (pid, alive_only, &p); if (jobp) *jobp = job; return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe;}/* Return the PROCESS * describing PID. If JOBP is non-null return the index into the jobs array of the job containing PID. Must be called with SIGCHLD blocked. */static PROCESS *find_process (pid, alive_only, jobp) pid_t pid; int alive_only; int *jobp; /* index into jobs list or NO_JOB */{ PROCESS *p; p = find_pipeline (pid, alive_only, jobp); while (p && p->pid != pid) p = p->next; return 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 intfind_job (pid, alive_only, procp) pid_t pid; int alive_only; PROCESS **procp;{ register int i; PROCESS *p; /* XXX could use js.j_firstj here, and should check js.j_lastj */ for (i = 0; i < js.j_jobslots; i++) {#if defined (DEBUG) if (i < js.j_firstj && jobs[i]) itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); if (i > js.j_lastj && jobs[i]) itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);#endif if (jobs[i]) { p = jobs[i]->pipe; do { if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p))) { if (procp) *procp = p; return (i); } p = p->next; } while (p != jobs[i]->pipe); } } return (NO_JOB);}/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as required by find_job. */intget_job_by_pid (pid, block) pid_t pid; int block;{ int job; sigset_t set, oset; if (block) BLOCK_CHILD (set, oset); job = find_job (pid, 0, NULL); if (block) UNBLOCK_CHILD (oset); return job;}/* Print descriptive information about the job with leader pid PID. */voiddescribe_pid (pid) pid_t pid;{ int job; sigset_t set, oset; BLOCK_CHILD (set, oset); job = find_job (pid, 0, NULL); if (job != NO_JOB) fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid); else programming_error (_("describe_pid: %ld: no such pid"), (long)pid); UNBLOCK_CHILD (oset);}static char *j_strsignal (s) int s;{ char *x; x = strsignal (s); if (x == 0) { x = retcode_name_buffer; sprintf (x, _("Signal %d"), s); } return x;}static char *printable_job_status (j, p, format) int j; PROCESS *p; int format;{ static char *temp; int es; temp = _("Done"); if (STOPPED (j) && format == 0) { if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0)) temp = _("Stopped"); else { temp = retcode_name_buffer; sprintf (temp, _("Stopped(%s)"), signal_name (WSTOPSIG (p->status))); } } else if (RUNNING (j)) temp = _("Running"); else { if (WIFSTOPPED (p->status)) temp = j_strsignal (WSTOPSIG (p->status)); else if (WIFSIGNALED (p->status)) temp = j_strsignal (WTERMSIG (p->status)); else if (WIFEXITED (p->status)) { temp = retcode_name_buffer; es = WEXITSTATUS (p->status); if (es == 0) strcpy (temp, _("Done")); else if (posixly_correct) sprintf (temp, _("Done(%d)"), es); else sprintf (temp, _("Exit %d"), es); } else temp = _("Unknown status"); } return temp;}/* This is the way to print out information on a job if you know the index. FORMAT is: JLIST_NORMAL) [1]+ Running emacs JLIST_LONG ) [1]+ 2378 Running emacs -1 ) [1]+ 2378 emacs JLIST_NORMAL) [1]+ Stopped ls | more JLIST_LONG ) [1]+ 2369 Stopped ls 2367 | more JLIST_PID_ONLY) Just list the pid of the process group leader (really the process group). JLIST_CHANGED_ONLY) Use format JLIST_NORMAL, but list only jobs about which the user has not been notified. *//* Print status for pipeline P. If JOB_INDEX is >= 0, it is the index into the JOBS array corresponding to this pipeline. FORMAT is as described above. Must be called with SIGCHLD blocked. If you're printing a pipeline that's not in the jobs array, like the current pipeline as it's being created, pass -1 for JOB_INDEX */static voidprint_pipeline (p, job_index, format, stream) PROCESS *p; int job_index, format; FILE *stream;{ PROCESS *first, *last, *show; int es, name_padding; char *temp; if (p == 0) return; first = last = p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -