src/thread/irix/SDL_syssem.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 16 Feb 2006 10:11:48 +0000
changeset 1361 19418e4422cb
child 1402 d910939febfa
permissions -rw-r--r--
New configure-based build system. Still work in progress, but much improved
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 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     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #include "SDL_thread.h"
    24 #include "SDL_timer.h"
    25 
    26 
    27 #include <stdio.h>
    28 #include <stdlib.h>
    29 #include <sys/types.h>
    30 #include <sys/ipc.h>
    31 #include <sys/sem.h>
    32 #include <errno.h>
    33 
    34 #include "SDL_error.h"
    35 #include "SDL_thread.h"
    36 
    37 
    38 struct SDL_semaphore {
    39 	int id;
    40 };
    41 
    42 /* Not defined by many operating systems, use configure to detect */
    43 /*
    44 #if !defined(HAVE_SEMUN)
    45 union semun {
    46 	int val;
    47 	struct semid_ds *buf;
    48 	ushort *array;
    49 };
    50 #endif
    51 */
    52 
    53 static struct sembuf op_trywait[2] = {
    54 	{ 0, -1, (IPC_NOWAIT|SEM_UNDO) } /* Decrement semaphore, no block */
    55 };
    56 static struct sembuf op_wait[2] = {
    57 	{ 0, -1, SEM_UNDO }		/* Decrement semaphore */
    58 };
    59 static struct sembuf op_post[1] = {
    60 	{ 0, 1, (IPC_NOWAIT|SEM_UNDO) }	/* Increment semaphore */
    61 };
    62 
    63 /* Create a blockable semaphore */
    64 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
    65 {
    66 	extern int _creating_thread_lock;	/* SDL_threads.c */
    67 	SDL_sem *sem;
    68 	union semun init;
    69 	key_t key;
    70 
    71 	sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
    72 	if ( sem == NULL ) {
    73 		SDL_OutOfMemory();
    74 		return(NULL);
    75 	}
    76 	/* This flag is true if we are creating the thread manager sem,
    77 	   which is never freed.  This allows us to reuse the same sem.
    78 	*/
    79 	if ( _creating_thread_lock ) {
    80 		key = 'S'+'D'+'L';
    81 	} else {
    82 		key = IPC_PRIVATE;
    83 	}
    84 	/* Keep trying to create sem while we don't own the requested key */
    85 	do {
    86 		if ( key != IPC_PRIVATE ) {
    87 			++key;
    88 		}
    89 		sem->id = semget(key, 1, (0600|IPC_CREAT));
    90 	} while ((sem->id < 0) && (key != IPC_PRIVATE) && (errno == EACCES));
    91 
    92 	/* Report the error if we eventually failed */
    93 	if ( sem->id < 0 ) {
    94 		SDL_SetError("Couldn't create semaphore");
    95 		SDL_free(sem);
    96 		return(NULL);
    97 	}
    98 	init.val = initial_value;	/* Initialize semaphore */
    99 	semctl(sem->id, 0, SETVAL, init);
   100 	return(sem);
   101 }
   102 
   103 void SDL_DestroySemaphore(SDL_sem *sem)
   104 {
   105 	if ( sem ) {
   106 #ifdef _SGI_SOURCE
   107 		semctl(sem->id, 0, IPC_RMID);
   108 #else
   109 		union semun dummy;
   110 		dummy.val = 0;
   111 		semctl(sem->id, 0, IPC_RMID, dummy);
   112 #endif
   113 		SDL_free(sem);
   114 	}
   115 }
   116 
   117 int SDL_SemTryWait(SDL_sem *sem)
   118 {
   119 	int retval;
   120 
   121 	if ( ! sem ) {
   122 		SDL_SetError("Passed a NULL semaphore");
   123 		return -1;
   124 	}
   125 
   126 	retval = 0;
   127   tryagain:
   128 	if ( semop(sem->id, op_trywait, 1) < 0 ) {
   129 		if ( errno == EINTR ) {
   130 			goto tryagain;
   131 		}
   132 		retval = SDL_MUTEX_TIMEDOUT;
   133 	}
   134 	return retval;
   135 }
   136 
   137 int SDL_SemWait(SDL_sem *sem)
   138 {
   139 	int retval;
   140 
   141 	if ( ! sem ) {
   142 		SDL_SetError("Passed a NULL semaphore");
   143 		return -1;
   144 	}
   145 
   146 	retval = 0;
   147   tryagain:
   148 	if ( semop(sem->id, op_wait, 1) < 0 ) {
   149 		if ( errno == EINTR ) {
   150 			goto tryagain;
   151 		}
   152 		SDL_SetError("Semaphore operation error");
   153 		retval = -1;
   154 	}
   155 	return retval;
   156 }
   157 
   158 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
   159 {
   160 	int retval;
   161 
   162 	if ( ! sem ) {
   163 		SDL_SetError("Passed a NULL semaphore");
   164 		return -1;
   165 	}
   166 
   167 	/* Try the easy cases first */
   168 	if ( timeout == 0 ) {
   169 		return SDL_SemTryWait(sem);
   170 	}
   171 	if ( timeout == SDL_MUTEX_MAXWAIT ) {
   172 		return SDL_SemWait(sem);
   173 	}
   174 
   175 	/* Ack!  We have to busy wait... */
   176 	timeout += SDL_GetTicks();
   177 	do {
   178 		retval = SDL_SemTryWait(sem);
   179 		if ( retval == 0 ) {
   180 			break;
   181 		}
   182 		SDL_Delay(1);
   183 	} while ( SDL_GetTicks() < timeout );
   184 
   185 	return retval;
   186 }
   187 
   188 Uint32 SDL_SemValue(SDL_sem *sem)
   189 {
   190 	int semval;
   191 	Uint32 value;
   192 	
   193 	value = 0;
   194 	if ( sem ) {
   195 	  tryagain:
   196 #ifdef _SGI_SOURCE
   197 		semval = semctl(sem->id, 0, GETVAL);
   198 #else
   199 		{
   200 		union semun arg;
   201 		arg.val = 0;
   202 		semval = semctl(sem->id, 0, GETVAL, arg);
   203 		}
   204 #endif
   205 		if ( semval < 0 ) {
   206 			if ( errno == EINTR ) {
   207 				goto tryagain;
   208 			}
   209 		} else {
   210 			value = (Uint32)semval;
   211 		}
   212 	}
   213 	return value;
   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 = 0;
   226   tryagain:
   227 	if ( semop(sem->id, op_post, 1) < 0 ) {
   228 		if ( errno == EINTR ) {
   229 			goto tryagain;
   230 		}
   231 		SDL_SetError("Semaphore operation error");
   232 		retval = -1;
   233 	}
   234 	return retval;
   235 }