Skip to content

Commit

Permalink
basic file descriptor support (cahirwpz#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalcieslak authored and cahirwpz committed Jan 4, 2017
1 parent 63e6fea commit 42fb0f0
Show file tree
Hide file tree
Showing 23 changed files with 669 additions and 68 deletions.
72 changes: 72 additions & 0 deletions include/file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef _SYS_FILE_H_
#define _SYS_FILE_H_

#include <stdint.h>
#include <stddef.h>
#include <mutex.h>
#include <uio.h>

typedef struct thread thread_t;
typedef struct file file_t;
typedef struct vnode vnode_t;

typedef int fo_read_t(file_t *f, thread_t *td, uio_t *uio);
typedef int fo_write_t(file_t *f, thread_t *td, uio_t *uio);
typedef int fo_close_t(file_t *f, thread_t *td);

typedef struct {
fo_read_t *fo_read;
fo_write_t *fo_write;
fo_close_t *fo_close;
} fileops_t;

typedef enum {
FT_VNODE = 1, /* regular file */
FT_PIPE = 2, /* pipe */
} filetype_t;

#define FF_READ 0x0001
#define FF_WRITE 0x0002
#define FF_APPEND 0x0004

/* File open flags as passed to sys_open. These need match what newlib provides
to user programs. */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2

typedef struct file {
void *f_data; /* File specific data */
fileops_t *f_ops;
filetype_t f_type; /* File type */
vnode_t *f_vnode;
int f_count; /* Reference count, ready for disposal if -1 */
unsigned f_flags; /* File flags FF_* */
mtx_t f_mtx;
} file_t;

void file_init();

void file_ref(file_t *f);
void file_unref(file_t *f);

file_t *file_alloc();
void file_destroy(file_t *f);
/* Drop reference counter and possibly destroy the file. */
void file_release(file_t *f);

static inline int FOP_READ(file_t *f, thread_t *td, uio_t *uio) {
return f->f_ops->fo_read(f, td, uio);
}

static inline int FOP_WRITE(file_t *f, thread_t *td, uio_t *uio) {
return f->f_ops->fo_write(f, td, uio);
}

static inline int FOP_CLOSE(file_t *f, thread_t *td) {
return f->f_ops->fo_close(f, td);
}

extern fileops_t badfileops;

#endif /* !_SYS_FILE_H_ */
47 changes: 47 additions & 0 deletions include/filedesc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef _SYS_FILEDESC_H_
#define _SYS_FILEDESC_H_

#include <file.h>
#include <bitstring.h>
#include <mutex.h>

/* The initial size of space allocated for file descriptors. According
to FreeBSD, this is more than enough for most applications. Each
process starts with this many descriptors, and more are allocated
on demand. */
#define NDFILE 20
/* Separate macro defining a hard limit on open files. */
#define MAXFILES 20

typedef struct fdtab {
file_t *fdt_files[NDFILE]; /* Open files array */
bitstr_t fdt_map[bitstr_size(NDFILE)]; /* Bitmap of used fds */
unsigned fdt_flags;
unsigned fdt_nfiles; /* Number of files allocated */
int fdt_count; /* Reference count, ready for disposal if -1 */
mtx_t fdt_mtx;
} fdtab_t;

/* Prepares memory pools for file descriptors and tables. */
void fd_init();

void fdtab_ref(fdtab_t *fdt);
void fdtab_unref(fdtab_t *fdt);

/* Allocates a new descriptor table. */
fdtab_t *fdtab_alloc();
/* Allocates a new descriptor table making it a copy of an existing one. */
fdtab_t *fdtab_copy(fdtab_t *fdt);
/* Frees the table and possibly closes underlying files. */
void fdtab_destroy(fdtab_t *fdt);
/* Drop reference counter and possibly destroy the table. */
void fdtab_release(fdtab_t *fdt);
/* Assign a file structure to a new descriptor. */
int fdtab_install_file(fdtab_t *fdt, file_t *f, int *fdp);
/* Extracts a reference to file from descriptor table for given number. */
int fdtab_get_file(fdtab_t *fdt, int fd, int flags, file_t **fp);
/* Closes a file descriptor.
* If it was the last reference to a file, the file is closed as well. */
int fdtab_close_fd(fdtab_t *fdt, int fd);

#endif /* !_SYS_FILEDESC_H_ */
4 changes: 4 additions & 0 deletions include/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef struct mount mount_t;
typedef struct vnode vnode_t;
typedef struct vfsconf vfsconf_t;
typedef struct statfs statfs_t;
typedef struct file file_t;

/* VFS operations */
typedef int vfs_mount_t(mount_t *m);
Expand Down Expand Up @@ -93,6 +94,9 @@ int vfs_domount(vfsconf_t *vfc, vnode_t *v);
* Increases use count on returned vnode. */
int vfs_lookup(const char *pathname, vnode_t **vp);

/* Looks up the vnode corresponding to the pathname and opens it into f. &*/
int vfs_open(file_t *f, char *pathname, int flags, int mode);

/* Initializes the VFS subsystem. */
void vfs_init();

Expand Down
3 changes: 3 additions & 0 deletions include/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ typedef uint8_t td_prio_t;
typedef uint32_t tid_t;
typedef struct vm_page vm_page_t;
typedef struct vm_map vm_map_t;
typedef struct fdtab fdtab_t;

#define TD_NAME_MAX 32

Expand All @@ -37,6 +38,8 @@ typedef struct thread {
vm_page_t *td_kstack_obj;
stack_t td_kstack;
vm_map_t *td_uspace; /* thread's user space map */
/* file descriptors table */
fdtab_t *td_fdtable;
/* waiting channel */
sleepq_t *td_sleepqueue;
void *td_wchan;
Expand Down
21 changes: 21 additions & 0 deletions include/vfs_syscalls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _SYS_VFS_SYSCALLS_H_
#define _SYS_VFS_SYSCALLS_H_

#include <uio.h>

typedef struct thread thread_t;
typedef struct syscall_args syscall_args_t;

/* Kernel interface */
int do_open(thread_t *td, char *pathname, int flags, int mode, int *fd);
int do_close(thread_t *td, int fd);
int do_read(thread_t *td, int fd, uio_t *uio);
int do_write(thread_t *td, int fd, uio_t *uio);

/* Syscall interface */
int sys_open(thread_t *td, syscall_args_t *args);
int sys_close(thread_t *td, syscall_args_t *args);
int sys_read(thread_t *td, syscall_args_t *args);
int sys_write(thread_t *td, syscall_args_t *args);

#endif /* !_SYS_VFS_SYSCALLS_H_ */
2 changes: 2 additions & 0 deletions include/vnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,6 @@ void vnode_unref(vnode_t *v);
/* Convenience function for filling in not supported vnodeops */
int vnode_op_notsup();

int vnode_open_generic(vnode_t *v, int mode, file_t *fp);

#endif /* !_SYS_VNODE_H_ */
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ SOURCES_C = \
devfs.c \
exception.c \
exec.c \
file.c \
filedesc.c \
interrupt.c \
malloc.c \
mutex.c \
Expand All @@ -25,6 +27,7 @@ SOURCES_C = \
turnstile.c \
uio.c \
vfs.c \
vfs_syscalls.c \
vm_map.c \
vm_object.c \
vm_pager.c \
Expand Down
5 changes: 3 additions & 2 deletions sys/dev_null.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <mount.h>
#include <devfs.h>
#include <malloc.h>
#include <vnode.h>
#include <linker_set.h>

static vnode_t *dev_null_device;
Expand Down Expand Up @@ -44,7 +45,7 @@ static int dev_zero_read(vnode_t *t, uio_t *uio) {
static vnodeops_t dev_null_vnodeops = {
.v_lookup = vnode_op_notsup,
.v_readdir = vnode_op_notsup,
.v_open = vnode_op_notsup,
.v_open = vnode_open_generic,
.v_write = dev_null_write,
.v_read = dev_null_read,
.v_getattr = vnode_op_notsup,
Expand All @@ -53,7 +54,7 @@ static vnodeops_t dev_null_vnodeops = {
static vnodeops_t dev_zero_vnodeops = {
.v_lookup = vnode_op_notsup,
.v_readdir = vnode_op_notsup,
.v_open = vnode_op_notsup,
.v_open = vnode_open_generic,
.v_write = dev_zero_write,
.v_read = dev_zero_read,
.v_getattr = vnode_op_notsup,
Expand Down
4 changes: 2 additions & 2 deletions sys/dev_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ static int dev_uart_write(vnode_t *t, uio_t *uio) {
}

static int dev_uart_read(vnode_t *t, uio_t *uio) {
return ENOTSUP;
return -ENOTSUP;
}

vnodeops_t dev_uart_vnodeops = {
.v_lookup = vnode_op_notsup,
.v_readdir = vnode_op_notsup,
.v_open = vnode_op_notsup,
.v_open = vnode_open_generic,
.v_write = dev_uart_write,
.v_read = dev_uart_read,
};
Expand Down
6 changes: 3 additions & 3 deletions sys/devfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ static devfs_device_t *devfs_get_by_name(const char *name) {
int devfs_install(const char *name, vnode_t *device) {
size_t n = strlen(name);
if (n >= DEVFS_NAME_MAX)
return ENAMETOOLONG;
return -ENAMETOOLONG;

if (devfs_get_by_name(name) != NULL)
return EEXIST;
return -EEXIST;

devfs_device_t *idev = kmalloc(devfs_pool, sizeof(devfs_device_t), M_ZERO);
strlcpy(idev->name, name, DEVFS_NAME_MAX);
Expand Down Expand Up @@ -90,7 +90,7 @@ static int devfs_root_lookup(vnode_t *dir, const char *name, vnode_t **res) {

devfs_device_t *idev = devfs_get_by_name(name);
if (!idev)
return ENOENT;
return -ENOENT;

*res = idev->dev;
vnode_ref(*res);
Expand Down
16 changes: 16 additions & 0 deletions sys/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <string.h>
#include <errno.h>
#include <sync.h>
#include <filedesc.h>
#include <vfs_syscalls.h>
#include <mips/stack.h>

#define EMBED_ELF_DECLARE(name) \
Expand Down Expand Up @@ -190,6 +192,20 @@ int do_exec(const exec_args_t *args) {
log("Stack real bottom at %p", (void *)stack_bottom);
prepare_program_stack(args, &stack_bottom);

thread_t *td = thread_self();
/* ... file descriptor table ... */
/* TODO: Copy/share file descriptor table! */
fdtab_t *fdt = fdtab_alloc();
fdtab_ref(fdt);
td->td_fdtable = fdt;

/* Before we have a working fork, let's initialize file descriptors required
by the standard library. */
int ignore;
do_open(td, "/dev/uart", O_RDONLY, 0, &ignore);
do_open(td, "/dev/uart", O_WRONLY, 0, &ignore);
do_open(td, "/dev/uart", O_WRONLY, 0, &ignore);

/* ... and user context. */
uctx_init(thread_self(), eh->e_entry, stack_bottom);

Expand Down
74 changes: 74 additions & 0 deletions sys/file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <file.h>
#include <malloc.h>
#include <stdc.h>
#include <errno.h>
#include <mutex.h>

static MALLOC_DEFINE(file_pool, "file pool");

void file_init() {
kmalloc_init(file_pool);
kmalloc_add_pages(file_pool, 2);
}

void file_ref(file_t *f) {
mtx_lock(&f->f_mtx);
assert(f->f_count >= 0);
f->f_count++;
mtx_unlock(&f->f_mtx);
}

void file_unref(file_t *f) {
mtx_lock(&f->f_mtx);
assert(f->f_count > 0);
if (--f->f_count == 0)
f->f_count = -1;
mtx_unlock(&f->f_mtx);
}

file_t *file_alloc() {
file_t *f = kmalloc(file_pool, sizeof(file_t), M_ZERO);
f->f_ops = &badfileops;
mtx_init(&f->f_mtx);
return f;
}

/* May be called after the last reference to a file has been dropped. */
void file_destroy(file_t *f) {
assert(f->f_count <= 0);

/* Note: If the file failed to open, we shall not close it. In such case its
fileops are set to badfileops. */
/* TODO: What if an error happens during close? */
if (f->f_ops != &badfileops)
FOP_CLOSE(f, thread_self());

kfree(file_pool, f);
}

void file_release(file_t *f) {
if (f) {
file_unref(f);
if (f->f_count < 0)
file_destroy(f);
}
}

/* Operations on invalid file descriptors */
static int badfo_read(file_t *f, struct thread *td, uio_t *uio) {
return -EBADF;
}

static int badfo_write(file_t *f, struct thread *td, uio_t *uio) {
return -EBADF;
}

static int badfo_close(file_t *f, struct thread *td) {
return -EBADF;
}

fileops_t badfileops = {
.fo_read = badfo_read,
.fo_write = badfo_write,
.fo_close = badfo_close,
};
Loading

0 comments on commit 42fb0f0

Please sign in to comment.