π©π»βπ» GITHUB λ ν¬μ§ν 리
π©π»βπ» GITHUB Hierarchical Process Structure μ΄μ
#include "threads/synch.h" /** project2-System Call */
#ifdef USERPROG
/* Owned by userprog/process.c. */
uint64_t *pml4; /* Page map level 4 */
/** project2-System Call */
int exit_status;
int fd_idx; // νμΌ λμ€ν¬λ¦½ν° μΈλ±μ€
struct file **fdt; // νμΌ λμ€ν¬λ¦½ν° ν
μ΄λΈ
struct file *runn_file; // μ€νμ€μΈ νμΌ
struct intr_frame parent_if; // λΆλͺ¨ νλ‘μΈμ€ if
struct list child_list;
struct list_elem child_elem;
struct semaphore fork_sema; // forkκ° μλ£λ λ signal
struct semaphore exit_sema; // μμ νλ‘μΈμ€ μ’
λ£ signal
struct semaphore wait_sema; // exit_semaλ₯Ό κΈ°λ€λ¦΄ λ μ¬μ©
#endif
static void
init_thread (struct thread *t, const char *name, int priority) {
ASSERT (t != NULL);
ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
ASSERT (name != NULL);
memset (t, 0, sizeof *t);
t->status = THREAD_BLOCKED;
strlcpy (t->name, name, sizeof t->name);
t->tf.rsp = (uint64_t) t + PGSIZE - sizeof (void *);
/** project1-Advanced Scheduler */
if (thread_mlfqs) {
mlfqs_priority(t);
list_push_back(&all_list, &t->all_elem);
} else {
t->priority = priority;
}
t->wait_lock = NULL;
list_init(&t->donations);
t->magic = THREAD_MAGIC;
/** #Advanced Scheduler */
t->original_priority = t->priority;
t->niceness = NICE_DEFAULT;
t->recent_cpu = RECENT_CPU_DEFAULT;
/** project2-System Call */
t->runn_file = NULL;
list_init(&t->child_list);
sema_init(&t->fork_sema, 0);
sema_init(&t->exit_sema, 0);
sema_init(&t->wait_sema, 0);
}
tid_t
thread_create (const char *name, int priority,
thread_func *function, void *aux) {
struct thread *t;
tid_t tid;
ASSERT (function != NULL);
/* Allocate thread. */
t = palloc_get_page (PAL_ZERO);
if (t == NULL)
return TID_ERROR;
/* Initialize thread. */
init_thread (t, name, priority);
tid = t->tid = allocate_tid ();
#ifdef USERPROG
/** project2-System Call */
t->fdt = palloc_get_multiple(PAL_ZERO, FDT_PAGES);
if (t->fdt == NULL)
return TID_ERROR;
t->exit_status = 0; // exit_status μ΄κΈ°ν
t->fd_idx = 3;
t->fdt[0] = 0; // stdin μμ½λ μ리 (dummy)
t->fdt[1] = 1; // stdout μμ½λ μ리 (dummy)
t->fdt[2] = 2; // stderr μμ½λ μ리 (dummy)
list_push_back(&thread_current()->child_list, &t->child_elem);
#endif
/* Call the kernel_thread if it scheduled.
* Note) rdi is 1st argument, and rsi is 2nd argument. */
t->tf.rip = (uintptr_t) kernel_thread;
t->tf.R.rdi = (uint64_t) function;
t->tf.R.rsi = (uint64_t) aux;
t->tf.ds = SEL_KDSEG;
t->tf.es = SEL_KDSEG;
t->tf.ss = SEL_KDSEG;
t->tf.cs = SEL_KCSEG;
t->tf.eflags = FLAG_IF;
/* Add to run queue. */
thread_unblock (t);
/** project1-Priority Scheduling */
if(t->priority > thread_current()->priority)
thread_yield();
return tid;
}
/** project2-System Call */
struct thread *get_child_process(int pid);
int process_add_file(struct file *f);
struct file *process_get_file(int fd);
int process_close_file(int fd);
β process.hμ ν¨μ μ μΈλΆν°!
/** project2-System Call */
struct thread
*get_child_process(int pid)
{
struct thread *curr = thread_current();
struct thread *t;
for (struct list_elem *e = list_begin(&curr->child_list); e != list_end(&curr->child_list); e = list_next(e)) {
t = list_entry(e, struct thread, child_elem);
if (pid == t->tid)
return t;
}
return NULL;
}
pid_t fork(const char *thread_name) {
check_address(thread_name);
return process_fork(thread_name, NULL);
}
tid_t
process_fork (const char *name, struct intr_frame *if_ UNUSED) {
struct thread *curr = thread_current();
struct intr_frame *f = (pg_round_up(rrsp()) - sizeof(struct intr_frame)); // νμ¬ μ°λ λμ if_λ νμ΄μ§ λ§μ§λ§μ λΆμ΄μλ€.
memcpy(&curr->parent_if, f, sizeof(struct intr_frame)); // 1. λΆλͺ¨λ₯Ό μ°ΎκΈ° μν΄μ 2. do_forkμ μ λ¬ν΄μ£ΌκΈ° μν΄μ
/* νμ¬ μ€λ λλ₯Ό μ μ€λ λλ‘ λ³΅μ ν©λλ€.*/
tid_t tid = thread_create(name, PRI_DEFAULT, __do_fork, curr);
if (tid == TID_ERROR)
return TID_ERROR;
struct thread *child = get_child_process(tid);
sema_down(&child->fork_sema); // μμ±λ§ ν΄λκ³ μμ νλ‘μΈμ€κ° __do_forkμμ fork_semaλ₯Ό sema_up ν΄μ€ λκΉμ§ λκΈ°
if (child->exit_status == TID_ERROR)
return TID_ERROR;
return tid; // λΆλͺ¨ νλ‘μΈμ€μ 리ν΄κ° : μμ±ν μμ νλ‘μΈμ€μ tid
}
static bool
duplicate_pte (uint64_t *pte, void *va, void *aux) {
struct thread *current = thread_current ();
struct thread *parent = (struct thread *) aux;
void *parent_page;
void *newpage;
bool writable;
/* 1. TODO: If the parent_page is kernel page, then return immediately. */
if (is_kernel_vaddr(va))
return true;
/* 2. Resolve VA from the parent's page map level 4. */
parent_page = pml4_get_page(parent->pml4, va);
if (parent_page == NULL)
return false;
/* 3. TODO: Allocate new PAL_USER page for the child and set result to
* TODO: NEWPAGE. */
newpage = palloc_get_page(PAL_ZERO);
if (newpage == NULL)
return false;
/* 4. TODO: Duplicate parent's page to the new page and
* TODO: check whether parent's page is writable or not (set WRITABLE
* TODO: according to the result). */
memcpy(newpage, parent_page, PGSIZE);
writable = is_writable(pte);
/* 5. Add new page to child's page table at address VA with WRITABLE
* permission. */
if (!pml4_set_page (current->pml4, va, newpage, writable)) {
/* 6. TODO: if fail to insert page, do error handling. */
return false;
}
return true;
}
static void
__do_fork (void *aux) {
struct intr_frame if_;
struct thread *parent = (struct thread *) aux;
struct thread *current = thread_current ();
/* TODO: somehow pass the parent_if. (i.e. process_fork()'s if_) */
struct intr_frame *parent_if = &parent->parent_if;
bool succ = true;
/* 1. Read the cpu context to local stack. */
memcpy (&if_, parent_if, sizeof (struct intr_frame));
if_.R.rax = 0; // μμ νλ‘μΈμ€μ returnκ° (0)
/* 2. Duplicate PT */
current->pml4 = pml4_create();
if (current->pml4 == NULL)
goto error;
process_activate (current);
#ifdef VM
supplemental_page_table_init (¤t->spt);
if (!supplemental_page_table_copy (¤t->spt, &parent->spt))
goto error;
#else
if (!pml4_for_each (parent->pml4, duplicate_pte, parent))
goto error;
#endif
/* TODO: Your code goes here.
* TODO: Hint) To duplicate the file object, use `file_duplicate`
* TODO: in include/filesys/file.h. Note that parent should not return
* TODO: from the fork() until this function successfully duplicates
* TODO: the resources of parent.*/
if (parent->fd_idx >= FDCOUNT_LIMIT)
goto error;
current->fd_idx = parent->fd_idx; // fdt λ° idx 볡μ
for (int fd = 3; fd < parent->fd_idx; fd++) {
if (parent->fdt[fd] == NULL)
continue;
current->fdt[fd] = file_duplicate(parent->fdt[fd]);
}
sema_up(¤t->fork_sema); // fork νλ‘μΈμ€κ° μ μμ μΌλ‘ μλ£λμΌλ―λ‘ νμ¬ forkμ© sema unblock
process_init();
/* Finally, switch to the newly created process. */
if (succ)
do_iret(&if_); // μ μ μ’
λ£ μ μμ Processλ₯Ό μννλ¬ κ°
error:
sema_up(¤t->fork_sema); // 볡μ μ μ€ν¨νμΌλ―λ‘ νμ¬ forkμ© sema unblock
exit(TID_ERROR);
}
int
exec(const char *cmd_line)
{
check_address(cmd_line);
off_t size = strlen(cmd_line) + 1;
char *cmd_copy = palloc_get_page(PAL_ZERO);
if (cmd_copy == NULL)
return -1;
memcpy(cmd_copy, cmd_line, size);
if (process_exec(cmd_copy) == -1)
return -1;
return 0; // process_exec μ±κ³΅μ λ¦¬ν΄ κ° μμ (do_iret)
}
int
process_exec (void *f_name) {
char *file_name = f_name;
bool success;
/* μ€λ λ ꡬ쑰μμλ intr_frameμ μ¬μ©ν μ μμ΅λλ€.
* νμ¬ μ°λ λκ° μ¬μ€μΌμ€ λλ©΄ μ€ν μ 보λ₯Ό λ©€λ²μκ² μ μ₯νκΈ° λλ¬Έμ
λλ€. */
struct intr_frame if_;
if_.ds = if_.es = if_.ss = SEL_UDSEG;
if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS;
/* We first kill the current context */
process_cleanup();
/** #Project 2: Command Line Parsing - λ¬Έμμ΄ λΆλ¦¬ */
char *ptr, *arg;
int argc = 0;
char *argv[64];
for (arg = strtok_r(file_name, " ", &ptr); arg != NULL; arg = strtok_r(NULL, " ", &ptr))
argv[argc++] = arg;
/* And then load the binary */
success = load(file_name, &if_);
/* If load failed, quit. */
if (!success)
return -1;
argument_stack(argv, argc, &if_);
palloc_free_page(file_name);
/** #Project 2: Command Line Parsing - λλ²κΉ
μ© ν΄ */
// hex_dump(if_.rsp, if_.rsp, USER_STACK - if_.rsp, true);
/* Start switched process. */
do_iret(&if_);
NOT_REACHED();
}
int wait(pid_t tid) {
return process_wait(tid);
}
int
process_wait (tid_t child_tid UNUSED) {
/* XXX: Hint) The pintos exit if process_wait (initd), we recommend you
* XXX: to add infinite loop here before
* XXX: implementing the process_wait. */
struct thread *child = get_child_process(child_tid);
if (child == NULL)
return -1;
sema_down(&child->wait_sema); // μμ νλ‘μΈμ€κ° μ’
λ£λ λ κΉμ§ λκΈ°.
int exit_status = child->exit_status;
list_remove(&child->child_elem);
sema_up(&child->exit_sema); // μμ νλ‘μΈμ€κ° μ£½μ μ μλλ‘ signal
return exit_status;
}