Example #1
0
int sys_fork(struct trapframe *tf, pid_t *retval){

  const char* name = "Anonymous student's process";


// create process struct for child
  struct proc *childp = proc_create_runprogram(name);
  if(childp == NULL){
    return ENOMEM; //OUT OF MEMORY
  }

// create and copy as to child
  struct addrspace* childas = kmalloc(sizeof(struct addrspace));
  if(childas == NULL){
    proc_destroy(childp);
    return ENOMEM;
  }

  if(as_copy(curproc->p_addrspace, &childas)){
    kfree(childas);
    as_destroy(childas);
    proc_destroy(childp);
    return ENOMEM;
  }
// attach new as to child proc
  childp->p_addrspace = childas;
  
// create parent child relationship
  struct procinfo *pi = array_get(procinfotable, childp->pid - 1);
  if(pi == NULL){
    kfree(childas);
    as_destroy(childas);
    proc_destroy(childp);
    return ECHILD; // NO SUCH CHILD IN THE INFO TABLE
  }
  pi->parent_pid = curproc->pid;

// create thread for child and pass it tf
  struct trapframe *childtf = kmalloc(sizeof(struct trapframe));
  memcpy(childtf,tf,sizeof(struct trapframe));

  void ** data = kmalloc(2*sizeof(void*));
  data[0] = (void*)childtf;
  data[1] = (void*)childas; 

  int err = thread_fork(name, childp,(void *)enter_forked_process, data, 0);
  if(err){
    kfree(childas);
    kfree(childtf);
    as_destroy(childas);
    proc_destroy(childp);
    kfree(childtf);
    return ENOMEM;
  }


  *retval = childp->pid;
  return 0;
}
struct proc* proc_createchild(struct proc* parent, struct addrspace** as) {
	struct proc* child = proc_create(parent->p_name);
	if (child == NULL) {
		return NULL;
	}

	unsigned int i;
	// TODO Move this to a separate method
	for (i = 0; i < array_num(parent->p_filetable); i++) {
		struct filetable_entry* entry = array_get(parent->p_filetable, i);
		struct filetable_entry* newentry = (struct filetable_entry*) kmalloc(sizeof(struct filetable_entry));
		if(entry == NULL) {
			proc_destroy(child);
			return NULL;
		}
		newentry->ft_fd =  entry->ft_fd;

		newentry->ft_handle = entry->ft_handle;
		filehandle_incref(entry->ft_handle);
		int s = array_add(child->p_filetable, newentry, NULL);

		if (s == ENOMEM) {
			proc_destroy(child);
			return NULL;
		}
	}

	child->p_fdcounter = parent->p_fdcounter;

	/** process table */
	if (addTo_processtable(child) != 0) {
		return NULL;
	}
	child->p_ppid = parent->p_pid;

	/** cwd */
	/*
	 * Lock the current process to copy its current directory.
	 * (We don't need to lock the new process, though, as we have
	 * the only reference to it.)
	 */
	spinlock_acquire(&(parent->p_lock));
	if (parent->p_cwd != NULL) {
		VOP_INCREF(parent->p_cwd);
		child->p_cwd = parent->p_cwd;
	}
	spinlock_release(&(parent->p_lock));

	/** address space */
	(void) as;
	return child;
}
Example #3
0
/**
 * exit will perform the following tasks:
 * 1. close all open files (through file_close_all())
 * 2. set the given exit code inside the proc structure.
 * 3. mark each child process as orphan.
 * 4. if orphan, will destroy the proc associated with the current thread.
 * 4.1 if not orphan, will signal the parent regarding our death.
 * 5. call thread_exit() so we become a zombie.
 */
