summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2022-05-06 14:41:58 +0200
committerdzwdz2022-05-06 14:41:58 +0200
commit8ee57c885a72854d1884a886de4db538a8468e07 (patch)
tree9c9f2eea8d7667ce7ed45dd71b6bbde40ce93f7e /src/kernel
parent53d21d1ccb75004d0085efedd688b695707a3138 (diff)
syscalls: merge fork() and fs_fork2()
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/proc.c12
-rw-r--r--src/kernel/syscalls.c67
2 files changed, 44 insertions, 35 deletions
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index ed257fd..7ef4579 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -44,7 +44,7 @@ struct process *process_seed(struct kmain_info *info) {
struct process *process_fork(struct process *parent, int flags) {
struct process *child = kmalloc(sizeof *child);
- memcpy(child, parent, sizeof *child);
+ memcpy(child, parent, sizeof *child); // TODO manually set fields
child->pages = pagedir_copy(parent->pages);
child->sibling = parent->child;
@@ -55,9 +55,13 @@ struct process *process_fork(struct process *parent, int flags) {
parent->handled_req = NULL; // TODO control this with a flag
- if (child->controlled) {
- child->controlled->potential_handlers++;
- child->controlled->refcount++;
+ if ((flags & FORK_NEWFS) == 0) {
+ if (child->controlled) {
+ child->controlled->potential_handlers++;
+ child->controlled->refcount++;
+ }
+ } else {
+ child->controlled = NULL;
}
for (handle_t h = 0; h < HANDLE_MAX; h++) {
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 3443b60..59358a8 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -39,9 +39,42 @@ int _syscall_await(void) {
}
}
-int _syscall_fork(int flags) {
- struct process *child = process_fork(process_current, flags);
+int _syscall_fork(int flags, handle_t __user *fs_front) {
+ struct process *child;
+ handle_t front;
+
+ if ((flags & FORK_NEWFS) && fs_front) {
+ /* we'll need to return a handle, check if that's possible */
+ front = process_find_free_handle(process_current, 1);
+ if (front < 0) SYSCALL_RETURN(-1);
+ }
+
+ child = process_fork(process_current, flags);
regs_savereturn(&child->regs, 0);
+
+ if ((flags & FORK_NEWFS) && fs_front) {
+ struct vfs_backend *backend = kmalloc(sizeof *backend);
+
+ process_current->handles[front] = handle_init(HANDLE_FS_FRONT);
+
+ backend->heap = true;
+ backend->is_user = true;
+ backend->potential_handlers = 1;
+ backend->refcount = 2; // child + handle
+ backend->user.handler = NULL;
+ backend->queue = NULL;
+
+ child->controlled = backend;
+
+ process_current->handles[front]->fs.backend = backend;
+
+ if (fs_front) {
+ /* failure ignored. if you pass an invalid pointer to this function,
+ * you just don't receive the handle. you'll probably segfault
+ * trying to access it anyways */
+ virt_cpy_to(process_current->pages, fs_front, &front, sizeof front);
+ }
+ }
SYSCALL_RETURN(1);
}
@@ -179,32 +212,6 @@ int _syscall_close(handle_t hid) {
SYSCALL_RETURN(0);
}
-handle_t _syscall_fs_fork2(void) {
- struct vfs_backend *backend;
- struct process *child;
- handle_t front;
-
- front = process_find_free_handle(process_current, 1);
- if (front < 0) SYSCALL_RETURN(-1);
- process_current->handles[front] = handle_init(HANDLE_FS_FRONT);
-
- backend = kmalloc(sizeof *backend);
- backend->heap = true;
- backend->is_user = true;
- backend->potential_handlers = 1;
- backend->refcount = 2; // child + handle
- backend->user.handler = NULL;
- backend->queue = NULL;
-
- child = process_fork(process_current, 0);
- if (child->controlled) vfs_backend_refdown(child->controlled);
- child->controlled = backend;
- regs_savereturn(&child->regs, 0);
-
- process_current->handles[front]->fs.backend = backend;
- SYSCALL_RETURN(front);
-}
-
int _syscall_fs_wait(char __user *buf, int max_len, struct fs_wait_response __user *res) {
struct vfs_backend *backend = process_current->controlled;
if (!backend) SYSCALL_RETURN(-1);
@@ -267,7 +274,7 @@ int _syscall(int num, int a, int b, int c, int d) {
case _SYSCALL_AWAIT:
return _syscall_await();
case _SYSCALL_FORK:
- return _syscall_fork(a);
+ return _syscall_fork(a, (userptr_t)b);
case _SYSCALL_OPEN:
return _syscall_open((userptr_t)a, b);
case _SYSCALL_MOUNT:
@@ -278,8 +285,6 @@ int _syscall(int num, int a, int b, int c, int d) {
return _syscall_write(a, (userptr_t)b, c, d);
case _SYSCALL_CLOSE:
return _syscall_close(a);
- case _SYSCALL_FS_FORK2:
- return _syscall_fs_fork2();
case _SYSCALL_FS_WAIT:
return _syscall_fs_wait((userptr_t)a, b, (userptr_t)c);
case _SYSCALL_FS_RESPOND: