-
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 6 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,65 @@ | ||
| /* | ||
| * Copyright (C) 2014-2018 Daniel Rossier <daniel.rossier@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 thread (waiter) waiting on a futex | ||
| */ | ||
| typedef struct futex_el { | ||
| struct list_head list; | ||
| tcb_t *waiter; | ||
| } futex_el_t; | ||
clemdiep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * list of futexes | ||
| */ | ||
| typedef struct futex { | ||
| struct list_head list; | ||
| struct list_head f_element; | ||
| uintptr_t key; | ||
| } futex_t; | ||
clemdiep marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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 */ | ||
| 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,163 @@ | ||
| /* | ||
| * 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; | ||
| futex_el_t *f_element; | ||
|
|
||
| flags = spin_lock_irqsave(&pcb->futex_lock); | ||
|
|
||
| if (*futex_w != val) | ||
| 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 (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); | ||
| } | ||
|
|
||
| /* Add the thread in the futex_element list */ | ||
| f_element = (futex_el_t *) calloc(1, sizeof(futex_el_t)); | ||
| if (f_element == NULL) | ||
| BUG(); | ||
clemdiep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| f_element->waiter = 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_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; | ||
| 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(); | ||
clemdiep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| /* 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 == nr_wake) | ||
| break; | ||
|
|
||
| list_del(&f_element->list); | ||
| ready(f_element->waiter); | ||
|
|
||
| idx++; | ||
| } | ||
|
|
||
| spin_unlock_irqrestore(&pcb->futex_lock, flags); | ||
|
|
||
| return 0; | ||
clemdiep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| 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; | ||
|
|
||
| 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; | ||
| } | ||
|
|
||
| /** | ||
| * futex_init - Futex initialization | ||
| */ | ||
| void futex_init(pcb_t *pcb) | ||
| { | ||
| INIT_LIST_HEAD(&pcb->futex); | ||
| spin_lock_init(&pcb->futex_lock); | ||
| } | ||
| 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.