Compare commits

...

5 Commits

Author SHA1 Message Date
Themis Demetriades
e1489e5244 Fix Bug: Free all entries in the fd hashtable when the process exits, (Saleh, Ethan) 2024-11-13 21:57:41 +00:00
Themis Demetriades
785f1a8d62 Fix child_results loop accessing after free() 2024-11-13 21:52:38 +00:00
Themis Demetriades
1368fa144a Add debugging messages for probing multi-oom test case 2024-11-13 18:57:02 +00:00
Themis Demetriades
446c50ea29 Remove superfluous process_exit () in start_process 2024-11-13 17:58:34 +00:00
Themis Demetriades
be68d81cf6 Fix memory leak in start_process due to not freeing proc_start_data when success in initializing stack 2024-11-13 17:21:42 +00:00
3 changed files with 60 additions and 27 deletions

View File

@@ -47,6 +47,9 @@ struct process_start_data
tokens while maintaining state. */ tokens while maintaining state. */
char file_name[FNAME_MAX_LEN + 1]; /* Name of the file of the process to char file_name[FNAME_MAX_LEN + 1]; /* Name of the file of the process to
be started. */ be started. */
struct semaphore load_sema;
bool success;
}; };
static thread_func start_process NO_RETURN; static thread_func start_process NO_RETURN;
@@ -62,11 +65,7 @@ process_execute (const char *cmd)
char *cmd_copy; char *cmd_copy;
tid_t tid; tid_t tid;
struct process_start_data *data = malloc (sizeof (struct process_start_data)); struct process_start_data data;
if (data == NULL)
{
return TID_ERROR;
}
/* Make a copy of command. /* Make a copy of command.
Otherwise there's a race between the caller and load(). */ Otherwise there's a race between the caller and load(). */
@@ -80,7 +79,7 @@ process_execute (const char *cmd)
/* Retrieve first argument of command, which is the file name /* Retrieve first argument of command, which is the file name
of the process. */ of the process. */
char *file_name = strtok_r (cmd_copy, " ", &data->cmd_saveptr); char *file_name = strtok_r (cmd_copy, " ", &data.cmd_saveptr);
/* NOTE: Currently, the file being executed is closed in load () and then /* NOTE: Currently, the file being executed is closed in load () and then
reopened here. Because load is an exported public function, this reopened here. Because load is an exported public function, this
@@ -95,12 +94,24 @@ process_execute (const char *cmd)
/* Create a new thread to execute the command, by initializing /* Create a new thread to execute the command, by initializing
it running the function 'start_process' with the appropriate it running the function 'start_process' with the appropriate
arguments. For details of arguments, see 'start_process'. */ arguments. For details of arguments, see 'start_process'. */
data->cmd = cmd_copy; data.cmd = cmd_copy;
strlcpy (data->file_name, file_name, FNAME_MAX_LEN + 1); strlcpy (data.file_name, file_name, FNAME_MAX_LEN + 1);
sema_init (&data.load_sema, 0);
data.success = false;
tid = thread_create (file_name, PRI_DEFAULT, start_process, &data);
tid = thread_create (file_name, PRI_DEFAULT, start_process, data);
if (tid == TID_ERROR) if (tid == TID_ERROR)
{
palloc_free_page (cmd_copy); palloc_free_page (cmd_copy);
}
else
{
sema_down (&data.load_sema);
if (!data.success)
tid = TID_ERROR;
}
return tid; return tid;
} }
@@ -118,7 +129,6 @@ static void
start_process (void *proc_start_data) start_process (void *proc_start_data)
{ {
struct intr_frame if_; struct intr_frame if_;
bool success;
struct process_start_data *data = proc_start_data; struct process_start_data *data = proc_start_data;
@@ -136,25 +146,27 @@ start_process (void *proc_start_data)
file_deny_write (exec_file); file_deny_write (exec_file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
success = load (data->file_name, &if_.eip, &if_.esp); data->success = load (data->file_name, &if_.eip, &if_.esp);
/* If load failed, quit. */ /* If load failed, free process startup data and quit. */
if (!success) if (!data->success)
{ {
palloc_free_page (data->cmd); palloc_free_page (data->cmd);
goto fail; sema_up (&data->load_sema);
thread_exit ();
} }
/* Initialize user process stack and free page used to store the /* Initialize user process stack and free page used to store the
command that executed the process. */ command that executed the process. */
success = process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name); bool success = process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name);
palloc_free_page (data->cmd); palloc_free_page (data->cmd);
data->success = success;
sema_up (&data->load_sema);
/* If stack initialization failed, free resources and quit. */ /* If stack initialization failed, free process resources and quit. */
if (!success) if (!success)
{ {
process_exit (); thread_exit ();
goto fail;
} }
/* Start the user process by simulating a return from an /* Start the user process by simulating a return from an
@@ -165,11 +177,6 @@ start_process (void *proc_start_data)
and jump to it. */ and jump to it. */
asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory"); asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory");
NOT_REACHED (); NOT_REACHED ();
/* If starting the process failed, free its common resources and exit. */
fail:
free (data);
thread_exit ();
} }
/* Helper function that initializes the stack of a newly created /* Helper function that initializes the stack of a newly created
@@ -300,7 +307,9 @@ process_wait (tid_t child_tid UNUSED)
break; break;
} }
if (child_result == NULL) if (child_result == NULL)
{
return -1; return -1;
}
/* Wait for child to die. */ /* Wait for child to die. */
sema_down (&child_result->sema); sema_down (&child_result->sema);
/* We need lock release in process_exit, so we need to acquire (and possibly /* We need lock release in process_exit, so we need to acquire (and possibly
@@ -314,6 +323,7 @@ process_wait (tid_t child_tid UNUSED)
int exit_status = child_result->exit_status; int exit_status = child_result->exit_status;
lock_release (&child_result->lock); lock_release (&child_result->lock);
free (child_result); free (child_result);
return exit_status; return exit_status;
} }
@@ -321,14 +331,20 @@ process_wait (tid_t child_tid UNUSED)
void void
process_exit (void) process_exit (void)
{ {
struct thread *cur = thread_current (); struct thread *cur = thread_current ();
uint32_t *pd; uint32_t *pd;
printf ("%s: exit(%d)\n", cur->name, cur->exit_status); printf ("%s: exit(%d)\n", cur->name, cur->exit_status);
/* Clean up all open files */
hash_destroy (&cur->open_files, fd_cleanup);
/* Close the executable file. */
if (cur->exec_file != NULL) if (cur->exec_file != NULL)
{ {
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
file_allow_write (cur->exec_file);
file_close (cur->exec_file); file_close (cur->exec_file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
} }
@@ -356,10 +372,11 @@ process_exit (void)
/* Free child process results or signal parent's death. */ /* Free child process results or signal parent's death. */
struct list_elem *e; struct list_elem *e;
for (e = list_begin (&cur->child_results); for (e = list_begin (&cur->child_results);
e != list_end (&cur->child_results); e = list_next (e)) e != list_end (&cur->child_results);)
{ {
struct process_result *result struct process_result *result
= list_entry (e, struct process_result, elem); = list_entry (e, struct process_result, elem);
struct list_elem *next = list_next (e);
lock_acquire (&result->lock); lock_acquire (&result->lock);
/* Child has died (and was not waited for). Free the result. */ /* Child has died (and was not waited for). Free the result. */
if (sema_try_down (&result->sema)) if (sema_try_down (&result->sema))
@@ -373,6 +390,7 @@ process_exit (void)
sema_up (&result->sema); sema_up (&result->sema);
lock_release (&result->lock); lock_release (&result->lock);
} }
e = next;
} }
/* Destroy the current process's page directory and switch back /* Destroy the current process's page directory and switch back

View File

@@ -378,6 +378,20 @@ fd_less (const struct hash_elem *a_, const struct hash_elem *b_,
return a->fd < b->fd; return a->fd < b->fd;
} }
/* Function to clean up an open file entry. Closes the file and frees the
associated memory. */
void
fd_cleanup (struct hash_elem *e, void *aux UNUSED)
{
struct open_file *file_info = hash_entry (e, struct open_file, elem);
lock_acquire (&filesys_lock);
file_close (file_info->file);
lock_release (&filesys_lock);
free (file_info);
}
/* Gets a file from its descriptor (FD number). If there is no file with the fd /* Gets a file from its descriptor (FD number). If there is no file with the fd
FD it returns NULL. */ FD it returns NULL. */
static struct open_file * static struct open_file *

View File

@@ -14,5 +14,6 @@ void syscall_init (void);
unsigned fd_hash (const struct hash_elem *element, void *aux); unsigned fd_hash (const struct hash_elem *element, void *aux);
bool fd_less (const struct hash_elem *a, const struct hash_elem *b, void *aux); bool fd_less (const struct hash_elem *a, const struct hash_elem *b, void *aux);
void fd_cleanup (struct hash_elem *e, void *aux);
#endif /* userprog/syscall.h */ #endif /* userprog/syscall.h */