?? jobs.c
字號:
for (i = js.j_jobslots; i; i--) if (jobs[i - 1]) break; } else {#if 0 /* This wraps around, but makes it inconvenient to extend the array */ for (i = js.j_lastj+1; i != js.j_lastj; i++) { if (i >= js.j_jobslots) i = 0; if (jobs[i] == 0) break; } if (i == js.j_lastj) i = js.j_jobslots;#else /* This doesn't wrap around yet. */ for (i = js.j_lastj ? js.j_lastj + 1 : js.j_lastj; i < js.j_jobslots; i++) if (jobs[i] == 0) break;#endif } /* Do we need more room? */ /* First try compaction */ if ((interactive_shell == 0 || subshell_environment) && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY) i = compact_jobs_list (0); /* If we can't compact, reallocate */ if (i == js.j_jobslots) { js.j_jobslots += JOB_SLOTS; jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *))); for (j = i; j < js.j_jobslots; j++) jobs[j] = (JOB *)NULL; } /* Add the current pipeline to the job list. */ if (the_pipeline) { register PROCESS *p; int any_running, any_stopped, n; newjob = (JOB *)xmalloc (sizeof (JOB)); for (n = 1, p = the_pipeline; p->next != the_pipeline; n++, p = p->next) ; p->next = (PROCESS *)NULL; newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *); for (p = newjob->pipe; p->next; p = p->next) ; p->next = newjob->pipe; the_pipeline = (PROCESS *)NULL; newjob->pgrp = pipeline_pgrp; pipeline_pgrp = 0; newjob->flags = 0; /* Flag to see if in another pgrp. */ if (job_control) newjob->flags |= J_JOBCONTROL; /* Set the state of this pipeline. */ p = newjob->pipe; any_running = any_stopped = 0; do { any_running |= PRUNNING (p); any_stopped |= PSTOPPED (p); p = p->next; } while (p != newjob->pipe); newjob->state = any_running ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); newjob->wd = job_working_directory (); newjob->deferred = deferred; newjob->j_cleanup = (sh_vptrfunc_t *)NULL; newjob->cleanarg = (PTR_T) NULL; jobs[i] = newjob; if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) setjstatus (i); if (newjob->state == JDEAD) { js.c_reaped += n; /* wouldn't have been done since this was not part of a job */ js.j_ndead++; } js.c_injobs += n; js.j_lastj = i; js.j_njobs++; } else newjob = (JOB *)NULL; if (newjob) js.j_lastmade = newjob; if (async) { if (newjob) { newjob->flags &= ~J_FOREGROUND; newjob->flags |= J_ASYNC; js.j_lastasync = newjob; } reset_current (); } else { if (newjob) { newjob->flags |= J_FOREGROUND; /* * !!!!! NOTE !!!!! (chet@ins.cwru.edu) * * The currently-accepted job control wisdom says to set the * terminal's process group n+1 times in an n-step pipeline: * once in the parent and once in each child. This is where * the parent gives it away. * * Don't give the terminal away if this shell is an asynchronous * subshell. * */ if (job_control && newjob->pgrp && (subshell_environment&SUBSHELL_ASYNC) == 0) maybe_give_terminal_to (shell_pgrp, newjob->pgrp, 0); } } stop_making_children (); UNBLOCK_CHILD (oset); return (newjob ? i : js.j_current);}/* Functions to manage the list of exited background pids whose status has been saved. */static struct pidstat *bgp_alloc (pid, status) pid_t pid; int status;{ struct pidstat *ps; ps = (struct pidstat *)xmalloc (sizeof (struct pidstat)); ps->pid = pid; ps->status = status; ps->next = (struct pidstat *)0; return ps;}static struct pidstat *bgp_add (pid, status) pid_t pid; int status;{ struct pidstat *ps; ps = bgp_alloc (pid, status); if (bgpids.list == 0) { bgpids.list = bgpids.end = ps; bgpids.npid = 0; /* just to make sure */ } else { bgpids.end->next = ps; bgpids.end = ps; } bgpids.npid++; if (bgpids.npid > js.c_childmax) bgp_prune (); return ps;}static intbgp_delete (pid) pid_t pid;{ struct pidstat *prev, *p; for (prev = p = bgpids.list; p; prev = p, p = p->next) if (p->pid == pid) { prev->next = p->next; /* remove from list */ break; } if (p == 0) return 0; /* not found */#if defined (DEBUG) itrace("bgp_delete: deleting %d", pid);#endif /* Housekeeping in the border cases. */ if (p == bgpids.list) bgpids.list = bgpids.list->next; else if (p == bgpids.end) bgpids.end = prev; bgpids.npid--; if (bgpids.npid == 0) bgpids.list = bgpids.end = 0; else if (bgpids.npid == 1) bgpids.end = bgpids.list; /* just to make sure */ free (p); return 1;}/* Clear out the list of saved statuses */static voidbgp_clear (){ struct pidstat *ps, *p; for (ps = bgpids.list; ps; ) { p = ps; ps = ps->next; free (p); } bgpids.list = bgpids.end = 0; bgpids.npid = 0;}/* Search for PID in the list of saved background pids; return its status if found. If not found, return -1. */static intbgp_search (pid) pid_t pid;{ struct pidstat *ps; for (ps = bgpids.list ; ps; ps = ps->next) if (ps->pid == pid) return ps->status; return -1;}static voidbgp_prune (){ struct pidstat *ps; while (bgpids.npid > js.c_childmax) { ps = bgpids.list; bgpids.list = bgpids.list->next; free (ps); bgpids.npid--; }}/* Reset the values of js.j_lastj and js.j_firstj after one or both have been deleted. The caller should check whether js.j_njobs is 0 before calling this. This wraps around, but the rest of the code does not. At this point, it should not matter. */static voidreset_job_indices (){ int old; if (jobs[js.j_firstj] == 0) { old = js.j_firstj++; if (old >= js.j_jobslots) old = js.j_jobslots - 1; while (js.j_firstj != old) { if (js.j_firstj >= js.j_jobslots) js.j_firstj = 0; if (jobs[js.j_firstj] || js.j_firstj == old) /* needed if old == 0 */ break; js.j_firstj++; } if (js.j_firstj == old) js.j_firstj = js.j_lastj = js.j_njobs = 0; } if (jobs[js.j_lastj] == 0) { old = js.j_lastj--; if (old < 0) old = 0; while (js.j_lastj != old) { if (js.j_lastj < 0) js.j_lastj = js.j_jobslots - 1; if (jobs[js.j_lastj] || js.j_lastj == old) /* needed if old == js.j_jobslots */ break; js.j_lastj--; } if (js.j_lastj == old) js.j_firstj = js.j_lastj = js.j_njobs = 0; }} /* Delete all DEAD jobs that the user had received notification about. */static voidcleanup_dead_jobs (){ register int i; int os; if (js.j_jobslots == 0 || jobs_list_frozen) return; QUEUE_SIGCHLD(os); /* XXX could use js.j_firstj and js.j_lastj here */ for (i = 0; i < js.j_jobslots; i++) {#if defined (DEBUG) if (i < js.j_firstj && jobs[i]) itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj); if (i > js.j_lastj && jobs[i]) itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);#endif if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i)) delete_job (i, 0); }#if defined (COPROCESS_SUPPORT) coproc_reap ();#endif UNQUEUE_SIGCHLD(os);}static intprocesses_in_job (job) int job;{ int nproc; register PROCESS *p; nproc = 0; p = jobs[job]->pipe; do { p = p->next; nproc++; } while (p != jobs[job]->pipe); return nproc;}static voiddelete_old_job (pid) pid_t pid;{ PROCESS *p; int job; job = find_job (pid, 0, &p); if (job != NO_JOB) {#ifdef DEBUG itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state);#endif if (JOBSTATE (job) == JDEAD) delete_job (job, DEL_NOBGPID); else { internal_warning (_("forked pid %d appears in running job %d"), pid, job); if (p) p->pid = 0; } }}/* Reallocate and compress the jobs list. This returns with a jobs array whose size is a multiple of JOB_SLOTS and can hold the current number of jobs. Heuristics are used to minimize the number of new reallocs. */static voidrealloc_jobs_list (){ sigset_t set, oset; int nsize, i, j, ncur, nprev; JOB **nlist; ncur = nprev = NO_JOB; nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS); nsize *= JOB_SLOTS; i = js.j_njobs % JOB_SLOTS; if (i == 0 || i > (JOB_SLOTS >> 1)) nsize += JOB_SLOTS; BLOCK_CHILD (set, oset); nlist = (js.j_jobslots == nsize) ? jobs : (JOB **) xmalloc (nsize * sizeof (JOB *)); js.c_reaped = js.j_ndead = 0; for (i = j = 0; i < js.j_jobslots; i++) if (jobs[i]) { if (i == js.j_current) ncur = j; if (i == js.j_previous) nprev = j; nlist[j++] = jobs[i]; if (jobs[i]->state == JDEAD) { js.j_ndead++; js.c_reaped += processes_in_job (i); } }#if defined (DEBUG) itrace ("realloc_jobs_list: resize jobs list from %d to %d", js.j_jobslots, nsize); itrace ("realloc_jobs_list: j_lastj changed from %d to %d", js.j_lastj, (j > 0) ? j - 1 : 0); itrace ("realloc_jobs_list: j_njobs changed from %d to %d", js.j_njobs, j); itrace ("realloc_jobs_list: js.j_ndead %d js.c_reaped %d", js.j_ndead, js.c_reaped);#endif js.j_firstj = 0; js.j_lastj = (j > 0) ? j - 1 : 0; js.j_njobs = j; js.j_jobslots = nsize; /* Zero out remaining slots in new jobs list */ for ( ; j < nsize; j++) nlist[j] = (JOB *)NULL; if (jobs != nlist) { free (jobs); jobs = nlist; } if (ncur != NO_JOB) js.j_current = ncur; if (nprev != NO_JOB) js.j_previous = nprev; /* Need to reset these */ if (js.j_current == NO_JOB || js.j_previous == NO_JOB || js.j_current > js.j_lastj || js.j_previous > js.j_lastj) reset_current ();#ifdef DEBUG itrace ("realloc_jobs_list: reset js.j_current (%d) and js.j_previous (%d)", js.j_current, js.j_previous);#endif UNBLOCK_CHILD (oset);}/* Compact the jobs list by removing dead jobs. Assumed that we have filled the jobs array to some predefined maximum. Called when the shell is not the foreground process (subshell_environment != 0). Returns the first available slot in the compacted list. If that value is js.j_jobslots, then the list needs to be reallocated. The jobs array may be in new memory if this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */static intcompact_jobs_list (flags) int flags;{ if (js.j_jobslots == 0 || jobs_list_frozen) return js.j_jobslots; reap_dead_jobs (); realloc_jobs_list ();#ifdef DEBUG itrace("compact_jobs_list: returning %d", (js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0);#endif return ((js.j_lastj || jobs[js.j_lastj]) ? js.j_lastj + 1 : 0);}/* Delete the job at INDEX from the job list. Must be called with SIGCHLD blocked. */voiddelete_job (job_index, dflags) int job_index, dflags;{ register JOB *temp; PROCESS *proc; int ndel; if (js.j_jobslots == 0 || jobs_list_frozen) return; if ((dflags & DEL_WARNSTOPPED) && subshell_environment == 0 && STOPPED (job_index)) internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp); temp = jobs[job_index]; if (temp == 0) return; if ((dflags & DEL_NOBGPID) == 0) { proc = find_last_proc (job_index, 0); /* Could do this just for J_ASYNC jobs, but we save all. */ if (proc) bgp_add (proc->pid, process_exit_status (proc->status)); } jobs[job_index] = (JOB *)NULL; if (temp == js.j_lastmade) js.j_lastmade = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -