output CRLF instead of just LF to serial
[minix3.git] / servers / pm / forkexit.c
blob4128656c1c724abf7df0c2392cadcd022c176883
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.
9 * The entry points into this file are:
10 * do_fork: perform the FORK system call
11 * do_pm_exit: perform the EXIT system call (by calling pm_exit())
12 * pm_exit: actually do the exiting
13 * do_wait: perform the WAITPID or WAIT system call
14 * tell_parent: tell parent about the death of a child
17 #include "pm.h"
18 #include <sys/wait.h>
19 #include <minix/callnr.h>
20 #include <minix/com.h>
21 #include <sys/resource.h>
22 #include <signal.h>
23 #include "mproc.h"
24 #include "param.h"
26 #define LAST_FEW 2 /* last few slots reserved for superuser */
28 FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
30 /*===========================================================================*
31 * do_fork *
32 *===========================================================================*/
33 PUBLIC int do_fork()
35 /* The process pointed to by 'mp' has forked. Create a child process. */
36 register struct mproc *rmp; /* pointer to parent */
37 register struct mproc *rmc; /* pointer to child */
38 int child_nr, s;
39 phys_clicks prog_clicks, child_base;
40 phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
41 pid_t new_pid;
42 static int next_child;
43 int n = 0, r;
45 /* If tables might fill up during FORK, don't even start since recovery half
46 * way through is such a nuisance.
48 rmp = mp;
49 if ((procs_in_use == NR_PROCS) ||
50 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
52 printf("PM: warning, process table is full!\n");
53 return(EAGAIN);
56 /* Determine how much memory to allocate. Only the data and stack need to
57 * be copied, because the text segment is either shared or of zero length.
59 prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
60 prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
61 prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
62 if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
64 /* Create a copy of the parent's core image for the child. */
65 child_abs = (phys_bytes) child_base << CLICK_SHIFT;
66 parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
67 s = sys_abscopy(parent_abs, child_abs, prog_bytes);
68 if (s < 0) panic(__FILE__,"do_fork can't copy", s);
70 /* Find a slot in 'mproc' for the child process. A slot must exist. */
71 do {
72 next_child = (next_child+1) % NR_PROCS;
73 n++;
74 } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
75 if(n > NR_PROCS)
76 panic(__FILE__,"do_fork can't find child slot", NO_NUM);
77 if(next_child < 0 || next_child >= NR_PROCS
78 || (mproc[next_child].mp_flags & IN_USE))
79 panic(__FILE__,"do_fork finds wrong child slot", next_child);
81 rmc = &mproc[next_child];
82 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
83 child_nr = (int)(rmc - mproc); /* slot number of the child */
84 procs_in_use++;
85 *rmc = *rmp; /* copy parent's process slot to child's */
86 rmc->mp_parent = who_p; /* record child's parent */
87 /* inherit only these flags */
88 rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP);
89 rmc->mp_child_utime = 0; /* reset administration */
90 rmc->mp_child_stime = 0; /* reset administration */
92 /* A separate I&D child keeps the parents text segment. The data and stack
93 * segments must refer to the new copy.
95 if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;
96 rmc->mp_seg[D].mem_phys = child_base;
97 rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys +
98 (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
99 rmc->mp_exitstatus = 0;
100 rmc->mp_sigstatus = 0;
102 /* Find a free pid for the child and put it in the table. */
103 new_pid = get_free_pid();
104 rmc->mp_pid = new_pid; /* assign pid to child */
106 /* Tell kernel and file system about the (now successful) FORK. */
107 if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint, rmc->mp_seg)) != OK) {
108 panic(__FILE__,"do_fork can't sys_fork", r);
111 if (rmc->mp_fs_call != PM_IDLE)
112 panic("pm", "do_fork: not idle", rmc->mp_fs_call);
113 rmc->mp_fs_call= PM_FORK;
114 r= notify(FS_PROC_NR);
115 if (r != OK) panic("pm", "do_fork: unable to notify FS", r);
117 /* Do not reply until FS is ready to process the fork
118 * request
120 return SUSPEND;
123 /*===========================================================================*
124 * do_fork_nb *
125 *===========================================================================*/
126 PUBLIC int do_fork_nb()
128 /* The process pointed to by 'mp' has forked. Create a child process. */
129 register struct mproc *rmp; /* pointer to parent */
130 register struct mproc *rmc; /* pointer to child */
131 int child_nr, s;
132 phys_clicks prog_clicks, child_base;
133 phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
134 pid_t new_pid;
135 static int next_child;
136 int n = 0, r;
138 /* Only system processes are allowed to use fork_nb */
139 if (!(mp->mp_flags & PRIV_PROC))
140 return EPERM;
142 /* If tables might fill up during FORK, don't even start since recovery half
143 * way through is such a nuisance.
145 rmp = mp;
146 if ((procs_in_use == NR_PROCS) ||
147 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
149 printf("PM: warning, process table is full!\n");
150 return(EAGAIN);
153 /* Determine how much memory to allocate. Only the data and stack need to
154 * be copied, because the text segment is either shared or of zero length.
156 prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
157 prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
158 prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
159 if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
161 /* Create a copy of the parent's core image for the child. */
162 child_abs = (phys_bytes) child_base << CLICK_SHIFT;
163 parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
164 s = sys_abscopy(parent_abs, child_abs, prog_bytes);
165 if (s < 0) panic(__FILE__,"do_fork can't copy", s);
167 /* Find a slot in 'mproc' for the child process. A slot must exist. */
168 do {
169 next_child = (next_child+1) % NR_PROCS;
170 n++;
171 } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
172 if(n > NR_PROCS)
173 panic(__FILE__,"do_fork can't find child slot", NO_NUM);
174 if(next_child < 0 || next_child >= NR_PROCS
175 || (mproc[next_child].mp_flags & IN_USE))
176 panic(__FILE__,"do_fork finds wrong child slot", next_child);
178 rmc = &mproc[next_child];
179 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
180 child_nr = (int)(rmc - mproc); /* slot number of the child */
181 procs_in_use++;
182 *rmc = *rmp; /* copy parent's process slot to child's */
183 rmc->mp_parent = who_p; /* record child's parent */
184 /* inherit only these flags */
185 rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP);
186 rmc->mp_child_utime = 0; /* reset administration */
187 rmc->mp_child_stime = 0; /* reset administration */
189 /* A separate I&D child keeps the parents text segment. The data and stack
190 * segments must refer to the new copy.
192 if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;
193 rmc->mp_seg[D].mem_phys = child_base;
194 rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys +
195 (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
196 rmc->mp_exitstatus = 0;
197 rmc->mp_sigstatus = 0;
199 /* Find a free pid for the child and put it in the table. */
200 new_pid = get_free_pid();
201 rmc->mp_pid = new_pid; /* assign pid to child */
203 /* Tell kernel and file system about the (now successful) FORK. */
204 if((r=sys_fork(who_e, child_nr, &rmc->mp_endpoint, rmc->mp_seg)) != OK) {
205 panic(__FILE__,"do_fork can't sys_fork", r);
208 if (rmc->mp_fs_call != PM_IDLE)
209 panic("pm", "do_fork: not idle", rmc->mp_fs_call);
210 rmc->mp_fs_call= PM_FORK_NB;
211 r= notify(FS_PROC_NR);
212 if (r != OK) panic("pm", "do_fork: unable to notify FS", r);
214 /* Wakeup the newly created process */
215 setreply(rmc-mproc, OK);
217 return rmc->mp_pid;
220 /*===========================================================================*
221 * do_pm_exit *
222 *===========================================================================*/
223 PUBLIC int do_pm_exit()
225 /* Perform the exit(status) system call. The real work is done by pm_exit(),
226 * which is also called when a process is killed by a signal.
228 pm_exit(mp, m_in.status, FALSE /*!for_trace*/);
229 return(SUSPEND); /* can't communicate from beyond the grave */
232 /*===========================================================================*
233 * pm_exit *
234 *===========================================================================*/
235 PUBLIC void pm_exit(rmp, exit_status, for_trace)
236 register struct mproc *rmp; /* pointer to the process to be terminated */
237 int exit_status; /* the process' exit status (for parent) */
238 int for_trace;
240 /* A process is done. Release most of the process' possessions. If its
241 * parent is waiting, release the rest, else keep the process slot and
242 * become a zombie.
244 register int proc_nr, proc_nr_e;
245 int parent_waiting, right_child, r;
246 pid_t pidarg, procgrp;
247 struct mproc *p_mp;
248 clock_t t[5];
250 proc_nr = (int) (rmp - mproc); /* get process slot number */
251 proc_nr_e = rmp->mp_endpoint;
253 /* Remember a session leader's process group. */
254 procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
256 /* If the exited process has a timer pending, kill it. */
257 if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr_e, (unsigned) 0);
259 /* Do accounting: fetch usage times and accumulate at parent. */
260 if((r=sys_times(proc_nr_e, t)) != OK)
261 panic(__FILE__,"pm_exit: sys_times failed", r);
263 p_mp = &mproc[rmp->mp_parent]; /* process' parent */
264 p_mp->mp_child_utime += t[0] + rmp->mp_child_utime; /* add user time */
265 p_mp->mp_child_stime += t[1] + rmp->mp_child_stime; /* add system time */
267 /* Tell the kernel the process is no longer runnable to prevent it from
268 * being scheduled in between the following steps. Then tell FS that it
269 * the process has exited and finally, clean up the process at the kernel.
270 * This order is important so that FS can tell drivers to cancel requests
271 * such as copying to/ from the exiting process, before it is gone.
273 sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */
275 if (proc_nr_e == INIT_PROC_NR)
277 printf("PM: INIT died\n");
278 return;
280 else
281 if(proc_nr_e != FS_PROC_NR) /* if it is not FS that is exiting.. */
283 /* Tell FS about the exiting process. */
284 if (rmp->mp_fs_call != PM_IDLE)
285 panic(__FILE__, "pm_exit: not idle", rmp->mp_fs_call);
286 rmp->mp_fs_call= (for_trace ? PM_EXIT_TR : PM_EXIT);
287 r= notify(FS_PROC_NR);
288 if (r != OK) panic(__FILE__, "pm_exit: unable to notify FS", r);
290 if (rmp->mp_flags & PRIV_PROC)
292 /* destroy system processes without waiting for FS */
293 if((r= sys_exit(rmp->mp_endpoint)) != OK)
294 panic(__FILE__, "pm_exit: sys_exit failed", r);
297 else
299 printf("PM: FS died\n");
300 return;
303 /* Pending reply messages for the dead process cannot be delivered. */
304 rmp->mp_flags &= ~REPLY;
306 /* Keep the process around until FS is finished with it. */
308 rmp->mp_exitstatus = (char) exit_status;
309 pidarg = p_mp->mp_wpid; /* who's being waited for? */
310 parent_waiting = p_mp->mp_flags & WAITING;
311 right_child = /* child meets one of the 3 tests? */
312 (pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
314 if (parent_waiting && right_child) {
315 tell_parent(rmp); /* tell parent */
316 } else {
317 rmp->mp_flags &= (IN_USE|PRIV_PROC);
318 rmp->mp_flags |= ZOMBIE; /* parent not waiting, zombify child */
319 sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
322 /* If the process has children, disinherit them. INIT is the new parent. */
323 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
324 if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
325 /* 'rmp' now points to a child to be disinherited. */
326 rmp->mp_parent = INIT_PROC_NR;
327 parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
328 if (parent_waiting && (rmp->mp_flags & ZOMBIE) &&
329 !(rmp->mp_flags & TOLD_PARENT) &&
330 rmp->mp_fs_call != PM_EXIT) {
331 cleanup(rmp);
336 /* Send a hangup to the process' process group if it was a session leader. */
337 if (procgrp != 0) check_sig(-procgrp, SIGHUP);
340 /*===========================================================================*
341 * do_waitpid *
342 *===========================================================================*/
343 PUBLIC int do_waitpid()
345 /* A process wants to wait for a child to terminate. If a child is already
346 * waiting, go clean it up and let this WAIT call terminate. Otherwise,
347 * really wait.
348 * A process calling WAIT never gets a reply in the usual way at the end
349 * of the main loop (unless WNOHANG is set or no qualifying child exists).
350 * If a child has already exited, the routine cleanup() sends the reply
351 * to awaken the caller.
352 * Both WAIT and WAITPID are handled by this code.
354 register struct mproc *rp;
355 int pidarg, options, children;
357 /* Set internal variables, depending on whether this is WAIT or WAITPID. */
358 pidarg = (call_nr == WAIT ? -1 : m_in.pid); /* 1st param of waitpid */
359 options = (call_nr == WAIT ? 0 : m_in.sig_nr); /* 3rd param of waitpid */
360 if (pidarg == 0) pidarg = -mp->mp_procgrp; /* pidarg < 0 ==> proc grp */
362 /* Is there a child waiting to be collected? At this point, pidarg != 0:
363 * pidarg > 0 means pidarg is pid of a specific process to wait for
364 * pidarg == -1 means wait for any child
365 * pidarg < -1 means wait for any child whose process group = -pidarg
367 children = 0;
368 for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
369 if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who_p) {
370 /* The value of pidarg determines which children qualify. */
371 if (pidarg > 0 && pidarg != rp->mp_pid) continue;
372 if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
373 if (rp->mp_flags & TOLD_PARENT) continue; /* post-ZOMBIE */
375 children++; /* this child is acceptable */
376 if (rp->mp_flags & ZOMBIE) {
377 /* This child meets the pid test and has exited. */
378 tell_parent(rp); /* this child has already exited */
379 if (rp->mp_fs_call == PM_IDLE)
380 real_cleanup(rp);
381 return(SUSPEND);
383 if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
384 /* This child meets the pid test and is being traced.*/
385 mp->mp_reply.reply_res2 = 0177|(rp->mp_sigstatus << 8);
386 rp->mp_sigstatus = 0;
387 return(rp->mp_pid);
392 /* No qualifying child has exited. Wait for one, unless none exists. */
393 if (children > 0) {
394 /* At least 1 child meets the pid test exists, but has not exited. */
395 if (options & WNOHANG) return(0); /* parent does not want to wait */
396 mp->mp_flags |= WAITING; /* parent wants to wait */
397 mp->mp_wpid = (pid_t) pidarg; /* save pid for later */
398 return(SUSPEND); /* do not reply, let it wait */
399 } else {
400 /* No child even meets the pid test. Return error immediately. */
401 return(ECHILD); /* no - parent has no children */
405 /*===========================================================================*
406 * cleanup *
407 *===========================================================================*/
408 PRIVATE void cleanup(child)
409 register struct mproc *child; /* tells which process is exiting */
411 /* Finish off the exit of a process. The process has exited or been killed
412 * by a signal, and its parent is waiting.
415 if (child->mp_fs_call != PM_IDLE)
416 panic(__FILE__, "cleanup: not idle", child->mp_fs_call);
418 tell_parent(child);
419 real_cleanup(child);
423 /*===========================================================================*
424 * tell_parent *
425 *===========================================================================*/
426 PUBLIC void tell_parent(child)
427 register struct mproc *child; /* tells which process is exiting */
429 int exitstatus, mp_parent;
430 struct mproc *parent;
432 mp_parent= child->mp_parent;
433 if (mp_parent <= 0)
434 panic(__FILE__, "tell_parent: bad value in mp_parent", mp_parent);
435 if(child->mp_flags & TOLD_PARENT)
436 panic(__FILE__, "tell_parent: telling parent again", NO_NUM);
437 parent = &mproc[mp_parent];
439 /* Wake up the parent by sending the reply message. */
440 exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
441 parent->mp_reply.reply_res2 = exitstatus;
442 setreply(child->mp_parent, child->mp_pid);
443 parent->mp_flags &= ~WAITING; /* parent no longer waiting */
444 child->mp_flags |= TOLD_PARENT; /* avoid informing parent twice */
447 /*===========================================================================*
448 * real_cleanup *
449 *===========================================================================*/
450 PUBLIC void real_cleanup(rmp)
451 register struct mproc *rmp; /* tells which process is exiting */
453 /* Release the process table entry and reinitialize some field. */
454 rmp->mp_pid = 0;
455 rmp->mp_flags = 0;
456 rmp->mp_child_utime = 0;
457 rmp->mp_child_stime = 0;
458 procs_in_use--;