minix/minix/kernel/system/do_fork.c
David van Moolenbroek 0f8e20a12c getrusage(2): zero out ru_nsignals field
The current value was both wrong (counting spawned kernel signals
rather than delivered user signals) and returned for the calling
process even if the request was for the process's children.
For now we are better off not populating this field at all.

Change-Id: I6c660be266b5746b7c3db57ae88fa7f872961ee2
2015-09-28 14:06:58 +00:00

134 lines
4.1 KiB
C

/* The kernel call implemented in this file:
* m_type: SYS_FORK
*
* The parameters for this kernel call are:
* m_lsys_krn_sys_fork.endpt (parent, process that forked)
* m_lsys_krn_sys_fork.slot (child's process table slot)
* m_lsys_krn_sys_fork.flags (fork flags)
* m_krn_lsys_sys_fork.endpt (endpoint of the child)
* m_krn_lsys_sys_fork.msgaddr (new memory map for the child)
*/
#include "kernel/system.h"
#include "kernel/vm.h"
#include <signal.h>
#include <string.h>
#include <assert.h>
#include <minix/endpoint.h>
#include <minix/u64.h>
#if USE_FORK
/*===========================================================================*
* do_fork *
*===========================================================================*/
int do_fork(struct proc * caller, message * m_ptr)
{
/* Handle sys_fork().
* m_lsys_krn_sys_fork.endpt has forked.
* The child is m_lsys_krn_sys_fork.slot.
*/
#if defined(__i386__)
char *old_fpu_save_area_p;
#endif
register struct proc *rpc; /* child process pointer */
struct proc *rpp; /* parent process pointer */
int gen;
int p_proc;
int namelen;
if(!isokendpt(m_ptr->m_lsys_krn_sys_fork.endpt, &p_proc))
return EINVAL;
rpp = proc_addr(p_proc);
rpc = proc_addr(m_ptr->m_lsys_krn_sys_fork.slot);
if (isemptyp(rpp) || ! isemptyp(rpc)) return(EINVAL);
assert(!(rpp->p_misc_flags & MF_DELIVERMSG));
/* needs to be receiving so we know where the message buffer is */
if(!RTS_ISSET(rpp, RTS_RECEIVING)) {
printf("kernel: fork not done synchronously?\n");
return EINVAL;
}
/* make sure that the FPU context is saved in parent before copy */
save_fpu(rpp);
/* Copy parent 'proc' struct to child. And reinitialize some fields. */
gen = _ENDPOINT_G(rpc->p_endpoint);
#if defined(__i386__)
old_fpu_save_area_p = rpc->p_seg.fpu_state;
#endif
*rpc = *rpp; /* copy 'proc' struct */
#if defined(__i386__)
rpc->p_seg.fpu_state = old_fpu_save_area_p;
if(proc_used_fpu(rpp))
memcpy(rpc->p_seg.fpu_state, rpp->p_seg.fpu_state, FPU_XFP_SIZE);
#endif
if(++gen >= _ENDPOINT_MAX_GENERATION) /* increase generation */
gen = 1; /* generation number wraparound */
rpc->p_nr = m_ptr->m_lsys_krn_sys_fork.slot; /* this was obliterated by copy */
rpc->p_endpoint = _ENDPOINT(gen, rpc->p_nr); /* new endpoint of slot */
rpc->p_reg.retreg = 0; /* child sees pid = 0 to know it is child */
rpc->p_user_time = 0; /* set all the accounting times to 0 */
rpc->p_sys_time = 0;
rpc->p_misc_flags &=
~(MF_VIRT_TIMER | MF_PROF_TIMER | MF_SC_TRACE | MF_SPROF_SEEN | MF_STEP);
rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */
rpc->p_prof_left = 0;
/* Mark process name as being a forked copy */
namelen = strlen(rpc->p_name);
#define FORKSTR "*F"
if(namelen+strlen(FORKSTR) < sizeof(rpc->p_name))
strcat(rpc->p_name, FORKSTR);
/* the child process is not runnable until it's scheduled. */
RTS_SET(rpc, RTS_NO_QUANTUM);
reset_proc_accounting(rpc);
rpc->p_cpu_time_left = 0;
rpc->p_cycles = 0;
rpc->p_kcall_cycles = 0;
rpc->p_kipc_cycles = 0;
/* If the parent is a privileged process, take away the privileges from the
* child process and inhibit it from running by setting the NO_PRIV flag.
* The caller should explicitly set the new privileges before executing.
*/
if (priv(rpp)->s_flags & SYS_PROC) {
rpc->p_priv = priv_addr(USER_PRIV_ID);
rpc->p_rts_flags |= RTS_NO_PRIV;
}
/* Calculate endpoint identifier, so caller knows what it is. */
m_ptr->m_krn_lsys_sys_fork.endpt = rpc->p_endpoint;
m_ptr->m_krn_lsys_sys_fork.msgaddr = rpp->p_delivermsg_vir;
/* Don't schedule process in VM mode until it has a new pagetable. */
if(m_ptr->m_lsys_krn_sys_fork.flags & PFF_VMINHIBIT) {
RTS_SET(rpc, RTS_VMINHIBIT);
}
/*
* Only one in group should have RTS_SIGNALED, child doesn't inherit tracing.
*/
RTS_UNSET(rpc, (RTS_SIGNALED | RTS_SIG_PENDING | RTS_P_STOP));
(void) sigemptyset(&rpc->p_pending);
#if defined(__i386__)
rpc->p_seg.p_cr3 = 0;
rpc->p_seg.p_cr3_v = NULL;
#elif defined(__arm__)
rpc->p_seg.p_ttbr = 0;
rpc->p_seg.p_ttbr_v = NULL;
#endif
return OK;
}
#endif /* USE_FORK */