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