받은 명령어를 단어로 나눠서 스택에 저장
받은 명령어가 /bin/ls -l foo bar 라면 밑의 사진 처럼 나눠서 넣는다
strtok_r를 이용해서 한 단어씩 나눈다.
우리는 64비트로 하기 때문에 8바이트씩 옮겨가면서 저장한다.
중간에 align도 해줘야한다.
void argument_stack(char **argv, int argc , void **rsp){
int total_len =0;
char *token;
char *save_ptr;
//스택주소를 감소시키면서 인자를 스택에 삽입
for(int i=argc-1; i>-1; i--){
//\0도 포함해야하니까
int len = strlen(argv[i])+1;
*rsp -= len;
total_len += len;
strlcpy(*rsp, argv[i], len);
argv[i] = *rsp;
}
*rsp -= ((total_len % 8) != 0 ? 8 - (total_len%8) : 0); //word-align
*rsp -= 8;
**(uint64_t **)rsp = NULL;
//주소를 스택에 삽입
for(int i=argc-1; 0<=i; i--){
*rsp -= 8;
**(uint64_t **) rsp = argv[i];
}
*rsp -= 8;
**(uint64_t **) rsp = 0;
}
syscall-nr.h에 보면 여러 시스템 콜이 나열 되어 있다. 우리는 그 시스템 콜이 불렸을 때의 상황을 코딩해 주면 된다. 그 중 우리가 해야할 부분은 이렇게 16가지이다. systemcall의 넘버는 f->R.rax에 저장되어있다.
SYS_HALT, /* Halt the operating system. */ SYS_EXIT, /* Terminate this process. */ SYS_FORK, /* Clone current process. */ SYS_EXEC, /* Switch current process. */ SYS_WAIT, /* Wait for a child process to die. */ SYS_CREATE, /* Create a file. */ SYS_REMOVE, /* Delete a file. */ SYS_OPEN, /* Open a file. */ SYS_FILESIZE, /* Obtain a file's size. */ SYS_READ, /* Read from a file. */ SYS_WRITE, /* Write to a file. */ SYS_SEEK, /* Change position in a file. */ SYS_TELL, /* Report current position in a file. */ SYS_CLOSE, /* Close a file. */
1) SYS_HALT
-핀토스 프로그램 종료하는 시스템 콜이다.
power_off()함수를 이용하면 된다.
2) SYS_EXIT
-현재 유저프로세스을 종료하는 시스템 콜이다.
printf ("%s: exit(%d)\n", thread_name(), status);로 끝났다는 것을 프린트해주고
스레드 exit상태로 바꿔준 후, thread_exit로 프로세스를 종료한다.
3) SYS_FORK
-현재 프로세스를 복사하여 자식 프로세스를 만드는 시스템 콜이다.
processfork()함수를 통해 fork로 해주는데,
이 부분이 완전 어렵다..^^
tid_t
process_fork (const char *name, struct intr_frame *if_ UNUSED) {
/* Clone current thread to new thread.*/
struct thread *cur = thread_current();
memcpy(&cur->parent_if, if_, sizeof(struct intr_frame));// Pass this intr_frame down to child
tid_t tid = thread_create (name, PRI_DEFAULT, __do_fork, cur);// 자식 스레드를 만든다
if(tid == TID_ERROR) return TID_ERROR;
//project 7
struct thread *child = get_child_with_pid(tid); //자식 찾기
sema_down(&child->fork_sema);
if(child->exit_status == -1){
return TID_ERROR;
}
//생성한 자식 스레드를 리턴
return tid;
}
코드로 대신하겠다. do_fork도 많이 고쳐줘야하는데 생략한다.
fork_sema를 이용해서 자식이 up해줄때까지 블락상태를 갖는다.
thread_create (name, PRI_DEFAULT, _do_fork, cur)여기서 자식을 만든다.
내가 자식 쓰레드가 안만들어져서 많이 헤맸었는데, _do_fork에서 if.R.rax=0을 해주지 않아서였다. 자식스레드의 리턴값은 0으로 해줘야하는데 말이다...ㅎ
이 _do_fork에서 fork_sema를 up해준다.
4) SYS_EXEC
-현재 프로세스를 실행 가능한 상태로 변경하는 시스템 콜이다.
process_exec함수를 이용한다. 성공하면 0 실패하면 -1을 리턴한다.
tid_t exec(const char *file_name){
int siz = strlen(file_name) + 1;
char *fn_copy = palloc_get_page(PAL_ZERO);
if (fn_copy == NULL)
exit(-1);
strlcpy(fn_copy, file_name, siz);
if (process_exec(fn_copy) == -1)
return -1;
// Not reachable
NOT_REACHED();
return 0;
}
5) SYS_WAIT
-부모 프로세스가 자식프로세스를 기다리는 시스템 콜이다.
process_wait를 이용한다.
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. */
//project 7
struct thread *child = get_child_with_pid(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->free_sema);//자식을 이제 놓아줘도 된다.
return exit_status;
}
6) SYS_CREATE
-새 파일을 만드는 시스템 콜이다.
이름과 사이즈를 인자로 받아오며, filesys_create(const char *name, off_t initial_siz) 함수를 이용하면 된다.
성공하면 true를 실패하면 false를 리턴한다.
7) SYS_REMOVE
-파일을 삭제하는 시스템 콜이다.
이름을 인자로 받아오며, filesys_remove (const char *name) 함수를 이용한다.
성공하면 true를 실패하면 false를 리턴한다.
8)SYS_OPEN
-file을 받아 오픈하는 시스템 콜이다.
filesys_open을 이용하며, 파일이 존재한다면 파일을 파일테이블에 넣고 file descriptor를 반환한다.
int open(const char *file){
struct file *fileobj = filesys_open(file);
if(fileobj==NULL) return -1;
int fd = add_file_to_fdt(fileobj);
if(fd == -1) file_close(fileobj);
return fd;
}
int add_file_to_fdt(struct file *file){
struct thread *cur = thread_current();
struct file **fdt = cur->fdTable;
while(cur->fdIdx < FDCOUNT_LIMIT && fdt[cur->fdIdx])
cur->fdIdx++;
if(cur->fdIdx >= FDCOUNT_LIMIT) return -1;
fdt[cur->fdIdx] = file;
return cur->fdIdx;
}
9)SYS_FILESIZE
-fd를 받아 파일의 크기를 바이트로 반환하는 시스템 콜이다.
fd로부터 파일을 찾아서 file_length로 길이를 리턴한다.
10)SYS_READ
-fd를 받아 파일을 읽는 시스템 콜이다.
fileobj이 1번, 즉 stdin이라면 사용자가 입력한것을 읽는다.
2번이라면 -1을 리턴한다.
그 외 파일이라면 file_read를 통해 파일을 읽고
파일 사이즈를 리턴한다.
int read(int fd, void *buffer, unsigned size){
int ret;
struct thread *cur = thread_current();
struct file *fileobj = find_file_by_fd(fd);
if(fileobj == NULL) return -1;
if(fileobj == 1){
if(cur->stdin_count ==0){
// Not reachable
NOT_REACHED();
remove_file_from_fdt(fd);
ret = -1;
}else{
int i;
unsigned char *buf = buffer;
for(i=0; i<size; i++){
char c = input_getc();
*buf++ = c;
if(c=='\0') break;
}
ret = i;
}
}else if( fileobj == 2) ret = -1;
else{
lock_acquire(&file_rw_lock);
ret = file_read(fileobj, buffer, size);
lock_release(&file_rw_lock);
}
return ret;
}
11)SYS_WRITE
-fd를 받아 파일에 쓰는 시스템 콜이다.
위의 read와 비슷하다.
int write (int fd, const void *buffer, unsigned size){
int ret;
struct file *fileobj = find_file_by_fd(fd);
if (fileobj == NULL)
return -1;
struct thread *cur = thread_current();
if (fileobj == 2){
if (cur->stdout_count == 0){
// Not reachable
NOT_REACHED();
remove_file_from_fdt(fd);
ret = -1;
}
else{
putbuf(buffer, size);
ret = size;
}
}
else if (fileobj == 1){
ret = -1;
}
else{
lock_acquire(&file_rw_lock);
ret = file_write(fileobj, buffer, size);
lock_release(&file_rw_lock);
}
return ret;
}
12)SYS_SEEK
-파일의 position을 바꿔주는 시스템콜인데, 사실 잘 모르겠다...ㅎ
13)SYS_TELL
-파일의 position을 알려주는 시스템콜인데, 이것도 사실 잘 모르겠다.
file_tell함수를 이용하면 된다.
14)SYS_CLOSE
-fd를 받아 파일을 닫는 시스템 콜이다.
실행 중인 파일에는 write를 못하게 해주는 것
file_deny_write함수를 이용한다.
이번 꺼는 정말 너무 어려워서 내 선에서 이해할 수 있는 정도만 이해하고 넘어가려고 한다. 다음 3-4는 할 수 있을까...?
이번 꺼는 97점까지 성공했다... 통과 못한게 2개인데... 나중에 시간 되면 다시 찾아보는것으로... 대신 팀끼리 같이한거는 100점맞긴함ㅋㅋㅋㅋ 다시 어디서 실수 했는지 찾아봐야지ㅎㅎㅎ
그리고 이번꺼는 github에서 많이 참고 해서 작성했다.
branch는 young-2이다.