2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include "pthread_private.h"
40 static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
43 pthread_mutex_init(pthread_mutex_t * mutex,
44 const pthread_mutexattr_t * mutex_attr)
46 enum pthread_mutextype type;
47 pthread_mutex_t pmutex;
53 /* Check if default mutex attributes: */
54 if (mutex_attr == NULL || *mutex_attr == NULL)
55 /* Default to a fast mutex: */
56 type = PTHREAD_MUTEX_DEFAULT;
58 else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)
59 /* Return an invalid argument error: */
62 /* Use the requested mutex type: */
63 type = (*mutex_attr)->m_type;
65 /* Check no errors so far: */
67 if ((pmutex = (pthread_mutex_t)
68 malloc(sizeof(struct pthread_mutex))) == NULL)
71 /* Reset the mutex flags: */
74 /* Process according to mutex type: */
77 case PTHREAD_MUTEX_DEFAULT:
78 case PTHREAD_MUTEX_NORMAL:
79 case PTHREAD_MUTEX_ERRORCHECK:
80 /* Nothing to do here. */
84 case PTHREAD_MUTEX_RECURSIVE:
85 /* Reset the mutex count: */
86 pmutex->m_data.m_count = 0;
89 /* Trap invalid mutex types: */
91 /* Return an invalid argument error: */
96 /* Initialise the rest of the mutex: */
97 _thread_queue_init(&pmutex->m_queue);
98 pmutex->m_flags |= MUTEX_FLAGS_INITED;
99 pmutex->m_owner = NULL;
100 pmutex->m_type = type;
101 memset(&pmutex->lock, 0,
102 sizeof(pmutex->lock));
111 /* Return the completion status: */
116 pthread_mutex_destroy(pthread_mutex_t * mutex)
120 if (mutex == NULL || *mutex == NULL)
123 /* Lock the mutex structure: */
124 _SPINLOCK(&(*mutex)->lock);
127 * Free the memory allocated for the mutex
133 * Leave the caller's pointer NULL now that
134 * the mutex has been destroyed:
139 /* Return the completion status: */
144 init_static (pthread_mutex_t *mutex)
148 _SPINLOCK(&static_init_lock);
151 ret = pthread_mutex_init(mutex, NULL);
155 _SPINUNLOCK(&static_init_lock);
161 pthread_mutex_trylock(pthread_mutex_t * mutex)
169 * If the mutex is statically initialized, perform the dynamic
172 else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
173 /* Lock the mutex structure: */
174 _SPINLOCK(&(*mutex)->lock);
176 /* Process according to mutex type: */
177 switch ((*mutex)->m_type) {
179 case PTHREAD_MUTEX_NORMAL:
180 case PTHREAD_MUTEX_DEFAULT:
181 case PTHREAD_MUTEX_ERRORCHECK:
182 /* Check if this mutex is not locked: */
183 if ((*mutex)->m_owner == NULL) {
184 /* Lock the mutex for the running thread: */
185 (*mutex)->m_owner = _thread_run;
187 /* Return a busy error: */
192 /* Counting mutex: */
193 case PTHREAD_MUTEX_RECURSIVE:
194 /* Check if this mutex is locked: */
195 if ((*mutex)->m_owner != NULL) {
197 * Check if the mutex is locked by the running
200 if ((*mutex)->m_owner == _thread_run) {
201 /* Increment the lock count: */
202 (*mutex)->m_data.m_count++;
204 /* Return a busy error: */
208 /* Lock the mutex for the running thread: */
209 (*mutex)->m_owner = _thread_run;
213 /* Trap invalid mutex types: */
215 /* Return an invalid argument error: */
220 /* Unlock the mutex structure: */
221 _SPINUNLOCK(&(*mutex)->lock);
224 /* Return the completion status: */
229 pthread_mutex_lock(pthread_mutex_t * mutex)
237 * If the mutex is statically initialized, perform the dynamic
240 else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
241 /* Lock the mutex structure: */
242 _SPINLOCK(&(*mutex)->lock);
244 /* Process according to mutex type: */
245 switch ((*mutex)->m_type) {
246 /* What SS2 define as a 'normal' mutex. This has to deadlock
247 on attempts to get a lock you already own. */
248 case PTHREAD_MUTEX_NORMAL:
249 if ((*mutex)->m_owner == _thread_run) {
250 /* Intetionally deadlock */
252 _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
256 /* Return error (not OK) on attempting to re-lock */
257 case PTHREAD_MUTEX_ERRORCHECK:
258 if ((*mutex)->m_owner == _thread_run) {
263 /* Fast mutexes do not check for any error conditions: */
264 case PTHREAD_MUTEX_DEFAULT:
267 * Enter a loop to wait for the mutex to be locked by the
270 while ((*mutex)->m_owner != _thread_run) {
271 /* Check if the mutex is not locked: */
272 if ((*mutex)->m_owner == NULL) {
273 /* Lock the mutex for this thread: */
274 (*mutex)->m_owner = _thread_run;
277 * Join the queue of threads waiting to lock
280 _thread_queue_enq(&(*mutex)->m_queue, _thread_run);
282 /* Wait for the mutex: */
283 _thread_kern_sched_state_unlock(
284 PS_MUTEX_WAIT, &(*mutex)->lock,
287 /* Lock the mutex again: */
288 _SPINLOCK(&(*mutex)->lock);
293 /* Counting mutex: */
294 case PTHREAD_MUTEX_RECURSIVE:
296 * Enter a loop to wait for the mutex to be locked by the
299 while ((*mutex)->m_owner != _thread_run) {
300 /* Check if the mutex is not locked: */
301 if ((*mutex)->m_owner == NULL) {
302 /* Lock the mutex for this thread: */
303 (*mutex)->m_owner = _thread_run;
305 /* Reset the lock count for this mutex: */
306 (*mutex)->m_data.m_count = 0;
309 * Join the queue of threads waiting to lock
312 _thread_queue_enq(&(*mutex)->m_queue, _thread_run);
314 /* Wait for the mutex: */
315 _thread_kern_sched_state_unlock(
316 PS_MUTEX_WAIT, &(*mutex)->lock,
319 /* Lock the mutex again: */
320 _SPINLOCK(&(*mutex)->lock);
324 /* Increment the lock count for this mutex: */
325 (*mutex)->m_data.m_count++;
328 /* Trap invalid mutex types: */
330 /* Return an invalid argument error: */
335 /* Unlock the mutex structure: */
336 _SPINUNLOCK(&(*mutex)->lock);
339 /* Return the completion status: */
344 pthread_mutex_unlock(pthread_mutex_t * mutex)
348 if (mutex == NULL || *mutex == NULL) {
351 /* Lock the mutex structure: */
352 _SPINLOCK(&(*mutex)->lock);
354 /* Process according to mutex type: */
355 switch ((*mutex)->m_type) {
356 /* Default & normal mutexes do not really need to check for
357 any error conditions: */
358 case PTHREAD_MUTEX_NORMAL:
359 case PTHREAD_MUTEX_DEFAULT:
360 case PTHREAD_MUTEX_ERRORCHECK:
361 /* Check if the running thread is not the owner of the mutex: */
362 if ((*mutex)->m_owner != _thread_run) {
363 /* Return an invalid argument error: */
364 ret = (*mutex)->m_owner ? EPERM : EINVAL;
367 * Get the next thread from the queue of threads waiting on
370 else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
371 /* Allow the new owner of the mutex to run: */
372 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
376 /* Counting mutex: */
377 case PTHREAD_MUTEX_RECURSIVE:
378 /* Check if the running thread is not the owner of the mutex: */
379 if ((*mutex)->m_owner != _thread_run) {
380 /* Return an invalid argument error: */
383 /* Check if there are still counts: */
384 else if ((*mutex)->m_data.m_count > 1) {
385 /* Decrement the count: */
386 (*mutex)->m_data.m_count--;
388 (*mutex)->m_data.m_count = 0;
390 * Get the next thread from the queue of threads waiting on
393 if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
394 /* Allow the new owner of the mutex to run: */
395 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
400 /* Trap invalid mutex types: */
402 /* Return an invalid argument error: */
407 /* Unlock the mutex structure: */
408 _SPINUNLOCK(&(*mutex)->lock);
411 /* Return the completion status: */