|
From: kosmirror <kos...@us...> - 2025-09-05 10:03:46
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "A pseudo Operating System for the Dreamcast.".
The branch, master has been updated
via 3a34e9a1c7fcee85e39b4b48f8472ecbd36e536e (commit)
via fddc6395b0c44c127d1144326bf286dd42eb134e (commit)
via 60cf12b9bfd3db31bd17e9fe9201a643e2baf4c3 (commit)
via 66efbf093368c9cdbf0e550c4c5201c4b70040c0 (commit)
via 547b84227269323a9d31850d4c33432401ba2851 (commit)
via 761d8ae1d2bf51840288a9518d326478a131595a (commit)
via c59c45ca4536a5c48eecd35630bb638fd18427fc (commit)
from ab8b89e33c5e6ccb9e9c898554f10460e9019330 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 3a34e9a1c7fcee85e39b4b48f8472ecbd36e536e
Author: Paul Cercueil <pa...@cr...>
Date: Wed May 21 13:39:51 2025 +0200
mutex: Unlock without disabling interrupts
To unlock a mutex, all we need to do is to set its holder pointer to
NULL. Since it can be done with a single 32-bit write, this is by
definition an atomic operation, and does not need locking.
Signed-off-by: Paul Cercueil <pa...@cr...>
commit fddc6395b0c44c127d1144326bf286dd42eb134e
Author: Paul Cercueil <pa...@cr...>
Date: Wed May 21 12:15:52 2025 +0200
mutex: Try to lock without disabling interrupts
Use an atomic compare-and-swap to set the current thread as the lock
owner, instead of going through disabling interrupts.
Signed-off-by: Paul Cercueil <pa...@cr...>
commit 60cf12b9bfd3db31bd17e9fe9201a643e2baf4c3
Author: Paul Cercueil <pa...@cr...>
Date: Wed May 21 12:13:01 2025 +0200
mutex: Move recursive/errcheck tests outside critical section
When the lock's holder is the current thread, we do not need IRQs to be
disabled to update the lock's counter, because a thread is not going to
race with itself.
Note how mutex_lock() now calls mutex_trylock() to factorize the code
(including the assert() call).
Signed-off-by: Paul Cercueil <pa...@cr...>
commit 66efbf093368c9cdbf0e550c4c5201c4b70040c0
Author: Paul Cercueil <pa...@cr...>
Date: Wed Sep 3 12:09:08 2025 +0200
mutex: Forbid recursive mutexes with mutex_unlock_as_thread()
Recursive mutexes are never used with mutex_unlock_as_thread(), and we
want to enforce that now with an assert().
Forbiding recursive mutexes with this function will allow further
optimizations later.
Signed-off-by: Paul Cercueil <pa...@cr...>
commit 547b84227269323a9d31850d4c33432401ba2851
Author: Paul Cercueil <pa...@cr...>
Date: Wed May 21 12:11:10 2025 +0200
mutex: Check mutex type using assert()
The case where the mutex type is not supported is never supposed to
happen. Therefore it makes sense to use an assert() call, so that this
code can be dropped on release builds.
Signed-off-by: Paul Cercueil <pa...@cr...>
commit 761d8ae1d2bf51840288a9518d326478a131595a
Author: Paul Cercueil <pa...@cr...>
Date: Mon Sep 1 12:22:10 2025 +0200
pthreads: Runtime-check mutex type before locking
The KOS mutexes will use an assert() to verify that the mutex type is
supported. To keep compatibility with the pthreads ABI, we need to move
the checks there.
Signed-off-by: Paul Cercueil <pa...@cr...>
commit c59c45ca4536a5c48eecd35630bb638fd18427fc
Author: Paul Cercueil <pa...@cr...>
Date: Mon Sep 1 12:17:13 2025 +0200
libc: Runtime-check mutex type before locking
The KOS mutexes will use an assert() to verify that the mutex type is
supported. To keep compatibility with the C11 ABI, we need to move the
checks there.
Signed-off-by: Paul Cercueil <pa...@cr...>
-----------------------------------------------------------------------
Summary of changes:
addons/libpthread/pthread_mutex_lock.c | 3 +
addons/libpthread/pthread_mutex_timedlock.c | 3 +
addons/libpthread/pthread_mutex_trylock.c | 3 +
include/kos/mutex.h | 7 +-
kernel/libc/c11/mtx_lock.c | 6 ++
kernel/libc/c11/mtx_timedlock.c | 5 ++
kernel/libc/c11/mtx_trylock.c | 5 ++
kernel/thread/mutex.c | 120 ++++++++++------------------
8 files changed, 71 insertions(+), 81 deletions(-)
diff --git a/addons/libpthread/pthread_mutex_lock.c b/addons/libpthread/pthread_mutex_lock.c
index c9996982..89ea42ba 100644
--- a/addons/libpthread/pthread_mutex_lock.c
+++ b/addons/libpthread/pthread_mutex_lock.c
@@ -13,6 +13,9 @@
int pthread_mutex_lock(pthread_mutex_t *mutex) {
int old, rv = 0;
+ if(mutex->mutex.type > MUTEX_TYPE_RECURSIVE)
+ return EINVAL;
+
old = errno;
if(mutex_lock(&mutex->mutex))
rv = errno;
diff --git a/addons/libpthread/pthread_mutex_timedlock.c b/addons/libpthread/pthread_mutex_timedlock.c
index 26dc5061..b1ee3561 100644
--- a/addons/libpthread/pthread_mutex_timedlock.c
+++ b/addons/libpthread/pthread_mutex_timedlock.c
@@ -21,6 +21,9 @@ int pthread_mutex_timedlock(pthread_mutex_t *__RESTRICT mutex,
if(!mutex || !abstime)
return EFAULT;
+ if(mutex->mutex.type > MUTEX_TYPE_RECURSIVE)
+ return EINVAL;
+
if(abstime->tv_nsec < 0 || abstime->tv_nsec > 1000000000L)
return EINVAL;
diff --git a/addons/libpthread/pthread_mutex_trylock.c b/addons/libpthread/pthread_mutex_trylock.c
index 2af75c23..4271483f 100644
--- a/addons/libpthread/pthread_mutex_trylock.c
+++ b/addons/libpthread/pthread_mutex_trylock.c
@@ -13,6 +13,9 @@
int pthread_mutex_trylock(pthread_mutex_t *mutex) {
int old, rv = 0;
+ if(mutex->mutex.type > MUTEX_TYPE_RECURSIVE)
+ return EINVAL;
+
old = errno;
if(mutex_trylock(&mutex->mutex))
rv = errno;
diff --git a/include/kos/mutex.h b/include/kos/mutex.h
index c2f467e9..1f5529e7 100644
--- a/include/kos/mutex.h
+++ b/include/kos/mutex.h
@@ -148,7 +148,6 @@ int mutex_destroy(mutex_t *m) __nonnull_all;
\par Error Conditions:
\em EPERM - called inside an interrupt \n
- \em EINVAL - the mutex has not been initialized properly \n
\em EAGAIN - lock has been acquired too many times (recursive) \n
\em EDEADLK - would deadlock (error-checking)
*/
@@ -169,7 +168,6 @@ int mutex_lock(mutex_t *m) __nonnull_all;
\retval -1 On error, sets errno as appropriate
\par Error Conditions:
- \em EINVAL - the mutex has not been initialized properly \n
\em EAGAIN - lock has been acquired too many times (recursive), or the
function was called inside an interrupt and the mutex was
already locked \n
@@ -192,7 +190,6 @@ int mutex_lock_irqsafe(mutex_t *m) __nonnull_all;
\par Error Conditions:
\em EPERM - called inside an interrupt \n
- \em EINVAL - the mutex has not been initialized properly \n
\em EINVAL - the timeout value was invalid (less than 0) \n
\em ETIMEDOUT - the timeout expired \n
\em EAGAIN - lock has been acquired too many times (recursive) \n
@@ -227,7 +224,6 @@ int __pure mutex_is_locked(const mutex_t *m) __nonnull_all;
\par Error Conditions:
\em EBUSY - the mutex is already locked (mutex_lock() would block) \n
- \em EINVAL - the mutex has not been initialized properly \n
\em EAGAIN - lock has been acquired too many times (recursive) \n
\em EDEADLK - would deadlock (error-checking)
*/
@@ -252,7 +248,8 @@ int mutex_unlock(mutex_t *m) __nonnull_all;
This function allows an IRQ handler to unlock a mutex that was locked by a
normal kernel thread. This function is only for use in IRQ handlers, so it
- will generally not be of much use outside of the kernel itself.
+ will generally not be of much use outside of the kernel itself. It cannot
+ be used with recursive mutexes.
\param m The mutex to unlock
\param thd The thread owning the mutex
diff --git a/kernel/libc/c11/mtx_lock.c b/kernel/libc/c11/mtx_lock.c
index 6e478cd4..a496f455 100644
--- a/kernel/libc/c11/mtx_lock.c
+++ b/kernel/libc/c11/mtx_lock.c
@@ -4,8 +4,14 @@
Copyright (C) 2014 Lawrence Sebald
*/
+#include <errno.h>
#include <threads.h>
int mtx_lock(mtx_t *mtx) {
+ if(mtx->type > MUTEX_TYPE_RECURSIVE) {
+ errno = EINVAL;
+ return -1;
+ }
+
return mutex_lock(mtx);
}
diff --git a/kernel/libc/c11/mtx_timedlock.c b/kernel/libc/c11/mtx_timedlock.c
index 1939bc7d..4fba4b4b 100644
--- a/kernel/libc/c11/mtx_timedlock.c
+++ b/kernel/libc/c11/mtx_timedlock.c
@@ -10,6 +10,11 @@
int mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts) {
int ms = 0;
+ if(mtx->type > MUTEX_TYPE_RECURSIVE) {
+ errno = EINVAL;
+ return -1;
+ }
+
/* Calculate the number of milliseconds to sleep for. No, you don't get
anywhere near nanosecond precision here. */
ms = ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
diff --git a/kernel/libc/c11/mtx_trylock.c b/kernel/libc/c11/mtx_trylock.c
index eead66a0..7567d024 100644
--- a/kernel/libc/c11/mtx_trylock.c
+++ b/kernel/libc/c11/mtx_trylock.c
@@ -8,6 +8,11 @@
#include <errno.h>
int mtx_trylock(mtx_t *mtx) {
+ if(mtx->type > MUTEX_TYPE_RECURSIVE) {
+ errno = EINVAL;
+ return -1;
+ }
+
if(mutex_trylock(mtx)) {
if(errno == EBUSY)
return thrd_busy;
diff --git a/kernel/thread/mutex.c b/kernel/thread/mutex.c
index 30772ade..617b0760 100644
--- a/kernel/thread/mutex.c
+++ b/kernel/thread/mutex.c
@@ -6,6 +6,8 @@
*/
+#include <assert.h>
+#include <stdatomic.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
@@ -84,28 +86,16 @@ int mutex_lock_timed(mutex_t *m, int timeout) {
return -1;
}
+ rv = mutex_trylock(m);
+ if(!rv || errno != EBUSY)
+ return rv;
+
irq_disable_scoped();
- if(m->type > MUTEX_TYPE_RECURSIVE) {
- errno = EINVAL;
- rv = -1;
- }
- else if(!m->count) {
+ if(!m->holder) {
m->count = 1;
m->holder = thd_current;
- }
- else if(m->type == MUTEX_TYPE_RECURSIVE && m->holder == thd_current) {
- if(m->count == INT_MAX) {
- errno = EAGAIN;
- rv = -1;
- }
- else {
- ++m->count;
- }
- }
- else if(m->type == MUTEX_TYPE_ERRORCHECK && m->holder == thd_current) {
- errno = EDEADLK;
- rv = -1;
+ rv = 0;
}
else {
if(timeout)
@@ -153,79 +143,59 @@ int mutex_lock_timed(mutex_t *m, int timeout) {
}
int __pure mutex_is_locked(const mutex_t *m) {
- return !!m->count;
+ return !!m->holder;
}
int mutex_trylock(mutex_t *m) {
- kthread_t *thd = thd_current;
+ kthread_t *thd = thd_current, *thd_none = NULL;
- irq_disable_scoped();
+ assert(m->type <= MUTEX_TYPE_RECURSIVE);
/* If we're inside of an interrupt, pick a special value for the thread that
would otherwise be impossible... */
if(irq_inside_int())
thd = IRQ_THREAD;
- if(m->type > MUTEX_TYPE_RECURSIVE) {
- errno = EINVAL;
- return -1;
- }
-
- /* Check if the lock is held by some other thread already */
- if(m->count && m->holder != thd) {
- errno = EBUSY;
- return -1;
- }
-
- m->holder = thd;
-
- switch(m->type) {
- case MUTEX_TYPE_NORMAL:
- case MUTEX_TYPE_OLDNORMAL:
- case MUTEX_TYPE_ERRORCHECK:
- if(m->count) {
- errno = EDEADLK;
- return -1;
- }
-
- m->count = 1;
- break;
+ if(m->holder == thd) {
+ if(m->type == MUTEX_TYPE_ERRORCHECK) {
+ errno = EDEADLK;
+ return -1;
+ }
- case MUTEX_TYPE_RECURSIVE:
+ if(m->type == MUTEX_TYPE_RECURSIVE) {
if(m->count == INT_MAX) {
errno = EAGAIN;
return -1;
}
++m->count;
- break;
+ return 0;
+ }
}
- return 0;
+ if(atomic_compare_exchange_strong(&m->holder, &thd_none, thd)) {
+ m->count = 1;
+ return 0;
+ }
+
+ /* We did not get the lock */
+ errno = EBUSY;
+ return -1;
}
static int __nonnull_all mutex_unlock_common(mutex_t *m, kthread_t *thd) {
- int wakeup = 0;
-
- irq_disable_scoped();
-
switch(m->type) {
- case MUTEX_TYPE_NORMAL:
- case MUTEX_TYPE_OLDNORMAL:
- m->count = 0;
- m->holder = NULL;
- wakeup = 1;
- break;
-
case MUTEX_TYPE_ERRORCHECK:
if(m->holder != thd) {
errno = EPERM;
return -1;
}
-
+ __fallthrough;
+ default:
+ case MUTEX_TYPE_NORMAL:
+ case MUTEX_TYPE_OLDNORMAL:
m->count = 0;
m->holder = NULL;
- wakeup = 1;
break;
case MUTEX_TYPE_RECURSIVE:
@@ -234,25 +204,19 @@ static int __nonnull_all mutex_unlock_common(mutex_t *m, kthread_t *thd) {
return -1;
}
- if(!--m->count) {
- m->holder = NULL;
- wakeup = 1;
- }
- break;
+ if(--m->count)
+ return 0;
- default:
- errno = EINVAL;
- return -1;
+ m->holder = NULL;
+ break;
}
- /* If we need to wake up a thread, do so. */
- if(wakeup) {
- /* Restore real priority in case we were dynamically boosted. */
- if (thd != IRQ_THREAD)
- thd->prio = thd->real_prio;
+ /* Restore real priority in case we were dynamically boosted. */
+ if (thd != IRQ_THREAD)
+ thd->prio = thd->real_prio;
- genwait_wake_one(m);
- }
+ /* If we need to wake up a thread, do so. */
+ genwait_wake_one(m);
return 0;
}
@@ -260,6 +224,8 @@ static int __nonnull_all mutex_unlock_common(mutex_t *m, kthread_t *thd) {
int mutex_unlock(mutex_t *m) {
kthread_t *thd = thd_current;
+ assert(m->type <= MUTEX_TYPE_RECURSIVE);
+
/* If we're inside of an interrupt, use the special value for the thread
from mutex_trylock(). */
if(irq_inside_int())
@@ -269,6 +235,8 @@ int mutex_unlock(mutex_t *m) {
}
int mutex_unlock_as_thread(mutex_t *m, kthread_t *thd) {
+ assert(m->type < MUTEX_TYPE_RECURSIVE); /* Unsafe with recursive mutexes */
+
/* Make sure we're in an IRQ handler */
if(!irq_inside_int()) {
errno = EACCES;
hooks/post-receive
--
A pseudo Operating System for the Dreamcast.
|