void
sys__exit( int code ) {
    struct proc		*p = NULL;
    int			err;

    KASSERT( curthread != NULL );
    KASSERT( curthread->td_proc != NULL );

    p = curthread->td_proc;

    //close all open files.
    err = file_close_all( p );
    if( err )
        panic( "problem closing a file." );

    //lock so we can adjust the return value.
    PROC_LOCK( p );
    p->p_retval = code;
    p->p_is_dead = true;

    //if we are orphans ourselves, no one is interested
    //in our return code, so we simply destroy ourselves.
    if( p->p_proc == NULL ) {
        PROC_UNLOCK( p );
        proc_destroy( p );
    }
    else {
        //signal that we are done.
        V( p->p_sem );
        PROC_UNLOCK( p );
    }

    //all that is left now is to kill our thread.
    thread_exit();
}
Example #4
0
term_t cbif_spawn3(proc_t *proc, term_t *regs)
{
	term_t m = regs[0];
	term_t f = regs[1];
	term_t args = regs[2];

	if (!is_atom(m))
		badarg(m);
	if (!is_atom(f))
		badarg(f);
	if (!is_list(args))
		badarg(args);

	if (list_len(args) < 0)
		badarg(args); // too odd

	proc_t *new_proc = proc_make(proc->group_leader);
	int x = proc_spawn_N(new_proc, m, f, args);
	if (x < 0)
	{
		proc_destroy(new_proc);	// safe
		fail(err_to_term(x));
	}

	return new_proc->pid;
}
Example #5
0
void
sys__exit(int exitcode)
{

    struct addrspace* as;
    struct proc* p = curproc;
    DEBUG(DB_EXEC, "sys_exit(): process %u exiting with code %d\n",p->p_pid,exitcode);

    KASSERT(p->p_addrspace != NULL);
    as_deactivate();
    as = proc_setas(NULL);
    as_destroy(as);
    proc_remthread(curthread);

    p->p_exitstatus = _MKWAIT_EXIT(exitcode);
    p->p_exitable = true;

    lock_acquire(p->p_waitpid_lk);
        cv_broadcast(p->p_waitpid_cv, p->p_waitpid_lk);
    lock_release(p->p_waitpid_lk);

    proc_destroy(p);
    thread_exit();
    panic("sys__exit(): unexpected return from thread_exit()\n");
}
Example #6
0
void etimer_cancel_by_receiver(term_t dst)
{
	etimer_t **ref = &active_timers;
	etimer_t *tm = active_timers;
	while (tm != 0)
	{
		if (tm->dst == dst)
		{
			if (tm->sender != 0)
			{
				assert(tm->sender->pending_timers > 0);
				tm->sender->pending_timers--;
				if (tm->sender->pending_timers == 0 &&
						tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS)
					proc_destroy(tm->sender);	// destroy a zombie process
			}

			*ref = tm->next;
			etimer_t *free_me = tm;
			tm = tm->next;

			free_me->next = free_timers;
			free_timers = free_me;
		}
		else
		{
			ref = &tm->next;
			tm = tm->next;
		}
	}
}
Example #7
0
int etimer_cancel(uint64_t ref_id, int64_t *left_ns)
{
	etimer_t **ref = &active_timers;
	etimer_t *tm = active_timers;
	while (tm != 0 && tm->ref_id != ref_id)
	{
		ref = &tm->next;
		tm = tm->next;
	}

	if (tm == 0)
		return -NOT_FOUND;

	*ref = tm->next;

	if (tm->sender != 0)
	{
		assert(tm->sender->pending_timers > 0);
		tm->sender->pending_timers--;
		if (tm->sender->pending_timers == 0 &&
				tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS)
			proc_destroy(tm->sender);	// destroy a zombie process
	}

	*left_ns = tm->timeout - monotonic_clock();

	//printk("*** etimer_cancel: ref_id %ld left_ms %ld\n", tm->ref_id, *left_ns /1000000);

	tm->next = free_timers;
	free_timers = tm;
	return 0;
}
Example #8
0
/*
 * Common code for cmd_prog and cmd_shell.
 *
 * Note that this does not wait for the subprogram to finish, but
 * returns immediately to the menu. This is usually not what you want,
 * so you should have it call your system-calls-assignment waitpid
 * code after forking.
 *
 * Also note that because the subprogram's thread uses the "args"
 * array and strings, until you do this a race condition exists
 * between that code and the menu input code.
 */
