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 #include "SDL_config.h"
23
24 /*
25 SDL_syssem.cpp
26
27 Epoc version by Markus Mertama (w@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
NewSema(const TDesC & aName,TAny * aPtr1,TAny * aPtr2)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 */
SDL_CreateSemaphore(Uint32 initial_value)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 */
SDL_DestroySemaphore(SDL_sem * sem)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 {
TInfoTInfo87 TInfo(TInt aTime, TInt aHandle) :
88 iTime(aTime), iHandle(aHandle), iVal(0) {}
89 TInt iTime;
90 TInt iHandle;
91 TInt iVal;
92 };
93
ThreadRun(TAny * aInfo)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
_WaitAll(SDL_sem * sem)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
SDL_SemWaitTimeout(SDL_sem * sem,Uint32 timeout)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
SDL_SemTryWait(SDL_sem * sem)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
SDL_SemWait(SDL_sem * sem)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 */
SDL_SemValue(SDL_sem * sem)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
SDL_SemPost(SDL_sem * sem)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