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
30static 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
46struct SDL_semaphore
47 {
48 TInt handle;
49 TInt count;
50 };
51
52
53extern TInt CreateUnique(TInt (*aFunc)(const TDesC& aName, TAny*, TAny*), TAny*, TAny*);
54#ifndef EKA2
55extern TInt NewThread(const TDesC& aName, TAny* aPtr1, TAny* aPtr2);
56#endif
57
58TInt 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 */
65SDL_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 */
80void 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    {
98        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
107TBool 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
121void _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
134int 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
179int SDL_SemTryWait(SDL_sem *sem)
180{
181    if(sem->count > 0)
182        {
183        sem->count--;
184        }
185    return SDL_MUTEX_TIMEOUT;
186}
187
188int SDL_SemWait(SDL_sem *sem)
189{
190	return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
191}
192
193/* Returns the current count of the semaphore */
194Uint32 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
203int 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