Ejemplo n.º 1
0
void proctable_exit_process(struct proc *proc_exited, int exitcode) {
  // DEBUG(DB_EXEC, "Exiting PID: %d from proctable\n", getPID(proc_exited));

  KASSERT(proc_exited != NULL);
  KASSERT(proc_exited->p_pid > 0);

  // set the process state to exited
  setState(proc_exited, PROC_EXITED);

  // encode the exit code as per the docs.
  setExitcode(proc_exited, _MKWAIT_EXIT(exitcode));

  // Next we need to evaluate some cases:
  // If proc_exited has living children, they should now have a NULL parent.
  // If proc_exited has dead children, they should now be destroyed.

  int exitedPID = getPID(proc_exited);

  // Find the children of proc_exited.
  for (int i = MIN_PID; i < pidLimit; i++) {
    struct proc* cur = procarray_get(procTable, i);
    if (cur != NULL && getPPID(cur) == exitedPID) {
      // Check state of child
      int state = getState(cur);
      
      // A running child has its parent set to NULL
      if (state == PROC_RUNNING) {
        setPPID(cur, PROC_NO_PID);
      }

      // An exited child can now be completely removed.
      else if (state == PROC_EXITED) {
        proctable_remove_process(cur);
      }
    }
  }

  // If proc_exited has no parent, it can be removed
  if (getPPID(proc_exited) == PROC_NO_PID) {
    proctable_remove_process(proc_exited);
  }

  // Otherwise if proc_exited has a parent
  // then proc_exited must wake its potentially waiting parent
  else {
    cv_signal(proc_exited->wait_cv, procTableLock);
  }
}
Ejemplo n.º 2
0
/*
 * Function called when user-level code hits a fatal fault.
 */
static
void
kill_curthread(u_int32_t epc, unsigned code, u_int32_t vaddr)
{
	assert(code<NTRAPCODES);
	kprintf("Fatal user mode trap %u (%s, epc 0x%x, vaddr 0x%x)\n",
		code, trapcodenames[code], epc, vaddr);

	#if OPT_A2
	fdtable_destroy();
	int result = proctable_remove_process(curthread->t_process->pid);
	// If there's an error in the above line, who cares. We're exiting the thread anyway.
	(void)result;
	thread_exit();
	#else
	panic("I don't know how to handle this\n");
	#endif /* OPT_A2 */
}
Ejemplo n.º 3
0
/*
This process wants to exit.
Need to clean up the process structure and the thread structure.

Does the process have a parent?
	If no, then what?
		then there are no threads waiting for it with waitpid. The parent must have exited, or it never had a parent.
		Since only parents are allowed to wait on children, then we can safely remove the process entirely.
			1) Give up the PID
			2) Forget the process entirely
	If yes, then what?
		then, we check if that parent is still running, or if it exited. 
		If it's running, there CAN be some processes waiting for this thread to finish. Since it has a parent, and parents need to always be able to get the exit code with waitpid,
		we must exit the process, clean it up, but leave a memory of it in the process table.
		If the parent is exited, then we do same thing as if it had no parent, because the exited parent will never wait for it's child.

Either way, we notify the "waiting" threads that are waiting for this process to end with a waitpid call.
All waitpid calls should wait for the thread to exit on a CV for that thread. The exiting process should broadcast to all threads on this CV.
*/
int sys__exit(int exitcode) 
{
	lock_acquire(proctable_lock);
	struct cv *waitpid_cv = curthread->t_process->waitpid_cv;
	
	fdtable_destroy();
	if (curthread->t_process->parent == NULL) {
		(void)exitcode;
		int result = proctable_remove_process(curthread->t_process->pid);
		// We're already exiting, so if there's an error with the line above, then it doesn't matter that much
		(void)result;
	} else {
		int result = proctable_set_process_exited(curthread->t_process->pid, exitcode);
		// We're already exiting, so if there's an error with the line above, then it doesn't matter that much
		(void)result;
	}

	// Notify the waiting threads that this process has exited
	cv_signal(waitpid_cv, proctable_lock);
	cv_destroy(waitpid_cv);
	lock_release(proctable_lock);
  	thread_exit(); // When thread exits, make sure it DOESN'T kfree the process, because it may still be needed. Instead, kfree the process in the process table
	return 0;
}
Ejemplo n.º 4
0
// The parent copies the appropriate data from itself to its child in this function
void start_child(void * data1, unsigned long unused) {
	(void)unused;
	struct fork_info * info = data1;
	struct addrspace * new_as;
	struct trapframe new_tf;

	/* copy address space */
	if (as_copy(info->parent->t_vmspace, &new_as)) {
		info->child_pid = ENOMEM; // Means no memory for process
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}
	curthread->t_vmspace = new_as;
	as_activate(new_as);

	/* copy trap frame to new curkstack */
	memcpy(&new_tf, info->tf, sizeof(struct trapframe));
	/* change tf's registers to return values for syscall */
	new_tf.tf_v0 = 0;
	new_tf.tf_a3 = 0;
	new_tf.tf_epc += 4;

	/* create process and get the pid */
	struct process *new_process = proctable_add_child_process(curthread->t_process);
	if (new_process == NULL) {
		info->child_pid = EAGAIN; // Means no more processes available in process table
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}
	info->child_pid = new_process->pid;
	new_process->parent = info->parent->t_process;

	// Attach new process to our thread
	curthread->t_process = new_process;

	// Initalize new file table
	int result = fdtable_create();
	if (result) 
	{
		// Error occured
		info->child_pid = result;
		result = proctable_remove_process(new_process->pid);
		// We're already exiting, so if there's an error with the line above, then it doesn't matter that much
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}

	struct process * parent_process = info->parent->t_process;
	lock_acquire(parent_process->t_fdtable_lock);

	// Copy file table
	// This requires the filetable to be locked and the refcounts of each file to be increased.
	int i;
	for (i = 0; i < OPEN_MAX ; i++) {
		new_process->t_fdtable->entries[i] = parent_process->t_fdtable->entries[i];
		if (new_process->t_fdtable->entries[i] != NULL) new_process->t_fdtable->entries[i]->refcount++;	// Increases the number of references to a file
	}
	lock_release(parent_process->t_fdtable_lock);

	// child is done, parent should resume.
	V(info->sem);

	mips_usermode(&new_tf);

	/* mips_usermode does not return */
	panic("start_child returned\n");
}