static
int
common_prog(int nargs, char **args)
{
	struct proc *proc;
	int result;

	/* Create a process for the new program to run in. */
	proc = proc_create_runprogram(args[0] /* name */);
	if (proc == NULL) {
		return ENOMEM;
	}

	result = thread_fork(args[0] /* thread name */,
			proc /* new process */,
			cmd_progthread /* thread function */,
			args /* thread arg */, nargs /* thread arg */);
	if (result) {
		kprintf("thread_fork failed: %s\n", strerror(result));
		proc_destroy(proc);
		return result;
	}

	/*
	 * The new process will be destroyed when the program exits...
	 * once you write the code for handling that.
	 */

	return 0;
}
Example #9
0
term_t cbif_spawn1(proc_t *proc, term_t *regs)
{
	term_t Fun = regs[0];
	if (!is_boxed(Fun))
		badarg(Fun);
	uint32_t *fdata = peel_boxed(Fun);
	if (boxed_tag(fdata) != SUBTAG_FUN)
		badarg(Fun);
	t_fun_t *f = (t_fun_t *)fdata;
	if (f->fe == 0)
		not_implemented("unloaded funs");
	if (fun_arity(fdata) != fun_num_free(fdata))
		badarg();

	proc_t *new_proc = proc_make(proc->group_leader);
	int x = proc_spawn_fun0_N(new_proc, f);
	if (x < 0)
	{
		proc_destroy(new_proc);
		if (x == -TOO_DEEP)
			fail(A_SYSTEM_LIMIT);
		else
			fail(A_NOT_SPAWNED);
	}

	return new_proc->pid;
}
Example #10
0
void sys__exit(int exitcode) {

  struct addrspace *as;
  struct proc *p = curproc;
  /* for now, just include this to keep the compiler from complaining about
     an unused variable */
  (void)exitcode;

  DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);

  KASSERT(curproc->p_addrspace != NULL);
  as_deactivate();
  /*
   * clear p_addrspace before calling as_destroy. Otherwise if
   * as_destroy sleeps (which is quite possible) when we
   * come back we'll be calling as_activate on a
   * half-destroyed address space. This tends to be
   * messily fatal.
   */
  as = curproc_setas(NULL);
  as_destroy(as);

  /* detach this thread from its process */
  /* note: curproc cannot be used after this call */
  proc_remthread(curthread);

  /* if this is the last user process in the system, proc_destroy()
     will wake up the kernel menu thread */
  proc_destroy(p);
  
  thread_exit();
  /* thread_exit() does not return, so we should never get here */
  panic("return from thread_exit in sys_exit\n");
}
Example #11
0
static void
unhandled_trap(struct hw_trapframe *state, const char* name)
{
	static spinlock_t screwup_lock = SPINLOCK_INITIALIZER;
	spin_lock(&screwup_lock);

	if(in_kernel(state))
	{
		print_trapframe(state);
		panic("Unhandled trap in kernel!\nTrap type: %s", name);
	}
	else
	{
		char tf_buf[1024];
		format_trapframe(state, tf_buf, sizeof(tf_buf));

		warn("Unhandled trap in user!\nTrap type: %s\n%s", name, tf_buf);
		backtrace();
		spin_unlock(&screwup_lock);

		assert(current);
		enable_irq();
		proc_destroy(current);
	}
}
Example #12
0
term_t cbif_spawn_link1(proc_t *proc, term_t *regs)
{
	term_t Fun = regs[0];
	if (!is_boxed(Fun))
		badarg(Fun);
	uint32_t *fdata = peel_boxed(Fun);
	if (boxed_tag(fdata) != SUBTAG_FUN)
		badarg(Fun);
	t_fun_t *f = (t_fun_t *)fdata;
	if (f->fe == 0)
		not_implemented("unloaded funs");

	proc_t *new_proc = proc_make(proc->group_leader);
	int x = proc_spawn_fun0_N(new_proc, f);
	if (x == 0)
		x = inter_link_establish_N(&new_proc->links, proc->pid);
	if (x == 0)
		x = inter_link_establish_N(&proc->links, new_proc->pid);
	if (x < 0)
	{
		proc_destroy(new_proc);
		// no need to unlink, new_proc might have a link to proc but it was destroyed anyway
		if (x == -TOO_DEEP)
			fail(A_SYSTEM_LIMIT);
		else
			fail(A_NOT_SPAWNED);
	}

	return new_proc->pid;
}
Example #13
0
term_t cbif_spawn_monitor1(proc_t *proc, term_t *regs)
{
	term_t Fun = regs[0];
	if (!is_boxed(Fun))
		badarg(Fun);
	uint32_t *fdata = peel_boxed(Fun);
	if (boxed_tag(fdata) != SUBTAG_FUN)
		badarg(Fun);
	t_fun_t *f = (t_fun_t *)fdata;
	if (f->fe == 0)
		not_implemented("unloaded funs");

	term_t ref = heap_make_ref(&proc->hp);

	proc_t *new_proc = proc_make(proc->group_leader);
	int x = proc_spawn_fun0_N(new_proc, f);
	if (x == 0)
	{
		uint64_t ref_id = local_ref_id(ref);
		x = monitor(ref_id, proc->pid, new_proc->pid);
	}
	if (x < 0)
	{
		// no need to demonitor
		proc_destroy(new_proc);

		if (x == -TOO_DEEP)
			fail(A_SYSTEM_LIMIT);
		else
			fail(A_NOT_SPAWNED);
	}

	return heap_tuple2(&proc->hp, new_proc->pid, ref);
}
Example #14
0
term_t cbif_spawn_link3(proc_t *proc, term_t *regs)
{
	term_t m = regs[0];
	term_t f = regs[1];
	term_t args = regs[2];

	if (!is_atom(m))
		badarg(m);
	if (!is_atom(f))
		badarg(f);
	if (!is_list(args))
		badarg(args);

	if (list_len(args) < 0)
		badarg(args); // too odd

	proc_t *new_proc = proc_make(proc->group_leader);
	int x = proc_spawn_N(new_proc, m, f, args);
	if (x == 0)
		x = inter_link_establish_N(&new_proc->links, proc->pid);
	if (x == 0)
		x = inter_link_establish_N(&proc->links, new_proc->pid);
	if (x < 0)
	{
		proc_destroy(new_proc);
		// no need to unlink, new_proc might have a link to proc but it is destroyed anyway
		fail(err_to_term(x));
	}

	return new_proc->pid;
}
Example #15
0
int sys_fork(struct trapframe * tf, pid_t * retval){
	struct trapframe * newtf = kmalloc(sizeof(struct trapframe));
	if (newtf == NULL) {
		return ENOMEM;
	}
	*newtf = *tf;
	// disabling ALL interrupts so we can fork safely
	int spl = splhigh();
	struct proc * child_proc = proc_fork(curproc);
	if (child_proc == NULL) {
		kfree(newtf);
		splx(spl);
		return ENOMEM; 
	}
	int ret = thread_fork(curthread->t_name, child_proc, &forked_child_thread_entry,
	(void*)newtf, (unsigned long)curproc->p_addrspace);
	// can enable interrupts now
	splx(spl); 
	if (ret) {
		proc_destroy(child_proc);
		kfree(newtf);
		return ret;
	}
	*retval = child_proc->pid;
	return(0);
}
Example #16
0
/*
 * Common code for cmd_prog and cmd_shell.
 *
 * Note that this does not wait for the subprogram to finish, but
 * returns immediately to the menu. This is usually not what you want,
 * so you should have it call your system-calls-assignment waitpid
 * code after forking.
 *
 * Also note that because the subprogram's thread uses the "args"
 * array and strings, until you do this a race condition exists
 * between that code and the menu input code.
 */
