blob: 4998b6aadc07559ecbc413f7d449329cf74650e5 [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*
2 * Copyright (c) 2008 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <debug.h>
24#include <err.h>
25#include <kernel/mutex.h>
26#include <kernel/thread.h>
27
28#if DEBUGLEVEL > 1
29#define MUTEX_CHECK 1
30#endif
31
32void mutex_init(mutex_t *m)
33{
34#if MUTEX_CHECK
35// ASSERT(m->magic != MUTEX_MAGIC);
36#endif
37
38 m->magic = MUTEX_MAGIC;
39 m->count = 0;
40 m->holder = 0;
41 wait_queue_init(&m->wait);
42}
43
44void mutex_destroy(mutex_t *m)
45{
46 enter_critical_section();
47
48#if MUTEX_CHECK
49 ASSERT(m->magic == MUTEX_MAGIC);
50#endif
51
52 if (m->holder != 0 && current_thread != m->holder)
53 panic("mutex_destroy: thread %p (%s) tried to release mutex %p it doesn't own. owned by %p (%s)\n",
54 current_thread, current_thread->name, m, m->holder, m->holder ? m->holder->name : "none");
55
56 m->magic = 0;
57 m->count = 0;
58 wait_queue_destroy(&m->wait, true);
59 exit_critical_section();
60}
61
62status_t mutex_acquire(mutex_t *m)
63{
64 status_t ret = NO_ERROR;
65
66 if (current_thread == m->holder)
67 panic("mutex_acquire: thread %p (%s) tried to acquire mutex %p it already owns.\n",
68 current_thread, current_thread->name, m);
69
70 enter_critical_section();
71
72#if MUTEX_CHECK
73 ASSERT(m->magic == MUTEX_MAGIC);
74#endif
75
76// dprintf("mutex_acquire: m %p, count %d, curr %p\n", m, m->count, current_thread);
77
78 m->count++;
79 if (unlikely(m->count > 1)) {
80 /*
81 * block on the wait queue. If it returns an error, it was likely destroyed
82 * out from underneath us, so make sure we dont scribble thread ownership
83 * on the mutex.
84 */
85 ret = wait_queue_block(&m->wait, INFINITE_TIME);
86 if (ret < 0)
87 goto err;
88 }
89 m->holder = current_thread;
90
91err:
92 exit_critical_section();
93
94 return ret;
95}
96
97status_t mutex_acquire_timeout(mutex_t *m, time_t timeout)
98{
99 status_t ret = NO_ERROR;
100
101 if (current_thread == m->holder)
102 panic("mutex_acquire_timeout: thread %p (%s) tried to acquire mutex %p it already owns.\n",
103 current_thread, current_thread->name, m);
104
105 if (timeout == INFINITE_TIME)
106 return mutex_acquire(m);
107
108 enter_critical_section();
109
110#if MUTEX_CHECK
111 ASSERT(m->magic == MUTEX_MAGIC);
112#endif
113
114// dprintf("mutex_acquire_timeout: m %p, count %d, curr %p, timeout %d\n", m, m->count, current_thread, timeout);
115
116 m->count++;
117 if (unlikely(m->count > 1)) {
118 ret = wait_queue_block(&m->wait, timeout);
119 if (ret < NO_ERROR) {
120 /* if the acquisition timed out, back out the acquire and exit */
121 if (ret == ERR_TIMED_OUT) {
122 /*
123 * XXX race: the mutex may have been destroyed after the timeout,
124 * but before we got scheduled again which makes messing with the
125 * count variable dangerous.
126 */
127 m->count--;
128 goto err;
129 }
130 /* if there was a general error, it may have been destroyed out from
131 * underneath us, so just exit (which is really an invalid state anyway)
132 */
133 }
134 }
135 m->holder = current_thread;
136
137err:
138 exit_critical_section();
139
140 return ret;
141}
142
143status_t mutex_release(mutex_t *m)
144{
145 if (current_thread != m->holder)
146 panic("mutex_release: thread %p (%s) tried to release mutex %p it doesn't own. owned by %p (%s)\n",
147 current_thread, current_thread->name, m, m->holder, m->holder ? m->holder->name : "none");
148
149 enter_critical_section();
150
151#if MUTEX_CHECK
152 ASSERT(m->magic == MUTEX_MAGIC);
153#endif
154
155// dprintf("mutex_release: m %p, count %d, holder %p, curr %p\n", m, m->count, m->holder, current_thread);
156
157 m->holder = 0;
158 m->count--;
159 if (unlikely(m->count >= 1)) {
160 /* release a thread */
161// dprintf("releasing thread\n");
162 wait_queue_wake_one(&m->wait, true, NO_ERROR);
163 }
164
165 exit_critical_section();
166
167 return NO_ERROR;
168}
169