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

Last change on this file since 354 was 1, checked in by alain, 8 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.