Updated to latest source.
[AROS-Contrib.git] / SDL / SDL_systimer.c
blob37e56ec6d4f0db53178393465f49a7c4b5cc9168
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
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.
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.
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
19 Sam Lantinga
20 slouken@libsdl.org
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
28 #define __TIMER_NOLIBBASE__
29 #define __GRAPHICS_NOLIBBASE__
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <exec/types.h>
39 #ifdef __SASC
40 #include <proto/dos.h>
41 #include <clib/graphics_protos.h>
42 #include <pragmas/graphics.h>
43 #include <clib/exec_protos.h>
44 #include <pragmas/exec.h>
45 #elif defined(WARPOS) || defined(__AROS__)
46 #include <proto/dos.h>
47 #include <proto/exec.h>
48 #include <proto/graphics.h>
49 #else
50 #include <inline/dos.h>
51 #include <inline/exec.h>
52 #include <inline/graphics.h>
53 #endif
54 #include "mydebug.h"
56 extern struct DosLibrary *DOSBase;
57 extern struct ExecBase *SysBase;
58 static struct GfxBase *GfxBase;
60 #include "SDL_error.h"
61 #include "SDL_timer.h"
62 #include "SDL_timer_c.h"
64 #if defined(DISABLE_THREADS) || defined(FORK_HACK)
65 #define USE_ITIMER
66 #endif
68 /* The first ticks value of the application */
70 #if defined (__AROS__) || !defined(__PPC__) || defined(MORPHOS)
71 static clock_t start;
73 #define USE_SYSTIME
75 #ifdef USE_SYSTIME
76 #include <devices/timer.h>
77 #include <proto/timer.h>
79 static struct timerequest *TimerIO = NULL;
80 static struct Device *TimerBase = NULL;
81 static struct timeval basetime;
82 static struct MsgPort *TimerMP = NULL;
84 static int fallback = 0;
86 static void close_timer(void)
88 D(bug("freeing timer resources..."));
89 if(TimerIO) {
90 CloseDevice((struct IORequest *)TimerIO);
91 DeleteIORequest((struct IORequest *)TimerIO);
92 TimerIO = NULL;
94 if(TimerMP) {
95 DeleteMsgPort(TimerMP);
96 TimerMP = NULL;
98 D(bug("OK\n"));
100 #endif
102 void SDL_StartTicks(void)
104 #ifndef USE_SYSTIME
105 /* Set first ticks value */
106 start=clock();
107 #else
108 struct MsgPort *TimerMP;
110 if (TimerBase || fallback) return;
112 if (!(TimerMP = CreateMsgPort())) {
113 start=clock();
114 fallback = 1;
115 return;
118 if (!(TimerIO = (struct timerequest *)
119 CreateIORequest(TimerMP, sizeof(struct timerequest)))) {
120 DeleteMsgPort(TimerMP);
121 start=clock();
122 fallback = 1;
123 return;
126 if (OpenDevice("timer.device", UNIT_VBLANK, &TimerIO->tr_node, 0)) {
127 DeleteMsgPort(TimerMP);
128 DeleteIORequest((struct IORequest *)TimerIO);
129 start=clock();
130 fallback = 1;
131 return;
134 TimerBase = TimerIO->tr_node.io_Device;
135 D(bug("Timer resource allocated.\n"));
137 GetSysTime(&basetime);
138 D(bug("Basetime: %lusecs %lumicro\n", basetime.tv_secs, basetime.tv_micro));
140 #ifndef SHARED_LIB
141 atexit(close_timer);
142 #endif
144 #endif
147 Uint32 SDL_GetTicks (void)
149 #ifdef USE_SYSTIME
150 if (fallback) {
151 #endif
152 clock_t ticks;
154 ticks=clock()-start;
156 #if CLOCKS_PER_SEC == 1000
157 return(ticks);
158 #else
159 return ticks*(1000/CLOCKS_PER_SEC);
160 #endif
162 #ifdef USE_SYSTIME
164 else {
165 struct timeval tv;
166 Uint32 tics;
168 GetSysTime(&tv);
170 if(basetime.tv_micro > tv.tv_micro) {
171 tv.tv_secs --;
173 tv.tv_micro += 1000000;
175 tics = ((tv.tv_secs - basetime.tv_secs) * 1000) +
176 ((tv.tv_micro - basetime.tv_micro)/1000);
178 return tics;
180 #endif
183 void SDL_Delay (Uint32 ms)
185 // Do a busy wait if time is less than 50ms
187 if(ms<50)
189 #ifndef USE_SYSTIME
190 clock_t to_wait=clock();
191 // most archs have clocks per sec == 1000
192 #if CLOCKS_PER_SEC != 1000
193 ms*=(CLOCKS_PER_SEC/1000);
194 #endif
195 to_wait+=ms;
197 while(clock()<to_wait);
198 #else
199 Uint32 to_wait = SDL_GetTicks() + ms;
201 while(SDL_GetTicks() < to_wait);
202 #endif
204 else
206 Delay(ms/20);
210 #elif defined(WARPOS)
211 /* Use the powerpc.library function GetSysTimePPC to get the time */
212 static ULONG start;
214 void SDL_StartTicks(void)
216 /* Set first ticks value */
217 struct timeval tval;
218 GetSysTimePPC(&tval);
219 start = (tval.tv_secs*1000 + tval.tv_micro/1000);
222 Uint32 SDL_GetTicks (void)
224 ULONG ticks;
225 struct timeval tval;
226 GetSysTimePPC(&tval);
228 ticks = (tval.tv_secs*1000 + tval.tv_micro/1000);
230 return (ticks-start); /* return time in ms */
233 void SDL_Delay (Uint32 ms)
235 // Do a busy wait if time is less than 50ms
237 if(ms<50)
239 ULONG to_wait;
240 ULONG t;
241 struct timeval tval;
242 GetSysTimePPC(&tval);
243 t = (tval.tv_secs*1000000 + tval.tv_micro);
244 to_wait = t + (ms*1000);
246 do {
247 GetSysTimePPC(&tval);
248 t = (tval.tv_secs*1000000 + tval.tv_micro);
250 while(t < to_wait);
252 else
254 Delay(ms/20);
259 #else
261 ULONG MY_CLOCKS_PER_SEC;
263 void PPC_TimerInit(void);
264 APTR MyTimer;
266 ULONG start[2];
268 void SDL_StartTicks(void)
270 /* Set first ticks value */
271 if(!MyTimer)
272 PPC_TimerInit();
274 PPCGetTimerObject(MyTimer,PPCTIMERTAG_CURRENTTICKS,start);
275 start[1]>>=10;
276 start[1]|=((result[0]&0x3ff)<<22);
277 start[0]>>=10;
280 Uint32 SDL_GetTicks (void)
282 ULONG result[2];
283 PPCGetTimerObject(MyTimer,PPCTIMERTAG_CURRENTTICKS,result);
285 // PPCAsr64p(result,10);
286 // Non va, la emulo:
288 result[1]>>=10;
289 result[1]|=((result[0]&0x3ff)<<22);
291 // Non mi interessa piu' result[0]
293 return result[1]*1000/MY_CLOCKS_PER_SEC;
296 void SDL_Delay (Uint32 ms)
298 // Do a busy wait if time is less than 50ms
300 if(ms<50)
302 ULONG to_wait[2],actual[2];
303 PPCGetTimerObject(MyTimer,PPCTIMERTAG_CURRENTTICKS,result);
304 actual[1]=0;
305 to_wait[1]+=ms*1000/MY_CLOCKS_PER_SEC;
307 while(actual[1]<to_wait[1])
309 PPCGetTimerObject(MyTimer,PPCTIMERTAG_CURRENTTICKS,actual);
312 else
314 Delay(ms/50);
318 void PPC_TimerInit(void)
320 struct TagItem tags[]=
322 PPCTIMERTAG_CPU,TRUE,
323 TAG_DONE,0
327 if(MyTimer=PPCCreateTimerObject(tags))
329 ULONG result[2];
331 PPCGetTimerObject(MyTimer,PPCTIMERTAG_TICKSPERSEC,result);
332 D(bug("Timer inizializzato, TPS: %lu - %lu\n",result[0],result[1]));
333 // PPCAsr64p(result,10);
334 result[1]>>=10;
335 result[1]|=((result[0]&0x3ff)<<22);
336 result[0]>>=10;
338 D(bug("Shiftato TPS: %lu - %lu\n",result[0],result[1]));
339 MY_CLOCKS_PER_SEC=result[1];
341 PPCGetTimerObject(MyTimer,PPCTIMERTAG_CURRENTTICKS,result);
343 D(bug("Current ticks: %lu - %lu\n",result[0],result[1]));
344 result[1]>>=10;
345 result[1]|=((result[0]&0x3ff)<<22);
346 result[0]>>=10;
347 // PPCAsr64p(result,10);
348 D(bug("Shiftato: %lu - %lu\n",result[0],result[1]));
350 else
352 D(bug("Errore nell'inizializzazione del timer!\n"));
356 #endif
358 #include "SDL_thread.h"
360 /* Data to handle a single periodic alarm */
361 static int timer_alive = 0;
362 static SDL_Thread *timer_thread = NULL;
364 static int RunTimer(void *unused)
366 D(bug("SYSTimer: Entering RunTimer loop..."));
368 if(GfxBase==NULL)
369 GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37);
371 while ( timer_alive ) {
372 if ( SDL_timer_running ) {
373 SDL_ThreadedTimerCheck();
375 if(GfxBase)
376 WaitTOF(); // Check the timer every fifth of seconds. Was SDL_Delay(1)->BusyWait!
377 else
378 Delay(1);
380 D(bug("SYSTimer: EXITING RunTimer loop..."));
381 return(0);
384 /* This is only called if the event thread is not running */
385 int SDL_SYS_TimerInit(void)
387 D(bug("Creating thread for the timer (NOITIMER)...\n"));
389 timer_alive = 1;
390 timer_thread = SDL_CreateThread(RunTimer, NULL);
391 if ( timer_thread == NULL )
393 D(bug("Creazione del thread fallita...\n"));
395 return(-1);
397 return(SDL_SetTimerThreaded(1));
400 void SDL_SYS_TimerQuit(void)
402 timer_alive = 0;
403 if ( timer_thread ) {
404 SDL_WaitThread(timer_thread, NULL);
405 timer_thread = NULL;
409 int SDL_SYS_StartTimer(void)
411 SDL_SetError("Internal logic error: AmigaOS uses threaded timer");
412 return(-1);
415 void SDL_SYS_StopTimer(void)
417 return;