static
int
common_prog(int nargs, char **args)
{
	struct proc *proc;
	int result;

#if OPT_SYNCHPROBS
	kprintf("Warning: this probably won't work with a "
		"synchronization-problems kernel.\n");
#endif

	/* Create a process for the new program to run in. */
	proc = proc_create_runprogram(args[0] /* name */);
	if (proc == NULL) {
		return ENOMEM;
	}

	result = thread_fork(args[0] /* thread name */,
			proc /* new process */,
			cmd_progthread /* thread function */,
			args /* thread arg */, nargs /* thread arg */);
	if (result) {
		kprintf("thread_fork failed: %s\n", strerror(result));
		proc_destroy(proc);
		return result;
	}

	/*
	 * The new process will be destroyed when the program exits...
	 * once you write the code for handling that.
	 */ 

	return 0;
}
Example #17
0
/*
 * Common code for cmd_prog and cmd_shell.
 *
 * Note that this does not wait for the subprogram to finish, but
 * returns immediately to the menu. This is usually not what you want,
 * so you should have it call your system-calls-assignment waitpid
 * code after forking.
 *
 * Also note that because the subprogram's thread uses the "args"
 * array and strings, until you do this a race condition exists
 * between that code and the menu input code.
 */
static
int
common_prog(int nargs, char **args)
{
	struct proc *proc;
	int result;

#if OPT_SYNCHPROBS
	kprintf("Warning: this probably won't work with a "
		"synchronization-problems kernel.\n");
#endif

	/* Create a process for the new program to run in. */
	proc = proc_create_runprogram(args[0] /* name */);
	if (proc == NULL) {
		return ENOMEM;
	}

        pid_t cpid = 0;
        int error = 0;
        error = proc_getAndCreateNewPid(&cpid);
        if (error)
        {
            proc_destroy(proc);
            return ENPROC;
        }
        proc->pid = cpid;
        proc_exitCodeNotNeeded(cpid);

	result = thread_fork(args[0] /* thread name */,
			proc /* new process */,
			cmd_progthread /* thread function */,
			args /* thread arg */, nargs /* thread arg */);
	if (result) {
		kprintf("thread_fork failed: %s\n", strerror(result));
		proc_destroy(proc);
		return result;
	}

#ifdef UW
	/* wait until the process we have just launched - and any others that it 
	   may fork - is finished before proceeding */
	P(no_proc_sem);
#endif // UW

	return 0;
}
Example #18
0
  /* this needs to be fixed to get exit() and waitpid() working properly */
