Исходные коды с внесенными модификациями и комментариями
Userprog/syscall.c
#include "userprog/syscall.h"
#include <stdio.h>
#include <syscall-nr.h>
#include "threads/interrupt.h"
#include "threads/thread.h"
#include <list.h>
#include "threads/init.h"
#include "lib/kernel/stdio.h"
#include "userprog/process.h"
#include "filesys/filesys.h"
#include "devices/input.h"
//deskriptor
struct fd_des{
int fd; //unique num
struct file *file; //opened file
struct list_elem elem;
struct list_elem t_elem; //processes lists
};
void halt(void);/*
int wait(int pid);
int exit(int status);
int create (const char *file, unsigned int initial_size);
int exec(const char *cmd_line);
int open(const char *file);
int close (int fd);
int write(int fd, const void *buffer, unsigned size);
int read(int fd, void *buffer, unsigned size);
static struct fd_des *find_fd_elem_by_fd(int fd);
static struct file *find_file_by_fd(int fd);*/
//struct of all user's processes
struct list file_list;
//lock
struct list file_lock;
static void syscall_handler (struct intr_frame *);
void
syscall_init (void)
{
intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
list_init(&file_list);
list_init(&file_lock);
}
static void
syscall_handler (struct intr_frame *f /*UNUSED*/)
{
int sys_num=*(int*)(f->esp);
switch(sys_num){
case SYS_HALT:
halt;
break;
/*case SYS_EXIT:
exit(*(int*)(f->esp+4));
break;
case SYS_EXEC:
f->eax=exec(*(char*)(f->esp+4));
break;
case SYS_WAIT:
f->eax=wait(*(int*)(f->esp+4));
break;
case SYS_CREATE:
f->eax=create(*(char*)(f->esp+4),*(int*)(f->esp+8));
break;
case SYS_READ:
f->eax=read(*(int*)(f->esp+4), *(char*)(f->esp+8), *(int*)(f->esp+12));
break;
case SYS_OPEN:
f->eax=open(*(char*)(f->esp+4));
break;
case SYS_WRITE:
f->eax=write(*(int*)(f->esp+4), *(char*)(f->esp+8), *(int*)(f->esp+12));
break;
case SYS_CLOSE:
f->eax=close(*(int*)(f->esp+4));
break;*/
default:
break;
}
//printf ("system call!\n");
//thread_exit ();
}
//Ended OS Pintos.
void halt(void)
{
shutdown_power_off();
}
/*
static struct fd_des *find_fd_elem_by_fd(int fd)
{
struct fd_des *des;
struct list_elem *l;
for(l=list_begin(&file_list); l!=list_end(&file_list);l=list_next(l));
{
des=list_entry(l,struct fd_des, elem);
if(des->fd==fd)
return des;
}
return NULL;
}
static struct file *find_file_by_fd(int fd)
{
struct fd_des *t=find_fd_elem_by_fd(fd);
if(!t)
return NULL;
return t->file;
}
//Waits while daughter process with id PID ends and returns statusof its ending.
int wait(int pid)
{
return process_wait(pid);
}
//Ended user's programm returned status. status 0 - ok
int exit(int status)
{
struct thread *t=thread_current();
struct list_elem *l;
printf("%s, exit %d.\n", thread_current()->name, status);
while (!list_empty (&t->files))
{
l=list_begin(&t->files);
close(list_entry(l,struct fd_des, t_elem)->fd);
}
thread_exit();
return -1;
}
//creates a new file «file» with size initial_size. returns TRUE if ok, otherwise FALSE.
int create (const char *file, unsigned int initial_size)
{
if(!file)
return exit(1);
return filesys_create(file, initial_size);
}
//starts file, which name is in cmd_line and returns new user's process id. Returns -1 if false
int exec(const char *cmd_line)
{
if(!cmd_line)
return -1;
return process_execute(cmd_line);
}
//open file named «file». Return fd or -1 if fail. fd 0 - STDIN_FILENO, fd 1 -STDOUT_FILENO.
int open(const char *file)
{
int temp=1;
struct file *f=filesys_open(file);
if(!file || !f)
return -1;
struct fd_des *des=(struct fd_des*)malloc(sizeof (struct fd_des));
if(!des)
{
file_close(f);
return -1;
}
des->file=f;
des->fd=++temp;
list_push_back (&file_list, &des->elem);
list_push_back(&thread_current()->files, &des->t_elem);
return (des->fd);
}
int close (int fd)
{
struct fd_des *des;
des=find_fd_elem_by_fd(fd);
if(!des)
return 0;
file_close(des->file);
list_remove(&des->elem);
list_remove(&des->t_elem);
//free(des);
return 0;
}
//writes SIZE byte to the fd file. returns num of recorded bytes or -1 if fail. if fd=1 then
// system must do console output
int write(int fd, const void *buffer, unsigned size)
{
struct file *file;
int length=-1;
lock_acquire(&file_lock);
if(fd == STDOUT_FILENO)
{
putbuf(buffer, size);
lock_release(&file_lock);
return size;
}
else if (fd == STDIN_FILENO)
goto finish;
else
{
file=find_file_by_fd(fd);
if(!file)
goto finish;
length=file_write(file,buffer,size);
}
finish:
lock_release(&file_lock);
return (length);
}
int read(int fd, void *buffer, unsigned size)
{
struct file *file;
int status=-1,i;
lock_acquire(&file_lock);
if(fd == STDIN_FILENO)
{
for(i = 1; i != size; i++)
*(uint8_t*)(buffer+i)=input_getc();
status=size;
goto finish;
}
else if (fd=STDOUT_FILENO)
goto finish;
else
{
file=find_file_by_fd(fd);
if(!file)
goto finish;
status=file_read(file,buffer,size);
}
finish:
lock_release(&file_lock);
return status;
}*/
Результат
После внесения модификаций я пробовал запустить некоторые тесты из Приложения III, где перечислен список тестов для системных вызовов. Они завершались приведенной ниже ошибкой Error 1 без объяснения.
После этого я сократил оператор switch до одного варианта: функции halt(), т.к. в ней мы вызываем готовую функцию завершения работы ОС Pintos и ничего не подаем на вход функции. Запустил тест halt и вышла снова эта ошибка.
Ответы на контрольные вопросы
1. В чем заключается идея системных вызовов?
Системные вызовы обеспечивают взаимосвязь между ядром и программами пользователя.
- В ОС Pintos используется только одно прерывание 0x30 и только один обработчик прерываний syscall_handler для всех системных вызовов. Как различить в syscall_handler системные вызовы?
Простым оператором switch и считанными из стека данными.
- Стандартом в построении операционных систем является следующее требование: системные вызовы read() и write() могут быть использованы только после вызова open(), а завершение их работы сопровождается вызовом close(). В чем причина появления этого требования? Почему нельзя иметь системные вызовы read() и write() без предварительного обращения к open() и close()?
Я бы назвал это чисто логическим требованием. Сначала мы открываем файл, потом читаем/записываем, потом закрываем.
- Что произойдет, если процесс-потомок завершится раньше, чем процесс-предок осуществит системный вызов wait()?
Перед вызовом wait() осуществляется проверка статуса процесса-потомка. Если у потомка статус THREAD_DYING, тогда я осуществил вывод THREAD_ERROR.
- В чем отличие в обработке внутренних и внешних прерываний в ОС Pintos? В ОС UNIX?
Внешние можно отключить с помощью intr_disable();