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 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/* Semaphore functions using the OS/2 API */
25
26#define INCL_DOS
27#define INCL_DOSERRORS
28#define INCL_DOSSEMAPHORES
29#include <os2.h>
30
31#include "SDL_thread.h"
32#include "SDL_timer.h"
33
34
35struct SDL_semaphore {
36        HMTX id;
37        HEV  changed;
38        Uint32 value;
39};
40
41
42/* Create a semaphore */
43DECLSPEC SDL_sem * SDLCALL SDL_CreateSemaphore(Uint32 initial_value)
44{
45        SDL_sem *sem;
46        ULONG ulrc;
47
48        /* Allocate sem memory */
49        sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
50        if ( sem ) {
51                /* Create the mutex semaphore */
52                ulrc = DosCreateMutexSem(NULL,&(sem->id),0,TRUE);
53                if ( ulrc ) {
54                        SDL_SetError("Couldn't create semaphore");
55                        SDL_free(sem);
56                        sem = NULL;
57                } else
58                {
59                    DosCreateEventSem(NULL, &(sem->changed), 0, FALSE);
60                    sem->value = initial_value;
61                    DosReleaseMutexSem(sem->id);
62                }
63        } else {
64                SDL_OutOfMemory();
65        }
66        return(sem);
67}
68
69/* Free the semaphore */
70DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem *sem)
71{
72        if ( sem ) {
73                if ( sem->id ) {
74                        DosCloseEventSem(sem->changed);
75                        DosCloseMutexSem(sem->id);
76                        sem->id = 0;
77                }
78                SDL_free(sem);
79        }
80}
81
82DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
83{
84        ULONG ulrc;
85
86        if ( ! sem ) {
87                SDL_SetError("Passed a NULL sem");
88                return -1;
89        }
90
91        if ( timeout == SDL_MUTEX_MAXWAIT ) {
92           while (1) {
93              ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT);
94              if (ulrc) {
95                 /* if error waiting mutex */
96                 SDL_SetError("DosRequestMutexSem() failed");
97                 return -1;
98              } else if (sem->value) {
99                        sem->value--;
100                        DosReleaseMutexSem(sem->id);
101                        return 0;
102                     } else {
103                        ULONG ulPostCount;
104                        DosResetEventSem(sem->changed, &ulPostCount);
105                        DosReleaseMutexSem(sem->id);
106                        /* continue waiting until somebody posts the semaphore */
107                        DosWaitEventSem(sem->changed, SEM_INDEFINITE_WAIT);
108                     }
109           }
110        } else
111        if ( timeout == 0 )
112        {
113            ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT);
114            if (ulrc==NO_ERROR)
115            {
116                if (sem->value)
117                {
118                    sem->value--;
119                    DosReleaseMutexSem(sem->id);
120                    return 0;
121                } else
122                {
123                    DosReleaseMutexSem(sem->id);
124                    return SDL_MUTEX_TIMEDOUT;
125                }
126            } else
127            {
128                SDL_SetError("DosRequestMutexSem() failed");
129                return -1;
130            }
131        } else {
132            ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT);
133            if (ulrc) {
134               /* if error waiting mutex */
135               SDL_SetError("DosRequestMutexSem() failed");
136               return -1;
137            } else
138              if (sem->value) {
139                sem->value--;
140                DosReleaseMutexSem(sem->id);
141                return 0;
142              } else {
143                ULONG ulPostCount;
144                DosResetEventSem(sem->changed, &ulPostCount);
145                DosReleaseMutexSem(sem->id);
146                /* continue waiting until somebody posts the semaphore */
147                ulrc = DosWaitEventSem(sem->changed, timeout);
148                if (ulrc==NO_ERROR)
149                  return 0;
150                else
151                  return SDL_MUTEX_TIMEDOUT;
152              }
153        }
154        /* never reached */
155        return -1;
156}
157
158DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem *sem)
159{
160        return SDL_SemWaitTimeout(sem, 0);
161}
162
163DECLSPEC int SDLCALL SDL_SemWait(SDL_sem *sem)
164{
165        return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
166}
167
168/* Returns the current count of the semaphore */
169DECLSPEC Uint32 SDLCALL SDL_SemValue(SDL_sem *sem)
170{
171        if ( ! sem ) {
172                SDL_SetError("Passed a NULL sem");
173                return 0;
174        }
175        return sem->value;
176}
177
178DECLSPEC int SDLCALL SDL_SemPost(SDL_sem *sem)
179{
180        if ( ! sem ) {
181                SDL_SetError("Passed a NULL sem");
182                return -1;
183        }
184        if ( DosRequestMutexSem(sem->id,SEM_INDEFINITE_WAIT) ) {
185                SDL_SetError("DosRequestMutexSem() failed");
186                return -1;
187        }
188        sem->value++;
189        DosPostEventSem(sem->changed);
190        DosReleaseMutexSem(sem->id);
191        return 0;
192}
193