]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: real advisory file locking (flock) replacing no-op stub
authorTulio A M Mendes <[email protected]>
Sat, 14 Feb 2026 00:02:38 +0000 (21:02 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 14 Feb 2026 00:02:38 +0000 (21:02 -0300)
- syscall.c: implemented flock_table (64 entries) with spinlock-protected
  advisory locking supporting LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB
- flock_do(): handles shared/exclusive acquisition with conflict detection,
  upgrade/downgrade of existing locks, blocking retry via process_sleep
- flock_release_pid(): releases all locks for a process on exit
- SYSCALL_EXIT: calls flock_release_pid before closing files
- errno.h: added ENOLCK=37, EWOULDBLOCK=EAGAIN (kernel + userland)
- sys/file.h: new userland header with LOCK_SH/EX/NB/UN defines

Previously flock() was a silent no-op returning 0. Now it provides
real advisory locking semantics needed by SQLite and daemons.

20/20 smoke tests pass.

include/errno.h
src/kernel/syscall.c
user/ulibc/include/errno.h
user/ulibc/include/sys/file.h [new file with mode: 0644]

index 27199271167ad6e55a64da6820fdb34a1cadf7c2..78105c910e82861a312a02fd3f20f9c9b3f95467 100644 (file)
@@ -35,5 +35,7 @@
 #define EPROTONOSUPPORT 93
 #define ECONNRESET 54
 #define ETIMEDOUT 60
+#define ENOLCK 37
+#define EWOULDBLOCK EAGAIN
 
 #endif
index 93c61734c083c48a9cce56a089d1f781ca271249..91ad0d7c958782a1b937c6eabf51fe73891b27be 100644 (file)
@@ -63,6 +63,106 @@ enum {
     FD_CLOEXEC = 1,
 };
 
+/* --- Advisory file locking (flock) --- */
+enum {
+    FLOCK_SH = 1,
+    FLOCK_EX = 2,
+    FLOCK_NB = 4,
+    FLOCK_UN = 8,
+};
+
+#define FLOCK_TABLE_SIZE 64
+
+struct flock_entry {
+    uint32_t inode;
+    uint32_t pid;
+    int      type;      /* FLOCK_SH or FLOCK_EX */
+    int      active;
+};
+
+static struct flock_entry flock_table[FLOCK_TABLE_SIZE];
+static spinlock_t flock_lock_g = {0};
+
+static int flock_can_acquire(uint32_t inode, uint32_t pid, int type) {
+    for (int i = 0; i < FLOCK_TABLE_SIZE; i++) {
+        if (!flock_table[i].active || flock_table[i].inode != inode)
+            continue;
+        if (flock_table[i].pid == pid)
+            continue; /* our own lock — will be upgraded/downgraded */
+        if (type == FLOCK_EX || flock_table[i].type == FLOCK_EX)
+            return 0; /* conflict */
+    }
+    return 1;
+}
+
+static int flock_do(uint32_t inode, uint32_t pid, int operation) {
+    int type = operation & (FLOCK_SH | FLOCK_EX);
+    int nonblock = operation & FLOCK_NB;
+
+    if (operation & FLOCK_UN) {
+        uintptr_t fl = spin_lock_irqsave(&flock_lock_g);
+        for (int i = 0; i < FLOCK_TABLE_SIZE; i++) {
+            if (flock_table[i].active && flock_table[i].inode == inode &&
+                flock_table[i].pid == pid) {
+                flock_table[i].active = 0;
+                break;
+            }
+        }
+        spin_unlock_irqrestore(&flock_lock_g, fl);
+        return 0;
+    }
+
+    if (!type) return -EINVAL;
+
+    for (;;) {
+        uintptr_t fl = spin_lock_irqsave(&flock_lock_g);
+
+        if (flock_can_acquire(inode, pid, type)) {
+            /* Find existing entry for this pid+inode or allocate new */
+            int slot = -1;
+            int free_slot = -1;
+            for (int i = 0; i < FLOCK_TABLE_SIZE; i++) {
+                if (flock_table[i].active && flock_table[i].inode == inode &&
+                    flock_table[i].pid == pid) {
+                    slot = i;
+                    break;
+                }
+                if (!flock_table[i].active && free_slot < 0)
+                    free_slot = i;
+            }
+            if (slot >= 0) {
+                flock_table[slot].type = type; /* upgrade/downgrade */
+            } else if (free_slot >= 0) {
+                flock_table[free_slot].inode = inode;
+                flock_table[free_slot].pid = pid;
+                flock_table[free_slot].type = type;
+                flock_table[free_slot].active = 1;
+            } else {
+                spin_unlock_irqrestore(&flock_lock_g, fl);
+                return -ENOLCK;
+            }
+            spin_unlock_irqrestore(&flock_lock_g, fl);
+            return 0;
+        }
+
+        spin_unlock_irqrestore(&flock_lock_g, fl);
+
+        if (nonblock) return -EWOULDBLOCK;
+
+        extern void process_sleep(uint32_t ticks);
+        process_sleep(1); /* block and retry */
+    }
+}
+
+static void flock_release_pid(uint32_t pid) {
+    uintptr_t fl = spin_lock_irqsave(&flock_lock_g);
+    for (int i = 0; i < FLOCK_TABLE_SIZE; i++) {
+        if (flock_table[i].active && flock_table[i].pid == pid)
+            flock_table[i].active = 0;
+    }
+    spin_unlock_irqrestore(&flock_lock_g, fl);
+}
+
 enum {
     FCNTL_F_DUPFD = 0,
     FCNTL_F_GETFD = 1,
@@ -1841,6 +1941,8 @@ void syscall_handler(struct registers* regs) {
     if (syscall_no == SYSCALL_EXIT) {
         int status = (int)sc_arg0(regs);
 
+        if (current_process) flock_release_pid(current_process->pid);
+
         for (int fd = 0; fd < PROCESS_MAX_FILES; fd++) {
             if (current_process && current_process->files[fd]) {
                 (void)fd_close(fd);
@@ -2327,10 +2429,12 @@ void syscall_handler(struct registers* regs) {
 
     if (syscall_no == SYSCALL_FLOCK) {
         int fd = (int)sc_arg0(regs);
+        int operation = (int)sc_arg1(regs);
         if (!current_process || fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd]) {
             sc_ret(regs) = (uint32_t)-EBADF;
         } else {
-            sc_ret(regs) = 0; /* advisory lock — no-op stub */
+            uint32_t ino = current_process->files[fd]->node->inode;
+            sc_ret(regs) = (uint32_t)flock_do(ino, current_process->pid, operation);
         }
         return;
     }
index a567956453ec3a31596b9b0ece178ff9cfc61737..a069abea18c2d1b02f4fb8f0699b3fc546c52637 100644 (file)
@@ -24,6 +24,8 @@ extern int errno;
 #define EPIPE   32
 #define ENOSYS  38
 #define ENOTEMPTY 39
+#define ENOLCK   37
+#define EWOULDBLOCK EAGAIN
 
 /* Convert raw syscall return to errno-style */
 static inline int __syscall_ret(int r) {
diff --git a/user/ulibc/include/sys/file.h b/user/ulibc/include/sys/file.h
new file mode 100644 (file)
index 0000000..9e34212
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef ULIBC_SYS_FILE_H
+#define ULIBC_SYS_FILE_H
+
+#define LOCK_SH  1   /* shared lock */
+#define LOCK_EX  2   /* exclusive lock */
+#define LOCK_NB  4   /* non-blocking */
+#define LOCK_UN  8   /* unlock */
+
+int flock(int fd, int operation);
+
+#endif