]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libkse/thread/thr_mutex.c
This commit was generated by cvs2svn to compensate for changes in r43892,
[FreeBSD/FreeBSD.git] / lib / libkse / thread / thr_mutex.c
1 /*
2  * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by John Birrell.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <string.h>
36 #ifdef _THREAD_SAFE
37 #include <pthread.h>
38 #include "pthread_private.h"
39
40 static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
41
42 int
43 pthread_mutex_init(pthread_mutex_t * mutex,
44                    const pthread_mutexattr_t * mutex_attr)
45 {
46         enum pthread_mutextype type;
47         pthread_mutex_t pmutex;
48         int             ret = 0;
49
50         if (mutex == NULL) {
51                 ret = EINVAL;
52         } else {
53                 /* Check if default mutex attributes: */
54                 if (mutex_attr == NULL || *mutex_attr == NULL)
55                         /* Default to a fast mutex: */
56                         type = PTHREAD_MUTEX_DEFAULT;
57
58                 else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)
59                         /* Return an invalid argument error: */
60                         ret = EINVAL;
61                 else
62                         /* Use the requested mutex type: */
63                         type = (*mutex_attr)->m_type;
64
65                 /* Check no errors so far: */
66                 if (ret == 0) {
67                         if ((pmutex = (pthread_mutex_t)
68                             malloc(sizeof(struct pthread_mutex))) == NULL)
69                                 ret = ENOMEM;
70                         else {
71                                 /* Reset the mutex flags: */
72                                 pmutex->m_flags = 0;
73
74                                 /* Process according to mutex type: */
75                                 switch (type) {
76                                 /* Fast mutex: */
77                                 case PTHREAD_MUTEX_DEFAULT:
78                                 case PTHREAD_MUTEX_NORMAL:
79                                 case PTHREAD_MUTEX_ERRORCHECK:
80                                         /* Nothing to do here. */
81                                         break;
82
83                                 /* Counting mutex: */
84                                 case PTHREAD_MUTEX_RECURSIVE:
85                                         /* Reset the mutex count: */
86                                         pmutex->m_data.m_count = 0;
87                                         break;
88
89                                 /* Trap invalid mutex types: */
90                                 default:
91                                         /* Return an invalid argument error: */
92                                         ret = EINVAL;
93                                         break;
94                                 }
95                                 if (ret == 0) {
96                                         /* Initialise the rest of the mutex: */
97                                         _thread_queue_init(&pmutex->m_queue);
98                                         pmutex->m_flags |= MUTEX_FLAGS_INITED;
99                                         pmutex->m_owner = NULL;
100                                         pmutex->m_type = type;
101                                         memset(&pmutex->lock, 0,
102                                             sizeof(pmutex->lock));
103                                         *mutex = pmutex;
104                                 } else {
105                                         free(pmutex);
106                                         *mutex = NULL;
107                                 }
108                         }
109                 }
110         }
111         /* Return the completion status: */
112         return (ret);
113 }
114
115 int
116 pthread_mutex_destroy(pthread_mutex_t * mutex)
117 {
118         int ret = 0;
119
120         if (mutex == NULL || *mutex == NULL)
121                 ret = EINVAL;
122         else {
123                 /* Lock the mutex structure: */
124                 _SPINLOCK(&(*mutex)->lock);
125
126                 /*
127                  * Free the memory allocated for the mutex
128                  * structure:
129                  */
130                 free(*mutex);
131
132                 /*
133                  * Leave the caller's pointer NULL now that
134                  * the mutex has been destroyed:
135                  */
136                 *mutex = NULL;
137         }
138
139         /* Return the completion status: */
140         return (ret);
141 }
142
143 static int
144 init_static (pthread_mutex_t *mutex)
145 {
146         int ret;
147
148         _SPINLOCK(&static_init_lock);
149
150         if (*mutex == NULL)
151                 ret = pthread_mutex_init(mutex, NULL);
152         else
153                 ret = 0;
154
155         _SPINUNLOCK(&static_init_lock);
156
157         return(ret);
158 }
159
160 int
161 pthread_mutex_trylock(pthread_mutex_t * mutex)
162 {
163         int             ret = 0;
164
165         if (mutex == NULL)
166                 ret = EINVAL;
167
168         /*
169          * If the mutex is statically initialized, perform the dynamic
170          * initialization:
171          */
172         else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
173                 /* Lock the mutex structure: */
174                 _SPINLOCK(&(*mutex)->lock);
175
176                 /* Process according to mutex type: */
177                 switch ((*mutex)->m_type) {
178                 /* Fast mutex: */
179                 case PTHREAD_MUTEX_NORMAL:
180                 case PTHREAD_MUTEX_DEFAULT:
181                 case PTHREAD_MUTEX_ERRORCHECK:
182                         /* Check if this mutex is not locked: */
183                         if ((*mutex)->m_owner == NULL) {
184                                 /* Lock the mutex for the running thread: */
185                                 (*mutex)->m_owner = _thread_run;
186                         } else {
187                                 /* Return a busy error: */
188                                 ret = EBUSY;
189                         }
190                         break;
191
192                 /* Counting mutex: */
193                 case PTHREAD_MUTEX_RECURSIVE:
194                         /* Check if this mutex is locked: */
195                         if ((*mutex)->m_owner != NULL) {
196                                 /*
197                                  * Check if the mutex is locked by the running
198                                  * thread: 
199                                  */
200                                 if ((*mutex)->m_owner == _thread_run) {
201                                         /* Increment the lock count: */
202                                         (*mutex)->m_data.m_count++;
203                                 } else {
204                                         /* Return a busy error: */
205                                         ret = EBUSY;
206                                 }
207                         } else {
208                                 /* Lock the mutex for the running thread: */
209                                 (*mutex)->m_owner = _thread_run;
210                         }
211                         break;
212
213                 /* Trap invalid mutex types: */
214                 default:
215                         /* Return an invalid argument error: */
216                         ret = EINVAL;
217                         break;
218                 }
219
220                 /* Unlock the mutex structure: */
221                 _SPINUNLOCK(&(*mutex)->lock);
222         }
223
224         /* Return the completion status: */
225         return (ret);
226 }
227
228 int
229 pthread_mutex_lock(pthread_mutex_t * mutex)
230 {
231         int             ret = 0;
232
233         if (mutex == NULL)
234                 ret = EINVAL;
235
236         /*
237          * If the mutex is statically initialized, perform the dynamic
238          * initialization:
239          */
240         else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
241                 /* Lock the mutex structure: */
242                 _SPINLOCK(&(*mutex)->lock);
243
244                 /* Process according to mutex type: */
245                 switch ((*mutex)->m_type) {
246                 /* What SS2 define as a 'normal' mutex.  This has to deadlock
247                    on attempts to get a lock you already own. */
248                 case PTHREAD_MUTEX_NORMAL:
249                         if ((*mutex)->m_owner == _thread_run) {
250                                 /* Intetionally deadlock */
251                                 for (;;)
252                                         _thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
253                         }
254                         goto COMMON_LOCK;
255                         
256                  /* Return error (not OK) on attempting to re-lock */
257                 case PTHREAD_MUTEX_ERRORCHECK:
258                         if ((*mutex)->m_owner == _thread_run) {
259                                 ret = EDEADLK;
260                                 break;
261                         }
262                         
263                 /* Fast mutexes do not check for any error conditions: */
264                 case PTHREAD_MUTEX_DEFAULT:
265                 COMMON_LOCK:
266                         /*
267                          * Enter a loop to wait for the mutex to be locked by the
268                          * current thread: 
269                          */
270                         while ((*mutex)->m_owner != _thread_run) {
271                                 /* Check if the mutex is not locked: */
272                                 if ((*mutex)->m_owner == NULL) {
273                                         /* Lock the mutex for this thread: */
274                                         (*mutex)->m_owner = _thread_run;
275                                 } else {
276                                         /*
277                                          * Join the queue of threads waiting to lock
278                                          * the mutex: 
279                                          */
280                                         _thread_queue_enq(&(*mutex)->m_queue, _thread_run);
281
282                                         /* Wait for the mutex: */
283                                         _thread_kern_sched_state_unlock(
284                                             PS_MUTEX_WAIT, &(*mutex)->lock,
285                                             __FILE__, __LINE__);
286
287                                         /* Lock the mutex again: */
288                                         _SPINLOCK(&(*mutex)->lock);
289                                 }
290                         }
291                         break;
292
293                 /* Counting mutex: */
294                 case PTHREAD_MUTEX_RECURSIVE:
295                         /*
296                          * Enter a loop to wait for the mutex to be locked by the
297                          * current thread: 
298                          */
299                         while ((*mutex)->m_owner != _thread_run) {
300                                 /* Check if the mutex is not locked: */
301                                 if ((*mutex)->m_owner == NULL) {
302                                         /* Lock the mutex for this thread: */
303                                         (*mutex)->m_owner = _thread_run;
304
305                                         /* Reset the lock count for this mutex: */
306                                         (*mutex)->m_data.m_count = 0;
307                                 } else {
308                                         /*
309                                          * Join the queue of threads waiting to lock
310                                          * the mutex: 
311                                          */
312                                         _thread_queue_enq(&(*mutex)->m_queue, _thread_run);
313
314                                         /* Wait for the mutex: */
315                                         _thread_kern_sched_state_unlock(
316                                             PS_MUTEX_WAIT, &(*mutex)->lock,
317                                             __FILE__, __LINE__);
318
319                                         /* Lock the mutex again: */
320                                         _SPINLOCK(&(*mutex)->lock);
321                                 }
322                         }
323
324                         /* Increment the lock count for this mutex: */
325                         (*mutex)->m_data.m_count++;
326                         break;
327
328                 /* Trap invalid mutex types: */
329                 default:
330                         /* Return an invalid argument error: */
331                         ret = EINVAL;
332                         break;
333                 }
334
335                 /* Unlock the mutex structure: */
336                 _SPINUNLOCK(&(*mutex)->lock);
337         }
338
339         /* Return the completion status: */
340         return (ret);
341 }
342
343 int
344 pthread_mutex_unlock(pthread_mutex_t * mutex)
345 {
346         int             ret = 0;
347
348         if (mutex == NULL || *mutex == NULL) {
349                 ret = EINVAL;
350         } else {
351                 /* Lock the mutex structure: */
352                 _SPINLOCK(&(*mutex)->lock);
353
354                 /* Process according to mutex type: */
355                 switch ((*mutex)->m_type) {
356                 /* Default & normal mutexes do not really need to check for
357                    any error conditions: */
358                 case PTHREAD_MUTEX_NORMAL:
359                 case PTHREAD_MUTEX_DEFAULT:
360                 case PTHREAD_MUTEX_ERRORCHECK:
361                         /* Check if the running thread is not the owner of the mutex: */
362                         if ((*mutex)->m_owner != _thread_run) {
363                                 /* Return an invalid argument error: */
364                                 ret = (*mutex)->m_owner ? EPERM : EINVAL;
365                         }
366                         /*
367                          * Get the next thread from the queue of threads waiting on
368                          * the mutex: 
369                          */
370                         else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
371                                 /* Allow the new owner of the mutex to run: */
372                                 PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
373                         }
374                         break;
375
376                 /* Counting mutex: */
377                 case PTHREAD_MUTEX_RECURSIVE:
378                         /* Check if the running thread is not the owner of the mutex: */
379                         if ((*mutex)->m_owner != _thread_run) {
380                                 /* Return an invalid argument error: */
381                                 ret = EINVAL;
382                         }
383                         /* Check if there are still counts: */
384                         else if ((*mutex)->m_data.m_count > 1) {
385                                 /* Decrement the count: */
386                                 (*mutex)->m_data.m_count--;
387                         } else {
388                                 (*mutex)->m_data.m_count = 0;
389                                 /*
390                                  * Get the next thread from the queue of threads waiting on
391                                  * the mutex: 
392                                  */
393                                 if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
394                                         /* Allow the new owner of the mutex to run: */
395                                         PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
396                                 }
397                         }
398                         break;
399
400                 /* Trap invalid mutex types: */
401                 default:
402                         /* Return an invalid argument error: */
403                         ret = EINVAL;
404                         break;
405                 }
406
407                 /* Unlock the mutex structure: */
408                 _SPINUNLOCK(&(*mutex)->lock);
409         }
410
411         /* Return the completion status: */
412         return (ret);
413 }
414 #endif