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
19 #include <minix/callnr.h>
20 #include <minix/com.h>
21 #include <sys/resource.h>
26 #define LAST_FEW 2 /* last few slots reserved for superuser */
28 FORWARD
_PROTOTYPE (void cleanup
, (register struct mproc
*child
) );
30 /*===========================================================================*
32 *===========================================================================*/
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 */
39 phys_clicks prog_clicks
, child_base
;
40 phys_bytes prog_bytes
, parent_abs
, child_abs
; /* Intel only */
42 static int next_child
;
45 /* If tables might fill up during FORK, don't even start since recovery half
46 * way through is such a nuisance.
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");
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. */
72 next_child
= (next_child
+1) % NR_PROCS
;
74 } while((mproc
[next_child
].mp_flags
& IN_USE
) && 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 */
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
123 /*===========================================================================*
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 */
132 phys_clicks prog_clicks
, child_base
;
133 phys_bytes prog_bytes
, parent_abs
, child_abs
; /* Intel only */
135 static int next_child
;
138 /* Only system processes are allowed to use fork_nb */
139 if (!(mp
->mp_flags
& PRIV_PROC
))
142 /* If tables might fill up during FORK, don't even start since recovery half
143 * way through is such a nuisance.
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");
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. */
169 next_child
= (next_child
+1) % NR_PROCS
;
171 } while((mproc
[next_child
].mp_flags
& IN_USE
) && 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 */
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
);
220 /*===========================================================================*
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 /*===========================================================================*
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) */
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
244 register int proc_nr
, proc_nr_e
;
245 int parent_waiting
, right_child
, r
;
246 pid_t pidarg
, procgrp
;
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");
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
);
299 printf("PM: FS died\n");
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 */
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
) {
336 /* Send a hangup to the process' process group if it was a session leader. */
337 if (procgrp
!= 0) check_sig(-procgrp
, SIGHUP
);
340 /*===========================================================================*
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,
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
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
)
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;
392 /* No qualifying child has exited. Wait for one, unless none exists. */
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 */
400 /* No child even meets the pid test. Return error immediately. */
401 return(ECHILD
); /* no - parent has no children */
405 /*===========================================================================*
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
);
423 /*===========================================================================*
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
;
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 /*===========================================================================*
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. */
456 rmp
->mp_child_utime
= 0;
457 rmp
->mp_child_stime
= 0;