-
Notifications
You must be signed in to change notification settings - Fork 8
Futex syscall implementation #221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fb05db6
f991130
756f5cf
539a7ed
d53c4e7
5746fa6
ab43bbc
027d7b5
8be034c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /* | ||
| * Copyright (C) 2014-2025 Daniel Rossier <daniel.rossier@heig-vd.ch> | ||
| * Copyright (C) 2025 Jean-Pierre Miceli <jean-pierre.miceli@heig-vd.ch> | ||
| * | ||
| * 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 <timer.h> | ||
| #include <thread.h> | ||
| #include <list.h> | ||
| #include <spinlock.h> | ||
| #include <syscall.h> | ||
|
|
||
| /* 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) | ||
|
|
||
| /** | ||
| * list of futexes | ||
| */ | ||
| typedef struct futex { | ||
| struct list_head list; | ||
| struct list_head f_element; | ||
| uintptr_t key; | ||
| } futex_t; | ||
|
|
||
| SYSCALL_DECLARE(futex, u32 *uaddr, int op, u32 val, const struct timespec *utime, u32 *uaddr2, u32 val3) | ||
|
|
||
| #endif /* FUTEX_H */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ obj-y += main.o \ | |
| thread.o \ | ||
| schedule.o \ | ||
| mutex.o \ | ||
| futex.o \ | ||
| spinlock.o \ | ||
| syscalls.o \ | ||
| softirq.o \ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| /* | ||
| * Copyright (C) 2025 Jean-Pierre Miceli <jean-pierre.miceli@heig-vd.ch> | ||
| * | ||
| * 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 <process.h> | ||
| #include <heap.h> | ||
| #include <errno.h> | ||
| #include <futex.h> | ||
|
|
||
| /** | ||
| * do_futex_wait - block on 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) | ||
| { | ||
| unsigned long flags; | ||
| pcb_t *pcb = current()->pcb; | ||
| struct list_head *pos; | ||
| futex_t *futex; | ||
| queue_thread_t f_element; | ||
|
|
||
| flags = spin_lock_irqsave(&pcb->futex_lock); | ||
|
|
||
| if (*futex_w != val) { | ||
| spin_unlock_irqrestore(&pcb->futex_lock, flags); | ||
| return -EAGAIN; | ||
clemdiep marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| /* 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 (list_is_head(pos, &pcb->futex)) { | ||
| /* no futex on futex_w */ | ||
| futex = (futex_t *) calloc(1, sizeof(futex_t)); | ||
| if (futex == NULL) | ||
| BUG(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should also returned -EINVAL
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is to indicate that
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make sense :-) |
||
|
|
||
| futex->key = (uintptr_t) futex_w; | ||
|
|
||
| INIT_LIST_HEAD(&futex->f_element); | ||
| list_add_tail(&futex->list, &pcb->futex); | ||
| } | ||
|
|
||
| f_element.tcb = current(); | ||
|
|
||
| list_add_tail(&f_element.list, &futex->f_element); | ||
|
|
||
| /* go to sleep. */ | ||
| 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); | ||
|
|
||
| spin_unlock_irqrestore(&pcb->futex_lock, flags); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * 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; | ||
| struct list_head *pos, *p; | ||
| futex_t *futex; | ||
| queue_thread_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; | ||
| } | ||
|
|
||
| /* 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; | ||
| } | ||
|
|
||
| /* wakes at most nr_wake of the waiters that are waiting */ | ||
| list_for_each_safe(pos, p, &futex->list) { | ||
| f_element = list_entry(pos, queue_thread_t, list); | ||
|
|
||
| if (idx == nr_wake) | ||
| break; | ||
|
|
||
| list_del(&f_element->list); | ||
| ready(f_element->tcb); | ||
|
|
||
| idx++; | ||
| } | ||
|
|
||
| spin_unlock_irqrestore(&pcb->futex_lock, flags); | ||
|
|
||
| return idx; | ||
| } | ||
|
|
||
| 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; | ||
|
|
||
| if (utime) | ||
| printk("[futex] utime parameter is not used in current implementation\n"); | ||
|
|
||
| switch (cmd) { | ||
| case FUTEX_WAIT: | ||
| return do_futex_wait(uaddr, val); | ||
clemdiep marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| case FUTEX_WAKE: | ||
| return do_futex_wake(uaddr, val); | ||
| 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; | ||
| } | ||
|
|
||
| return -ENOSYS; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,7 @@ newfstatat | |
| mmap | ||
| mmap2 | ||
| nanosleep | ||
| futex | ||
| pipe IPC_PIPE | ||
| pipe2 IPC_PIPE | ||
| rt_sigaction IPC_SIGNAL | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.