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

Last change on this file since 0db0df2 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
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * Copyright (c) 2023 Jiří Zárevúcky
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
30/** @addtogroup kernel_sync
31 * @{
32 */
33
34/**
35 * @file
36 * @brief Mutexes.
37 */
38
39#include <assert.h>
40#include <errno.h>
41#include <synch/mutex.h>
42#include <synch/semaphore.h>
43#include <arch.h>
44#include <stacktrace.h>
45#include <cpu.h>
46#include <proc/thread.h>
47
48/** Initialize mutex.
49 *
50 * @param mtx Mutex.
51 * @param type Type of the mutex.
52 */
53void mutex_initialize(mutex_t *mtx, mutex_type_t type)
54{
55 mtx->type = type;
56 mtx->owner = NULL;
57 mtx->nesting = 0;
58 semaphore_initialize(&mtx->sem, 1);
59}
60
61/** Find out whether the mutex is currently locked.
62 *
63 * @param mtx Mutex.
64 *
65 * @return True if the mutex is locked, false otherwise.
66 */
67bool mutex_locked(mutex_t *mtx)
68{
69 errno_t rc = semaphore_trydown(&mtx->sem);
70 if (rc == EOK) {
71 semaphore_up(&mtx->sem);
72 }
73 return rc != EOK;
74}
75
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}
96
97/** Acquire mutex.
98 *
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.
120 *
121 * @param mtx Mutex.
122 * @param usec Timeout in microseconds.
123 *
124 * @return EOK if lock was successfully acquired, something else otherwise.
125 */
126errno_t mutex_lock_timeout(mutex_t *mtx, uint32_t usec)
127{
128 if (usec != 0) {
129 assert(mtx->type != MUTEX_ACTIVE);
130 assert(THREAD);
131 }
132
133 if (mtx->type == MUTEX_RECURSIVE && mtx->owner == THREAD) {
134 assert(THREAD);
135 mtx->nesting++;
136 return EOK;
137 }
138
139 errno_t rc = semaphore_down_timeout(&mtx->sem, usec);
140 if (rc == EOK) {
141 mtx->owner = THREAD;
142 mtx->nesting = 1;
143 }
144 return rc;
145}
146
147/** Attempt to acquire mutex without blocking.
148 *
149 * @return EOK if lock was successfully acquired, something else otherwise.
150 */
151errno_t mutex_trylock(mutex_t *mtx)
152{
153 return mutex_lock_timeout(mtx, 0);
154}
155
156/** Release mutex.
157 *
158 * @param mtx Mutex.
159 */
160void mutex_unlock(mutex_t *mtx)
161{
162 if (mtx->type == MUTEX_RECURSIVE) {
163 assert(mtx->owner == THREAD);
164 if (--mtx->nesting > 0)
165 return;
166 mtx->owner = NULL;
167 }
168 semaphore_up(&mtx->sem);
169}
170
171/** @}
172 */
Note: See TracBrowser for help on using the repository browser.