📄 forkexit.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/mm/forkexit.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16800 /* This file deals with creating processes (via FORK) and deleting them (via
16801 * EXIT/WAIT). When a process forks, a new slot in the 'mproc' table is
16802 * allocated for it, and a copy of the parent's core image is made for the
16803 * child. Then the kernel and file system are informed. A process is removed
16804 * from the 'mproc' table when two events have occurred: (1) it has exited or
16805 * been killed by a signal, and (2) the parent has done a WAIT. If the process
16806 * exits first, it continues to occupy a slot until the parent does a WAIT.
16807 *
16808 * The entry points into this file are:
16809 * do_fork: perform the FORK system call
16810 * do_mm_exit: perform the EXIT system call (by calling mm_exit())
16811 * mm_exit: actually do the exiting
16812 * do_wait: perform the WAITPID or WAIT system call
16813 */
16814
16815
16816 #include "mm.h"
16817 #include <sys/wait.h>
16818 #include <minix/callnr.h>
16819 #include <signal.h>
16820 #include "mproc.h"
16821 #include "param.h"
16822
16823 #define LAST_FEW 2 /* last few slots reserved for superuser */
16824
16825 PRIVATE pid_t next_pid = INIT_PID+1; /* next pid to be assigned */
16826
16827 FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
16828
16829 /*===========================================================================*
16830 * do_fork *
16831 *===========================================================================*/
16832 PUBLIC int do_fork()
16833 {
16834 /* The process pointed to by 'mp' has forked. Create a child process. */
16835
16836 register struct mproc *rmp; /* pointer to parent */
16837 register struct mproc *rmc; /* pointer to child */
16838 int i, child_nr, t;
16839 phys_clicks prog_clicks, child_base = 0;
16840 phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
16841
16842 /* If tables might fill up during FORK, don't even start since recovery half
16843 * way through is such a nuisance.
16844 */
16845 rmp = mp;
16846 if (procs_in_use == NR_PROCS) return(EAGAIN);
16847 if (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0)return(EAGAIN);
16848
16849 /* Determine how much memory to allocate. Only the data and stack need to
16850 * be copied, because the text segment is either shared or of zero length.
16851 */
16852 prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
16853 prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
16854 prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
16855 if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(EAGAIN);
16856
16857 /* Create a copy of the parent's core image for the child. */
16858 child_abs = (phys_bytes) child_base << CLICK_SHIFT;
16859 parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
16860 i = sys_copy(ABS, 0, parent_abs, ABS, 0, child_abs, prog_bytes);
16861 if (i < 0) panic("do_fork can't copy", i);
16862
16863 /* Find a slot in 'mproc' for the child process. A slot must exist. */
16864 for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
16865 if ( (rmc->mp_flags & IN_USE) == 0) break;
16866
16867 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
16868 child_nr = (int)(rmc - mproc); /* slot number of the child */
16869 procs_in_use++;
16870 *rmc = *rmp; /* copy parent's process slot to child's */
16871
16872 rmc->mp_parent = who; /* record child's parent */
16873 rmc->mp_flags &= ~TRACED; /* child does not inherit trace status */
16874 /* A separate I&D child keeps the parents text segment. The data and stack
16875 * segments must refer to the new copy.
16876 */
16877 if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;
16878 rmc->mp_seg[D].mem_phys = child_base;
16879 rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys +
16880 (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
16881 rmc->mp_exitstatus = 0;
16882 rmc->mp_sigstatus = 0;
16883
16884 /* Find a free pid for the child and put it in the table. */
16885 do {
16886 t = 0; /* 't' = 0 means pid still free */
16887 next_pid = (next_pid < 30000 ? next_pid + 1 : INIT_PID + 1);
16888 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
16889 if (rmp->mp_pid == next_pid || rmp->mp_procgrp == next_pid) {
16890 t = 1;
16891 break;
16892 }
16893 rmc->mp_pid = next_pid; /* assign pid to child */
16894 } while (t);
16895
16896 /* Tell kernel and file system about the (now successful) FORK. */
16897 sys_fork(who, child_nr, rmc->mp_pid, child_base); /* child_base is 68K only*/
16898 tell_fs(FORK, who, child_nr, rmc->mp_pid);
16899
16900 /* Report child's memory map to kernel. */
16901 sys_newmap(child_nr, rmc->mp_seg);
16902
16903 /* Reply to child to wake it up. */
16904 reply(child_nr, 0, 0, NIL_PTR);
16905 return(next_pid); /* child's pid */
16906 }
16909 /*===========================================================================*
16910 * do_mm_exit *
16911 *===========================================================================*/
16912 PUBLIC int do_mm_exit()
16913 {
16914 /* Perform the exit(status) system call. The real work is done by mm_exit(),
16915 * which is also called when a process is killed by a signal.
16916 */
16917
16918 mm_exit(mp, status);
16919 dont_reply = TRUE; /* don't reply to newly terminated process */
16920 return(OK); /* pro forma return code */
16921 }
16924 /*===========================================================================*
16925 * mm_exit *
16926 *===========================================================================*/
16927 PUBLIC void mm_exit(rmp, exit_status)
16928 register struct mproc *rmp; /* pointer to the process to be terminated */
16929 int exit_status; /* the process' exit status (for parent) */
16930 {
16931 /* A process is done. Release most of the process' possessions. If its
16932 * parent is waiting, release the rest, else hang.
16933 */
16934
16935 register int proc_nr;
16936 int parent_waiting, right_child;
16937 pid_t pidarg, procgrp;
16938 phys_clicks base, size, s; /* base and size used on 68000 only */
16939
16940 proc_nr = (int) (rmp - mproc); /* get process slot number */
16941
16942 /* Remember a session leader's process group. */
16943 procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
16944
16945 /* If the exited process has a timer pending, kill it. */
16946 if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);
16947
16948 /* Tell the kernel and FS that the process is no longer runnable. */
16949 tell_fs(EXIT, proc_nr, 0, 0); /* file system can free the proc slot */
16950 sys_xit(rmp->mp_parent, proc_nr, &base, &size);
16951
16952 /* Release the memory occupied by the child. */
16953 if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
16954 /* No other process shares the text segment, so free it. */
16955 free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
16956 }
16957 /* Free the data and stack segments. */
16958 free_mem(rmp->mp_seg[D].mem_phys,
16959 rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
16960
16961 /* The process slot can only be freed if the parent has done a WAIT. */
16962 rmp->mp_exitstatus = (char) exit_status;
16963 pidarg = mproc[rmp->mp_parent].mp_wpid; /* who's being waited for? */
16964 parent_waiting = mproc[rmp->mp_parent].mp_flags & WAITING;
16965 if (pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp)
16966 right_child = TRUE; /* child meets one of the 3 tests */
16967 else
16968 right_child = FALSE; /* child fails all 3 tests */
16969 if (parent_waiting && right_child)
16970 cleanup(rmp); /* tell parent and release child slot */
16971 else
16972 rmp->mp_flags |= HANGING; /* parent not waiting, suspend child */
16973
16974 /* If the process has children, disinherit them. INIT is the new parent. */
16975 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
16976 if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
16977 /* 'rmp' now points to a child to be disinherited. */
16978 rmp->mp_parent = INIT_PROC_NR;
16979 parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
16980 if (parent_waiting && (rmp->mp_flags & HANGING)) cleanup(rmp);
16981 }
16982 }
16983
16984 /* Send a hangup to the process' process group if it was a session leader. */
16985 if (procgrp != 0) check_sig(-procgrp, SIGHUP);
16986 }
16989 /*===========================================================================*
16990 * do_waitpid *
16991 *===========================================================================*/
16992 PUBLIC int do_waitpid()
16993 {
16994 /* A process wants to wait for a child to terminate. If one is already waiting,
16995 * go clean it up and let this WAIT call terminate. Otherwise, really wait.
16996 * Both WAIT and WAITPID are handled by this code.
16997 */
16998
16999 register struct mproc *rp;
17000 int pidarg, options, children, res2;
17001
17002 /* A process calling WAIT never gets a reply in the usual way via the
17003 * reply() in the main loop (unless WNOHANG is set or no qualifying child
17004 * exists). If a child has already exited, the routine cleanup() sends
17005 * the reply to awaken the caller.
17006 */
17007
17008 /* Set internal variables, depending on whether this is WAIT or WAITPID. */
17009 pidarg = (mm_call == WAIT ? -1 : pid); /* first param of waitpid */
17010 options = (mm_call == WAIT ? 0 : sig_nr); /* third param of waitpid */
17011 if (pidarg == 0) pidarg = -mp->mp_procgrp; /* pidarg < 0 ==> proc grp */
17012
17013 /* Is there a child waiting to be collected? At this point, pidarg != 0:
17014 * pidarg > 0 means pidarg is pid of a specific process to wait for
17015 * pidarg == -1 means wait for any child
17016 * pidarg < -1 means wait for any child whose process group = -pidarg
17017 */
17018 children = 0;
17019 for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
17020 if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
17021 /* The value of pidarg determines which children qualify. */
17022 if (pidarg > 0 && pidarg != rp->mp_pid) continue;
17023 if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
17024
17025 children++; /* this child is acceptable */
17026 if (rp->mp_flags & HANGING) {
17027 /* This child meets the pid test and has exited. */
17028 cleanup(rp); /* this child has already exited */
17029 dont_reply = TRUE;
17030 return(OK);
17031 }
17032 if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
17033 /* This child meets the pid test and is being traced.*/
17034 res2 = 0177 | (rp->mp_sigstatus << 8);
17035 reply(who, rp->mp_pid, res2, NIL_PTR);
17036 dont_reply = TRUE;
17037 rp->mp_sigstatus = 0;
17038 return(OK);
17039 }
17040 }
17041 }
17042
17043 /* No qualifying child has exited. Wait for one, unless none exists. */
17044 if (children > 0) {
17045 /* At least 1 child meets the pid test exists, but has not exited. */
17046 if (options & WNOHANG) return(0); /* parent does not want to wait */
17047 mp->mp_flags |= WAITING; /* parent wants to wait */
17048 mp->mp_wpid = (pid_t) pidarg; /* save pid for later */
17049 dont_reply = TRUE; /* do not reply now though */
17050 return(OK); /* yes - wait for one to exit */
17051 } else {
17052 /* No child even meets the pid test. Return error immediately. */
17053 return(ECHILD); /* no - parent has no children */
17054 }
17055 }
17058 /*===========================================================================*
17059 * cleanup *
17060 *===========================================================================*/
17061 PRIVATE void cleanup(child)
17062 register struct mproc *child; /* tells which process is exiting */
17063 {
17064 /* Finish off the exit of a process. The process has exited or been killed
17065 * by a signal, and its parent is waiting.
17066 */
17067
17068 int exitstatus;
17069
17070 /* Wake up the parent. */
17071 exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
17072 reply(child->mp_parent, child->mp_pid, exitstatus, NIL_PTR);
17073 mproc[child->mp_parent].mp_flags &= ~WAITING; /* parent no longer waiting */
17074
17075 /* Release the process table entry. */
17076 child->mp_flags = 0;
17077 procs_in_use--;
17078 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -