comparison src/timer/os2/SDL_systimer.c @ 1895:c121d94672cb

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