Mercurial > sdl-ios-xcode
view src/thread/linux/SDL_syssem.c @ 315:3333b6e68289
Date: Sat, 23 Mar 2002 13:53:37 +0200
From: "Mike Gorchak" <mike@malva.ua>
Subject: Big QNX patch again.
Added 8bit palette emulation code for window mode with bpp>=15.
Added store/restore original palette for 8bit modes.
Added more information about photon API call fails.
Rewroten change palette code, slow but works.
Fixed bug with set caption before window was inited.
Fixed bugs with some initial state of variables.
Fixed bug with storing old video mode settings.
Fixed bug with switching to fullscreen mode and back.
Fixed few double SEGFAULTS during parachute mode.
Removed compilation warning with no PgWaitHWIdle prototype.
Removed pack of dead unusable code.
Cleanups SDL_PrivateVideoData structure, some headers.
Some code formatting.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 23 Mar 2002 20:19:44 +0000 |
parents | f6ffac90895c |
children | b8d311d90021 |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@libsdl.org */ #ifdef SAVE_RCSID static char rcsid = "@(#) $Id$"; #endif #include <stdlib.h> #include "SDL_error.h" #include "SDL_thread.h" #include "SDL_timer.h" #ifdef linux /* Look to see if glibc is available, and if so, what version */ #include <features.h> #if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) #warning Working around a bug in glibc 2.0 pthreads #undef SDL_USE_PTHREADS /* The bug is actually a problem where threads are suspended, but don't wake up when the thread manager sends them a signal. This is a problem with thread creation too, but it happens less often. :-/ We avoid this by using System V IPC for semaphores. */ #endif /* glibc 2.0 */ #endif /* linux */ #ifdef SDL_USE_PTHREADS #ifdef SDL_NO_PTHREAD_SEMAPHORES #include "generic/SDL_syssem.c" #else #include <stdio.h> #include <stdlib.h> #include <unistd.h> /* For getpid() */ #include <pthread.h> #include <semaphore.h> /* Wrapper around POSIX 1003.1b semaphores */ #ifdef MACOSX #define USE_NAMED_SEMAPHORES /* Broken sem_getvalue() in MacOS X Public Beta */ #define BROKEN_SEMGETVALUE #endif /* MACOSX */ struct SDL_semaphore { sem_t *sem; #ifndef USE_NAMED_SEMAPHORES sem_t sem_data; #endif #ifdef BROKEN_SEMGETVALUE /* This is a little hack for MacOS X - It's not thread-safe, but it's better than nothing */ int sem_value; #endif }; /* Create a semaphore, initialized with value */ SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) { SDL_sem *sem = (SDL_sem *) malloc(sizeof(SDL_sem)); if ( sem ) { #ifdef USE_NAMED_SEMAPHORES static int semnum = 0; char name[32]; sprintf(name, "/SDL_sem-%d-%4.4d", getpid(), semnum++); sem->sem = sem_open(name, O_CREAT, 0600, initial_value); if ( sem->sem == (sem_t *)SEM_FAILED ) { SDL_SetError("sem_open(%s) failed", name); free(sem); sem = NULL; } else { sem_unlink(name); } #else if ( sem_init(&sem->sem_data, 0, initial_value) < 0 ) { SDL_SetError("sem_init() failed"); free(sem); sem = NULL; } else { sem->sem = &sem->sem_data; } #endif /* USE_NAMED_SEMAPHORES */ #ifdef BROKEN_SEMGETVALUE if ( sem ) { sem->sem_value = initial_value; } #endif /* BROKEN_SEMGETVALUE */ } else { SDL_OutOfMemory(); } return sem; } void SDL_DestroySemaphore(SDL_sem *sem) { if ( sem ) { #ifdef USE_NAMED_SEMAPHORES sem_close(sem->sem); #else sem_destroy(sem->sem); #endif free(sem); } } int SDL_SemTryWait(SDL_sem *sem) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } retval = SDL_MUTEX_TIMEDOUT; if ( sem_trywait(sem->sem) == 0 ) { #ifdef BROKEN_SEMGETVALUE --sem->sem_value; #endif retval = 0; } return retval; } int SDL_SemWait(SDL_sem *sem) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } #ifdef BROKEN_SEMGETVALUE --sem->sem_value; #endif retval = sem_wait(sem->sem); if ( retval < 0 ) { SDL_SetError("sem_wait() failed"); } return retval; } int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } /* Try the easy cases first */ if ( timeout == 0 ) { return SDL_SemTryWait(sem); } if ( timeout == SDL_MUTEX_MAXWAIT ) { return SDL_SemWait(sem); } /* Ack! We have to busy wait... */ timeout += SDL_GetTicks(); do { retval = SDL_SemTryWait(sem); if ( retval == 0 ) { break; } SDL_Delay(1); } while ( SDL_GetTicks() < timeout ); return retval; } Uint32 SDL_SemValue(SDL_sem *sem) { int ret = 0; if ( sem ) { #ifdef BROKEN_SEMGETVALUE ret = sem->sem_value; #else sem_getvalue(sem->sem, &ret); #endif if ( ret < 0 ) { ret = 0; } } return (Uint32)ret; } int SDL_SemPost(SDL_sem *sem) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } #ifdef BROKEN_SEMGETVALUE ++sem->sem_value; #endif retval = sem_post(sem->sem); if ( retval < 0 ) { SDL_SetError("sem_post() failed"); } return retval; } #endif /* NO_PTHREAD_SEMAPHORES */ #else /* System V IPC implementation */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <errno.h> #include "SDL_error.h" #include "SDL_thread.h" struct SDL_semaphore { int id; }; /* Not defined by many operating systems, use configure to detect */ #if !defined(HAVE_SEMUN) union semun { int val; struct semid_ds *buf; ushort *array; }; #endif static struct sembuf op_trywait[2] = { { 0, -1, (IPC_NOWAIT|SEM_UNDO) } /* Decrement semaphore, no block */ }; static struct sembuf op_wait[2] = { { 0, -1, SEM_UNDO } /* Decrement semaphore */ }; static struct sembuf op_post[1] = { { 0, 1, (IPC_NOWAIT|SEM_UNDO) } /* Increment semaphore */ }; /* Create a blockable semaphore */ SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) { extern int _creating_thread_lock; /* SDL_threads.c */ SDL_sem *sem; union semun init; key_t key; sem = (SDL_sem *)malloc(sizeof(*sem)); if ( sem == NULL ) { SDL_OutOfMemory(); return(NULL); } /* This flag is true if we are creating the thread manager sem, which is never freed. This allows us to reuse the same sem. */ if ( _creating_thread_lock ) { key = 'S'+'D'+'L'; } else { key = IPC_PRIVATE; } /* Keep trying to create sem while we don't own the requested key */ do { if ( key != IPC_PRIVATE ) { ++key; } sem->id = semget(key, 1, (0600|IPC_CREAT)); } while ((sem->id < 0) && (key != IPC_PRIVATE) && (errno == EACCES)); /* Report the error if we eventually failed */ if ( sem->id < 0 ) { SDL_SetError("Couldn't create semaphore"); free(sem); return(NULL); } init.val = initial_value; /* Initialize semaphore */ semctl(sem->id, 0, SETVAL, init); return(sem); } void SDL_DestroySemaphore(SDL_sem *sem) { if ( sem ) { #ifdef _SGI_SOURCE semctl(sem->id, 0, IPC_RMID); #else union semun dummy; dummy.val = 0; semctl(sem->id, 0, IPC_RMID, dummy); #endif free(sem); } } int SDL_SemTryWait(SDL_sem *sem) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } retval = 0; tryagain: if ( semop(sem->id, op_trywait, 1) < 0 ) { if ( errno == EINTR ) { goto tryagain; } retval = SDL_MUTEX_TIMEDOUT; } return retval; } int SDL_SemWait(SDL_sem *sem) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } retval = 0; tryagain: if ( semop(sem->id, op_wait, 1) < 0 ) { if ( errno == EINTR ) { goto tryagain; } SDL_SetError("Semaphore operation error"); retval = -1; } return retval; } int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } /* Try the easy cases first */ if ( timeout == 0 ) { return SDL_SemTryWait(sem); } if ( timeout == SDL_MUTEX_MAXWAIT ) { return SDL_SemWait(sem); } /* Ack! We have to busy wait... */ timeout += SDL_GetTicks(); do { retval = SDL_SemTryWait(sem); if ( retval == 0 ) { break; } SDL_Delay(1); } while ( SDL_GetTicks() < timeout ); return retval; } Uint32 SDL_SemValue(SDL_sem *sem) { int semval; Uint32 value; value = 0; if ( sem ) { tryagain: #ifdef _SGI_SOURCE semval = semctl(sem->id, 0, GETVAL); #else { union semun arg; arg.val = 0; semval = semctl(sem->id, 0, GETVAL, arg); } #endif if ( semval < 0 ) { if ( errno == EINTR ) { goto tryagain; } } else { value = (Uint32)semval; } } return value; } int SDL_SemPost(SDL_sem *sem) { int retval; if ( ! sem ) { SDL_SetError("Passed a NULL semaphore"); return -1; } retval = 0; tryagain: if ( semop(sem->id, op_post, 1) < 0 ) { if ( errno == EINTR ) { goto tryagain; } SDL_SetError("Semaphore operation error"); retval = -1; } return retval; } #endif /* SDL_USE_PTHREADS */