symbian-qemu-0.9.1-12/libsdl-trunk/src/timer/os2/SDL_systimer.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2006 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 #ifdef SDL_TIMER_OS2
       
    25 
       
    26 #define INCL_DOSMISC
       
    27 #define INCL_DOSERRORS
       
    28 #define INCL_DOSSEMAPHORES
       
    29 #define INCL_DOSDATETIME
       
    30 #define INCL_DOSPROCESS
       
    31 #define INCL_DOSPROFILE
       
    32 #define INCL_DOSEXCEPTIONS
       
    33 #include <os2.h>
       
    34 
       
    35 #include "SDL_thread.h"
       
    36 #include "SDL_timer.h"
       
    37 #include "../SDL_timer_c.h"
       
    38 
       
    39 
       
    40 #define TIME_WRAP_VALUE (~(DWORD)0)
       
    41 
       
    42 /* The first high-resolution ticks value of the application */
       
    43 static long long hires_start_ticks;
       
    44 /* The number of ticks per second of the high-resolution performance counter */
       
    45 static ULONG hires_ticks_per_second;
       
    46 
       
    47 void SDL_StartTicks(void)
       
    48 {
       
    49         DosTmrQueryFreq(&hires_ticks_per_second);
       
    50         DosTmrQueryTime((PQWORD)&hires_start_ticks);
       
    51 }
       
    52 
       
    53 DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
       
    54 {
       
    55         long long hires_now;
       
    56         ULONG ticks = ticks;
       
    57 
       
    58         DosTmrQueryTime((PQWORD)&hires_now);
       
    59 /*
       
    60         hires_now -= hires_start_ticks;
       
    61         hires_now *= 1000;
       
    62         hires_now /= hires_ticks_per_second;
       
    63 */
       
    64         /* inline asm to avoid runtime inclusion */
       
    65         _asm {
       
    66            push edx
       
    67            push eax
       
    68            mov eax, dword ptr hires_now
       
    69            mov edx, dword ptr hires_now+4
       
    70            sub eax, dword ptr hires_start_ticks
       
    71            sbb edx, dword ptr hires_start_ticks+4
       
    72            mov ebx,1000
       
    73            mov ecx,edx
       
    74            mul ebx
       
    75            push eax
       
    76            push edx
       
    77            mov eax,ecx
       
    78            mul ebx
       
    79            pop eax
       
    80            add edx,eax
       
    81            pop eax
       
    82            mov ebx, dword ptr hires_ticks_per_second
       
    83            div ebx
       
    84            mov dword ptr ticks, eax
       
    85            pop edx
       
    86            pop eax
       
    87         }
       
    88 
       
    89         return ticks;
       
    90 
       
    91 }
       
    92 
       
    93 /* High resolution sleep, originally made by Ilya Zakharevich */
       
    94 DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
       
    95 {
       
    96   /* This is similar to DosSleep(), but has 8ms granularity in time-critical
       
    97      threads even on Warp3. */
       
    98   HEV     hevEvent1     = 0;   /* Event semaphore handle    */
       
    99   HTIMER  htimerEvent1  = 0;   /* Timer handle              */
       
   100   APIRET  rc            = NO_ERROR;  /* Return code               */
       
   101   int ret = 1;
       
   102   ULONG priority = 0, nesting;   /* Shut down the warnings */
       
   103   PPIB pib;
       
   104   PTIB tib;
       
   105   char *e = NULL;
       
   106   APIRET badrc;
       
   107   int switch_priority = 50;
       
   108 
       
   109   DosCreateEventSem(NULL,      /* Unnamed */
       
   110                     &hevEvent1,  /* Handle of semaphore returned */
       
   111                     DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */
       
   112                     FALSE);      /* Semaphore is in RESET state  */
       
   113 
       
   114   if (ms >= switch_priority)
       
   115     switch_priority = 0;
       
   116   if (switch_priority)
       
   117   {
       
   118     if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR)
       
   119       switch_priority = 0;
       
   120     else
       
   121     {
       
   122  /* In Warp3, to switch scheduling to 8ms step, one needs to do 
       
   123     DosAsyncTimer() in time-critical thread.  On laters versions,
       
   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 }
       
   180 
       
   181 /* Data to handle a single periodic alarm */
       
   182 static int timer_alive = 0;
       
   183 static SDL_Thread *timer = NULL;
       
   184 
       
   185 static int SDLCALL RunTimer(void *unused)
       
   186 {
       
   187         DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
       
   188         while ( timer_alive ) {
       
   189                 if ( SDL_timer_running ) {
       
   190                         SDL_ThreadedTimerCheck();
       
   191                 }
       
   192                 SDL_Delay(10);
       
   193         }
       
   194         return(0);
       
   195 }
       
   196 
       
   197 /* This is only called if the event thread is not running */
       
   198 int SDL_SYS_TimerInit(void)
       
   199 {
       
   200         timer_alive = 1;
       
   201         timer = SDL_CreateThread(RunTimer, NULL);
       
   202         if ( timer == NULL )
       
   203                 return(-1);
       
   204         return(SDL_SetTimerThreaded(1));
       
   205 }
       
   206 
       
   207 void SDL_SYS_TimerQuit(void)
       
   208 {
       
   209         timer_alive = 0;
       
   210         if ( timer ) {
       
   211                 SDL_WaitThread(timer, NULL);
       
   212                 timer = NULL;
       
   213         }
       
   214 }
       
   215 
       
   216 int SDL_SYS_StartTimer(void)
       
   217 {
       
   218         SDL_SetError("Internal logic error: OS/2 uses threaded timer");
       
   219         return(-1);
       
   220 }
       
   221 
       
   222 void SDL_SYS_StopTimer(void)
       
   223 {
       
   224         return;
       
   225 }
       
   226 
       
   227 #endif /* SDL_TIMER_OS2 */