123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- #include <assert.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <kern/atomic.h>
- #include <kern/init.h>
- #include <kern/macros.h>
- #include <kern/rtmutex.h>
- #include <kern/rtmutex_types.h>
- #include <kern/syscnt.h>
- #include <kern/thread.h>
- #include <kern/turnstile.h>
- static struct thread*
- rtmutex_get_thread (uintptr_t owner)
- {
- return ((struct thread *)(owner & RTMUTEX_OWNER_MASK));
- }
- static void
- rtmutex_set_contended (struct rtmutex *rtmutex)
- {
- atomic_or_rel (&rtmutex->owner, RTMUTEX_CONTENDED);
- }
- static int
- rtmutex_lock_slow_common (struct rtmutex *rtmutex, bool timed, uint64_t ticks)
- {
- int error = 0;
- uintptr_t self = (uintptr_t)thread_self (), bits = RTMUTEX_CONTENDED;
- struct turnstile *turnstile = turnstile_lend (rtmutex);
- rtmutex_set_contended (rtmutex);
- while (1)
- {
- uintptr_t owner = atomic_cas_acq (&rtmutex->owner, bits, self | bits);
- assert ((owner & bits) == bits);
- if (owner == bits)
- break;
- struct thread *thread = rtmutex_get_thread (owner);
- if (! timed)
- turnstile_wait (turnstile, "rtmutex", thread);
- else
- {
- error = turnstile_timedwait (turnstile, "rtmutex", thread, ticks);
- if (error)
- break;
- }
- bits |= RTMUTEX_FORCE_WAIT;
- }
- if (error)
- {
-
- if (turnstile_empty (turnstile))
- {
- uintptr_t owner = atomic_load_rlx (&rtmutex->owner);
- if (owner & RTMUTEX_CONTENDED)
- {
- owner &= RTMUTEX_OWNER_MASK;
- atomic_store_rlx (&rtmutex->owner, owner);
- }
- }
- goto out;
- }
- turnstile_own (turnstile);
- if (turnstile_empty (turnstile))
- {
- #ifdef NDEBUG
- atomic_store_rel (&rtmutex->owner, self);
- #else
- uintptr_t owner = atomic_swap_rlx (&rtmutex->owner, self);
- assert (owner == (self | bits));
- #endif
- }
- out:
- turnstile_return (turnstile);
-
- return (error);
- }
- void
- rtmutex_lock_slow (struct rtmutex *rtmutex)
- {
- int error = rtmutex_lock_slow_common (rtmutex, false, 0);
- assert (! error);
- }
- int
- rtmutex_timedlock_slow (struct rtmutex *rtmutex, uint64_t ticks)
- {
- return (rtmutex_lock_slow_common (rtmutex, true, ticks));
- }
- void
- rtmutex_unlock_slow (struct rtmutex *rtmutex)
- {
- struct turnstile *turnstile;
- while (1)
- {
- turnstile = turnstile_acquire (rtmutex);
- if (turnstile)
- break;
- else if (!(rtmutex_unlock_fast (rtmutex) & RTMUTEX_CONTENDED))
- goto out;
- }
- #ifdef NDEBUG
- atomic_store_rel (&rtmutex->owner, RTMUTEX_FORCE_WAIT | RTMUTEX_CONTENDED);
- #else
- uintptr_t owner = atomic_swap_rel (&rtmutex->owner,
- RTMUTEX_FORCE_WAIT | RTMUTEX_CONTENDED);
- assert (rtmutex_get_thread (owner) == thread_self ());
- #endif
- turnstile_disown (turnstile);
- turnstile_signal (turnstile);
- turnstile_release (turnstile);
- out:
- thread_propagate_priority ();
- }
|