]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: POSIX message queues (mq_open, mq_close, mq_send, mq_receive, mq_unlink)
authorTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 01:05:30 +0000 (22:05 -0300)
committerTulio A M Mendes <[email protected]>
Sun, 15 Feb 2026 01:05:30 +0000 (22:05 -0300)
- 8 named queues, 16 messages x 256 bytes each
- Spinlock-protected circular buffer per queue
- SYSCALL_MQ_OPEN=97, MQ_CLOSE=98, MQ_SEND=99, MQ_RECEIVE=100, MQ_UNLINK=101
- Added EMSGSIZE errno (90)
- 35/35 smoke tests pass, cppcheck clean

include/errno.h
include/syscall.h
src/kernel/syscall.c

index ec682f445537b4794b058f6f79d643f61ccdb97c..77335b1adbe1ea36a7d91966807e104d751bd236 100644 (file)
@@ -37,6 +37,7 @@
 #define ETIMEDOUT 60
 #define ENOLCK 37
 #define EBUSY 16
+#define EMSGSIZE 90
 #define EWOULDBLOCK EAGAIN
 
 #endif
index 3baebe90746e3e1fb735f334cf5e02b9898c0f8a..532d720cb00b8d651f5d83239a087dda7cf72318 100644 (file)
@@ -120,6 +120,11 @@ enum {
     SYSCALL_WAITID     = 94,
     SYSCALL_SIGQUEUE   = 95,
     SYSCALL_POSIX_SPAWN = 96,
+    SYSCALL_MQ_OPEN     = 97,
+    SYSCALL_MQ_CLOSE    = 98,
+    SYSCALL_MQ_SEND     = 99,
+    SYSCALL_MQ_RECEIVE  = 100,
+    SYSCALL_MQ_UNLINK   = 101,
 };
 
 #endif
index a4b6dbe415d05feef0ebd32a968e84c984298784..6e388b8547b90ef42fd894eae2c0a9d21fa9fa69 100644 (file)
@@ -64,6 +64,135 @@ enum {
     FD_CLOEXEC = 1,
 };
 
+/* --- POSIX message queues --- */
+#define MQ_MAX_QUEUES  8
+#define MQ_MAX_MSGS    16
+#define MQ_MSG_SIZE    256
+
+struct mq_msg {
+    uint8_t  data[MQ_MSG_SIZE];
+    uint32_t len;
+    uint32_t prio;
+};
+
+struct mq_queue {
+    int      active;
+    char     name[32];
+    struct mq_msg msgs[MQ_MAX_MSGS];
+    uint32_t head;
+    uint32_t tail;
+    uint32_t count;
+    uint32_t maxmsg;
+    uint32_t msgsize;
+};
+
+static struct mq_queue mq_table[MQ_MAX_QUEUES];
+static spinlock_t mq_lock = {0};
+
+static int mq_find_by_name(const char* name) {
+    for (int i = 0; i < MQ_MAX_QUEUES; i++) {
+        if (mq_table[i].active && strcmp(mq_table[i].name, name) == 0)
+            return i;
+    }
+    return -1;
+}
+
+static int syscall_mq_open_impl(const char* user_name, uint32_t oflag) {
+    char name[32];
+    if (copy_from_user(name, user_name, 31) < 0) return -EFAULT;
+    name[31] = 0;
+
+    uintptr_t fl = spin_lock_irqsave(&mq_lock);
+    int idx = mq_find_by_name(name);
+    if (idx >= 0) {
+        spin_unlock_irqrestore(&mq_lock, fl);
+        return idx;
+    }
+    if (!(oflag & 0x40U)) { /* O_CREAT */
+        spin_unlock_irqrestore(&mq_lock, fl);
+        return -ENOENT;
+    }
+    for (int i = 0; i < MQ_MAX_QUEUES; i++) {
+        if (!mq_table[i].active) {
+            memset(&mq_table[i], 0, sizeof(mq_table[i]));
+            mq_table[i].active = 1;
+            strcpy(mq_table[i].name, name);
+            mq_table[i].maxmsg = MQ_MAX_MSGS;
+            mq_table[i].msgsize = MQ_MSG_SIZE;
+            spin_unlock_irqrestore(&mq_lock, fl);
+            return i;
+        }
+    }
+    spin_unlock_irqrestore(&mq_lock, fl);
+    return -ENOSPC;
+}
+
+static int syscall_mq_close_impl(int mqd) {
+    (void)mqd;
+    return 0;
+}
+
+static int syscall_mq_send_impl(int mqd, const void* user_buf, uint32_t len, uint32_t prio) {
+    if (mqd < 0 || mqd >= MQ_MAX_QUEUES) return -EBADF;
+    if (len > MQ_MSG_SIZE) return -EMSGSIZE;
+
+    uintptr_t fl = spin_lock_irqsave(&mq_lock);
+    struct mq_queue* q = &mq_table[mqd];
+    if (!q->active) { spin_unlock_irqrestore(&mq_lock, fl); return -EBADF; }
+    if (q->count >= q->maxmsg) { spin_unlock_irqrestore(&mq_lock, fl); return -EAGAIN; }
+
+    struct mq_msg* m = &q->msgs[q->tail];
+    spin_unlock_irqrestore(&mq_lock, fl);
+
+    if (copy_from_user(m->data, user_buf, len) < 0) return -EFAULT;
+    m->len = len;
+    m->prio = prio;
+
+    fl = spin_lock_irqsave(&mq_lock);
+    q->tail = (q->tail + 1) % q->maxmsg;
+    q->count++;
+    spin_unlock_irqrestore(&mq_lock, fl);
+    return 0;
+}
+
+static int syscall_mq_receive_impl(int mqd, void* user_buf, uint32_t len, uint32_t* user_prio) {
+    if (mqd < 0 || mqd >= MQ_MAX_QUEUES) return -EBADF;
+
+    uintptr_t fl = spin_lock_irqsave(&mq_lock);
+    struct mq_queue* q = &mq_table[mqd];
+    if (!q->active) { spin_unlock_irqrestore(&mq_lock, fl); return -EBADF; }
+    if (q->count == 0) { spin_unlock_irqrestore(&mq_lock, fl); return -EAGAIN; }
+
+    struct mq_msg* m = &q->msgs[q->head];
+    uint32_t mlen = m->len;
+    uint32_t mprio = m->prio;
+    if (mlen > len) mlen = len;
+
+    q->head = (q->head + 1) % q->maxmsg;
+    q->count--;
+    spin_unlock_irqrestore(&mq_lock, fl);
+
+    if (copy_to_user(user_buf, m->data, mlen) < 0) return -EFAULT;
+    if (user_prio) {
+        if (user_range_ok(user_prio, 4))
+            (void)copy_to_user(user_prio, &mprio, 4);
+    }
+    return (int)mlen;
+}
+
+static int syscall_mq_unlink_impl(const char* user_name) {
+    char name[32];
+    if (copy_from_user(name, user_name, 31) < 0) return -EFAULT;
+    name[31] = 0;
+
+    uintptr_t fl = spin_lock_irqsave(&mq_lock);
+    int idx = mq_find_by_name(name);
+    if (idx < 0) { spin_unlock_irqrestore(&mq_lock, fl); return -ENOENT; }
+    mq_table[idx].active = 0;
+    spin_unlock_irqrestore(&mq_lock, fl);
+    return 0;
+}
+
 /* --- Advisory file locking (flock) --- */
 enum {
     FLOCK_SH = 1,
@@ -3392,6 +3521,33 @@ static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no)
         return;
     }
 
+    if (syscall_no == SYSCALL_MQ_OPEN) {
+        const char* name = (const char*)sc_arg0(regs);
+        uint32_t oflag = sc_arg1(regs);
+        sc_ret(regs) = (uint32_t)syscall_mq_open_impl(name, oflag);
+        return;
+    }
+    if (syscall_no == SYSCALL_MQ_CLOSE) {
+        sc_ret(regs) = (uint32_t)syscall_mq_close_impl((int)sc_arg0(regs));
+        return;
+    }
+    if (syscall_no == SYSCALL_MQ_SEND) {
+        sc_ret(regs) = (uint32_t)syscall_mq_send_impl(
+            (int)sc_arg0(regs), (const void*)sc_arg1(regs),
+            sc_arg2(regs), sc_arg3(regs));
+        return;
+    }
+    if (syscall_no == SYSCALL_MQ_RECEIVE) {
+        sc_ret(regs) = (uint32_t)syscall_mq_receive_impl(
+            (int)sc_arg0(regs), (void*)sc_arg1(regs),
+            sc_arg2(regs), (uint32_t*)sc_arg3(regs));
+        return;
+    }
+    if (syscall_no == SYSCALL_MQ_UNLINK) {
+        sc_ret(regs) = (uint32_t)syscall_mq_unlink_impl((const char*)sc_arg0(regs));
+        return;
+    }
+
     sc_ret(regs) = (uint32_t)-ENOSYS;
 }