Changes in kernel/generic/src/synch/mutex.c [9f2f5ee:76e17d7c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/synch/mutex.c
r9f2f5ee r76e17d7c 1 1 /* 2 2 * Copyright (c) 2001-2004 Jakub Jermar 3 * Copyright (c) 202 5Jiří Zárevúcky3 * Copyright (c) 2023 Jiří Zárevúcky 4 4 * All rights reserved. 5 5 * … … 39 39 #include <assert.h> 40 40 #include <errno.h> 41 #include <proc/thread.h>42 #include <stdatomic.h>43 41 #include <synch/mutex.h> 44 42 #include <synch/semaphore.h> 43 #include <arch.h> 44 #include <stacktrace.h> 45 #include <cpu.h> 46 #include <proc/thread.h> 45 47 46 48 /** Initialize mutex. … … 51 53 void mutex_initialize(mutex_t *mtx, mutex_type_t type) 52 54 { 53 *mtx = MUTEX_INITIALIZER(*mtx, type); 54 } 55 56 /** A race in mtx->owner access is unavoidable, so we have to make 57 * access to it formally atomic. These are convenience functions to 58 * read/write the variable without memory barriers, since we don't need 59 * them and C11 atomics default to the strongest possible memory ordering 60 * by default, which is utterly ridiculous. 61 */ 62 static inline thread_t *_get_owner(mutex_t *mtx) 63 { 64 return atomic_load_explicit(&mtx->owner, memory_order_relaxed); 65 } 66 67 /** Counterpart to _get_owner(). */ 68 static inline void _set_owner(mutex_t *mtx, thread_t *owner) 69 { 70 atomic_store_explicit(&mtx->owner, owner, memory_order_relaxed); 55 mtx->type = type; 56 mtx->owner = NULL; 57 mtx->nesting = 0; 58 semaphore_initialize(&mtx->sem, 1); 71 59 } 72 60 … … 79 67 bool mutex_locked(mutex_t *mtx) 80 68 { 81 if (!THREAD) 82 return mtx->nesting > 0; 69 errno_t rc = semaphore_trydown(&mtx->sem); 70 if (rc == EOK) { 71 semaphore_up(&mtx->sem); 72 } 73 return rc != EOK; 74 } 83 75 84 return _get_owner(mtx) == THREAD; 76 static void mutex_lock_active(mutex_t *mtx) 77 { 78 assert((mtx->type == MUTEX_ACTIVE) || !THREAD); 79 80 const unsigned deadlock_treshold = 100000000; 81 unsigned int cnt = 0; 82 bool deadlock_reported = false; 83 84 while (semaphore_trydown(&mtx->sem) != EOK) { 85 if (cnt++ > deadlock_treshold) { 86 printf("cpu%u: looping on active mutex %p\n", CPU->id, mtx); 87 stack_trace(); 88 cnt = 0; 89 deadlock_reported = true; 90 } 91 } 92 93 if (deadlock_reported) 94 printf("cpu%u: not deadlocked\n", CPU->id); 85 95 } 86 96 … … 91 101 void mutex_lock(mutex_t *mtx) 92 102 { 93 if ( !THREAD) {94 assert( mtx->type == MUTEX_RECURSIVE || mtx->nesting == 0);103 if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) { 104 assert(THREAD); 95 105 mtx->nesting++; 96 106 return; 97 107 } 98 108 99 if (_get_owner(mtx) == THREAD) { 100 /* This will also detect nested locks on a non-recursive mutex. */ 101 assert(mtx->type == MUTEX_RECURSIVE); 102 assert(mtx->nesting > 0); 103 mtx->nesting++; 109 if (mtx->type == MUTEX_ACTIVE || !THREAD) { 110 mutex_lock_active(mtx); 104 111 return; 105 112 } 106 113 107 114 semaphore_down(&mtx->sem); 108 109 _set_owner(mtx, THREAD); 110 assert(mtx->nesting == 0); 115 mtx->owner = THREAD; 111 116 mtx->nesting = 1; 112 117 } … … 121 126 errno_t mutex_lock_timeout(mutex_t *mtx, uint32_t usec) 122 127 { 123 if (!THREAD) { 124 assert(mtx->type == MUTEX_RECURSIVE || mtx->nesting == 0); 125 mtx->nesting++; 126 return EOK; 128 if (usec != 0) { 129 assert(mtx->type != MUTEX_ACTIVE); 130 assert(THREAD); 127 131 } 128 132 129 if (_get_owner(mtx) == THREAD) { 130 assert(mtx->type == MUTEX_RECURSIVE); 131 assert(mtx->nesting > 0); 133 if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) { 134 assert(THREAD); 132 135 mtx->nesting++; 133 136 return EOK; … … 135 138 136 139 errno_t rc = semaphore_down_timeout(&mtx->sem, usec); 137 if (rc != EOK) 138 return rc; 139 140 _set_owner(mtx, THREAD); 141 assert(mtx->nesting == 0); 142 mtx->nesting = 1; 143 return EOK; 140 if (rc == EOK) { 141 mtx->owner = THREAD; 142 mtx->nesting = 1; 143 } 144 return rc; 144 145 } 145 146 … … 159 160 void mutex_unlock(mutex_t *mtx) 160 161 { 161 if (--mtx->nesting > 0) { 162 assert(mtx->type == MUTEX_RECURSIVE); 163 return; 162 if (mtx->type == MUTEX_RECURSIVE) { 163 assert(mtx->owner == THREAD); 164 if (--mtx->nesting > 0) 165 return; 166 mtx->owner = NULL; 164 167 } 165 166 assert(mtx->nesting == 0);167 168 if (!THREAD)169 return;170 171 assert(_get_owner(mtx) == THREAD);172 _set_owner(mtx, NULL);173 174 168 semaphore_up(&mtx->sem); 175 169 }
Note:
See TracChangeset
for help on using the changeset viewer.