void sys__exit(int exitcode, int type) {
  struct addrspace *as;
  struct proc *p = curproc;

  DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);
  KASSERT(curproc->p_addrspace != NULL);
  as_deactivate();
  /*
   * clear p_addrspace before calling as_destroy. Otherwise if
   * as_destroy sleeps (which is quite possible) when we
   * come back we'll be calling as_activate on a
   * half-destroyed address space. This tends to be
   * messily fatal.
   */
  as = curproc_setas(NULL);
  as_destroy(as);


  lock_acquire(p->proc_exit_lock);

 
 if(!p->proc_parent_exited && p->pid > 1){
	

	// Parent didnt exit yet, so we must only semi-destroy the proc
	proc_set_exit_status(p,exitcode, type);

	
	cv_broadcast(p->proc_exit_cv, p->proc_exit_lock);


	proc_exited_signal(p);
        /* detach this thread from its process */
        /* note: curproc cannot be used after this call */


        proc_remthread(curthread);
	// semi_destroy will release the proc_exit_lock for us.


	proc_semi_destroy(p);


 	lock_release(p->proc_exit_lock);
  }else{
	proc_exited_signal(p);
	lock_release(p->proc_exit_lock);
  	/* detach this thread from its process */
  	/* note: curproc cannot be used after this call */
	proc_remthread(curthread);
	/* if this is the last user process in the system, proc_destroy()
        will wake up the kernel menu thread */
	proc_destroy(p);
  }
  thread_exit();
  /* thread_exit() does not return, so we should never get here */
  panic("return from thread_exit in sys_exit\n");
}
Example #19
0
void scheduler_exit_process(proc_t *proc, term_t reason)
{
	assert(proc->my_queue == MY_QUEUE_NONE);

//	if (reason != A_NORMAL || proc->name == A_INIT)
//	{
//		if (proc->name == noval)
//			printk("*** Process %pt exits: %pt\n",
//				   			T(proc->pid), T(reason));
//		else
//			printk("*** Process %pt (%pt) exits: %pt\n",
//				   			T(proc->pid), T(proc->name), T(reason));
//	}

	// init calls halt() rather then exits normally
	assert(proc->name != A_INIT);

	//
	// Remove/unfix ETS table(s)
	//
	// NB: must precede monitor and link notifications
	//
	ets_process_exits(proc->pid);

	// Notify monitoring processes
	//
	int x = notify_monitors_N(proc->pid, reason);
	if (x < 0)
		printk("scheduler_exit_process: monitoring message(s)"
					" not delivered: pid %pt reason %pt\n", T(proc->pid), T(reason));

	// Cancel timers that are known to have proc->pid as their destination
	//
	etimer_cancel_by_receiver(proc->pid);

	//
	// Notify linked processes/outlets
	//
	inter_links_notify(&proc->links, proc->pid, reason);

	if (proc->name != noval)
		scheduler_unregister(proc);

	hash_set_N(registry, &proc->pid, sizeof(proc->pid), 0);	// never fails

	if (proc->pending_timers == 0)
		proc_destroy(proc);
	else
	{
		// The process is entering a 'zombie' state. There are pending timers
		// that have references to the process heap and thus the process heap
		// can not be released now. The process gets destroyed later, when the
		// last pending timer is fired or cancelled.
		proc->my_queue = MY_QUEUE_PENDING_TIMERS;
	}
}
Example #20
0
/*
void free_root(struct procinfo* pi){
  KASSERT(pi != NULL);
  if (pi->parent_pid == -1){
    array_set(proc)
  }
  
}*/
void sys__exit(int exitcode) {

  struct addrspace *as;
  struct proc *p = curproc;
  /* for now, just include this to keep the compiler from complaining about
     an unused variable */
  #if OPT_A2
  
  struct procinfo *pi = array_get(procinfotable, p->pid-1);
  
  if(pi == NULL){
    goto parentexited;
  }

  lock_acquire(p->p_waitpid_lock);
  
  pi->exit_code = _MKWAIT_EXIT(exitcode);
  pi->active = 0;
  cv_broadcast(pi->waitpid_cv,p->p_waitpid_lock);

  lock_release(p->p_waitpid_lock);

  free_children(p->pid);
  
parentexited:  
  #else

  (void)exitcode;

  #endif
  DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);

  KASSERT(curproc->p_addrspace != NULL);
  as_deactivate();
  /*
   * clear p_addrspace before calling as_destroy. Otherwise if
   * as_destroy sleeps (which is quite possible) when we
   * come back we'll be calling as_activate on a
   * half-destroyed address space. This tends to be
   * messily fatal.
   */
  as = curproc_setas(NULL);
  as_destroy(as);

  /* detach this thread from its process */
  /* note: curproc cannot be used after this call */
  proc_remthread(curthread);

  /* if this is the last user process in the system, proc_destroy()
     will wake up the kernel menu thread */
  proc_destroy(p);
  
  thread_exit();
  /* thread_exit() does not return, so we should never get here */
  panic("return from thread_exit in sys_exit\n");
}
Example #21
0
static int erlang_fire(etimer_t *tm)
{
	proc_t *to_proc = (is_atom(tm->dst))
		?scheduler_process_by_name(tm->dst)
		:scheduler_lookup(tm->dst);

	int rc = 0;
	if (to_proc != 0)
	{
		term_t marsh_msg = tm->msg;
		if (tm->sender != to_proc)	// tm->sender may be zero
		{
			rc = heap_copy_terms_N(&to_proc->hp, &marsh_msg, 1);
			if (rc < 0)
				goto error;
		}

		term_t env_msg = marsh_msg;	// {timeout,TRef,Msg} or Msg
		if (tm->enveloped)
		{
			term_t tref = heap_remake_local_ref_N(&to_proc->hp, tm->ref_id);
			if (tref == noval)
			{
				rc = -NO_MEMORY;
				goto error;
			}

			uint32_t *htop = heap_alloc_N(&to_proc->hp, 1 +3);
			if (htop == 0)
			{
				rc = -NO_MEMORY;
				goto error;
			}
			heap_set_top(&to_proc->hp, htop +1 +3);
			env_msg = tag_tuple(htop);
			htop[0] = 3;
			htop[1] = A_TIMEOUT;
			htop[2] = tref;
			htop[3] = marsh_msg;
		}

		rc = scheduler_new_local_mail_N(to_proc, env_msg);
	}

error:
	if (tm->sender != 0)
	{
		assert(tm->sender->pending_timers > 0);
		tm->sender->pending_timers--;
		if (tm->sender->pending_timers == 0 &&
				tm->sender->my_queue == MY_QUEUE_PENDING_TIMERS)
			proc_destroy(tm->sender);	// destroy a zombie process
	}

	return rc;
}
Example #22
0
int sys_waitpid(pid_t pid, userptr_t returncode, int flags, pid_t *retval) {
	(void) pid;
	(void) returncode;
	(void) flags;
	(void) retval;
	int *test = kmalloc(sizeof(int));
	int result;

	// TODO: a lot of sanity checks for this one.
	if (pid < 1 || pid > PID_MAX){
		return ESRCH;
	}
	if (pid == curproc->pid) {
		return ECHILD;
	}
	if (flags != 0 && flags != WNOHANG) {
		return EINVAL;
	}

	if (returncode != NULL) {
		result = copyin(returncode, test, sizeof(int));
		if (result) {
			return result;
		}
	}

	// TODO: what's the _MKWAIT_EXIT stuff?
	lock_acquire(proc_table_lock);
	struct proc *child = proc_table[pid];

	if (child == NULL) {
		lock_release(proc_table_lock);
		return ESRCH;
	}

	if (child->parent_pid != curproc->pid) {
		lock_release(proc_table_lock);
		return ECHILD;
	}

	if (!child->exited) {
		// We always wait on the child's cv
		cv_wait(child->waitpid_cv, proc_table_lock);
		KASSERT(child->exited);
	}

	if (returncode != NULL) {
		// Give back returncode
		copyout(&child->exitcode, returncode, sizeof(int));
	}
	*retval = pid;
	proc_destroy(child);
	lock_release(proc_table_lock);
	return 0;
}
int
sys_waitpid (pid_t pid, int *status, int options, int32_t *retval)
{
    int result, p_status;
    struct proc *p_child;

    KASSERT (curproc != NULL);

    result = 0;
    *retval = -1;

    result = get_proc(pid, &p_child);
    if (result)
        return result;

    if (curproc != p_child->parent)
        return ECHILD;

    /* filter out supported options */
    switch (options) {
        case 0:
        case WNOHANG:
        // case WUNTRACED:
        break;
        default:
            return EINVAL;
    }

    if ((options == WNOHANG) && !p_child->exited) {
        *retval = 0;
        return result;
    }

    if (status != NULL && (!as_is_addr_valid(curproc->p_addrspace, (vaddr_t) status)))
        return EFAULT;

    if (!p_child->exited)
        P(p_child->exit_sem);

    KASSERT (p_child->exited);

    p_status = p_child->exit_status;

    if (status) {
        result = copyout((const void *) &p_status, (userptr_t) status, sizeof(int));
        if (result)
            return result;
    }

    proc_destroy(p_child);

    *retval = pid;

    return 0;
}
Example #24
0
term_t bif_destroy_process1(term_t Pid, process_t *ctx)
{
	process_t *proc;
	if (!is_pid(Pid))
		return A_BADARG;
	proc = proc_lookup(pid_serial(Pid));
	if (proc)
		proc_destroy(proc);
	result(A_TRUE);
	return AI_OK;
}
Example #25
0
void proctable_remove_process(struct proc *proc_removed) {
  KASSERT(proc_removed != NULL);

  int pid = getPID(proc_removed);
  procarray_set(procTable, pid, NULL);
  procCount--;

  /* if this is the last user process in the system, proc_destroy()
     will wake up the kernel menu thread */
  proc_destroy(proc_removed);
}
Example #26
0
void sys__exit(int exitcode) {
	(void) exitcode;

	lock_acquire(proc_table_lock);

	// orphan all children, should be done no matter what
	for (int i = 0; i < PID_MAX; i++) {
		// Found a children
		if (proc_table[i] != NULL && proc_table[i]->parent_pid == curproc->pid) {
			proc_table[i]->parent_pid = INVALID_PID;
			// weird case, parent doesn't wait, but exited later
			if (proc_table[i]->exited) {
				proc_destroy(proc_table[i]);
			}
		}
	}

	// set exitcode stuff is probably unnecessary for orphan
	if (curproc->parent_pid == INVALID_PID) {
		// Parent is dead, suicide
		proc_destroy(curproc);
	} else {
		// do fancy shit and don't destroy itself
		// it should be destroyed by parent in waitpid

		// TODO: This is probably not a good design
		curproc->exited = true;
		curproc->exitcode = _MKWAIT_EXIT(exitcode);
		// Wake up parent
		cv_signal(curproc->waitpid_cv, proc_table_lock);
	}

	lock_release(proc_table_lock);
	// kfree(curproc);
	thread_exit();
}
Example #27
0
/*
 * Common code for cmd_prog and cmd_shell.
 *
 * Note that this does not wait for the subprogram to finish, but
 * returns immediately to the menu. This is usually not what you want,
 * so you should have it call your system-calls-assignment waitpid
 * code after forking.
 *
 * Also note that because the subprogram's thread uses the "args"
 * array and strings, until you do this a race condition exists
 * between that code and the menu input code.
 */
