src/thread/bsdi/SDL_syssem.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 17 Dec 2001 19:56:28 +0000
changeset 256 640dcf27d2f7
child 271 9631db4d9ee1
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library 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 GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@devolution.com
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdlib.h>
    29 #include "SDL_error.h"
    30 #include "SDL_thread.h"
    31 #include "SDL_timer.h"
    32 
    33 #ifdef SDL_USE_PTHREADS
    34 
    35 #include <stdio.h>
    36 #include <stdlib.h>
    37 #include <unistd.h>			/* For getpid() */
    38 #include <pthread.h>
    39 
    40 
    41 /*
    42  * This is semaphore.h inlined here so that BSD/OS POSIX semaphore are
    43  * completely selfcontained without requiring any additional include files
    44  * or libraries not present in the stock system
    45 */
    46 
    47 /* semaphore.h: POSIX 1003.1b semaphores */
    48 
    49 /*-
    50  * Copyright (c) 1996, 1997
    51  *	HD Associates, Inc.  All rights reserved.
    52  *
    53  * Redistribution and use in source and binary forms, with or without
    54  * modification, are permitted provided that the following conditions
    55  * are met:
    56  * 1. Redistributions of source code must retain the above copyright
    57  *    notice, this list of conditions and the following disclaimer.
    58  * 2. Redistributions in binary form must reproduce the above copyright
    59  *    notice, this list of conditions and the following disclaimer in the
    60  *    documentation and/or other materials provided with the distribution.
    61  * 3. All advertising materials mentioning features or use of this software
    62  *    must display the following acknowledgement:
    63  *	This product includes software developed by HD Associates, Inc
    64  * 4. Neither the name of the author nor the names of any co-contributors
    65  *    may be used to endorse or promote products derived from this software
    66  *    without specific prior written permission.
    67  *
    68  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
    69  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    70  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    71  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
    72  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    73  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    74  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    75  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    76  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    77  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    78  * SUCH DAMAGE.
    79  *
    80  * $FreeBSD: src/sys/posix4/semaphore.h,v 1.6 2000/01/20 07:55:42 jasone Exp $
    81  */
    82 
    83 #include <machine/limits.h>
    84 
    85 #include <sys/types.h>
    86 #include <fcntl.h>
    87 
    88 /* Opaque type definition. */
    89 struct sem;
    90 typedef struct sem *sem_t;
    91 
    92 #define SEM_FAILED	((sem_t *)0)
    93 #define SEM_VALUE_MAX	UINT_MAX
    94 
    95 #include <sys/cdefs.h>
    96 
    97 __BEGIN_DECLS
    98 int	 sem_init __P((sem_t *, int, unsigned int));
    99 int	 sem_destroy __P((sem_t *));
   100 sem_t	*sem_open __P((const char *, int, ...));
   101 int	 sem_close __P((sem_t *));
   102 int	 sem_unlink __P((const char *));
   103 int	 sem_wait __P((sem_t *));
   104 int	 sem_trywait __P((sem_t *));
   105 int	 sem_post __P((sem_t *));
   106 int	 sem_getvalue __P((sem_t *, int *));
   107 __END_DECLS
   108 
   109 /* END of inlined semaphore.h */
   110 
   111 /* Wrapper around POSIX 1003.1b semaphores */
   112 
   113 struct SDL_semaphore {
   114 	sem_t *sem;
   115 	sem_t sem_data;
   116 };
   117 
   118 /* Create a semaphore, initialized with value */
   119 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
   120 {
   121 	SDL_sem *sem = (SDL_sem *) malloc(sizeof(SDL_sem));
   122 	if ( sem ) {
   123 		if ( sem_init(&sem->sem_data, 0, initial_value) < 0 ) {
   124 			SDL_SetError("sem_init() failed");
   125 			free(sem);
   126 			sem = NULL;
   127 		} else {
   128 			sem->sem = &sem->sem_data;
   129 		}
   130 	} else {
   131 		SDL_OutOfMemory();
   132 	}
   133 	return sem;
   134 }
   135 
   136 void SDL_DestroySemaphore(SDL_sem *sem)
   137 {
   138 	if ( sem ) {
   139 		sem_destroy(sem->sem);
   140 		free(sem);
   141 	}
   142 }
   143 
   144 int SDL_SemTryWait(SDL_sem *sem)
   145 {
   146 	int retval;
   147 
   148 	if ( ! sem ) {
   149 		SDL_SetError("Passed a NULL semaphore");
   150 		return -1;
   151 	}
   152 	retval = SDL_MUTEX_TIMEDOUT;
   153 	if ( sem_trywait(sem->sem) == 0 )
   154 		retval = 0;
   155 	return retval;
   156 }
   157 
   158 int SDL_SemWait(SDL_sem *sem)
   159 {
   160 	int retval;
   161 
   162 	if ( ! sem ) {
   163 		SDL_SetError("Passed a NULL semaphore");
   164 		return -1;
   165 	}
   166 
   167 	retval = sem_wait(sem->sem);
   168 	if ( retval < 0 ) {
   169 		SDL_SetError("sem_wait() failed");
   170 	}
   171 	return retval;
   172 }
   173 
   174 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
   175 {
   176 	int retval;
   177 
   178 	if ( ! sem ) {
   179 		SDL_SetError("Passed a NULL semaphore");
   180 		return -1;
   181 	}
   182 
   183 	/* Try the easy cases first */
   184 	if ( timeout == 0 ) {
   185 		return SDL_SemTryWait(sem);
   186 	}
   187 	if ( timeout == SDL_MUTEX_MAXWAIT ) {
   188 		return SDL_SemWait(sem);
   189 	}
   190 
   191 	/* Ack!  We have to busy wait... */
   192 	timeout += SDL_GetTicks();
   193 	do {
   194 		retval = SDL_SemTryWait(sem);
   195 		if ( retval == 0 ) {
   196 			break;
   197 		}
   198 		SDL_Delay(1);
   199 	} while ( SDL_GetTicks() < timeout );
   200 
   201 	return retval;
   202 }
   203 
   204 Uint32 SDL_SemValue(SDL_sem *sem)
   205 {
   206 	int ret = 0;
   207 	if ( sem ) {
   208 		sem_getvalue(sem->sem, &ret);
   209 		if ( ret < 0 ) {
   210 			ret = 0;
   211 		}
   212 	}
   213 	return (Uint32)ret;
   214 }
   215 
   216 int SDL_SemPost(SDL_sem *sem)
   217 {
   218 	int retval;
   219 
   220 	if ( ! sem ) {
   221 		SDL_SetError("Passed a NULL semaphore");
   222 		return -1;
   223 	}
   224 
   225 	retval = sem_post(sem->sem);
   226 	if ( retval < 0 ) {
   227 		SDL_SetError("sem_post() failed");
   228 	}
   229 	return retval;
   230 }
   231 
   232 /* 
   233  * BEGIN inlined uthread_sem.c.  This is done here so that no extra libraries
   234  * or include files not present in BSD/OS are required
   235 */
   236 
   237 /*
   238  * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
   239  * All rights reserved.
   240  * 
   241  * Redistribution and use in source and binary forms, with or without
   242  * modification, are permitted provided that the following conditions
   243  * are met:
   244  * 1. Redistributions of source code must retain the above copyright
   245  *    notice(s), this list of conditions and the following disclaimer as
   246  *    the first lines of this file unmodified other than the possible
   247  *    addition of one or more copyright notices.
   248  * 2. Redistributions in binary form must reproduce the above copyright
   249  *    notice(s), this list of conditions and the following disclaimer in
   250  *    the documentation and/or other materials provided with the
   251  *    distribution.
   252  * 
   253  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
   254  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   255  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   256  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
   257  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   258  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   259  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   260  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   261  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   262  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   263  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   264  *
   265  * $FreeBSD: src/lib/libc_r/uthread/uthread_sem.c,v 1.3.2.1 2000/07/18 02:05:57 jasone Exp $
   266  */
   267 
   268 #include <errno.h>
   269 #include <semaphore.h>
   270 #include <pthread.h>
   271 
   272 /* Begin thread_private.h kluge */
   273 /*
   274  * These come out of (or should go into) thread_private.h - rather than have 
   275  * to copy (or symlink) the files from the source tree these definitions are 
   276  * inlined here.  Obviously these go away when this module is part of libc.
   277 */
   278 struct sem {
   279 #define SEM_MAGIC       ((u_int32_t) 0x09fa4012)
   280         u_int32_t       magic;
   281         pthread_mutex_t lock;
   282         pthread_cond_t  gtzero;
   283         u_int32_t       count;
   284         u_int32_t       nwaiters;
   285 };
   286 
   287 extern pthread_once_t _thread_init_once;
   288 extern int _threads_initialized;
   289 extern void  _thread_init __P((void));
   290 #define THREAD_INIT() \
   291 	(void) pthread_once(&_thread_init_once, _thread_init)
   292 #define THREAD_SAFE() \
   293 	(_threads_initialized != 0)
   294 
   295 #define _SEM_CHECK_VALIDITY(sem)		\
   296 	if ((*(sem))->magic != SEM_MAGIC) {	\
   297 		errno = EINVAL;			\
   298 		retval = -1;			\
   299 		goto RETURN;			\
   300 	}
   301 /* End thread_private.h kluge */
   302 
   303 int
   304 sem_init(sem_t *sem, int pshared, unsigned int value)
   305 {
   306 	int	retval;
   307 
   308 	if (!THREAD_SAFE())
   309 		THREAD_INIT();
   310 
   311 	/*
   312 	 * Range check the arguments.
   313 	 */
   314 	if (pshared != 0) {
   315 		/*
   316 		 * The user wants a semaphore that can be shared among
   317 		 * processes, which this implementation can't do.  Sounds like a
   318 		 * permissions problem to me (yeah right).
   319 		 */
   320 		errno = EPERM;
   321 		retval = -1;
   322 		goto RETURN;
   323 	}
   324 
   325 	if (value > SEM_VALUE_MAX) {
   326 		errno = EINVAL;
   327 		retval = -1;
   328 		goto RETURN;
   329 	}
   330 
   331 	*sem = (sem_t)malloc(sizeof(struct sem));
   332 	if (*sem == NULL) {
   333 		errno = ENOSPC;
   334 		retval = -1;
   335 		goto RETURN;
   336 	}
   337 
   338 	/*
   339 	 * Initialize the semaphore.
   340 	 */
   341 	if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) {
   342 		free(*sem);
   343 		errno = ENOSPC;
   344 		retval = -1;
   345 		goto RETURN;
   346 	}
   347 
   348 	if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) {
   349 		pthread_mutex_destroy(&(*sem)->lock);
   350 		free(*sem);
   351 		errno = ENOSPC;
   352 		retval = -1;
   353 		goto RETURN;
   354 	}
   355 	
   356 	(*sem)->count = (u_int32_t)value;
   357 	(*sem)->nwaiters = 0;
   358 	(*sem)->magic = SEM_MAGIC;
   359 
   360 	retval = 0;
   361   RETURN:
   362 	return retval;
   363 }
   364 
   365 int
   366 sem_destroy(sem_t *sem)
   367 {
   368 	int	retval;
   369 	
   370 	_SEM_CHECK_VALIDITY(sem);
   371 
   372 	/* Make sure there are no waiters. */
   373 	pthread_mutex_lock(&(*sem)->lock);
   374 	if ((*sem)->nwaiters > 0) {
   375 		pthread_mutex_unlock(&(*sem)->lock);
   376 		errno = EBUSY;
   377 		retval = -1;
   378 		goto RETURN;
   379 	}
   380 	pthread_mutex_unlock(&(*sem)->lock);
   381 	
   382 	pthread_mutex_destroy(&(*sem)->lock);
   383 	pthread_cond_destroy(&(*sem)->gtzero);
   384 	(*sem)->magic = 0;
   385 
   386 	free(*sem);
   387 
   388 	retval = 0;
   389   RETURN:
   390 	return retval;
   391 }
   392 
   393 sem_t *
   394 sem_open(const char *name, int oflag, ...)
   395 {
   396 	errno = ENOSYS;
   397 	return SEM_FAILED;
   398 }
   399 
   400 int
   401 sem_close(sem_t *sem)
   402 {
   403 	errno = ENOSYS;
   404 	return -1;
   405 }
   406 
   407 int
   408 sem_unlink(const char *name)
   409 {
   410 	errno = ENOSYS;
   411 	return -1;
   412 }
   413 
   414 int
   415 sem_wait(sem_t *sem)
   416 {
   417 	int	retval;
   418 
   419 	pthread_testcancel();
   420 	
   421 	_SEM_CHECK_VALIDITY(sem);
   422 
   423 	pthread_mutex_lock(&(*sem)->lock);
   424 
   425 	while ((*sem)->count == 0) {
   426 		(*sem)->nwaiters++;
   427 		pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock);
   428 		(*sem)->nwaiters--;
   429 	}
   430 	(*sem)->count--;
   431 
   432 	pthread_mutex_unlock(&(*sem)->lock);
   433 
   434 	retval = 0;
   435   RETURN:
   436 
   437 	pthread_testcancel();
   438 	return retval;
   439 }
   440 
   441 int
   442 sem_trywait(sem_t *sem)
   443 {
   444 	int	retval;
   445 
   446 	_SEM_CHECK_VALIDITY(sem);
   447 
   448 	pthread_mutex_lock(&(*sem)->lock);
   449 
   450 	if ((*sem)->count > 0) {
   451 		(*sem)->count--;
   452 		retval = 0;
   453 	} else {
   454 		errno = EAGAIN;
   455 		retval = -1;
   456 	}
   457 	
   458 	pthread_mutex_unlock(&(*sem)->lock);
   459 
   460   RETURN:
   461 	return retval;
   462 }
   463 
   464 int
   465 sem_post(sem_t *sem)
   466 {
   467 	int	retval;
   468 
   469 	_SEM_CHECK_VALIDITY(sem);
   470 
   471 	pthread_mutex_lock(&(*sem)->lock);
   472 
   473 	(*sem)->count++;
   474 	if ((*sem)->nwaiters > 0) {
   475 		/*
   476 		 * We must use pthread_cond_broadcast() rather than
   477 		 * pthread_cond_signal() in order to assure that the highest
   478 		 * priority thread is run by the scheduler, since
   479 		 * pthread_cond_signal() signals waiting threads in FIFO order.
   480 		 */
   481 		pthread_cond_broadcast(&(*sem)->gtzero);
   482 	}
   483 
   484 	pthread_mutex_unlock(&(*sem)->lock);
   485 
   486 	retval = 0;
   487   RETURN:
   488 	return retval;
   489 }
   490 
   491 int
   492 sem_getvalue(sem_t *sem, int *sval)
   493 {
   494 	int	retval;
   495 
   496 	_SEM_CHECK_VALIDITY(sem);
   497 
   498 	pthread_mutex_lock(&(*sem)->lock);
   499 	*sval = (int)(*sem)->count;
   500 	pthread_mutex_unlock(&(*sem)->lock);
   501 
   502 	retval = 0;
   503   RETURN:
   504 	return retval;
   505 }
   506 
   507 /* END of inlined uthread_sem.c */
   508 #endif /* SDL_USE_PTHREADS */