(main): Use exit, not pthread_exit.
[kopensolaris-gnu/glibc.git] / linuxthreads / mutex.c
1 /* Linuxthreads - a simple clone()-based implementation of Posix        */
2 /* threads for Linux.                                                   */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
4 /*                                                                      */
5 /* This program is free software; you can redistribute it and/or        */
6 /* modify it under the terms of the GNU Library General Public License  */
7 /* as published by the Free Software Foundation; either version 2       */
8 /* of the License, or (at your option) any later version.               */
9 /*                                                                      */
10 /* This program is distributed in the hope that it will be useful,      */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
13 /* GNU Library General Public License for more details.                 */
14
15 /* Mutexes */
16
17 #include <errno.h>
18 #include <sched.h>
19 #include <stddef.h>
20 #include "pthread.h"
21 #include "internals.h"
22 #include "spinlock.h"
23 #include "queue.h"
24 #include "restart.h"
25
26 int __pthread_mutex_init(pthread_mutex_t * mutex,
27                        const pthread_mutexattr_t * mutex_attr)
28 {
29   __pthread_init_lock(&mutex->m_lock);
30   mutex->m_kind =
31     mutex_attr == NULL ? PTHREAD_MUTEX_FAST_NP : mutex_attr->mutexkind;
32   mutex->m_count = 0;
33   mutex->m_owner = NULL;
34   return 0;
35 }
36 weak_alias (__pthread_mutex_init, pthread_mutex_init)
37
38 int __pthread_mutex_destroy(pthread_mutex_t * mutex)
39 {
40   if (mutex->m_lock.status != 0) return EBUSY;
41   return 0;
42 }
43 weak_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
44
45 int __pthread_mutex_trylock(pthread_mutex_t * mutex)
46 {
47   pthread_descr self;
48   int retcode;
49
50   switch(mutex->m_kind) {
51   case PTHREAD_MUTEX_FAST_NP:
52     retcode = __pthread_trylock(&mutex->m_lock);
53     return retcode;
54   case PTHREAD_MUTEX_RECURSIVE_NP:
55     self = thread_self();
56     if (mutex->m_owner == self) {
57       mutex->m_count++;
58       return 0;
59     }
60     retcode = __pthread_trylock(&mutex->m_lock);
61     if (retcode == 0) {
62       mutex->m_owner = self;
63       mutex->m_count = 0;
64     }
65     return retcode;
66   case PTHREAD_MUTEX_ERRORCHECK_NP:
67     retcode = __pthread_trylock(&mutex->m_lock);
68     if (retcode == 0) {
69       mutex->m_owner = thread_self();
70     }
71     return retcode;
72   default:
73     return EINVAL;
74   }
75 }
76 weak_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
77
78 int __pthread_mutex_lock(pthread_mutex_t * mutex)
79 {
80   pthread_descr self;
81
82   switch(mutex->m_kind) {
83   case PTHREAD_MUTEX_FAST_NP:
84     __pthread_lock(&mutex->m_lock);
85     return 0;
86   case PTHREAD_MUTEX_RECURSIVE_NP:
87     self = thread_self();
88     if (mutex->m_owner == self) {
89       mutex->m_count++;
90       return 0;
91     }
92     __pthread_lock(&mutex->m_lock);
93     mutex->m_owner = self;
94     mutex->m_count = 0;
95     return 0;
96   case PTHREAD_MUTEX_ERRORCHECK_NP:
97     self = thread_self();
98     if (mutex->m_owner == self) return EDEADLK;
99     __pthread_lock(&mutex->m_lock);
100     mutex->m_owner = self;
101     return 0;
102   default:
103     return EINVAL;
104   }
105 }
106 weak_alias (__pthread_mutex_lock, pthread_mutex_lock)
107
108 int __pthread_mutex_unlock(pthread_mutex_t * mutex)
109 {
110   switch (mutex->m_kind) {
111   case PTHREAD_MUTEX_FAST_NP:
112     __pthread_unlock(&mutex->m_lock);
113     return 0;
114   case PTHREAD_MUTEX_RECURSIVE_NP:
115     if (mutex->m_count > 0) {
116       mutex->m_count--;
117       return 0;
118     }
119     mutex->m_owner = NULL;
120     __pthread_unlock(&mutex->m_lock);
121     return 0;
122   case PTHREAD_MUTEX_ERRORCHECK_NP:
123     if (mutex->m_owner != thread_self() || mutex->m_lock.status == 0)
124       return EPERM;
125     mutex->m_owner = NULL;
126     __pthread_unlock(&mutex->m_lock);
127     return 0;
128   default:
129     return EINVAL;
130   }
131 }
132 weak_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
133
134 int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
135 {
136   attr->mutexkind = PTHREAD_MUTEX_FAST_NP;
137   return 0;
138 }
139 weak_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
140
141 int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
142 {
143   return 0;
144 }
145 weak_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
146
147 int __pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind)
148 {
149   if (kind != PTHREAD_MUTEX_FAST_NP
150       && kind != PTHREAD_MUTEX_RECURSIVE_NP
151       && kind != PTHREAD_MUTEX_ERRORCHECK_NP)
152     return EINVAL;
153   attr->mutexkind = kind;
154   return 0;
155 }
156 weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
157 strong_alias (__pthread_mutexattr_setkind_np, __pthread_mutexattr_settype)
158 weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype)
159
160 int __pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr, int *kind)
161 {
162   *kind = attr->mutexkind;
163   return 0;
164 }
165 weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np)
166 strong_alias (__pthread_mutexattr_getkind_np, __pthread_mutexattr_gettype)
167 weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype)
168
169 /* Once-only execution */
170
171 static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
172 static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER;
173
174 enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 };
175
176 int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void))
177 {
178   /* Test without locking first for speed */
179   if (*once_control == DONE) return 0;
180   /* Lock and test again */
181   pthread_mutex_lock(&once_masterlock);
182   /* If init_routine is being called from another routine, wait until
183      it completes. */
184   while (*once_control == IN_PROGRESS) {
185     pthread_cond_wait(&once_finished, &once_masterlock);
186   }
187   /* Here *once_control is stable and either NEVER or DONE. */
188   if (*once_control == NEVER) {
189     *once_control = IN_PROGRESS;
190     pthread_mutex_unlock(&once_masterlock);
191     init_routine();
192     pthread_mutex_lock(&once_masterlock);
193     *once_control = DONE;
194     pthread_cond_broadcast(&once_finished);
195   }
196   pthread_mutex_unlock(&once_masterlock);
197   return 0;
198 }
199 weak_alias (__pthread_once, pthread_once)