thr_mutex.c revision 31402
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 || *mutex == NULL) {
166		ret = EINVAL;
167	} else {
168		/* Block signals: */
169		_thread_kern_sig_block(&status);
170
171		/* Process according to mutex type: */
172		switch ((*mutex)->m_type) {
173		/* Fast mutex: */
174		case MUTEX_TYPE_FAST:
175			/* Check if this mutex is not locked: */
176			if ((*mutex)->m_owner == NULL) {
177				/* Lock the mutex for the running thread: */
178				(*mutex)->m_owner = _thread_run;
179			} else {
180				/* Return a busy error: */
181				ret = EBUSY;
182			}
183			break;
184
185		/* Counting mutex: */
186		case MUTEX_TYPE_COUNTING_FAST:
187			/* Check if this mutex is locked: */
188			if ((*mutex)->m_owner != NULL) {
189				/*
190				 * Check if the mutex is locked by the running
191				 * thread:
192				 */
193				if ((*mutex)->m_owner == _thread_run) {
194					/* Increment the lock count: */
195					(*mutex)->m_data.m_count++;
196				} else {
197					/* Return a busy error: */
198					ret = EBUSY;
199				}
200			} else {
201				/* Lock the mutex for the running thread: */
202				(*mutex)->m_owner = _thread_run;
203			}
204			break;
205
206		/* Trap invalid mutex types: */
207		default:
208			/* Return an invalid argument error: */
209			ret = EINVAL;
210			break;
211		}
212
213		/* Unblock signals: */
214		_thread_kern_sig_unblock(status);
215	}
216
217	/* Return the completion status: */
218	return (ret);
219}
220
221int
222pthread_mutex_lock(pthread_mutex_t * mutex)
223{
224	int             ret = 0;
225	int             status;
226
227	if (mutex == NULL || *mutex == NULL) {
228		ret = EINVAL;
229	} else {
230		/* Block signals: */
231		_thread_kern_sig_block(&status);
232
233		/* Process according to mutex type: */
234		switch ((*mutex)->m_type) {
235		/* Fast mutexes do not check for any error conditions: */
236		case MUTEX_TYPE_FAST:
237			/*
238			 * Enter a loop to wait for the mutex to be locked by the
239			 * current thread:
240			 */
241			while ((*mutex)->m_owner != _thread_run) {
242				/* Check if the mutex is not locked: */
243				if ((*mutex)->m_owner == NULL) {
244					/* Lock the mutex for this thread: */
245					(*mutex)->m_owner = _thread_run;
246				} else {
247					/*
248					 * Join the queue of threads waiting to lock
249					 * the mutex:
250					 */
251					_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
252
253					/* Block signals: */
254					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
255
256					/* Block signals: */
257					_thread_kern_sig_block(NULL);
258				}
259			}
260			break;
261
262		/* Counting mutex: */
263		case MUTEX_TYPE_COUNTING_FAST:
264			/*
265			 * Enter a loop to wait for the mutex to be locked by the
266			 * current thread:
267			 */
268			while ((*mutex)->m_owner != _thread_run) {
269				/* Check if the mutex is not locked: */
270				if ((*mutex)->m_owner == NULL) {
271					/* Lock the mutex for this thread: */
272					(*mutex)->m_owner = _thread_run;
273
274					/* Reset the lock count for this mutex: */
275					(*mutex)->m_data.m_count = 0;
276				} else {
277					/*
278					 * Join the queue of threads waiting to lock
279					 * the mutex:
280					 */
281					_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
282
283					/* Block signals: */
284					_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
285
286					/* Block signals: */
287					_thread_kern_sig_block(NULL);
288				}
289			}
290
291			/* Increment the lock count for this mutex: */
292			(*mutex)->m_data.m_count++;
293			break;
294
295		/* Trap invalid mutex types: */
296		default:
297			/* Return an invalid argument error: */
298			ret = EINVAL;
299			break;
300		}
301
302		/* Unblock signals: */
303		_thread_kern_sig_unblock(status);
304	}
305
306	/* Return the completion status: */
307	return (ret);
308}
309
310int
311pthread_mutex_unlock(pthread_mutex_t * mutex)
312{
313	int             ret = 0;
314	int             status;
315
316	if (mutex == NULL || *mutex == NULL) {
317		ret = EINVAL;
318	} else {
319		/* Block signals: */
320		_thread_kern_sig_block(&status);
321
322		/* Process according to mutex type: */
323		switch ((*mutex)->m_type) {
324		/* Fast mutexes do not check for any error conditions: */
325		case MUTEX_TYPE_FAST:
326			/* Check if the running thread is not the owner of the mutex: */
327			if ((*mutex)->m_owner != _thread_run) {
328				/* Return an invalid argument error: */
329				ret = EINVAL;
330			}
331			/*
332			 * Get the next thread from the queue of threads waiting on
333			 * the mutex:
334			 */
335			else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
336				/* Allow the new owner of the mutex to run: */
337				PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
338			}
339			break;
340
341		/* Counting mutex: */
342		case MUTEX_TYPE_COUNTING_FAST:
343			/* Check if the running thread is not the owner of the mutex: */
344			if ((*mutex)->m_owner != _thread_run) {
345				/* Return an invalid argument error: */
346				ret = EINVAL;
347			}
348			/* Check if there are still counts: */
349			else if ((*mutex)->m_data.m_count) {
350				/* Decrement the count: */
351				(*mutex)->m_data.m_count--;
352			}
353			/*
354			 * Get the next thread from the queue of threads waiting on
355			 * the mutex:
356			 */
357			else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
358				/* Allow the new owner of the mutex to run: */
359				PTHREAD_NEW_STATE((*mutex)->m_owner,PS_RUNNING);
360			}
361			break;
362
363		/* Trap invalid mutex types: */
364		default:
365			/* Return an invalid argument error: */
366			ret = EINVAL;
367			break;
368		}
369
370		/* Unblock signals: */
371		_thread_kern_sig_unblock(status);
372	}
373
374	/* Return the completion status: */
375	return (ret);
376}
377#endif
378