Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions pintos/include/threads/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ typedef int tid_t;
#define PRI_MIN 0 /* Lowest priority. */
#define PRI_DEFAULT 31 /* Default priority. */
#define PRI_MAX 63 /* Highest priority. */
#define FD_TABLE_SIZE 128

/* A kernel thread or user process.
*
Expand Down Expand Up @@ -107,12 +106,14 @@ struct thread
uint64_t *pml4; /* Page map level 4 */

int exit_status;
struct file **fd_table;

struct fdt_entry **fdt_entry;

struct list child_list;
// struct thread *parent;
struct child *child_info;
struct file *executable;
int FD_TABLE_SIZE;

#endif
#ifdef VM
Expand All @@ -125,11 +126,21 @@ struct thread
unsigned magic; /* Detects stack overflow. */
};

struct child {
enum fd_type { STDIN, STDOUT, FILE, DIR }; //DIR은 과제 4

struct fdt_entry {
enum fd_type type;
struct file *fdt; // type FILE인 경우 가져다 쓰기
int ref_cnt;
/* dir인 경우 추가??(과제4) */
};

struct child {
struct list_elem child_elem;
tid_t child_tid;
int exit_status;
bool waited;
bool p_alive;
struct semaphore wait_sema;
};

Expand Down
5 changes: 4 additions & 1 deletion pintos/tests/userprog/dup2/Make.tests
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# -*- makefile -*-

tests/userprog/dup2_TESTS = $(addprefix tests/userprog/dup2/dup2-,complex simple)
tests/userprog/dup2_TESTS = $(addprefix tests/userprog/dup2/dup2-,complex simple fork-link)

tests/userprog/dup2_PROGS = $(tests/userprog/dup2_TESTS)

tests/userprog/dup2/dup2-complex_SRC = tests/userprog/dup2/dup2-complex.c \
tests/lib.c tests/userprog/boundary.c
tests/userprog/dup2/dup2-simple_SRC = tests/userprog/dup2/dup2-simple.c \
tests/lib.c tests/userprog/boundary.c
tests/userprog/dup2/dup2-fork-link_SRC = tests/userprog/dup2/dup2-fork-link.c \
tests/lib.c

tests/userprog/dup2/dup2-complex_PUTFILES += tests/userprog/dup2/sample.txt
tests/userprog/dup2/dup2-simple_PUTFILES += tests/userprog/dup2/sample.txt
tests/userprog/dup2/dup2-fork-link_PUTFILES += tests/userprog/dup2/sample.txt
40 changes: 40 additions & 0 deletions pintos/tests/userprog/dup2/dup2-fork-link.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* Confirm that dup2-linked descriptors stay linked after fork. The child
sees the primed offset, advances it once, and the parent observes the
updated position as soon as the child exits. */

#include <stdio.h>
#include <syscall.h>
#include "tests/lib.h"

int
main (int argc UNUSED, char *argv[] UNUSED) {
test_name = "dup2-fork-link";

char buf[16];
int fd = open ("sample.txt");
CHECK (fd > 1, "open \"sample.txt\"");
CHECK (read (fd, buf, 5) == 5, "set offset to 5");
int dup_fd = dup2 (fd, 30);
CHECK (dup_fd == 30, "dup2 to 30");
pid_t pid = fork ("dup-child");
if (pid < 0)
fail ("fork failed");

if (pid == 0) {
int off_fd = tell (fd);
int off_dup = tell (dup_fd);
if (off_fd != 5 || off_dup != 5)
fail ("child inherited offsets fd=%d dup=%d (expected 5)", off_fd, off_dup);

CHECK (read (dup_fd, buf, 7) == 7, "child read dup fd");
off_fd = tell (fd);
off_dup = tell (dup_fd);
if (off_fd != 12 || off_dup != 12)
fail ("child offsets diverged after read (fd=%d dup=%d)", off_fd, off_dup);
exit (0);
}

if (pid > 0)
CHECK (wait (pid) == 0, "wait child");
return 0;
}
21 changes: 21 additions & 0 deletions pintos/tests/userprog/dup2/dup2-fork-link.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- perl -*-
use strict;
use warnings;
use tests::tests;
check_expected (IGNORE_EXIT_CODES => 1, [
<<'EOF',
(dup2-fork-link) open "sample.txt"
(dup2-fork-link) set offset to 5
(dup2-fork-link) dup2 to 30
(dup2-fork-link) child read dup fd
(dup2-fork-link) wait child
EOF
,<<'EOF',
(dup2-fork-link) open "sample.txt"
(dup2-fork-link) set offset to 5
(dup2-fork-link) dup2 to 30
(dup2-fork-link) wait child
(dup2-fork-link) child read dup fd
EOF
]);
pass;
3 changes: 2 additions & 1 deletion pintos/userprog/.test_config
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ priority-donate-chain | --fs-disk=10 | -q -threads-tests -f run | 'priority-don
[extra]
dup2-simple | --fs-disk=10 -p tests/userprog/dup2/dup2-simple:dup2-simple -p ../../tests/userprog/dup2/sample.txt:sample.txt | -q -f run | 'dup2-simple' | tests/userprog/dup2
dup2-complex | --fs-disk=10 -p tests/userprog/dup2/dup2-complex:dup2-complex -p ../../tests/userprog/dup2/sample.txt:sample.txt | -q -f run | 'dup2-complex' | tests/userprog/dup2
dup2-fork-link | --fs-disk=10 -p tests/userprog/dup2/dup2-fork-link:dup2-fork-link -p ../../tests/userprog/dup2/sample.txt:sample.txt | -q -f run | 'dup2-fork-link' | tests/userprog/dup2


# Total testcases: 97
# Generated on 2025-07-29
# Generated on 2025-07-29
147 changes: 147 additions & 0 deletions pintos/userprog/fdt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#include "userprog/fdt.h"
#include "filesys/file.h"
#include "threads/synch.h"
#include <string.h>

/* file_lock is defined in syscall.c. */
extern struct lock file_lock;

/* file 받아서 fd 자리에 fdt_entry 만들기 */
bool
open_fdt_entry(struct fdt_entry **fdt_entry, int fd, struct file *file){

if(fdt_entry == NULL || file == NULL)
return false;

struct fdt_entry *entry = calloc(1, sizeof(struct fdt_entry));
if(entry == NULL)
return false;

fdt_entry[fd] = entry;
fdt_entry[fd]->fdt = file;
fdt_entry[fd]->ref_cnt = 1;
fdt_entry[fd]->type = FILE;

return true;
}


/* ref_cnt 기준으로 파일 닫기 */
void
close_fdt_entry(struct fdt_entry **table, int fd){
struct fdt_entry *ent = table[fd];
if (ent == NULL)
return;

table[fd] = NULL;
ent->ref_cnt--;
if (ent->type == FILE && ent->fdt != NULL) {
if (ent->ref_cnt == 0) {
lock_acquire(&file_lock);
file_close(ent->fdt);
lock_release(&file_lock);
}
}
if (ent->ref_cnt == 0)
free(ent);
}

/* 2^n 크기로 확장, 새 슬롯을 0으로 채우기 */
bool
increase_fdt_size(struct thread *t, int fd) {
int old_size = t->FD_TABLE_SIZE;
if (fd < old_size)
return true;

/* 2^n 값 구하기 */
int need = fd + 1;
int new_size = old_size ? old_size : 1;
while (new_size < need)
new_size <<= 1;

struct fdt_entry **old_entry = t->fdt_entry;
if (old_entry == NULL)
return false;

/* 새 버퍼를 0으로 초기화, 기존 내용을 복사 */
struct fdt_entry **new_entry = calloc(new_size, sizeof(struct fdt_entry*));
if (new_entry == NULL)
return false;
memcpy(new_entry, old_entry, old_size * sizeof(struct fdt_entry*));

t->fdt_entry = new_entry;
t->FD_TABLE_SIZE = new_size;

free(old_entry);

return true;
}

/* parent 엔트리 깊은 복사 해서 child에 연결 */
/* FILE일 경우만 dup, STDIN/STDOUT 이면 그냥 만들기*/
bool
dup_fdt_entry(struct fdt_entry *parent_ent, struct fdt_entry **child_ent){
if (parent_ent == NULL || child_ent == NULL)
return false;

struct fdt_entry *entry = calloc(1, sizeof(struct fdt_entry));
if(entry == NULL)
return false;

entry->type = parent_ent->type;
entry->ref_cnt = parent_ent->ref_cnt;

if(parent_ent->type == FILE){
lock_acquire(&file_lock);
struct file *dup = file_duplicate(parent_ent->fdt);
lock_release(&file_lock);
if (dup == NULL){
free(entry);
return false;
}
entry->fdt = dup;
}

*child_ent = entry;
return true;
}

/* 부모 fdt_entry배열 fork*/
bool
fork_fdt(struct thread *parent, struct thread *child){
for (int i = 0; i < parent->FD_TABLE_SIZE; i++) {
struct fdt_entry *p_entry = parent->fdt_entry[i];
if (p_entry == NULL)
continue;

/* 부모에서 같은 엔트리를 공유한 fd라면 자식도 동일 포인터 공유 */
bool dup_find = false;
if(p_entry->ref_cnt >= 2){
for (int j = 0; j < i; j++) {
if (parent->fdt_entry[j] == p_entry) {
child->fdt_entry[i] = child->fdt_entry[j];
dup_find = true;
break;
}
}
}
/* dup 연결 했으면 만들기 생략 */
if (dup_find)
continue;

if (!dup_fdt_entry(p_entry, &child->fdt_entry[i]))
return false;
}

return true;
}

/* fd 0,1은 건너뛰고 비어 있는 가장 낮은 fd 반환. 없으면 -1. */
int
find_empty_fd(struct thread *t){
for (int i = 2; i < t->FD_TABLE_SIZE; i++){
if (t->fdt_entry[i] == NULL)
return i;
}
return -1;
}
13 changes: 13 additions & 0 deletions pintos/userprog/fdt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef USERPROG_FDT_H
#define USERPROG_FDT_H

#include "threads/thread.h"

bool open_fdt_entry(struct fdt_entry **fdt_entry, int fd, struct file *file);
void close_fdt_entry(struct fdt_entry **table, int fd);
bool increase_fdt_size(struct thread *t, int fd);
bool dup_fdt_entry(struct fdt_entry *parent_ent, struct fdt_entry **child_ent);
bool fork_fdt(struct thread *parent, struct thread *child);
int find_empty_fd(struct thread *t);

#endif /* USERPROG_FDT_H */
Loading