diff --git a/src/userprog/process.c b/src/userprog/process.c index accd108..6c5f364 100644 --- a/src/userprog/process.c +++ b/src/userprog/process.c @@ -34,6 +34,18 @@ struct arg_elem struct list_elem elem; }; +/* Holds the data required to be passed from a kernel thread to a thread + that executes process_start for the purpose of starting a user process. */ +struct process_start_data + { + char *cmd; /* Pointer to a copy of the command used to execute the process. + Allocated a page that must be freed by process_start. */ + char *cmd_saveptr; /* Value pointed to by 'saveptr' argument used by + successive calls to strtok_r to split 'cmd' into + tokens while maintaining state. */ + char *file_name; /* Name of the file of the process to be started. */ + }; + static thread_func start_process NO_RETURN; static bool load (const char *cmdline, void (**eip) (void), void **esp); @@ -44,66 +56,73 @@ static bool load (const char *cmdline, void (**eip) (void), void **esp); tid_t process_execute (const char *cmd) { - char *fn_copy; + char *cmd_copy; tid_t tid; + struct process_start_data data; - /* Make a copy of FILE_NAME. + /* Make a copy of command. Otherwise there's a race between the caller and load(). */ - fn_copy = palloc_get_page (0); - if (fn_copy == NULL) + cmd_copy = palloc_get_page (0); + if (cmd_copy == NULL) return TID_ERROR; /* Imposing implicit limit that the command line arguments including the user program name fit within a single page. */ - strlcpy (fn_copy, cmd, PGSIZE); + strlcpy (cmd_copy, cmd, PGSIZE); - /* Create a new thread to execute FILE_NAME. */ - tid = thread_create (cmd, PRI_DEFAULT, start_process, fn_copy); + /* Retrieve first argument of command, which is the file name + of the process. */ + char *file_name = strtok_r (cmd_copy, " ", &data.cmd_saveptr); + if (strlen (file_name) > FNAME_MAX_LEN) + file_name[FNAME_MAX_LEN + 1] = '\n'; + + /* Create a new thread to execute the command, by initializing + it running the function 'start_process' with the appropriate + arguments. For details of arguments, see 'start_process'. */ + data.cmd = cmd_copy; + data.file_name = file_name; + + tid = thread_create (file_name, PRI_DEFAULT, start_process, &data); if (tid == TID_ERROR) - palloc_free_page (fn_copy); + palloc_free_page (cmd_copy); return tid; } static bool process_init_stack (char *cmd_saveptr, void **esp, char *file_name); static void *push_to_stack (void **esp, void *data, size_t data_size); -/* A thread function that loads a user process and starts it - running. */ +/* Make the current thread execute 'cmd', passing in a copy of the + command string used for processing, the saveptr used by strtok_r + (in order to further tokenize the same command and retrieve its + arguments), as well as the name of the file being executed. This + involves loading the specified file and starting it running. */ static void -start_process (void *cmd) +start_process (void *proc_start_data) { struct intr_frame if_; bool success; - /* Retrieve first argument of command, which is the file name - of the process. */ - char *saveptr; - char *file_name = strtok_r (cmd, " ", &saveptr); - if (strlen (file_name) > FNAME_MAX_LEN) - file_name[FNAME_MAX_LEN + 1] = '\n'; - - /* TODO: Move naming of thread to process_execute, so start - tokenizing there. */ - strlcpy (thread_current ()->name, file_name, FNAME_MAX_LEN + 1); + struct process_start_data *data = proc_start_data; + ASSERT (data->cmd_saveptr != NULL); /* 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); + success = load (data->file_name, &if_.eip, &if_.esp); /* If load failed, quit. */ if (!success) { - palloc_free_page (cmd); + palloc_free_page (data->cmd); thread_exit (); } /* Initialize user process stack and free page used to store the command that executed the process. */ - success = process_init_stack (saveptr, &if_.esp, file_name); - palloc_free_page (cmd); + success = process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name); + palloc_free_page (data->cmd); /* If stack initialization failed, free resources and quit. */ if (!success)