comparison src/timer/os2/SDL_systimer.c @ 1662:782fd950bd46 SDL-1.3

Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API. WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid. The code is now run through a consistent indent format: indent -i4 -nut -nsc -br -ce The headers are being converted to automatically generate doxygen documentation.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:04:16 +0000
parents 92947e3a18db
children 4da1ee79c9af
comparison
equal deleted inserted replaced
1661:281d3f4870e5 1662:782fd950bd46
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 =
99 HTIMER htimerEvent1 = 0; /* Timer handle */ 150 DosSetPriority (PRTYS_THREAD, (priority >> 8) & 0xFF, 0, 0)))
100 APIRET rc = NO_ERROR; /* Return code */ 151 rc = DosSetPriority (PRTYS_THREAD, 0, priority & 0xFF, 0);
101 int ret = 1; 152 }
102 ULONG priority = 0, nesting; /* Shut down the warnings */ 153 if (switch_priority)
103 PPIB pib; 154 rc = DosExitMustComplete (&nesting); /* Ignore errors */
104 PTIB tib; 155
105 char *e = NULL; 156 /* The actual blocking call is made with "normal" priority. This way we
106 APIRET badrc; 157 should not bother with DosSleep(0) etc. to compensate for us interrupting
107 int switch_priority = 50; 158 higher-priority threads. The goal is to prohibit the system spending too
108 159 much time halt()ing, not to run us "no matter what". */
109 DosCreateEventSem(NULL, /* Unnamed */ 160 if (!e) /* Wait for AsyncTimer event */
110 &hevEvent1, /* Handle of semaphore returned */ 161 badrc = DosWaitEventSem (hevEvent1, SEM_INDEFINITE_WAIT);
111 DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */ 162
112 FALSE); /* Semaphore is in RESET state */ 163 if (e); /* Do nothing */
113 164 else if (badrc == ERROR_INTERRUPT)
114 if (ms >= switch_priority) 165 ret = 0;
115 switch_priority = 0; 166 else if (badrc)
116 if (switch_priority) 167 e = "DosWaitEventSem";
117 { 168 if ((rc = DosCloseEventSem (hevEvent1)) && !e) { /* Get rid of semaphore */
118 if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR) 169 e = "DosCloseEventSem";
119 switch_priority = 0; 170 badrc = rc;
120 else 171 }
121 { 172 if (e) {
122 /* In Warp3, to switch scheduling to 8ms step, one needs to do 173 SDL_SetError ("[SDL_Delay] : Had error in %s(), rc is 0x%x\n", e,
123 DosAsyncTimer() in time-critical thread. On laters versions, 174 badrc);
124 more and more cases of wait-for-something are covered. 175 }
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 } 176 }
180 177
181 /* Data to handle a single periodic alarm */ 178 /* Data to handle a single periodic alarm */
182 static int timer_alive = 0; 179 static int timer_alive = 0;
183 static SDL_Thread *timer = NULL; 180 static SDL_Thread *timer = NULL;
184 181
185 static int RunTimer(void *unused) 182 static int
186 { 183 RunTimer (void *unused)
187 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); 184 {
188 while ( timer_alive ) { 185 DosSetPriority (PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
189 if ( SDL_timer_running ) { 186 while (timer_alive) {
190 SDL_ThreadedTimerCheck(); 187 if (SDL_timer_running) {
191 } 188 SDL_ThreadedTimerCheck ();
192 SDL_Delay(10);
193 } 189 }
194 return(0); 190 SDL_Delay (10);
191 }
192 return (0);
195 } 193 }
196 194
197 /* This is only called if the event thread is not running */ 195 /* This is only called if the event thread is not running */
198 int SDL_SYS_TimerInit(void) 196 int
199 { 197 SDL_SYS_TimerInit (void)
200 timer_alive = 1; 198 {
201 timer = SDL_CreateThread(RunTimer, NULL); 199 timer_alive = 1;
202 if ( timer == NULL ) 200 timer = SDL_CreateThread (RunTimer, NULL);
203 return(-1); 201 if (timer == NULL)
204 return(SDL_SetTimerThreaded(1)); 202 return (-1);
205 } 203 return (SDL_SetTimerThreaded (1));
206 204 }
207 void SDL_SYS_TimerQuit(void) 205
208 { 206 void
209 timer_alive = 0; 207 SDL_SYS_TimerQuit (void)
210 if ( timer ) { 208 {
211 SDL_WaitThread(timer, NULL); 209 timer_alive = 0;
212 timer = NULL; 210 if (timer) {
213 } 211 SDL_WaitThread (timer, NULL);
214 } 212 timer = NULL;
215 213 }
216 int SDL_SYS_StartTimer(void) 214 }
217 { 215
218 SDL_SetError("Internal logic error: OS/2 uses threaded timer"); 216 int
219 return(-1); 217 SDL_SYS_StartTimer (void)
220 } 218 {
221 219 SDL_SetError ("Internal logic error: OS/2 uses threaded timer");
222 void SDL_SYS_StopTimer(void) 220 return (-1);
223 { 221 }
224 return; 222
223 void
224 SDL_SYS_StopTimer (void)
225 {
226 return;
225 } 227 }
226 228
227 #endif /* SDL_TIMER_OS2 */ 229 #endif /* SDL_TIMER_OS2 */
230 /* vi: set ts=4 sw=4 expandtab: */