comparison src/timer/os2/SDL_systimer.c @ 1190:173c063d4f55

OS/2 port! This was mostly, if not entirely, written by "Doodle" and "Caetano": doodle@scenergy.dfmk.hu daniel@caetano.eng.br --ryan.
author Ryan C. Gordon <icculus@icculus.org>
date Wed, 23 Nov 2005 07:29:56 +0000
parents
children c9b51268668f
comparison
equal deleted inserted replaced
1189:c96b326b90ba 1190:173c063d4f55
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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@libsdl.org
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 #define INCL_DOSMISC
29 #define INCL_DOSERRORS
30 #define INCL_DOSSEMAPHORES
31 #define INCL_DOSDATETIME
32 #define INCL_DOSPROCESS
33 #define INCL_DOSPROFILE
34 #define INCL_DOSEXCEPTIONS
35 #include <os2.h>
36
37 #include "SDL_thread.h"
38 #include "SDL_timer.h"
39 #include "SDL_timer_c.h"
40 #include "SDL_error.h"
41
42
43 #define TIME_WRAP_VALUE (~(DWORD)0)
44
45 /* The first high-resolution ticks value of the application */
46 static long long hires_start_ticks;
47 /* The number of ticks per second of the high-resolution performance counter */
48 static ULONG hires_ticks_per_second;
49
50 void SDL_StartTicks(void)
51 {
52 DosTmrQueryFreq(&hires_ticks_per_second);
53 DosTmrQueryTime((PQWORD)&hires_start_ticks);
54 }
55
56 DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
57 {
58 long long hires_now;
59 ULONG ticks = ticks;
60
61 DosTmrQueryTime((PQWORD)&hires_now);
62 /*
63 hires_now -= hires_start_ticks;
64 hires_now *= 1000;
65 hires_now /= hires_ticks_per_second;
66 */
67 /* inline asm to avoid runtime inclusion */
68 _asm {
69 push edx
70 push eax
71 mov eax, dword ptr hires_now
72 mov edx, dword ptr hires_now+4
73 sub eax, dword ptr hires_start_ticks
74 sbb edx, dword ptr hires_start_ticks+4
75 mov ebx,1000
76 mov ecx,edx
77 mul ebx
78 push eax
79 push edx
80 mov eax,ecx
81 mul ebx
82 pop eax
83 add edx,eax
84 pop eax
85 mov ebx, dword ptr hires_ticks_per_second
86 div ebx
87 mov dword ptr ticks, eax
88 pop edx
89 pop eax
90 }
91
92 return ticks;
93
94 }
95
96 /* High resolution sleep, originally made by Ilya Zakharevich */
97 DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
98 {
99 /* This is similar to DosSleep(), but has 8ms granularity in time-critical
100 threads even on Warp3. */
101 HEV hevEvent1 = 0; /* Event semaphore handle */
102 HTIMER htimerEvent1 = 0; /* Timer handle */
103 APIRET rc = NO_ERROR; /* Return code */
104 int ret = 1;
105 ULONG priority = 0, nesting; /* Shut down the warnings */
106 PPIB pib;
107 PTIB tib;
108 char *e = NULL;
109 APIRET badrc;
110 int switch_priority = 50;
111
112 DosCreateEventSem(NULL, /* Unnamed */
113 &hevEvent1, /* Handle of semaphore returned */
114 DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */
115 FALSE); /* Semaphore is in RESET state */
116
117 if (ms >= switch_priority)
118 switch_priority = 0;
119 if (switch_priority)
120 {
121 if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR)
122 switch_priority = 0;
123 else
124 {
125 /* In Warp3, to switch scheduling to 8ms step, one needs to do
126 DosAsyncTimer() in time-critical thread. On laters versions,
127 more and more cases of wait-for-something are covered.
128
129 It turns out that on Warp3fp42 it is the priority at the time
130 of DosAsyncTimer() which matters. Let's hope that this works
131 with later versions too... XXXX
132 */
133 priority = (tib->tib_ptib2->tib2_ulpri);
134 if ((priority & 0xFF00) == 0x0300) /* already time-critical */
135 switch_priority = 0;
136 /* Make us time-critical. Just modifying TIB is not enough... */
137 /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/
138 /* We do not want to run at high priority if a signal causes us
139 to longjmp() out of this section... */
140 if (DosEnterMustComplete(&nesting))
141 switch_priority = 0;
142 else
143 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
144 }
145 }
146
147 if ((badrc = DosAsyncTimer(ms,
148 (HSEM) hevEvent1, /* Semaphore to post */
149 &htimerEvent1))) /* Timer handler (returned) */
150 e = "DosAsyncTimer";
151
152 if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300)
153 {
154 /* Nobody switched priority while we slept... Ignore errors... */
155 /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */
156 if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0)))
157 rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0);
158 }
159 if (switch_priority)
160 rc = DosExitMustComplete(&nesting); /* Ignore errors */
161
162 /* The actual blocking call is made with "normal" priority. This way we
163 should not bother with DosSleep(0) etc. to compensate for us interrupting
164 higher-priority threads. The goal is to prohibit the system spending too
165 much time halt()ing, not to run us "no matter what". */
166 if (!e) /* Wait for AsyncTimer event */
167 badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT);
168
169 if (e) ; /* Do nothing */
170 else if (badrc == ERROR_INTERRUPT)
171 ret = 0;
172 else if (badrc)
173 e = "DosWaitEventSem";
174 if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */
175 e = "DosCloseEventSem";
176 badrc = rc;
177 }
178 if (e)
179 {
180 SDL_SetError("[SDL_Delay] : Had error in %s(), rc is 0x%x\n", e, badrc);
181 }
182 }
183
184 /* Data to handle a single periodic alarm */
185 static int timer_alive = 0;
186 static SDL_Thread *timer = NULL;
187
188 static int RunTimer(void *unused)
189 {
190 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
191 while ( timer_alive ) {
192 if ( SDL_timer_running ) {
193 SDL_ThreadedTimerCheck();
194 }
195 SDL_Delay(10);
196 }
197 return(0);
198 }
199
200 /* This is only called if the event thread is not running */
201 int SDL_SYS_TimerInit(void)
202 {
203 timer_alive = 1;
204 timer = SDL_CreateThread(RunTimer, NULL);
205 if ( timer == NULL )
206 return(-1);
207 return(SDL_SetTimerThreaded(1));
208 }
209
210 void SDL_SYS_TimerQuit(void)
211 {
212 timer_alive = 0;
213 if ( timer ) {
214 SDL_WaitThread(timer, NULL);
215 timer = NULL;
216 }
217 }
218
219 int SDL_SYS_StartTimer(void)
220 {
221 SDL_SetError("Internal logic error: OS/2 uses threaded timer");
222 return(-1);
223 }
224
225 void SDL_SYS_StopTimer(void)
226 {
227 return;
228 }
229
230