static
int
common_prog(int nargs, char **args)
{
	struct proc *proc;
	int result;
	int status;
	int retval;
	unsigned tc;

	/* Create a process for the new program to run in. */
	proc = proc_create_runprogram(args[0] /* name */);
	if (proc == NULL) {
		return ENOMEM;
	}

	tc = thread_count;

	result = thread_fork(args[0] /* thread name */,
			proc /* new process */,
			cmd_progthread /* thread function */,
			args /* thread arg */, nargs /* thread arg */);



	if (result) {
		kprintf("thread_fork failed: %s\n", strerror(result));
		proc_destroy(proc);
		return result;
	}
	result = sys_waitpid(proc->pid, &status, 0 , &retval);
	if (result ) {
		kprintf_n("sys_waitpid done with result %d for pid %d \n",result,proc->pid );
		//return 0;
	}

	/*
	 * The new process will be destroyed when the program exits...
	 * once you write the code for handling that.
	 */

	// Wait for all threads to finish cleanup, otherwise khu be a bit behind,
	// especially once swapping is enabled.
	thread_wait_for_count(tc);

	return 0;
}
Example #28
0
void sys__exit(int exitcode) {
  struct addrspace *as;
  struct proc *p = curproc;
#if OPT_A2
  int pid = (int)curproc->pid;
  struct proc_entry *entry = process_table[pid];
  lock_acquire(entry->exit_mutex);
  process_table[pid]->exited = 1;
  process_table[pid]->exitcode = exitcode;
  //if(lock_do_i_hold(entry->exit_mutex))
  cv_signal(entry->exit_wait, entry->exit_mutex);
  lock_release(entry->exit_mutex);



#else
  /* for now, just include this to keep the compiler from complaining about
     an unused variable */
  (void)exitcode;
#endif
  kprintf("is exiting: %d\n", pid);
  DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);

  KASSERT(curproc->p_addrspace != NULL);
  as_deactivate();
  /*
   * clear p_addrspace before calling as_destroy. Otherwise if
   * as_destroy sleeps (which is quite possible) when we
   * come back we'll be calling as_activate on a
   * half-destroyed address space. This tends to be
   * messily fatal.
   */
  as = curproc_setas(NULL);
  as_destroy(as);

  /* detach this thread from its process */
  /* note: curproc cannot be used after this call */
  proc_remthread(curthread);

  /* if this is the last user process in the system, proc_destroy()
     will wake up the kernel menu thread */
  proc_destroy(p);
  
  thread_exit();
  /* thread_exit() does not return, so we should never get here */
  panic("return from thread_exit in sys_exit\n");
}
Example #29
0
/**
   Main test 
*/
int main( int argc, char **argv )
{
	setlocale( LC_ALL, "" );
	srand( time( 0 ) );

	program_name=L"(ignore)";
	
	say( L"Testing low-level functionality");
	say( L"Lines beginning with '(ignore):' are not errors, they are warning messages\ngenerated by the fish parser library when given broken input, and can be\nignored. All actual errors begin with 'Error:'." );

	proc_init();	
	halloc_util_init();
	event_init();	
	parser_init();
	function_init();
	builtin_init();
	reader_init();
	env_init();

	test_util();
	test_escape();
	test_convert();
	test_tok();
	test_parser();
	test_expand();
	test_path();
	
	say( L"Encountered %d errors in low-level tests", err_count );

	/*
	  Skip performance tests for now, since they seem to hang when running from inside make (?)
	*/
//	say( L"Testing performance" );
//	perf_complete();
		
	env_destroy();
	reader_destroy();	
	parser_destroy();
	function_destroy();
	builtin_destroy();
	wutil_destroy();
	event_destroy();
	proc_destroy();
	halloc_util_destroy();
	
}
int sys_waitpid(pid_t pid, userptr_t status, int options, int *retval) {
    (void) options;
    int result;

    /* Arguments Error Handling */

    struct proc* waitproc = get_proc_pid(pid);
    if(waitproc == NULL) {
        return ESRCH;
    }
    // check if status pointer is aligned by 4 bytes
    if((uintptr_t)(const void *)(status) % 4 != 0) {
        return EFAULT;
    }

    // check for badflags
    if(options != 0) {
        return EINVAL;
    }

    if(pid == curthread->t_proc->pid || pid == curthread->t_proc->ppid) {
        return ECHILD;
    }

    if(curthread->t_proc->pid != waitproc->ppid) {
        return ECHILD;
    }
    
    if(waitproc->exited == false)
        P(waitproc->p_exitsem);
    if((int *) status != NULL) {
        result = copyout((const void *) &(waitproc->exitcode), status, sizeof(int));
        if(result)
            //V(waitproc->p_exitsem);
            return EFAULT;
    }
    dealloc_pid(waitproc);
//    kprintf("********************** destroying process - %d \n", dealloc_pid(waitproc));
    proc_destroy(waitproc);
    *retval = pid;
    return 0;
}