src/thread/bsdi/SDL_syssem.c
changeset 256 640dcf27d2f7
child 271 9631db4d9ee1
equal deleted inserted replaced
255:dcb5e869f8b5 256:640dcf27d2f7
       
     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 */