Update.
[platform/upstream/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 strong_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 strong_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 strong_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, NULL);
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, self);
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, self);
100     mutex->__m_owner = self;
101     return 0;
102   default:
103     return EINVAL;
104   }
105 }
106 strong_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 strong_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 strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
140
141 int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
142 {
143   return 0;
144 }
145 strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
146
147 int __pthread_mutexattr_settype(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_settype, pthread_mutexattr_settype)
157 strong_alias ( __pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
158 weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
159
160 int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind)
161 {
162   *kind = attr->__mutexkind;
163   return 0;
164 }
165 weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype)
166 strong_alias (__pthread_mutexattr_gettype, __pthread_mutexattr_getkind_np)
167 weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np)
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 /* If a thread is canceled while calling the init_routine out of
177    pthread once, this handler will reset the once_control variable
178    to the NEVER state. */
179
180 static void pthread_once_cancelhandler(void *arg)
181 {
182     pthread_once_t *once_control = arg;
183
184     pthread_mutex_lock(&once_masterlock);
185     *once_control = NEVER;
186     pthread_mutex_unlock(&once_masterlock);
187     pthread_cond_broadcast(&once_finished);
188 }
189
190 int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void))
191 {
192   /* flag for doing the condition broadcast outside of mutex */
193   int state_changed;
194
195   /* Test without locking first for speed */
196   if (*once_control == DONE) return 0;
197   /* Lock and test again */
198
199   state_changed = 0;
200
201   pthread_mutex_lock(&once_masterlock);
202   /* If init_routine is being called from another routine, wait until
203      it completes. */
204   while (*once_control == IN_PROGRESS) {
205     pthread_cond_wait(&once_finished, &once_masterlock);
206   }
207   /* Here *once_control is stable and either NEVER or DONE. */
208   if (*once_control == NEVER) {
209     *once_control = IN_PROGRESS;
210     pthread_mutex_unlock(&once_masterlock);
211     pthread_cleanup_push(pthread_once_cancelhandler, once_control);
212     init_routine();
213     pthread_cleanup_pop(0);
214     pthread_mutex_lock(&once_masterlock);
215     *once_control = DONE;
216     state_changed = 1;
217   }
218   pthread_mutex_unlock(&once_masterlock);
219
220   if (state_changed)
221     pthread_cond_broadcast(&once_finished);
222
223   return 0;
224 }
225 strong_alias (__pthread_once, pthread_once)