source: mainline/kernel/generic/src/synch/mutex.c@ c89ae25

topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c89ae25 was 76e17d7c, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Reorganize mutex implementation

  • Property mode set to 100644
File size: 4.1 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2004 Jakub Jermar
[76e17d7c]3 * Copyright (c) 2023 Jiří Zárevúcky
[f761f1eb]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[e88eb48]30/** @addtogroup kernel_sync
[b45c443]31 * @{
32 */
33
[cf26ba9]34/**
[b45c443]35 * @file
[2e4e706]36 * @brief Mutexes.
[cf26ba9]37 */
[2e4e706]38
[63e27ef]39#include <assert.h>
[897fd8f1]40#include <errno.h>
[f761f1eb]41#include <synch/mutex.h>
42#include <synch/semaphore.h>
[a3900cc]43#include <arch.h>
[311929ec]44#include <stacktrace.h>
[1066041]45#include <cpu.h>
46#include <proc/thread.h>
[f761f1eb]47
[08a19ba]48/** Initialize mutex.
[63975c6]49 *
[15d9fe6]50 * @param mtx Mutex.
51 * @param type Type of the mutex.
[63975c6]52 */
[08a19ba]53void mutex_initialize(mutex_t *mtx, mutex_type_t type)
[f761f1eb]54{
[08a19ba]55 mtx->type = type;
[15d9fe6]56 mtx->owner = NULL;
57 mtx->nesting = 0;
[f761f1eb]58 semaphore_initialize(&mtx->sem, 1);
59}
60
[d7da4284]61/** Find out whether the mutex is currently locked.
62 *
[15d9fe6]63 * @param mtx Mutex.
64 *
65 * @return True if the mutex is locked, false otherwise.
[d7da4284]66 */
67bool mutex_locked(mutex_t *mtx)
68{
[e994898]69 errno_t rc = semaphore_trydown(&mtx->sem);
70 if (rc == EOK) {
[4c78104]71 semaphore_up(&mtx->sem);
72 }
[e994898]73 return rc != EOK;
[d7da4284]74}
75
[76e17d7c]76static 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);
95}
[fce7b43]96
[08a19ba]97/** Acquire mutex.
[63975c6]98 *
[76e17d7c]99 * This operation is uninterruptible and cannot fail.
100 */
101void mutex_lock(mutex_t *mtx)
102{
103 if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
104 assert(THREAD);
105 mtx->nesting++;
106 return;
107 }
108
109 if (mtx->type == MUTEX_ACTIVE || !THREAD) {
110 mutex_lock_active(mtx);
111 return;
112 }
113
114 semaphore_down(&mtx->sem);
115 mtx->owner = THREAD;
116 mtx->nesting = 1;
117}
118
119/** Acquire mutex with timeout.
[63975c6]120 *
[15d9fe6]121 * @param mtx Mutex.
122 * @param usec Timeout in microseconds.
[2e4e706]123 *
[76e17d7c]124 * @return EOK if lock was successfully acquired, something else otherwise.
[63975c6]125 */
[76e17d7c]126errno_t mutex_lock_timeout(mutex_t *mtx, uint32_t usec)
[f761f1eb]127{
[76e17d7c]128 if (usec != 0) {
129 assert(mtx->type != MUTEX_ACTIVE);
[15d9fe6]130 assert(THREAD);
[76e17d7c]131 }
[15d9fe6]132
[76e17d7c]133 if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
134 assert(THREAD);
135 mtx->nesting++;
136 return EOK;
[08a19ba]137 }
138
[76e17d7c]139 errno_t rc = semaphore_down_timeout(&mtx->sem, usec);
140 if (rc == EOK) {
141 mtx->owner = THREAD;
142 mtx->nesting = 1;
143 }
[08a19ba]144 return rc;
[f761f1eb]145}
146
[76e17d7c]147/** Attempt to acquire mutex without blocking.
148 *
149 * @return EOK if lock was successfully acquired, something else otherwise.
150 */
[5110d0a]151errno_t mutex_trylock(mutex_t *mtx)
152{
[76e17d7c]153 return mutex_lock_timeout(mtx, 0);
[5110d0a]154}
155
[08a19ba]156/** Release mutex.
[63975c6]157 *
[15d9fe6]158 * @param mtx Mutex.
[63975c6]159 */
[f761f1eb]160void mutex_unlock(mutex_t *mtx)
161{
[15d9fe6]162 if (mtx->type == MUTEX_RECURSIVE) {
163 assert(mtx->owner == THREAD);
164 if (--mtx->nesting > 0)
165 return;
166 mtx->owner = NULL;
167 }
[f761f1eb]168 semaphore_up(&mtx->sem);
169}
[116d1ef4]170
[cc73a8a1]171/** @}
[b45c443]172 */
Note: See TracBrowser for help on using the repository browser.