Exemple #1
0
void
interrupt(registers_t *reg)
{
	// The processor responds to a system call interrupt by saving some of
	// the application's state on the kernel's stack, then jumping to
	// kernel assembly code (in mpos-int.S, for your information).
	// That code saves more registers on the kernel's stack, then calls
	// interrupt().  The first thing we must do, then, is copy the saved
	// registers into the 'current' process descriptor.
	current->p_registers = *reg;

	switch (reg->reg_intno) {

	case INT_SYS_GETPID:
		// The 'sys_getpid' system call returns the current
		// process's process ID.  System calls return results to user
		// code by putting those results in a register.  Like Linux,
		// we use %eax for system call return values.  The code is
		// surprisingly simple:
		current->p_registers.reg_eax = current->p_pid;
		run(current);

	case INT_SYS_FORK:
		// The 'sys_fork' system call should create a new process.
		// You will have to complete the do_fork() function!
		current->p_registers.reg_eax = do_fork(current);
		run(current);

	case INT_SYS_YIELD:
		// The 'sys_yield' system call asks the kernel to schedule a
		// different process.  (MiniprocOS is cooperatively
		// scheduled, so we need a special system call to do this.)
		// The schedule() function picks another process and runs it.
		schedule();

	case INT_SYS_EXIT:
		// 'sys_exit' exits the current process, which is marked as
		// non-runnable.
		// The process stored its exit status in the %eax register
		// before calling the system call.  The %eax REGISTER has
		// changed by now, but we can read the APPLICATION's setting
		// for this register out of 'current->p_registers'.
        current->p_exit_status = current->p_registers.reg_eax;
        if (current->p_waitqueue > 0) {
            proc_array[current->p_waitqueue].p_registers.reg_eax = current->p_exit_status;
            proc_array[current->p_waitqueue].p_state = P_RUNNABLE;
        }
        current->p_state = P_EMPTY;
		schedule();
            
    case INT_SYS_NEWTHREAD:
        // system call to sys_newthread; starts with an empty stack, starts by executing the start_function (the function's address becomes the new thread's instruction pointer)
            current->p_registers.reg_eax = do_newthread(current, current->p_registers.reg_eax);
            run(current);
            

	case INT_SYS_WAIT: {
		// 'sys_wait' is called to retrieve a process's exit status.
		// It's an error to call sys_wait for:
		// * A process ID that's out of range (<= 0 or >= NPROCS).
		// * The current process.
		// * A process that doesn't exist (p_state == P_EMPTY).
		// (In the Unix operating system, only process P's parent
		// can call sys_wait(P).  In MiniprocOS, we allow ANY
		// process to call sys_wait(P).)

		pid_t p = current->p_registers.reg_eax;
		if (p <= 0 || p >= NPROCS || p == current->p_pid
		    || proc_array[p].p_state == P_EMPTY)
			current->p_registers.reg_eax = -1;
		else if (proc_array[p].p_state == P_ZOMBIE)
			current->p_registers.reg_eax = proc_array[p].p_exit_status;
		else {
            proc_array[p].p_waitqueue = current->p_pid;
            current->p_state = P_BLOCKED;
        }
		schedule();
	}

	default:
		while (1)
			/* do nothing */;

	}
}
Exemple #2
0
void
interrupt(registers_t *reg)
{
	// The processor responds to a system call interrupt by saving some of
	// the application's state on the kernel's stack, then jumping to
	// kernel assembly code (in mpos-int.S, for your information).
	// That code saves more registers on the kernel's stack, then calls
	// interrupt().  The first thing we must do, then, is copy the saved
	// registers into the 'current' process descriptor.
	current->p_registers = *reg;

	switch (reg->reg_intno) {

	case INT_SYS_GETPID:
		// The 'sys_getpid' system call returns the current
		// process's process ID.  System calls return results to user
		// code by putting those results in a register.  Like Linux,
		// we use %eax for system call return values.  The code is
		// surprisingly simple:
		current->p_registers.reg_eax = current->p_pid;
		run(current);

	case INT_SYS_FORK:
		// The 'sys_fork' system call should create a new process.
		// You will have to complete the do_fork() function!
		current->p_registers.reg_eax = do_fork(current);
		run(current);
		
	case INT_SYS_NEWTHREAD:
		// The 'sys_newthread' system call creates a new thread process, which 
		// shares the same space as the calling process. The thread begins 
		// executing the start_function. Returns the child thread's process id.
		current->p_registers.reg_eax = do_newthread(current, current->p_registers.reg_eax);
		run(current);

	case INT_SYS_YIELD:
		// The 'sys_yield' system call asks the kernel to schedule a
		// different process.  (MiniprocOS is cooperatively
		// scheduled, so we need a special system call to do this.)
		// The schedule() function picks another process and runs it.
		schedule();

	case INT_SYS_EXIT:
		// 'sys_exit' exits the current process, which is marked as
		// non-runnable.
		// The process stored its exit status in the %eax register
		// before calling the system call.  The %eax REGISTER has
		// changed by now, but we can read the APPLICATION's setting
		// for this register out of 'current->p_registers'.
		current->p_state = P_ZOMBIE;
		current->p_exit_status = current->p_registers.reg_eax;
		
		if (current->p_waiting != NULL)	// wake any sleeping processes
		{
			current->p_waiting->p_state = P_RUNNABLE;
			current->p_waiting->p_registers.reg_eax = current->p_exit_status;
			current->p_state = P_EMPTY;	// free completed process
		}
		
		schedule();
		
	case INT_SYS_KILL: {
		// 'sys_kill' forces a process to exit. It's an error to call sys_kill 
		// for an out-of-range PID, the current process, a process that doesn't 
		// exist or is dead. Returns 0 if successful, -1 if not.

		pid_t p = current->p_registers.reg_eax;		
		process_t* target = &proc_array[p];
		
		if (p <= 0 || p >= NPROCS || p == current->p_pid
		    || proc_array[p].p_state == P_EMPTY)
			current->p_registers.reg_eax = -1;
		else if (target->p_state != P_ZOMBIE)// perform exit operations
		{
			target->p_state = P_ZOMBIE;
			target->p_exit_status = -1;
			
			if (target->p_waiting != NULL)	// wake any sleeping processes
			{
				target->p_waiting->p_state = P_RUNNABLE;
				target->p_waiting->p_registers.reg_eax = target->p_exit_status;
				target->p_state = P_EMPTY;	// free completed process
			}
			
			current->p_registers.reg_eax = 0; // successful, return 0
		}
		else // process already exited
			current->p_registers.reg_eax = 0;
		
		run(current);
	}

	case INT_SYS_WAIT: {
		// 'sys_wait' is called to retrieve a process's exit status.
		// It's an error to call sys_wait for:
		// * A process ID that's out of range (<= 0 or >= NPROCS).
		// * The current process.
		// * A process that doesn't exist (p_state == P_EMPTY).
		// (In the Unix operating system, only process P's parent
		// can call sys_wait(P).  In MiniprocOS, we allow ANY
		// process to call sys_wait(P).)

		pid_t p = current->p_registers.reg_eax;
		if (p <= 0 || p >= NPROCS || p == current->p_pid
		    || proc_array[p].p_state == P_EMPTY)
			current->p_registers.reg_eax = -1;
		else if (proc_array[p].p_state == P_ZOMBIE)
		{
			current->p_registers.reg_eax = proc_array[p].p_exit_status;
			proc_array[p].p_state = P_EMPTY;	// free zombie process
		}
		else
		{
			proc_array[p].p_waiting = current;	// add calling process to wait queue
			current->p_state = P_BLOCKED;		// put calling process to sleep
		}
		schedule();
	}

	default:
		while (1)
			/* do nothing */;

	}
}