diff options
| author | klaar36 <klas.arvidsson@liu.se> | 2015-03-20 17:30:24 +0100 |
|---|---|---|
| committer | klaar36 <klas.arvidsson@liu.se> | 2015-03-20 17:30:24 +0100 |
| commit | e7bc50ca8ffcaa6ed68ebd2315f78b0f5a7d10ad (patch) | |
| tree | 4de97af7207676b69cb6a9aba8cb443cc134855d /src/userprog/process.c | |
| parent | b0418a24e709f0632d2ede5b0f327c422931939b (diff) | |
| download | pintos-rs-e7bc50ca8ffcaa6ed68ebd2315f78b0f5a7d10ad.tar.gz | |
Initial Pintos
Diffstat (limited to 'src/userprog/process.c')
| -rw-r--r-- | src/userprog/process.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/src/userprog/process.c b/src/userprog/process.c new file mode 100644 index 0000000..7df8778 --- /dev/null +++ b/src/userprog/process.c @@ -0,0 +1,275 @@ +#include <debug.h> +#include <stdio.h> +#include <string.h> + +#include "userprog/gdt.h" /* SEL_* constants */ +#include "userprog/process.h" +#include "userprog/load.h" +#include "userprog/pagedir.h" /* pagedir_activate etc. */ +#include "userprog/tss.h" /* tss_update */ +#include "filesys/file.h" +#include "threads/flags.h" /* FLAG_* constants */ +#include "threads/thread.h" +#include "threads/vaddr.h" /* PHYS_BASE */ +#include "threads/interrupt.h" /* if_ */ + +/* Headers not yet used that you may need for various reasons. */ +#include "threads/synch.h" +#include "threads/malloc.h" +#include "lib/kernel/list.h" + +#include "userprog/flist.h" +#include "userprog/plist.h" + +/* HACK defines code you must remove and implement in a proper way */ +#define HACK + + +/* This function is called at boot time (threads/init.c) to initialize + * the process subsystem. */ +void process_init(void) +{ +} + +/* This function is currently never called. As thread_exit does not + * have an exit status parameter, this could be used to handle that + * instead. Note however that all cleanup after a process must be done + * in process_cleanup, and that process_cleanup are already called + * from thread_exit - do not call cleanup twice! */ +void process_exit(int status UNUSED) +{ +} + +/* Print a list of all running processes. The list shall include all + * relevant debug information in a clean, readable format. */ +void process_print_list() +{ +} + + +struct parameters_to_start_process +{ + char* command_line; +}; + +static void +start_process(struct parameters_to_start_process* parameters) NO_RETURN; + +/* Starts a new proccess by creating a new thread to run it. The + process is loaded from the file specified in the COMMAND_LINE and + started with the arguments on the COMMAND_LINE. The new thread may + be scheduled (and may even exit) before process_execute() returns. + Returns the new process's thread id, or TID_ERROR if the thread + cannot be created. */ +int +process_execute (const char *command_line) +{ + char debug_name[64]; + int command_line_size = strlen(command_line) + 1; + tid_t thread_id = -1; + int process_id = -1; + + /* LOCAL variable will cease existence when function return! */ + struct parameters_to_start_process arguments; + + debug("%s#%d: process_execute(\"%s\") ENTERED\n", + thread_current()->name, + thread_current()->tid, + command_line); + + /* COPY command line out of parent process memory */ + arguments.command_line = malloc(command_line_size); + strlcpy(arguments.command_line, command_line, command_line_size); + + + strlcpy_first_word (debug_name, command_line, 64); + + /* SCHEDULES function `start_process' to run (LATER) */ + thread_id = thread_create (debug_name, PRI_DEFAULT, + (thread_func*)start_process, &arguments); + + process_id = thread_id; + + /* AVOID bad stuff by turning off. YOU will fix this! */ + power_off(); + + + /* WHICH thread may still be using this right now? */ + free(arguments.command_line); + + debug("%s#%d: process_execute(\"%s\") RETURNS %d\n", + thread_current()->name, + thread_current()->tid, + command_line, process_id); + + /* MUST be -1 if `load' in `start_process' return false */ + return process_id; +} + +/* A thread function that loads a user process and starts it + running. */ +static void +start_process (struct parameters_to_start_process* parameters) +{ + /* The last argument passed to thread_create is received here... */ + struct intr_frame if_; + bool success; + + char file_name[64]; + strlcpy_first_word (file_name, parameters->command_line, 64); + + debug("%s#%d: start_process(\"%s\") ENTERED\n", + thread_current()->name, + thread_current()->tid, + parameters->command_line); + + /* Initialize interrupt frame and load executable. */ + memset (&if_, 0, sizeof if_); + if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG; + if_.cs = SEL_UCSEG; + if_.eflags = FLAG_IF | FLAG_MBS; + + success = load (file_name, &if_.eip, &if_.esp); + + debug("%s#%d: start_process(...): load returned %d\n", + thread_current()->name, + thread_current()->tid, + success); + + if (success) + { + /* We managed to load the new program to a process, and have + allocated memory for a process stack. The stack top is in + if_.esp, now we must prepare and place the arguments to main on + the stack. */ + + /* A temporary solution is to modify the stack pointer to + "pretend" the arguments are present on the stack. A normal + C-function expects the stack to contain, in order, the return + address, the first argument, the second argument etc. */ + + HACK if_.esp -= 12; /* Unacceptable solution. */ + + /* The stack and stack pointer should be setup correct just before + the process start, so this is the place to dump stack content + for debug purposes. Disable the dump when it works. */ + +// dump_stack ( PHYS_BASE + 15, PHYS_BASE - if_.esp + 16 ); + + } + + debug("%s#%d: start_process(\"%s\") DONE\n", + thread_current()->name, + thread_current()->tid, + parameters->command_line); + + + /* If load fail, quit. Load may fail for several reasons. + Some simple examples: + - File doeas not exist + - File do not contain a valid program + - Not enough memory + */ + if ( ! success ) + { + thread_exit (); + } + + /* Start the user process by simulating a return from an interrupt, + implemented by intr_exit (in threads/intr-stubs.S). Because + intr_exit takes all of its arguments on the stack in the form of + a `struct intr_frame', we just point the stack pointer (%esp) to + our stack frame and jump to it. */ + asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory"); + NOT_REACHED (); +} + +/* Wait for process `child_id' to die and then return its exit + status. If it was terminated by the kernel (i.e. killed due to an + exception), return -1. If `child_id' is invalid or if it was not a + child of the calling process, or if process_wait() has already been + successfully called for the given `child_id', return -1 + immediately, without waiting. + + This function will be implemented last, after a communication + mechanism between parent and child is established. */ +int +process_wait (int child_id) +{ + int status = -1; + struct thread *cur = thread_current (); + + debug("%s#%d: process_wait(%d) ENTERED\n", + cur->name, cur->tid, child_id); + /* Yes! You need to do something good here ! */ + debug("%s#%d: process_wait(%d) RETURNS %d\n", + cur->name, cur->tid, child_id, status); + + return status; +} + +/* Free the current process's resources. This function is called + automatically from thread_exit() to make sure cleanup of any + process resources is always done. That is correct behaviour. But + know that thread_exit() is called at many places inside the kernel, + mostly in case of some unrecoverable error in a thread. + + In such case it may happen that some data is not yet available, or + initialized. You must make sure that nay data needed IS available + or initialized to something sane, or else that any such situation + is detected. +*/ + +void +process_cleanup (void) +{ + struct thread *cur = thread_current (); + uint32_t *pd = cur->pagedir; + int status = -1; + + debug("%s#%d: process_cleanup() ENTERED\n", cur->name, cur->tid); + + /* Later tests DEPEND on this output to work correct. You will have + * to find the actual exit status in your process list. It is + * important to do this printf BEFORE you tell the parent process + * that you exit. (Since the parent may be the main() function, + * that may sometimes poweroff as soon as process_wait() returns, + * possibly before the prontf is completed.) + */ + printf("%s: exit(%d)\n", thread_name(), status); + + /* Destroy the current process's page directory and switch back + to the kernel-only page directory. */ + if (pd != NULL) + { + /* Correct ordering here is crucial. We must set + cur->pagedir to NULL before switching page directories, + so that a timer interrupt can't switch back to the + process page directory. We must activate the base page + directory before destroying the process's page + directory, or our active page directory will be one + that's been freed (and cleared). */ + cur->pagedir = NULL; + pagedir_activate (NULL); + pagedir_destroy (pd); + } + debug("%s#%d: process_cleanup() DONE with status %d\n", + cur->name, cur->tid, status); +} + +/* Sets up the CPU for running user code in the current + thread. + This function is called on every context switch. */ +void +process_activate (void) +{ + struct thread *t = thread_current (); + + /* Activate thread's page tables. */ + pagedir_activate (t->pagedir); + + /* Set thread's kernel stack for use in processing + interrupts. */ + tss_update (); +} + |
