thr_mutex.c revision 35027
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#ifdef _THREAD_SAFE
36#include <pthread.h>
37#include "pthread_private.h"
38
39int
40pthread_mutex_init(pthread_mutex_t * mutex,
41		   const pthread_mutexattr_t * mutex_attr)
42{
43	enum pthread_mutextype type;
44	pthread_mutex_t	pmutex;
45	int             ret = 0;
46	int             status;
47
48	if (mutex == NULL) {
49		ret = EINVAL;
50	} else {
51		/* Check if default mutex attributes: */
52		if (mutex_attr == NULL || *mutex_attr == NULL) {
53			/* Default to a fast mutex: */
54			type = MUTEX_TYPE_FAST;
55		} else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) {
56			/* Return an invalid argument error: */
57			ret = EINVAL;
58		} else {
59			/* Use the requested mutex type: */
60			type = (*mutex_attr)->m_type;
61		}
62
63		/* Check no errors so far: */
64		if (ret == 0) {
65			if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) {
66				ret = ENOMEM;
67			} else {
68				/* Reset the mutex flags: */
69				pmutex->m_flags = 0;
70
71				/* Block signals: */
72				_thread_kern_sig_block(&status);
73
74				/* Process according to mutex type: */
75				switch (type) {
76				/* Fast mutex: */
77				case MUTEX_TYPE_FAST:
78					/* Nothing to do here. */
79					break;
80
81				/* Counting mutex: */
82				case MUTEX_TYPE_COUNTING_FAST:
83					/* Reset the mutex count: */
84					pmutex->m_data.m_count = 0;
85					break;
86
87				/* Trap invalid mutex types: */
88				default:
89					/* Return an invalid argument error: */
90					ret = EINVAL;
91					break;
92				}
93				if (ret == 0) {
94					/* Initialise the rest of the mutex: */
95					_thread_queue_init(&pmutex->m_queue);
96					pmutex->m_flags |= MUTEX_FLAGS_INITED;
97					pmutex->m_owner = NULL;
98					pmutex->m_type = type;
99					*mutex = pmutex;
100				} else {
101					free(pmutex);
102					*mutex = NULL;
103				}
104
105				/* Unblock signals: */
106				_thread_kern_sig_unblock(status);
107			}
108		}
109	}
110	/* Return the completion status: */
111	return (ret);
112}
113
114int
115pthread_mutex_destroy(pthread_mutex_t * mutex)
116{
117	int             ret = 0;
118	int             status;
119
120	if (mutex == NULL || *mutex == NULL) {
121		ret = EINVAL;
122	} else {
123		/* Block signals: */
124		_thread_kern_sig_block(&status);
125
126		/* Process according to mutex type: */
127		switch ((*mutex)->m_type) {
128		/* Fast mutex: */
129		case MUTEX_TYPE_FAST:
130			/* Nothing to do here. */
131			break;
132
133		/* Counting mutex: */
134		case MUTEX_TYPE_COUNTING_FAST:
135			/* Reset the mutex count: */
136			(*mutex)->m_data.m_count = 0;
137			break;
138
139		/* Trap undefined mutex types: */
140		default:
141			/* Return an invalid argument error: */
142			ret = EINVAL;
143			break;
144		}
145
146		/* Clean up the mutex in case that others want to use it: */
147		_thread_queue_init(&(*mutex)->m_queue);
148		(*mutex)->m_owner = NULL;
149		(*mutex)->m_flags = 0;
150
151		/* Unblock signals: */
152		_thread_kern_sig_unblock(status);
153	}
154
155	/* Return the completion status: */
156	return (ret);
157}
158
159int
160pthread_mutex_trylock(pthread_mutex_t * mutex)
161{
162	int             ret = 0;
163	int             status;
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 ||
173	    (ret = pthread_mutex_init(mutex,NULL)) == 0) {
174		/* Block signals: */
175		_thread_kern_sig_block(&status);
176
177		/* Process according to mutex type: */
178		switch ((*mutex)->m_type) {
179		/* Fast mutex: */
180		case MUTEX_TYPE_FAST:
181			/* Check if this mutex is not locked: */
182			if ((*mutex)->m_owner == NULL) {
183				/* Lock the mutex for the running thread: */
184				(*mutex)->m_owner = _thread_run;
185			} else {
186				/* Return a busy error: */
187				ret = EBUSY;
188			}
189			break;
190
191		/* Counting mutex: */
192		case MUTEX_TYPE_COUNTING_FAST:
193			/* Check if this mutex is locked: */
194			if ((*mutex)->m_owner != NULL) {
195				/*
196				 * Check if the mutex is locked by the running
197				 * thread:
198				 */
199				if ((*mutex)->m_owner == _thread_run) {
200					/* Increment the lock count: */
201					(*mutex)->m_data.m_count++;
202				} else {
203					/* Return a busy error: */
204					ret = EBUSY;
205				}
206			} else {
207				/* Lock the mutex for the running thread: */
208				(*mutex)->m_owner = _thread_run;
209			}
210			break;
211
212		/* Trap invalid mutex types: */
213		default:
214			/* Return an invalid argument error: */
215			ret = EINVAL;
216			break;
217		}
218
219		/* Unblock signals: */
220		_thread_kern_sig_unblock(status);
221	}
222
223	/* Return the completion status: */
224	return (ret);
225}
226
227int
228pthread_mutex_lock(pthread_mutex_t * mutex)
229{
230	int             ret = 0;
231	int             status;
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 ||
241	    (ret = pthread_mutex_init(mutex,NULL)) == 0) {
242		/* Block signals: */
243		_thread_kern_sig_block(&status);
244
245		/* Process according to mutex type: */
246		switch ((*mutex)->m_type) {
247		/* Fast mutexes do not check for any error conditions: */
248		case MUTEX_TYPE_FAST:
249			/*
250			 * Enter a loop to wait for the mutex to be locked by the
251			 * current thread:
252			 */
253			while ((*mutex)->m_owner != _thread_run) {
254				/* Check if the mutex is not locked: */
255				if ((*mutex)->m_owner == NULL) {
256					/* Lock the mutex for this thread: */
257					(*mutex)->m_owner = _thread_run;
258				} else {
259					/*
260					 * Join the queue of threads waiting to lock
261					 * the mutex:
262					 */
263					_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
264
265					/* Block signals: */
266					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
267
268					/* Block signals: */
269					_thread_kern_sig_block(NULL);
270				}
271			}
272			break;
273
274		/* Counting mutex: */
275		case MUTEX_TYPE_COUNTING_FAST:
276			/*
277			 * Enter a loop to wait for the mutex to be locked by the
278			 * current thread:
279			 */
280			while ((*mutex)->m_owner != _thread_run) {
281				/* Check if the mutex is not locked: */
282				if ((*mutex)->m_owner == NULL) {
283					/* Lock the mutex for this thread: */
284					(*mutex)->m_owner = _thread_run;
285
286					/* Reset the lock count for this mutex: */
287					(*mutex)->m_data.m_count = 0;
288				} else {
289					/*
290					 * Join the queue of threads waiting to lock
291					 * the mutex:
292					 */
293					_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
294
295					/* Block signals: */
296					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
297
298					/* Block signals: */
299					_thread_kern_sig_block(NULL);
300				}
301			}
302
303			/* Increment the lock count for this mutex: */
304			(*mutex)->m_data.m_count++;
305			break;
306
307		/* Trap invalid mutex types: */
308		default:
309			/* Return an invalid argument error: */
310			ret = EINVAL;
311			break;
312		}
313
314		/* Unblock signals: */
315		_thread_kern_sig_unblock(status);
316	}
317
318	/* Return the completion status: */
319	return (ret);
320}
321
322int
323pthread_mutex_unlock(pthread_mutex_t * mutex)
324{
325	int             ret = 0;
326	int             status;
327
328	if (mutex == NULL || *mutex == NULL) {
329		ret = EINVAL;
330	} else {
331		/* Block signals: */
332		_thread_kern_sig_block(&status);
333
334		/* Process according to mutex type: */
335		switch ((*mutex)->m_type) {
336		/* Fast mutexes do not check for any error conditions: */
337		case MUTEX_TYPE_FAST:
338			/* Check if the running thread is not the owner of the mutex: */
339			if ((*mutex)->m_owner != _thread_run) {
340				/* Return an invalid argument error: */
341				ret = EINVAL;
342			}
343			/*
344			 * Get the next thread from the queue of threads waiting on
345			 * the mutex:
346			 */
347			else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
348				/* Allow the new owner of the mutex to run: */
349				PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
350			}
351			break;
352
353		/* Counting mutex: */
354		case MUTEX_TYPE_COUNTING_FAST:
355			/* Check if the running thread is not the owner of the mutex: */
356			if ((*mutex)->m_owner != _thread_run) {
357				/* Return an invalid argument error: */
358				ret = EINVAL;
359			}
360			/* Check if there are still counts: */
361			else if ((*mutex)->m_data.m_count) {
362				/* Decrement the count: */
363				(*mutex)->m_data.m_count--;
364			}
365			/*
366			 * Get the next thread from the queue of threads waiting on
367			 * the mutex:
368			 */
369			else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
370				/* Allow the new owner of the mutex to run: */
371				PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
372			}
373			break;
374
375		/* Trap invalid mutex types: */
376		default:
377			/* Return an invalid argument error: */
378			ret = EINVAL;
379			break;
380		}
381
382		/* Unblock signals: */
383		_thread_kern_sig_unblock(status);
384	}
385
386	/* Return the completion status: */
387	return (ret);
388}
389#endif
390