source: trunk/sys/libpthread/pthread_mutex.c@ 17

Last change on this file since 17 was 1, checked in by alain, 9 years ago

First import

File size: 7.3 KB
Line 
1/*
2 * pthread_mutex.c - pthread mutex related functions
3 *
4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
5 * Copyright (c) 2011,2012 UPMC Sorbonne Universites
6 *
7 * This file is part of ALMOS.
8 *
9 * ALMOS is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2.0 of the License.
12 *
13 * ALMOS is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ALMOS; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <errno.h>
24#include <sys/types.h>
25#include <pthread.h>
26#include <semaphore.h>
27#include <stdio.h>
28#include <sys/syscall.h>
29#include <cpu-syscall.h>
30#include <assert.h>
31#include <unistd.h>
32
33#define USE_PTSPINLOCK 1
34#define USE_HEURISTIC_LOCK 0
35//#define CONFIG_MUTEX_DEBUG
36
37#ifdef CONFIG_MUTEX_DEBUG
38#define mdmsg(...) fprintf(stderr, __VA_ARGS__)
39#else
40#define mdmsg(...)
41#endif
42
43#define print_mutex(x) \
44 do{mdmsg("%s: mtx @%x, [v %u, w %d, t %d, s %d, c %d]\n", \
45 __FUNCTION__, \
46 (unsigned)(x), \
47 (unsigned)(x)->value, \
48 (unsigned)(x)->waiting, \
49 (x)->attr.type, \
50 (x)->attr.scope, \
51 (x)->attr.cntr);}while(0)
52
53int pthread_mutexattr_init(pthread_mutexattr_t *attr)
54{
55 if(attr == NULL) return EINVAL;
56
57 attr->type = PTHREAD_MUTEX_DEFAULT;
58 attr->scope = PTHREAD_PROCESS_PRIVATE;
59 attr->cntr = 0;
60 return 0;
61}
62
63int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
64{
65 if((attr == NULL) || ((pshared != PTHREAD_PROCESS_SHARED) && (pshared != PTHREAD_PROCESS_PRIVATE)))
66 return EINVAL;
67
68 attr->scope = attr->scope;
69 return 0;
70}
71
72int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
73{
74 if(attr == NULL)
75 return EINVAL;
76
77 *pshared = (int)attr->scope;
78 return 0;
79}
80
81int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
82{
83 if(attr == NULL)
84 return EINVAL;
85
86 *type = (int)attr->type;
87 return 0;
88}
89
90int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
91{
92 if(attr == NULL)
93 return EINVAL;
94
95 if(type == PTHREAD_MUTEX_RECURSIVE)
96 attr->type = (uint8_t)type;
97 else
98 attr->type = PTHREAD_MUTEX_DEFAULT;
99
100 return 0;
101}
102
103int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
104{
105 return 0;
106}
107
108int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)
109{
110 int err;
111 pthread_mutexattr_t _attr;
112
113 if(mutex == NULL)
114 return EINVAL;
115
116 if(attr == NULL)
117 {
118 pthread_mutexattr_init(&_attr);
119 attr = &_attr;
120 }
121
122 err = pthread_spin_init(&mutex->lock, 0);
123
124 if(err) return err;
125
126 mutex->value = __PTHREAD_OBJECT_FREE;
127 mutex->waiting = 0;
128 mutex->attr.type = attr->type;
129 mutex->attr.scope = attr->scope;
130 mutex->attr.cntr = attr->cntr;
131
132 if(mutex->attr.scope == PTHREAD_PROCESS_SHARED)
133 return sem_init(&mutex->sem, PTHREAD_PROCESS_SHARED, 1);
134
135 return 0;
136}
137
138int pthread_mutex_lock (pthread_mutex_t *mutex)
139{
140 volatile uint_t cntr;
141 register __pthread_tls_t *tls;
142 register uint_t this;
143 register const uint_t limit1 = 100000;
144 register const uint_t limit2 = 2 * limit1;
145 int err;
146
147 if(mutex == NULL)
148 return EINVAL;
149
150 cntr = 0;
151 this = (uint_t)pthread_self();
152 int pid = getpid();
153
154 if(mutex->value == __PTHREAD_OBJECT_DESTROYED)
155 return EINVAL;
156
157 if((mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) && (mutex->value == this))
158 {
159 mutex->attr.cntr += 1;
160 return 0;
161 }
162
163 if(mutex->value == this)
164 return EDEADLK;
165
166 if(mutex->attr.scope == PTHREAD_PROCESS_SHARED)
167 return sem_wait(&mutex->sem);
168
169 for(cntr = 0; ((cntr < limit2) && (mutex->value != __PTHREAD_OBJECT_FREE)); cntr++)
170 {
171 if((cntr > limit1) && (mutex->value != __PTHREAD_OBJECT_FREE))// && (mutex->waiting > 4))
172 break;
173 }
174
175#if USE_PTSPINLOCK
176 err = pthread_spin_lock(&mutex->lock);
177 if(err) return err;
178#else
179 cpu_spinlock_lock(&mutex->lock);
180#endif
181
182 if(mutex->value == __PTHREAD_OBJECT_FREE)
183 {
184 mutex->value = this;
185
186#if USE_PTSPINLOCK
187 (void)pthread_spin_unlock(&mutex->lock);
188#else
189 cpu_spinlock_unlock(&mutex->lock);
190#endif
191 return 0;
192 }
193
194 if(mutex->waiting == 0)
195 list_root_init(&mutex->queue);
196
197 mutex->waiting += 1;
198 tls = cpu_get_tls();
199
200 struct __shared_s *shared = (struct __shared_s*)__pthread_tls_get(tls,__PT_TLS_SHARED);
201
202 list_add_last(&mutex->queue, &shared->list);
203
204#if USE_PTSPINLOCK
205 (void)pthread_spin_unlock(&mutex->lock);
206#else
207 cpu_spinlock_unlock(&mutex->lock);
208#endif
209 /* TODO: compute syscall return value (signals treatment) */
210 (void)cpu_syscall(NULL, NULL, NULL, NULL, SYS_SLEEP);
211
212 cpu_wbflush();
213
214 return 0;
215}
216
217int pthread_mutex_unlock (pthread_mutex_t *mutex)
218{
219 int err;
220 struct __shared_s *next;
221 uint_t this;
222
223 int pid = getpid();
224
225 if(mutex == NULL)
226 return EINVAL;
227
228 this = (uint_t)pthread_self();
229
230 if((mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) &&
231 (mutex->value == this) &&
232 (mutex->attr.cntr > 0))
233 {
234 mutex->attr.cntr -= 1;
235 return 0;
236 }
237
238 if(mutex->attr.scope == PTHREAD_PROCESS_SHARED)
239 {
240 if(mutex->value != this)
241 err = EPERM;
242 else
243 err = sem_post(&mutex->sem);
244
245 return err;
246 }
247
248#if USE_PTSPINLOCK
249 err = pthread_spin_lock(&mutex->lock);
250 if(err) return err;
251#else
252 cpu_spinlock_lock(&mutex->lock);
253#endif
254
255 if(mutex->value != this)
256 {
257 (void)pthread_spin_unlock(&mutex->lock);
258 return EPERM;
259 }
260
261 if(mutex->waiting == 0)
262 {
263 mutex->value = __PTHREAD_OBJECT_FREE;
264
265#if USE_PTSPINLOCK
266 (void)pthread_spin_unlock(&mutex->lock);
267#else
268 cpu_spinlock_unlock(&mutex->lock);
269#endif
270 return 0;
271 }
272
273#if 0
274 if(!(list_empty(&mutex->queue)))
275#endif
276 {
277 next = list_first(&mutex->queue, struct __shared_s, list);
278 list_unlink(&next->list);
279
280 mutex->waiting --;
281 mutex->value = next->tid;
282 cpu_wbflush();
283
284 (void)cpu_syscall((void*)next->tid, NULL, NULL, NULL, SYS_WAKEUP);
285 }
286
287#if USE_PTSPINLOCK
288 (void)pthread_spin_unlock(&mutex->lock);
289#else
290 cpu_spinlock_unlock(&mutex->lock);
291#endif
292 return 0;
293}
294
295
296int pthread_mutex_trylock (pthread_mutex_t *mutex)
297{
298 int err;
299 uint_t this;
300
301 if(mutex == NULL)
302 return EINVAL;
303
304 this = (uint_t)pthread_self();
305
306 if((mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) && (mutex->value == this))
307 {
308 mutex->attr.cntr += 1;
309 return 0;
310 }
311
312 if(mutex->value == this)
313 return EDEADLK;
314
315 if(mutex->attr.scope == PTHREAD_PROCESS_SHARED)
316 return sem_trywait(&mutex->sem);
317
318 if(mutex->value != __PTHREAD_OBJECT_FREE)
319 return EBUSY;
320
321#if USE_PTSPINLOCK
322 err = pthread_spin_lock(&mutex->lock);
323 if(err) return err;
324#else
325 cpu_spinlock_lock(&mutex->lock);
326#endif
327
328 if(mutex->value != __PTHREAD_OBJECT_FREE)
329 err = EBUSY;
330 else
331 mutex->value = this;
332
333#if USE_PTSPINLOCK
334 (void)pthread_spin_unlock(&mutex->lock);
335#else
336 cpu_spinlock_unlock(&mutex->lock);
337#endif
338
339 return err;
340}
341
342
343int pthread_mutex_destroy (pthread_mutex_t *mutex)
344{
345 int err;
346
347 if(mutex == NULL)
348 return EINVAL;
349
350 if(mutex->attr.scope == PTHREAD_PROCESS_SHARED)
351 return sem_destroy(&mutex->sem);
352
353 print_mutex(mutex);
354
355 if((mutex->waiting != 0) || (mutex->value != __PTHREAD_OBJECT_FREE))
356 return EBUSY;
357
358 err = pthread_spin_destroy(&mutex->lock);
359
360 if(err) return err;
361
362 mutex->value = __PTHREAD_OBJECT_DESTROYED;
363 mutex->waiting = __PTHREAD_OBJECT_BUSY;
364 return 0;
365}
366
Note: See TracBrowser for help on using the repository browser.