1 /* This file deals with creating processes (via FORK) and deleting them (via
2 * EXIT/WAIT). When a process forks, a new slot in the 'mproc' table is
3 * allocated for it, and a copy of the parent's core image is made for the
4 * child. Then the kernel and file system are informed. A process is removed
5 * from the 'mproc' table when two events have occurred: (1) it has exited or
6 * been killed by a signal, and (2) the parent has done a WAIT. If the process
7 * exits first, it continues to occupy a slot until the parent does a WAIT.
8 *
9 * The entry points into this file are:
10 * do_fork: perform the FORK system call
11 * do_mm_exit: perform the EXIT system call (by calling mm_exit())
12 * mm_exit: actually do the exiting
13 * do_wait: perform the WAITPID or WAIT system call
14 */
15
16
17 #include "mm.h"
18 #include <sys/wait.h>
19 #include <minix/callnr.h>
20 #include <signal.h>
21 #include "mproc.h"
22 #include "param.h"
23
24 /*
25 * This file has been changed quite a lot to allow for extendable data
26 * and stack segments in smx. Consequently, all INTEL-specific code
27 * has been removed to improve readability.
28 */
29 #if (MACHINE != SUN)
30 #error "This file has been tailored for use with Solaris MINIX only"
31 #endif
32
33 #define LAST_FEW 2 /* last few slots reserved for superuser */
34
35 PRIVATE pid_t next_pid = INIT_PID+1; /* next pid to be assigned */
36
37 FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
38
39 /*===========================================================================*
40 * do_fork *
41 *===========================================================================*/
42 PUBLIC int do_fork()
43 {
44 /* The process pointed to by 'mp' has forked. Create a child process. */
45
46 register struct mproc *rmp; /* pointer to parent */
47 register struct mproc *rmc; /* pointer to child */
48 int i, child_nr, t;
49 phys_clicks prog_clicks, child_base = 0;
50 phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
51
52 /* If tables might fill up during FORK, don't even start since recovery half
53 * way through is such a nuisance.
54 */
55 rmp = mp;
56 if (procs_in_use == NR_PROCS) return(EAGAIN);
57 if (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0)return(EAGAIN);
58
59 /* Determine how much memory to allocate. Only the data and stack need to
60 * be copied, because the text segment is either shared or of zero length.
61 */
62 prog_clicks = (phys_clicks) rmp->mp_seg[D].mem_len + rmp->mp_seg[S].mem_len;
63 prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
64 if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
65
66 /* Create a copy of the parent's core image for the child. */
67 child_abs = (phys_bytes) child_base << CLICK_SHIFT;
68 parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
69 i = sys_copy(ABS, 0, parent_abs, ABS, 0, child_abs,
70 rmp->mp_seg[D].mem_len << CLICK_SHIFT);
71 if (i < 0) panic("do_fork can't copy", i);
72 i = sys_copy(ABS, 0, rmp->mp_seg[S].mem_phys << CLICK_SHIFT, ABS, 0,
73 child_abs + (rmp->mp_seg[D].mem_len << CLICK_SHIFT),
74 rmp->mp_seg[S].mem_len << CLICK_SHIFT);
75 if (i < 0) panic("do_fork can't copy", i);
76
77 /* Find a slot in 'mproc' for the child process. A slot must exist. */
78 for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
79 if ( (rmc->mp_flags & IN_USE) == 0) break;
80
81 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
82 child_nr = (int)(rmc - mproc); /* slot number of the child */
83 procs_in_use++;
84 *rmc = *rmp; /* copy parent's process slot to child's */
85
86 rmc->mp_parent = who; /* record child's parent */
87 rmc->mp_flags &= ~TRACED; /* child does not inherit trace status */
88 /*
89 * In smx, only processes with separate I&D are supported.
90 */
91 if (!(rmc->mp_flags & SEPARATE)) {
92 panic("do_fork: process without separate I&D segments", NO_NUM);
93 }
94 rmc->mp_seg[D].mem_phys = child_base;
95 rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + rmc->mp_seg[D].mem_len;
96 rmc->mp_exitstatus = 0;
97 rmc->mp_sigstatus = 0;
98
99 /* Find a free pid for the child and put it in the table. */
100 do {
101 t = 0; /* 't' = 0 means pid still free */
102 next_pid = (next_pid < 30000 ? next_pid + 1 : INIT_PID + 1);
103 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
104 if (rmp->mp_pid == next_pid || rmp->mp_procgrp == next_pid) {
105 t = 1;
106 break;
107 }
108 rmc->mp_pid = next_pid; /* assign pid to child */
109 } while (t);
110
111 /* Tell kernel and file system about the (now successful) FORK. */
112 sys_fork(who, child_nr, rmc->mp_pid, child_base); /* child_base is 68K only*/
113 tell_fs(FORK, who, child_nr, rmc->mp_pid);
114
115 /* Report child's memory map to kernel. */
116 sys_newmap(child_nr, rmc->mp_seg);
117
118 /* Reply to child to wake it up. */
119 reply(child_nr, 0, 0, NIL_PTR);
120 return(next_pid); /* child's pid */
121 }
122
123
124 /*===========================================================================*
125 * do_mm_exit *
126 *===========================================================================*/
127 PUBLIC int do_mm_exit()
128 {
129 /* Perform the exit(status) system call. The real work is done by mm_exit(),
130 * which is also called when a process is killed by a signal.
131 */
132
133 mm_exit(mp, status);
134 dont_reply = TRUE; /* don't reply to newly terminated process */
135 return(OK); /* pro forma return code */
136 }
137
138
139 /*===========================================================================*
140 * mm_exit *
141 *===========================================================================*/
142 PUBLIC void mm_exit(rmp, exit_status)
143 register struct mproc *rmp; /* pointer to the process to be terminated */
144 int exit_status; /* the process' exit status (for parent) */
145 {
146 /* A process is done. Release most of the process' possessions. If its
147 * parent is waiting, release the rest, else hang.
148 */
149
150 register int proc_nr;
151 int parent_waiting, right_child;
152 pid_t pidarg, procgrp;
153 phys_clicks base, size;
154
155 proc_nr = (int) (rmp - mproc); /* get process slot number */
156
157 /* Remember a session leader's process group. */
158 procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
159
160 /* If the exited process has a timer pending, kill it. */
161 if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);
162
163 /* Tell the kernel and FS that the process is no longer runnable. */
164 tell_fs(EXIT, proc_nr, 0, 0); /* file system can free the proc slot */
165 sys_xit(rmp->mp_parent, proc_nr, &base, &size);
166
167 /* Release the memory occupied by the child. */
168 if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
169 /* No other process shares the text segment, so free it. */
170 free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
171 }
172 /* Free the data and stack segments. */
173 free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[D].mem_len);
174 free_mem(rmp->mp_seg[S].mem_phys, rmp->mp_seg[S].mem_len);
175
176 /* The process slot can only be freed if the parent has done a WAIT. */
177 rmp->mp_exitstatus = (char) exit_status;
178 pidarg = mproc[rmp->mp_parent].mp_wpid; /* who's being waited for? */
179 parent_waiting = mproc[rmp->mp_parent].mp_flags & WAITING;
180 if (pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp)
181 right_child = TRUE; /* child meets one of the 3 tests */
182 else
183 right_child = FALSE; /* child fails all 3 tests */
184 if (parent_waiting && right_child)
185 cleanup(rmp); /* tell parent and release child slot */
186 else
187 rmp->mp_flags |= HANGING; /* parent not waiting, suspend child */
188
189 /* If the process has children, disinherit them. INIT is the new parent. */
190 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
191 if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
192 /* 'rmp' now points to a child to be disinherited. */
193 rmp->mp_parent = INIT_PROC_NR;
194 parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
195 if (parent_waiting && (rmp->mp_flags & HANGING)) cleanup(rmp);
196 }
197 }
198
199 /* Send a hangup to the process' process group if it was a session leader. */
200 if (procgrp != 0) check_sig(-procgrp, SIGHUP);
201 }
202
203
204 /*===========================================================================*
205 * do_waitpid *
206 *===========================================================================*/
207 PUBLIC int do_waitpid()
208 {
209 /* A process wants to wait for a child to terminate. If one is already waiting,
210 * go clean it up and let this WAIT call terminate. Otherwise, really wait.
211 * Both WAIT and WAITPID are handled by this code.
212 */
213
214 register struct mproc *rp;
215 int pidarg, options, children, res2;
216
217 /* A process calling WAIT never gets a reply in the usual way via the
218 * reply() in the main loop (unless WNOHANG is set or no qualifying child
219 * exists). If a child has already exited, the routine cleanup() sends
220 * the reply to awaken the caller.
221 */
222
223 /* Set internal variables, depending on whether this is WAIT or WAITPID. */
224 pidarg = (mm_call == WAIT ? -1 : pid); /* first param of waitpid */
225 options = (mm_call == WAIT ? 0 : sig_nr); /* third param of waitpid */
226 if (pidarg == 0) pidarg = -mp->mp_procgrp; /* pidarg < 0 ==> proc grp */
227
228 /* Is there a child waiting to be collected? At this point, pidarg != 0:
229 * pidarg > 0 means pidarg is pid of a specific process to wait for
230 * pidarg == -1 means wait for any child
231 * pidarg < -1 means wait for any child whose process group = -pidarg
232 */
233 children = 0;
234 for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
235 if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
236 /* The value of pidarg determines which children qualify. */
237 if (pidarg > 0 && pidarg != rp->mp_pid) continue;
238 if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
239
240 children++; /* this child is acceptable */
241 if (rp->mp_flags & HANGING) {
242 /* This child meets the pid test and has exited. */
243 cleanup(rp); /* this child has already exited */
244 dont_reply = TRUE;
245 return(OK);
246 }
247 if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
248 /* This child meets the pid test and is being traced.*/
249 res2 = 0177 | (rp->mp_sigstatus << 8);
250 reply(who, rp->mp_pid, res2, NIL_PTR);
251 dont_reply = TRUE;
252 rp->mp_sigstatus = 0;
253 return(OK);
254 }
255 }
256 }
257
258 /* No qualifying child has exited. Wait for one, unless none exists. */
259 if (children > 0) {
260 /* At least 1 child meets the pid test exists, but has not exited. */
261 if (options & WNOHANG) return(0); /* parent does not want to wait */
262 mp->mp_flags |= WAITING; /* parent wants to wait */
263 mp->mp_wpid = (pid_t) pidarg; /* save pid for later */
264 dont_reply = TRUE; /* do not reply now though */
265 return(OK); /* yes - wait for one to exit */
266 } else {
267 /* No child even meets the pid test. Return error immediately. */
268 return(ECHILD); /* no - parent has no children */
269 }
270 }
271
272
273 /*===========================================================================*
274 * cleanup *
275 *===========================================================================*/
276 PRIVATE void cleanup(child)
277 register struct mproc *child; /* tells which process is exiting */
278 {
279 /* Finish off the exit of a process. The process has exited or been killed
280 * by a signal, and its parent is waiting.
281 */
282
283 int exitstatus;
284
285 /* Wake up the parent. */
286 exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
287 reply(child->mp_parent, child->mp_pid, exitstatus, NIL_PTR);
288 mproc[child->mp_parent].mp_flags &= ~WAITING; /* parent no longer waiting */
289
290 /* Release the process table entry. */
291 child->mp_flags = 0;
292 procs_in_use--;
293 }
294
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.