⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 forkexit.c

📁 Minix3.11的源码。[MINIX 3是一个为高可靠性应用而设计的自由且简洁的类UNIX系统。]
💻 C
字号:
/* This file deals with creating processes (via FORK) and deleting them (via * EXIT/WAIT).  When a process forks, a new slot in the 'mproc' table is * allocated for it, and a copy of the parent's core image is made for the * child.  Then the kernel and file system are informed.  A process is removed * from the 'mproc' table when two events have occurred: (1) it has exited or * been killed by a signal, and (2) the parent has done a WAIT.  If the process * exits first, it continues to occupy a slot until the parent does a WAIT. * * The entry points into this file are: *   do_fork:	 perform the FORK system call *   do_pm_exit: perform the EXIT system call (by calling pm_exit()) *   pm_exit:	 actually do the exiting *   do_wait:	 perform the WAITPID or WAIT system call */#include "pm.h"#include <sys/wait.h>#include <minix/callnr.h>#include <minix/com.h>#include <signal.h>#include "mproc.h"#include "param.h"#define LAST_FEW            2	/* last few slots reserved for superuser */FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );/*===========================================================================* *				do_fork					     * *===========================================================================*/PUBLIC int do_fork(){/* The process pointed to by 'mp' has forked.  Create a child process. */  register struct mproc *rmp;	/* pointer to parent */  register struct mproc *rmc;	/* pointer to child */  int child_nr, s;  phys_clicks prog_clicks, child_base;  phys_bytes prog_bytes, parent_abs, child_abs;	/* Intel only */  pid_t new_pid; /* If tables might fill up during FORK, don't even start since recovery half  * way through is such a nuisance.  */  rmp = mp;  if ((procs_in_use == NR_PROCS) ||   		(procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))  {  	printf("PM: warning, process table is full!\n");  	return(EAGAIN);  }  /* Determine how much memory to allocate.  Only the data and stack need to   * be copied, because the text segment is either shared or of zero length.   */  prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;  prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);  prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;  if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);  /* Create a copy of the parent's core image for the child. */  child_abs = (phys_bytes) child_base << CLICK_SHIFT;  parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;  s = sys_abscopy(parent_abs, child_abs, prog_bytes);  if (s < 0) panic(__FILE__,"do_fork can't copy", s);  /* Find a slot in 'mproc' for the child process.  A slot must exist. */  for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)	if ( (rmc->mp_flags & IN_USE) == 0) break;  /* Set up the child and its memory map; copy its 'mproc' slot from parent. */  child_nr = (int)(rmc - mproc);	/* slot number of the child */  procs_in_use++;  *rmc = *rmp;			/* copy parent's process slot to child's */  rmc->mp_parent = who;			/* record child's parent */  /* inherit only these flags */  rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP);  rmc->mp_child_utime = 0;		/* reset administration */  rmc->mp_child_stime = 0;		/* reset administration */  /* A separate I&D child keeps the parents text segment.  The data and stack   * segments must refer to the new copy.   */  if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;  rmc->mp_seg[D].mem_phys = child_base;  rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + 			(rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);  rmc->mp_exitstatus = 0;  rmc->mp_sigstatus = 0;  /* Find a free pid for the child and put it in the table. */  new_pid = get_free_pid();  rmc->mp_pid = new_pid;	/* assign pid to child */  /* Tell kernel and file system about the (now successful) FORK. */  sys_fork(who, child_nr);  tell_fs(FORK, who, child_nr, rmc->mp_pid);  /* Report child's memory map to kernel. */  sys_newmap(child_nr, rmc->mp_seg);  /* Reply to child to wake it up. */  setreply(child_nr, 0);		/* only parent gets details */  rmp->mp_reply.procnr = child_nr;	/* child's process number */  return(new_pid);		 	/* child's pid */}/*===========================================================================* *				do_pm_exit				     * *===========================================================================*/PUBLIC int do_pm_exit(){/* Perform the exit(status) system call. The real work is done by pm_exit(), * which is also called when a process is killed by a signal. */  pm_exit(mp, m_in.status);  return(SUSPEND);		/* can't communicate from beyond the grave */}/*===========================================================================* *				pm_exit					     * *===========================================================================*/PUBLIC void pm_exit(rmp, exit_status)register struct mproc *rmp;	/* pointer to the process to be terminated */int exit_status;		/* the process' exit status (for parent) */{/* A process is done.  Release most of the process' possessions.  If its * parent is waiting, release the rest, else keep the process slot and * become a zombie. */  register int proc_nr;  int parent_waiting, right_child;  pid_t pidarg, procgrp;  struct mproc *p_mp;  clock_t t[5];  proc_nr = (int) (rmp - mproc);	/* get process slot number */  /* Remember a session leader's process group. */  procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;  /* If the exited process has a timer pending, kill it. */  if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);  /* Do accounting: fetch usage times and accumulate at parent. */  sys_times(proc_nr, t);  p_mp = &mproc[rmp->mp_parent];			/* process' parent */  p_mp->mp_child_utime += t[0] + rmp->mp_child_utime;	/* add user time */  p_mp->mp_child_stime += t[1] + rmp->mp_child_stime;	/* add system time */  /* Tell the kernel and FS that the process is no longer runnable. */  tell_fs(EXIT, proc_nr, 0, 0);  /* file system can free the proc slot */  sys_exit(proc_nr);  /* Pending reply messages for the dead process cannot be delivered. */  rmp->mp_flags &= ~REPLY;    /* Release the memory occupied by the child. */  if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {	/* No other process shares the text segment, so free it. */	free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);  }  /* Free the data and stack segments. */  free_mem(rmp->mp_seg[D].mem_phys,      rmp->mp_seg[S].mem_vir         + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);  /* The process slot can only be freed if the parent has done a WAIT. */  rmp->mp_exitstatus = (char) exit_status;  pidarg = p_mp->mp_wpid;		/* who's being waited for? */  parent_waiting = p_mp->mp_flags & WAITING;  right_child =				/* child meets one of the 3 tests? */	(pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);  if (parent_waiting && right_child) {	cleanup(rmp);			/* tell parent and release child slot */  } else {	rmp->mp_flags = IN_USE|ZOMBIE;	/* parent not waiting, zombify child */	sig_proc(p_mp, SIGCHLD);	/* send parent a "child died" signal */  }  /* If the process has children, disinherit them.  INIT is the new parent. */  for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {	if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {		/* 'rmp' now points to a child to be disinherited. */		rmp->mp_parent = INIT_PROC_NR;		parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;		if (parent_waiting && (rmp->mp_flags & ZOMBIE)) cleanup(rmp);	}  }  /* Send a hangup to the process' process group if it was a session leader. */  if (procgrp != 0) check_sig(-procgrp, SIGHUP);}/*===========================================================================* *				do_waitpid				     * *===========================================================================*/PUBLIC int do_waitpid(){/* A process wants to wait for a child to terminate. If a child is already  * waiting, go clean it up and let this WAIT call terminate.  Otherwise,  * really wait.  * A process calling WAIT never gets a reply in the usual way at the end * of the main loop (unless WNOHANG is set or no qualifying child exists). * If a child has already exited, the routine cleanup() sends the reply * to awaken the caller. * Both WAIT and WAITPID are handled by this code. */  register struct mproc *rp;  int pidarg, options, children;  /* Set internal variables, depending on whether this is WAIT or WAITPID. */  pidarg  = (call_nr == WAIT ? -1 : m_in.pid);	   /* 1st param of waitpid */  options = (call_nr == WAIT ?  0 : m_in.sig_nr);  /* 3rd param of waitpid */  if (pidarg == 0) pidarg = -mp->mp_procgrp;	/* pidarg < 0 ==> proc grp */  /* Is there a child waiting to be collected? At this point, pidarg != 0:   *	pidarg  >  0 means pidarg is pid of a specific process to wait for   *	pidarg == -1 means wait for any child   *	pidarg  < -1 means wait for any child whose process group = -pidarg   */  children = 0;  for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {	if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {		/* The value of pidarg determines which children qualify. */		if (pidarg  > 0 && pidarg != rp->mp_pid) continue;		if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;		children++;		/* this child is acceptable */		if (rp->mp_flags & ZOMBIE) {			/* This child meets the pid test and has exited. */			cleanup(rp);	/* this child has already exited */			return(SUSPEND);		}		if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {			/* This child meets the pid test and is being traced.*/			mp->mp_reply.reply_res2 = 0177|(rp->mp_sigstatus << 8);			rp->mp_sigstatus = 0;			return(rp->mp_pid);		}	}  }  /* No qualifying child has exited.  Wait for one, unless none exists. */  if (children > 0) {	/* At least 1 child meets the pid test exists, but has not exited. */	if (options & WNOHANG) return(0);    /* parent does not want to wait */	mp->mp_flags |= WAITING;	     /* parent wants to wait */	mp->mp_wpid = (pid_t) pidarg;	     /* save pid for later */	return(SUSPEND);		     /* do not reply, let it wait */  } else {	/* No child even meets the pid test.  Return error immediately. */	return(ECHILD);			     /* no - parent has no children */  }}/*===========================================================================* *				cleanup					     * *===========================================================================*/PRIVATE void cleanup(child)register struct mproc *child;	/* tells which process is exiting */{/* Finish off the exit of a process.  The process has exited or been killed * by a signal, and its parent is waiting. */  struct mproc *parent = &mproc[child->mp_parent];  int exitstatus;  /* Wake up the parent by sending the reply message. */  exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);  parent->mp_reply.reply_res2 = exitstatus;  setreply(child->mp_parent, child->mp_pid);  parent->mp_flags &= ~WAITING;		/* parent no longer waiting */  /* Release the process table entry and reinitialize some field. */  child->mp_pid = 0;  child->mp_flags = 0;  child->mp_child_utime = 0;  child->mp_child_stime = 0;  procs_in_use--;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -