From fb05db6d06bb6a32bb4fd6c3002670f1c1d08ec0 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 3 Nov 2025 08:55:59 +0100 Subject: [PATCH 1/9] Add template for futex syscall Signed-off-by: Jean-Pierre Miceli --- so3/include/futex.h | 45 +++++++++++++++++++++++++++++++++++++++++++ so3/kernel/Makefile | 1 + so3/kernel/futex.c | 44 ++++++++++++++++++++++++++++++++++++++++++ so3/kernel/syscalls.c | 1 + so3/syscall.tbl | 1 + 5 files changed, 92 insertions(+) create mode 100644 so3/include/futex.h create mode 100644 so3/kernel/futex.c diff --git a/so3/include/futex.h b/so3/include/futex.h new file mode 100644 index 000000000..0cd6afe4c --- /dev/null +++ b/so3/include/futex.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014-2018 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef FUTEX_H +#define FUTEX_H + +#include +#include + +/* Commands */ +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 +#define FUTEX_WAIT_BITSET 9 + +#define FUTEX_PRIVATE_FLAG 128 +#define FUTEX_CLOCK_REALTIME 256 +#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) + + +SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec * utime, + u32 *uaddr2, u32 val3) + +#endif /* FUTEX_H */ diff --git a/so3/kernel/Makefile b/so3/kernel/Makefile index 8b9900a3d..71f68a103 100644 --- a/so3/kernel/Makefile +++ b/so3/kernel/Makefile @@ -8,6 +8,7 @@ obj-y += main.o \ thread.o \ schedule.o \ mutex.o \ + futex.o \ spinlock.o \ syscalls.o \ softirq.o \ diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c new file mode 100644 index 000000000..7d30e36ba --- /dev/null +++ b/so3/kernel/futex.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 Jean-Pierre Miceli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +SYSCALL_DEFINE6(futex, u32 *, uaddr, int, op, u32, val, + const struct timespec *, utime, + u32 *, uaddr2, u32, val3) +{ + + // unsigned int flags = futex_to_flags(op); + int cmd = op & FUTEX_CMD_MASK; + + switch (cmd) { + case FUTEX_WAIT: + break; + case FUTEX_WAKE: + break; + default: + printk("Futex cmd '%d' not supported !\n"); + return -EINVAL; + } + + return -ENOSYS; +} + + + diff --git a/so3/kernel/syscalls.c b/so3/kernel/syscalls.c index b87cc486d..251dc1430 100644 --- a/so3/kernel/syscalls.c +++ b/so3/kernel/syscalls.c @@ -28,6 +28,7 @@ #include #include #include +#include #include extern void __get_syscall_args_ext(uint32_t *syscall_no); diff --git a/so3/syscall.tbl b/so3/syscall.tbl index 1a3921119..a5b247c27 100644 --- a/so3/syscall.tbl +++ b/so3/syscall.tbl @@ -37,6 +37,7 @@ newfstatat mmap mmap2 nanosleep +futex pipe IPC_PIPE pipe2 IPC_PIPE rt_sigaction IPC_SIGNAL From f991130c425e827de0c3d7e62949552523d88c87 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Tue, 4 Nov 2025 14:35:08 +0100 Subject: [PATCH 2/9] [futex] Initial implementation of FUTEX_WAIT cmd The implementation uses lists Signed-off-by: Jean-Pierre Miceli --- so3/include/futex.h | 42 ++++++++++++++++++++++++++ so3/include/process.h | 6 ++++ so3/kernel/futex.c | 70 +++++++++++++++++++++++++++++++++++++++++-- so3/kernel/process.c | 7 +++++ 4 files changed, 122 insertions(+), 3 deletions(-) diff --git a/so3/include/futex.h b/so3/include/futex.h index 0cd6afe4c..c51a9bd2d 100644 --- a/so3/include/futex.h +++ b/so3/include/futex.h @@ -20,6 +20,9 @@ #define FUTEX_H #include +#include +#include +#include #include /* Commands */ @@ -38,6 +41,45 @@ #define FUTEX_CLOCK_REALTIME 256 #define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) +/* + * Hash buckets are shared by all the futex_keys that hash to the same + * location. Each key may have multiple futex_q structures, one for each task + * waiting on a futex. + */ +// struct futex_hash_bucket { +// atomic_t waiters; +// spinlock_t lock; +// struct plist_head chain; +// }; + +typedef struct futex_el { + struct list_head list; + tcb_t *tcb; +} futex_el_t; + +typedef struct futex { + struct list_head list; + struct list_head f_element; + uintptr_t key; +} futex_t; + + +/** + * struct futex_q - The hashed futex queue entry, one per waiting task + * + * @list: priority-sorted list of tasks waiting on this futex + * @lock_ptr: the hash bucket lock + * @key: the key the futex is hashed on + * @task: the task waiting on the futex + */ +// struct futex_q { +// struct plist_node list; +// struct futex_hash_bucket *lock_ptr; +// struct futex_key key; +// struct task_struct *task; // the sleeping thread +// }; + + SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec * utime, u32 *uaddr2, u32 val3) diff --git a/so3/include/process.h b/so3/include/process.h index 5b444deab..1fdb04a95 100644 --- a/so3/include/process.h +++ b/so3/include/process.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -82,6 +84,10 @@ struct pcb { /* Number of pages required by this process (including binary image) */ size_t page_count; + /* List of futexes */ + struct list_head futex; + spinlock_t futex_lock; + /* List of frames (physical pages) belonging to this process */ struct list_head page_list; diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index 7d30e36ba..2d8d8beb7 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -16,12 +16,70 @@ * */ +#include +#include #include #include -SYSCALL_DEFINE6(futex, u32 *, uaddr, int, op, u32, val, +/** + * do_futex_wait - + * + * @param futex_w + */ +static int do_futex_wait(uint32_t *futex_w, uint32_t val) +{ + unsigned long flags; + pcb_t *pcb = current()->pcb; + spinlock_t f_lock = pcb->futex_lock; + struct list_head *pos; + futex_t *futex; + futex_el_t *f_element; + + flags = spin_lock_irqsave(&f_lock); + + if (*futex_w != val) + return -EAGAIN; + + /* look if a futex_w already exists */ + list_for_each(pos, &pcb->futex) { + futex = list_entry(pos, futex_t, list); + + if ((uintptr_t)futex_w == futex->key) + break; + } + + if (pos == &pcb->futex) { + /* no futex on futex_w */ + futex = (futex_t *)calloc(1, sizeof(futex_t)); + if (futex == NULL) + BUG(); + + list_add_tail(&futex->list, &pcb->futex); + } + + /* Add the thread in the futex_element list */ + f_element = (futex_el_t *)calloc(1, sizeof(futex_el_t)); + if (f_element == NULL) + BUG(); + + f_element->tcb = current(); + + list_add_tail(&f_element->list, &futex->f_element); + + /* go to sleep. */ + spin_unlock(&f_lock); + waiting(); + + BUG_ON(local_irq_is_enabled()); + + spin_unlock_irqrestore(&f_lock, flags); + + return 0; +} + +SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct timespec *, utime, - u32 *, uaddr2, u32, val3) + uint32_t *, uaddr2, uint32_t, val3) { // unsigned int flags = futex_to_flags(op); @@ -29,7 +87,7 @@ SYSCALL_DEFINE6(futex, u32 *, uaddr, int, op, u32, val, switch (cmd) { case FUTEX_WAIT: - break; + return do_futex_wait(uaddr, val); case FUTEX_WAKE: break; default: @@ -41,4 +99,10 @@ SYSCALL_DEFINE6(futex, u32 *, uaddr, int, op, u32, val, } +void futex_init(void) +{ + +} + + diff --git a/so3/kernel/process.c b/so3/kernel/process.c index 13ec54092..3e0eff200 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -205,6 +205,10 @@ pcb_t *new_process(void) /* Init the list of pages */ INIT_LIST_HEAD(&pcb->page_list); + /* Init the futex */ + INIT_LIST_HEAD(&pcb->futex); + spin_lock_init(&pcb->futex_lock); + pcb->pid = pid_current++; for (i = 0; i < PROC_MAX_THREADS; i++) @@ -213,6 +217,9 @@ pcb_t *new_process(void) /* Init the list of child threads */ INIT_LIST_HEAD(&pcb->threads); + /* Init the 'futex' list */ + INIT_LIST_HEAD(&pcb->futex); + /* Process-related memory management */ /* Create the 1st level page table */ From 756f5cf437897c737ce778f153b775f6c95a5f2c Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Tue, 4 Nov 2025 15:51:16 +0100 Subject: [PATCH 3/9] [futex] Initial implementation of FUTEX_WAKE cmd Signed-off-by: Jean-Pierre Miceli --- so3/kernel/futex.c | 54 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index 2d8d8beb7..157c54015 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -30,12 +30,11 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) { unsigned long flags; pcb_t *pcb = current()->pcb; - spinlock_t f_lock = pcb->futex_lock; struct list_head *pos; futex_t *futex; futex_el_t *f_element; - flags = spin_lock_irqsave(&f_lock); + flags = spin_lock_irqsave(&pcb->futex_lock); if (*futex_w != val) return -EAGAIN; @@ -54,6 +53,8 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) if (futex == NULL) BUG(); + futex->key = (uintptr_t)futex_w; + list_add_tail(&futex->list, &pcb->futex); } @@ -67,16 +68,59 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) list_add_tail(&f_element->list, &futex->f_element); /* go to sleep. */ - spin_unlock(&f_lock); + spin_unlock(&pcb->futex_lock); waiting(); BUG_ON(local_irq_is_enabled()); - spin_unlock_irqrestore(&f_lock, flags); + spin_unlock_irqrestore(&pcb->futex_lock, flags); return 0; } +static int do_futex_wake(uint32_t *futex_w, uint32_t val) +{ + unsigned long flags; + pcb_t *pcb = current()->pcb; + struct list_head *pos, *p; + futex_t *futex; + futex_el_t *f_element; + unsigned idx = 0; + + flags = spin_lock_irqsave(&pcb->futex_lock); + + /* Search for the futex element with futex_w as key */ + list_for_each(pos, &pcb->futex) { + futex = list_entry(pos, futex_t, list); + + if ((uintptr_t)futex_w == futex->key) + break; + } + + if (pos == &pcb->futex) + /* key does not exists in futex - Error */ + BUG(); + + /* wakes at most val of the waiters that are waiting */ + list_for_each_safe(pos, p, &futex->list) { + f_element = list_entry(pos, futex_el_t, list); + + if (idx == val) + break; + + list_del(&f_element->list); + ready(f_element->tcb); + + idx++; + } + + spin_unlock_irqrestore(&pcb->futex_lock, flags); + + return 0; + +} + + SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct timespec *, utime, uint32_t *, uaddr2, uint32_t, val3) @@ -89,7 +133,7 @@ SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, case FUTEX_WAIT: return do_futex_wait(uaddr, val); case FUTEX_WAKE: - break; + return do_futex_wake(uaddr, val); default: printk("Futex cmd '%d' not supported !\n"); return -EINVAL; From 539a7ed2b95ce2d9e5bd267033e0da231b2636f1 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Fri, 7 Nov 2025 11:41:32 +0100 Subject: [PATCH 4/9] [futex] Clean-up Signed-off-by: Jean-Pierre Miceli --- so3/include/futex.h | 38 +++++++++----------------------------- so3/kernel/futex.c | 44 ++++++++++++++++++++++++++++++-------------- so3/kernel/process.c | 6 +----- 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/so3/include/futex.h b/so3/include/futex.h index c51a9bd2d..426da9673 100644 --- a/so3/include/futex.h +++ b/so3/include/futex.h @@ -41,47 +41,27 @@ #define FUTEX_CLOCK_REALTIME 256 #define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) -/* - * Hash buckets are shared by all the futex_keys that hash to the same - * location. Each key may have multiple futex_q structures, one for each task - * waiting on a futex. +/** + * list of thread (waiter) waiting on a futex */ -// struct futex_hash_bucket { -// atomic_t waiters; -// spinlock_t lock; -// struct plist_head chain; -// }; - typedef struct futex_el { struct list_head list; - tcb_t *tcb; + tcb_t *waiter; } futex_el_t; +/** + * list of futexes + */ typedef struct futex { struct list_head list; struct list_head f_element; uintptr_t key; } futex_t; - -/** - * struct futex_q - The hashed futex queue entry, one per waiting task - * - * @list: priority-sorted list of tasks waiting on this futex - * @lock_ptr: the hash bucket lock - * @key: the key the futex is hashed on - * @task: the task waiting on the futex - */ -// struct futex_q { -// struct plist_node list; -// struct futex_hash_bucket *lock_ptr; -// struct futex_key key; -// struct task_struct *task; // the sleeping thread -// }; - - - SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec * utime, u32 *uaddr2, u32 val3) + +void futex_init(pcb_t *pcb); + #endif /* FUTEX_H */ diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index 157c54015..d3f6ac876 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -22,9 +22,11 @@ #include /** - * do_futex_wait - + * do_futex_wait - block on futex_w * - * @param futex_w + * @param futex_w address of the futex word + * @param val expected value of the futex word + * @return 0 on success or error value */ static int do_futex_wait(uint32_t *futex_w, uint32_t val) { @@ -55,6 +57,7 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) futex->key = (uintptr_t)futex_w; + INIT_LIST_HEAD(&futex->f_element); list_add_tail(&futex->list, &pcb->futex); } @@ -63,7 +66,7 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) if (f_element == NULL) BUG(); - f_element->tcb = current(); + f_element->waiter = current(); list_add_tail(&f_element->list, &futex->f_element); @@ -78,7 +81,13 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) return 0; } -static int do_futex_wake(uint32_t *futex_w, uint32_t val) +/** + * do_futex_wake - wake one or more tasks blocked on uaddr + * + * @nr_wake wake up to this many tasks + * @return the number of waiters that were woken up + */ +static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) { unsigned long flags; pcb_t *pcb = current()->pcb; @@ -101,15 +110,15 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t val) /* key does not exists in futex - Error */ BUG(); - /* wakes at most val of the waiters that are waiting */ + /* wakes at most nr_wake of the waiters that are waiting */ list_for_each_safe(pos, p, &futex->list) { f_element = list_entry(pos, futex_el_t, list); - if (idx == val) + if (idx == nr_wake) break; list_del(&f_element->list); - ready(f_element->tcb); + ready(f_element->waiter); idx++; } @@ -120,13 +129,10 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t val) } - SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct timespec *, utime, uint32_t *, uaddr2, uint32_t, val3) { - - // unsigned int flags = futex_to_flags(op); int cmd = op & FUTEX_CMD_MASK; switch (cmd) { @@ -134,7 +140,14 @@ SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, return do_futex_wait(uaddr, val); case FUTEX_WAKE: return do_futex_wake(uaddr, val); - default: + case FUTEX_FD: + case FUTEX_REQUEUE: + case FUTEX_CMP_REQUEUE: + case FUTEX_WAKE_OP: + case FUTEX_LOCK_PI: + case FUTEX_UNLOCK_PI: + case FUTEX_TRYLOCK_PI: + case FUTEX_WAIT_BITSET: printk("Futex cmd '%d' not supported !\n"); return -EINVAL; } @@ -142,10 +155,13 @@ SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, return -ENOSYS; } - -void futex_init(void) +/** + * futex_init - Futex initialization + */ +void futex_init(pcb_t *pcb) { - + INIT_LIST_HEAD(&pcb->futex); + spin_lock_init(&pcb->futex_lock); } diff --git a/so3/kernel/process.c b/so3/kernel/process.c index 3e0eff200..41cf33917 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -206,8 +206,7 @@ pcb_t *new_process(void) INIT_LIST_HEAD(&pcb->page_list); /* Init the futex */ - INIT_LIST_HEAD(&pcb->futex); - spin_lock_init(&pcb->futex_lock); + futex_init(pcb); pcb->pid = pid_current++; @@ -217,9 +216,6 @@ pcb_t *new_process(void) /* Init the list of child threads */ INIT_LIST_HEAD(&pcb->threads); - /* Init the 'futex' list */ - INIT_LIST_HEAD(&pcb->futex); - /* Process-related memory management */ /* Create the 1st level page table */ From d53c4e7b252231eeae9f84ab2d611f74fa2be44b Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Fri, 7 Nov 2025 11:54:12 +0100 Subject: [PATCH 5/9] [futex] fix clang-format Signed-off-by: Jean-Pierre Miceli --- so3/include/futex.h | 28 +++++++++++++--------------- so3/kernel/futex.c | 19 +++++++------------ 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/so3/include/futex.h b/so3/include/futex.h index 426da9673..5777e29b7 100644 --- a/so3/include/futex.h +++ b/so3/include/futex.h @@ -26,20 +26,20 @@ #include /* Commands */ -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 -#define FUTEX_FD 2 -#define FUTEX_REQUEUE 3 -#define FUTEX_CMP_REQUEUE 4 -#define FUTEX_WAKE_OP 5 -#define FUTEX_LOCK_PI 6 -#define FUTEX_UNLOCK_PI 7 -#define FUTEX_TRYLOCK_PI 8 -#define FUTEX_WAIT_BITSET 9 +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 +#define FUTEX_WAIT_BITSET 9 #define FUTEX_PRIVATE_FLAG 128 -#define FUTEX_CLOCK_REALTIME 256 -#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) +#define FUTEX_CLOCK_REALTIME 256 +#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) /** * list of thread (waiter) waiting on a futex @@ -58,9 +58,7 @@ typedef struct futex { uintptr_t key; } futex_t; -SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec * utime, - u32 *uaddr2, u32 val3) - +SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec *utime, u32 *uaddr2, u32 val3) void futex_init(pcb_t *pcb); diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index d3f6ac876..819e72d7e 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -45,24 +45,24 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) list_for_each(pos, &pcb->futex) { futex = list_entry(pos, futex_t, list); - if ((uintptr_t)futex_w == futex->key) + if ((uintptr_t) futex_w == futex->key) break; } if (pos == &pcb->futex) { /* no futex on futex_w */ - futex = (futex_t *)calloc(1, sizeof(futex_t)); + futex = (futex_t *) calloc(1, sizeof(futex_t)); if (futex == NULL) BUG(); - futex->key = (uintptr_t)futex_w; + futex->key = (uintptr_t) futex_w; INIT_LIST_HEAD(&futex->f_element); list_add_tail(&futex->list, &pcb->futex); } /* Add the thread in the futex_element list */ - f_element = (futex_el_t *)calloc(1, sizeof(futex_el_t)); + f_element = (futex_el_t *) calloc(1, sizeof(futex_el_t)); if (f_element == NULL) BUG(); @@ -102,7 +102,7 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) list_for_each(pos, &pcb->futex) { futex = list_entry(pos, futex_t, list); - if ((uintptr_t)futex_w == futex->key) + if ((uintptr_t) futex_w == futex->key) break; } @@ -126,12 +126,10 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) spin_unlock_irqrestore(&pcb->futex_lock, flags); return 0; - } -SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, - const struct timespec *, utime, - uint32_t *, uaddr2, uint32_t, val3) +SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct timespec *, utime, uint32_t *, uaddr2, uint32_t, + val3) { int cmd = op & FUTEX_CMD_MASK; @@ -163,6 +161,3 @@ void futex_init(pcb_t *pcb) INIT_LIST_HEAD(&pcb->futex); spin_lock_init(&pcb->futex_lock); } - - - From 5746fa60eb6f189966403b510169cea0a764a4d9 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 10 Nov 2025 08:31:38 +0100 Subject: [PATCH 6/9] Remove "mutex" syscalls Signed-off-by: Jean-Pierre Miceli --- so3/include/mutex.h | 4 ---- so3/kernel/mutex.c | 21 --------------------- 2 files changed, 25 deletions(-) diff --git a/so3/include/mutex.h b/so3/include/mutex.h index 49f3847c9..2e8f2d63a 100644 --- a/so3/include/mutex.h +++ b/so3/include/mutex.h @@ -59,8 +59,4 @@ void mutex_lock(struct mutex *lock); void mutex_unlock(struct mutex *lock); void mutex_init(struct mutex *lock); -SYSCALL_DECLARE(mutex_init, void); -SYSCALL_DECLARE(mutex_lock, unsigned long number); -SYSCALL_DECLARE(mutex_unlock, unsigned long number); - #endif /* MUTEX_H */ diff --git a/so3/kernel/mutex.c b/so3/kernel/mutex.c index 7915cef27..4714292e9 100644 --- a/so3/kernel/mutex.c +++ b/so3/kernel/mutex.c @@ -146,27 +146,6 @@ void mutex_unlock(struct mutex *lock) schedule(); } -/* - * The following syscall implementation are a first attempt, mainly used for debugging kernel mutexes. - */ -SYSCALL_DEFINE1(mutex_lock, unsigned long, number) -{ - if (number >= N_MUTEX) { - return -EINVAL; - } - mutex_lock(¤t()->pcb->lock[number]); - return 0; -} - -SYSCALL_DEFINE1(mutex_unlock, unsigned long, number) -{ - if (number >= N_MUTEX) { - return -EINVAL; - } - mutex_unlock(¤t()->pcb->lock[number]); - return 0; -} - void mutex_init(struct mutex *lock) { memset(lock, 0, sizeof(struct mutex)); From ab43bbcde2ea6ac84e6c43b392d8d0a89584d028 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 10 Nov 2025 16:27:33 +0100 Subject: [PATCH 7/9] [futex] clean-up based on code review Signed-off-by: Jean-Pierre Miceli --- so3/include/futex.h | 13 ++----------- so3/kernel/futex.c | 44 ++++++++++++++++++++------------------------ so3/kernel/process.c | 3 ++- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/so3/include/futex.h b/so3/include/futex.h index 5777e29b7..688bc56f9 100644 --- a/so3/include/futex.h +++ b/so3/include/futex.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014-2018 Daniel Rossier + * Copyright (C) 2014-2025 Daniel Rossier + * Copyright (C) 2025 Jean-Pierre Miceli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -41,14 +42,6 @@ #define FUTEX_CLOCK_REALTIME 256 #define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) -/** - * list of thread (waiter) waiting on a futex - */ -typedef struct futex_el { - struct list_head list; - tcb_t *waiter; -} futex_el_t; - /** * list of futexes */ @@ -60,6 +53,4 @@ typedef struct futex { SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec *utime, u32 *uaddr2, u32 val3) -void futex_init(pcb_t *pcb); - #endif /* FUTEX_H */ diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index 819e72d7e..346f4ec30 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -34,12 +34,14 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) pcb_t *pcb = current()->pcb; struct list_head *pos; futex_t *futex; - futex_el_t *f_element; + queue_thread_t f_element; flags = spin_lock_irqsave(&pcb->futex_lock); - if (*futex_w != val) + if (*futex_w != val) { + spin_unlock_irqrestore(&pcb->futex_lock, flags); return -EAGAIN; + } /* look if a futex_w already exists */ list_for_each(pos, &pcb->futex) { @@ -61,19 +63,17 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) list_add_tail(&futex->list, &pcb->futex); } - /* Add the thread in the futex_element list */ - f_element = (futex_el_t *) calloc(1, sizeof(futex_el_t)); - if (f_element == NULL) - BUG(); - - f_element->waiter = current(); + f_element.tcb = current(); - list_add_tail(&f_element->list, &futex->f_element); + list_add_tail(&f_element.list, &futex->f_element); /* go to sleep. */ spin_unlock(&pcb->futex_lock); waiting(); + if (list_empty(&futex->f_element)) + free(futex); + BUG_ON(local_irq_is_enabled()); spin_unlock_irqrestore(&pcb->futex_lock, flags); @@ -93,7 +93,7 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) pcb_t *pcb = current()->pcb; struct list_head *pos, *p; futex_t *futex; - futex_el_t *f_element; + queue_thread_t *f_element; unsigned idx = 0; flags = spin_lock_irqsave(&pcb->futex_lock); @@ -106,26 +106,28 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) break; } - if (pos == &pcb->futex) + if (pos == &pcb->futex) { /* key does not exists in futex - Error */ - BUG(); + spin_unlock_irqrestore(&pcb->futex_lock, flags); + return -EINVAL(); + } /* wakes at most nr_wake of the waiters that are waiting */ list_for_each_safe(pos, p, &futex->list) { - f_element = list_entry(pos, futex_el_t, list); + f_element = list_entry(pos, queue_thread_t, list); if (idx == nr_wake) break; list_del(&f_element->list); - ready(f_element->waiter); + ready(f_element->tcb); idx++; } spin_unlock_irqrestore(&pcb->futex_lock, flags); - return 0; + return idx; } SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct timespec *, utime, uint32_t *, uaddr2, uint32_t, @@ -133,6 +135,9 @@ SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct t { int cmd = op & FUTEX_CMD_MASK; + if (utime) + printk("[futex] utime parameter is not used in current implementation\n"); + switch (cmd) { case FUTEX_WAIT: return do_futex_wait(uaddr, val); @@ -152,12 +157,3 @@ SYSCALL_DEFINE6(futex, uint32_t *, uaddr, int, op, uint32_t, val, const struct t return -ENOSYS; } - -/** - * futex_init - Futex initialization - */ -void futex_init(pcb_t *pcb) -{ - INIT_LIST_HEAD(&pcb->futex); - spin_lock_init(&pcb->futex_lock); -} diff --git a/so3/kernel/process.c b/so3/kernel/process.c index 41cf33917..e9ade4316 100644 --- a/so3/kernel/process.c +++ b/so3/kernel/process.c @@ -206,7 +206,8 @@ pcb_t *new_process(void) INIT_LIST_HEAD(&pcb->page_list); /* Init the futex */ - futex_init(pcb); + INIT_LIST_HEAD(&pcb->futex); + spin_lock_init(&pcb->futex_lock); pcb->pid = pid_current++; From 027d7b5259e9c8bfd3f7e33399b93b41ebb5e88f Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Mon, 10 Nov 2025 16:57:21 +0100 Subject: [PATCH 8/9] [futex] Fix typo introduced in previous commit Signed-off-by: Jean-Pierre Miceli --- so3/kernel/futex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index 346f4ec30..b2406ffc9 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -109,7 +109,7 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) if (pos == &pcb->futex) { /* key does not exists in futex - Error */ spin_unlock_irqrestore(&pcb->futex_lock, flags); - return -EINVAL(); + return -EINVAL; } /* wakes at most nr_wake of the waiters that are waiting */ From 8be034c63591a6561ece883c0c176fd2029a2817 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Miceli Date: Tue, 11 Nov 2025 17:11:09 +0100 Subject: [PATCH 9/9] [futex] make clearer the search of key in lists Signed-off-by: Jean-Pierre Miceli --- so3/include/list.h | 10 ++++++++++ so3/kernel/futex.c | 11 +++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/so3/include/list.h b/so3/include/list.h index c6790da98..164a9ea20 100644 --- a/so3/include/list.h +++ b/so3/include/list.h @@ -169,6 +169,16 @@ static inline int list_is_last(const struct list_head *list, const struct list_h return list->next == head; } +/** + * list_is_head - tests whether @list is the list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + /** * list_empty - tests whether a list is empty * @head: the list to test. diff --git a/so3/kernel/futex.c b/so3/kernel/futex.c index b2406ffc9..0672ef76e 100644 --- a/so3/kernel/futex.c +++ b/so3/kernel/futex.c @@ -51,7 +51,7 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) break; } - if (pos == &pcb->futex) { + if (list_is_head(pos, &pcb->futex)) { /* no futex on futex_w */ futex = (futex_t *) calloc(1, sizeof(futex_t)); if (futex == NULL) @@ -71,11 +71,13 @@ static int do_futex_wait(uint32_t *futex_w, uint32_t val) spin_unlock(&pcb->futex_lock); waiting(); + BUG_ON(local_irq_is_enabled()); + + spin_lock(&pcb->futex_lock); + if (list_empty(&futex->f_element)) free(futex); - BUG_ON(local_irq_is_enabled()); - spin_unlock_irqrestore(&pcb->futex_lock, flags); return 0; @@ -106,7 +108,8 @@ static int do_futex_wake(uint32_t *futex_w, uint32_t nr_wake) break; } - if (pos == &pcb->futex) { + /* Check if the wanted key was found in the list */ + if (list_is_head(pos, &pcb->futex)) { /* key does not exists in futex - Error */ spin_unlock_irqrestore(&pcb->futex_lock, flags); return -EINVAL;