/* Thread support */
uint32_t tgid; /* Thread group ID (== pid for group leader) */
uint32_t flags; /* PROCESS_FLAG_* */
+ uint32_t as_refcount; /* CLONE_VM address space reference count */
uintptr_t tls_base; /* User-space TLS base (set via SET_THREAD_AREA) */
uint32_t* clear_child_tid; /* User address to clear + futex-wake on exit */
*/
#include "process.h"
+
+/* ---- CLONE_VM address-space refcount table ---- */
+#define AS_REFCOUNT_MAX 64
+static struct { uintptr_t as; uint32_t refcnt; } g_as_refcnt[AS_REFCOUNT_MAX];
+
+static void as_refcount_inc(uintptr_t as) {
+ if (!as) return;
+ for (int i = 0; i < AS_REFCOUNT_MAX; i++) {
+ if (g_as_refcnt[i].as == as) { g_as_refcnt[i].refcnt++; return; }
+ }
+ for (int i = 0; i < AS_REFCOUNT_MAX; i++) {
+ if (g_as_refcnt[i].as == 0) { g_as_refcnt[i].as = as; g_as_refcnt[i].refcnt = 1; return; }
+ }
+}
+
+static uint32_t as_refcount_dec(uintptr_t as) {
+ if (!as) return 0;
+ for (int i = 0; i < AS_REFCOUNT_MAX; i++) {
+ if (g_as_refcnt[i].as == as) {
+ if (g_as_refcnt[i].refcnt > 0) g_as_refcnt[i].refcnt--;
+ uint32_t r = g_as_refcnt[i].refcnt;
+ if (r == 0) { g_as_refcnt[i].as = 0; }
+ return r;
+ }
+ }
+ return 0;
+}
#include "pmm.h"
#include "vmm.h"
#include "heap.h"
}
if (p->addr_space && p->addr_space != kernel_as) {
- /* Threads share addr_space with group leader; don't destroy it */
- if (!(p->flags & PROCESS_FLAG_THREAD)) {
+ if (p->flags & PROCESS_FLAG_THREAD) {
+ /* Thread: decrement the AS refcount; destroy if last ref */
+ if (as_refcount_dec(p->addr_space) == 0) {
+ vmm_as_destroy(p->addr_space);
+ }
+ } else if (p->as_refcount > 0) {
+ /* Leader with live threads: decrement refcount; last one destroys */
+ if (as_refcount_dec(p->addr_space) == 0) {
+ vmm_as_destroy(p->addr_space);
+ }
+ } else {
+ /* Regular process (no CLONE_VM threads): safe to destroy */
vmm_as_destroy(p->addr_space);
}
p->addr_space = 0;
if (clone_flags & CLONE_VM) {
proc->addr_space = current_process->addr_space;
proc->flags |= PROCESS_FLAG_THREAD;
+ /* If this is the first thread, add the parent's own ref to the table */
+ if (current_process->as_refcount == 0) {
+ as_refcount_inc(proc->addr_space); /* parent's ref */
+ }
+ as_refcount_inc(proc->addr_space); /* child's ref */
+ current_process->as_refcount++;
} else {
proc->addr_space = vmm_as_clone_user_cow(current_process->addr_space);
if (!proc->addr_space) {
if (rc < 0) return rc;
} else if (!node) {
return -ENOENT;
+ } else if ((flags & 0x40U) != 0U && (flags & 0x80U) != 0U) {
+ /* O_CREAT | O_EXCL on existing file → EEXIST */
+ return -EEXIST;
+ } else if ((flags & 0x10000U) != 0U && !(node->flags & FS_DIRECTORY)) {
+ /* O_DIRECTORY on non-directory → ENOTDIR */
+ return -ENOTDIR;
} else if ((flags & 0x200U) != 0U && node->flags == FS_FILE) {
/* O_TRUNC on existing file */
if (node->i_ops && node->i_ops->truncate) {
return 0;
}
-static int syscall_mkdir_impl(const char* user_path) {
+static int syscall_mkdir_impl(const char* user_path, uint32_t mode) {
+ (void)mode; /* TODO: pass mode to vfs_mkdir once FS backends support it */
if (!user_path) return -EFAULT;
char path[128];
if (syscall_no == SYSCALL_MKDIR) {
const char* path = (const char*)sc_arg0(regs);
- sc_ret(regs) = (uint32_t)syscall_mkdir_impl(path);
+ uint32_t mode = sc_arg1(regs);
+ sc_ret(regs) = (uint32_t)syscall_mkdir_impl(path, mode);
return;
}
uint32_t length = sc_arg1(regs);
struct file* f = fd_get(fd);
if (!f || !f->node) { sc_ret(regs) = (uint32_t)-EBADF; return; }
+ if ((f->flags & 3U) == 0U) { sc_ret(regs) = (uint32_t)-EBADF; return; } /* O_RDONLY */
if (!(f->node->flags & FS_FILE)) { sc_ret(regs) = (uint32_t)-EINVAL; return; }
f->node->length = length;
sc_ret(regs) = 0;
fs_node_t* node = vfs_lookup(path);
if (!node) { sc_ret(regs) = (uint32_t)-ENOENT; return; }
if (!(node->flags & FS_FILE)) { sc_ret(regs) = (uint32_t)-EISDIR; return; }
+ if (vfs_check_permission(node, 2) != 0) { sc_ret(regs) = (uint32_t)-EACCES; return; } /* write */
node->length = length;
sc_ret(regs) = 0;
return;
char* const argv[], char* const envp[]) {
(void)file_actions;
(void)attrp;
- (void)envp;
- int ret = _syscall2(SYS_POSIX_SPAWN, (int)path, (int)argv);
+ int ret = _syscall4(SYS_POSIX_SPAWN, (int)pid, (int)path, (int)argv, (int)envp);
if (ret < 0) {
errno = -ret;
return -ret;