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 (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* 25 SDL_syssem.cpp 26 27 Epoc version by Markus Mertama (w (at) iki.fi) 28 */ 29 30 /* Semaphore functions using the Win32 API */ 31 32 #include <e32std.h> 33 34 #include "SDL_error.h" 35 #include "SDL_thread.h" 36 37 38 #define SDL_MUTEX_TIMEOUT -2 39 40 struct SDL_semaphore 41 { 42 TInt handle; 43 TInt count; 44 }; 45 46 extern TInt CreateUnique(TInt (*aFunc)(const TDesC& aName, TAny*, TAny*), TAny*, TAny*); 47 extern TInt NewThread(const TDesC& aName, TAny* aPtr1, TAny* aPtr2); 48 49 TInt NewSema(const TDesC& aName, TAny* aPtr1, TAny* aPtr2) 50 { 51 TInt value = *((TInt*) aPtr2); 52 return ((RSemaphore*)aPtr1)->CreateGlobal(aName, value); 53 } 54 55 /* Create a semaphore */ 56 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value) 57 { 58 RSemaphore s; 59 TInt status = CreateUnique(NewSema, &s, &initial_value); 60 if(status != KErrNone) 61 { 62 SDL_SetError("Couldn't create semaphore"); 63 } 64 SDL_semaphore* sem = new /*(ELeave)*/ SDL_semaphore; 65 sem->handle = s.Handle(); 66 sem->count = initial_value; 67 return(sem); 68 } 69 70 /* Free the semaphore */ 71 void SDL_DestroySemaphore(SDL_sem *sem) 72 { 73 if ( sem ) 74 { 75 RSemaphore sema; 76 sema.SetHandle(sem->handle); 77 sema.Signal(sema.Count()); 78 sema.Close(); 79 delete sem; 80 sem = NULL; 81 } 82 } 83 84 85 struct TInfo 86 { 87 TInfo(TInt aTime, TInt aHandle) : 88 iTime(aTime), iHandle(aHandle), iVal(0) {} 89 TInt iTime; 90 TInt iHandle; 91 TInt iVal; 92 }; 93 94 TBool ThreadRun(TAny* aInfo) 95 { 96 TInfo* info = STATIC_CAST(TInfo*, aInfo); 97 User::After(info->iTime); 98 RSemaphore sema; 99 sema.SetHandle(info->iHandle); 100 sema.Signal(); 101 info->iVal = SDL_MUTEX_TIMEOUT; 102 return 0; 103 } 104 105 106 107 108 void _WaitAll(SDL_sem *sem) 109 { 110 //since SemTryWait may changed the counter. 111 //this may not be atomic, but hopes it works. 112 RSemaphore sema; 113 sema.SetHandle(sem->handle); 114 sema.Wait(); 115 while(sem->count < 0) 116 { 117 sema.Wait(); 118 } 119 } 120 121 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) 122 { 123 if ( ! sem ) { 124 SDL_SetError("Passed a NULL sem"); 125 return -1; 126 } 127 128 if ( timeout == SDL_MUTEX_MAXWAIT ) 129 { 130 _WaitAll(sem); 131 return SDL_MUTEX_MAXWAIT; 132 } 133 134 135 RThread thread; 136 137 TInfo* info = new (ELeave)TInfo(timeout, sem->handle); 138 139 TInt status = CreateUnique(NewThread, &thread, info); 140 141 if(status != KErrNone) 142 return status; 143 144 thread.Resume(); 145 146 _WaitAll(sem); 147 148 if(thread.ExitType() == EExitPending) 149 { 150 thread.Kill(SDL_MUTEX_TIMEOUT); 151 } 152 153 thread.Close(); 154 155 return info->iVal; 156 } 157 158 int SDL_SemTryWait(SDL_sem *sem) 159 { 160 if(sem->count > 0) 161 { 162 sem->count--; 163 } 164 return SDL_MUTEX_TIMEOUT; 165 } 166 167 int SDL_SemWait(SDL_sem *sem) 168 { 169 return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT); 170 } 171 172 /* Returns the current count of the semaphore */ 173 Uint32 SDL_SemValue(SDL_sem *sem) 174 { 175 if ( ! sem ) { 176 SDL_SetError("Passed a NULL sem"); 177 return 0; 178 } 179 return sem->count; 180 } 181 182 int SDL_SemPost(SDL_sem *sem) 183 { 184 if ( ! sem ) { 185 SDL_SetError("Passed a NULL sem"); 186 return -1; 187 } 188 sem->count++; 189 RSemaphore sema; 190 sema.SetHandle(sem->handle); 191 sema.Signal(); 192 return 0; 193 } 194