diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/timer/os2/SDL_systimer.c	Wed Nov 23 07:29:56 2005 +0000
@@ -0,0 +1,230 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+#define INCL_DOSMISC
+#define INCL_DOSERRORS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSDATETIME
+#define INCL_DOSPROCESS
+#define INCL_DOSPROFILE
+#define INCL_DOSEXCEPTIONS
+#include <os2.h>
+
+#include "SDL_thread.h"
+#include "SDL_timer.h"
+#include "SDL_timer_c.h"
+#include "SDL_error.h"
+
+
+#define TIME_WRAP_VALUE (~(DWORD)0)
+
+/* The first high-resolution ticks value of the application */
+static long long hires_start_ticks;
+/* The number of ticks per second of the high-resolution performance counter */
+static ULONG hires_ticks_per_second;
+
+void SDL_StartTicks(void)
+{
+        DosTmrQueryFreq(&hires_ticks_per_second);
+        DosTmrQueryTime((PQWORD)&hires_start_ticks);
+}
+
+DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
+{
+        long long hires_now;
+        ULONG ticks = ticks;
+
+        DosTmrQueryTime((PQWORD)&hires_now);
+/*
+        hires_now -= hires_start_ticks;
+        hires_now *= 1000;
+        hires_now /= hires_ticks_per_second;
+*/
+        /* inline asm to avoid runtime inclusion */
+        _asm {
+           push edx
+           push eax
+           mov eax, dword ptr hires_now
+           mov edx, dword ptr hires_now+4
+           sub eax, dword ptr hires_start_ticks
+           sbb edx, dword ptr hires_start_ticks+4
+           mov ebx,1000
+           mov ecx,edx
+           mul ebx
+           push eax
+           push edx
+           mov eax,ecx
+           mul ebx
+           pop eax
+           add edx,eax
+           pop eax
+           mov ebx, dword ptr hires_ticks_per_second
+           div ebx
+           mov dword ptr ticks, eax
+           pop edx
+           pop eax
+        }
+
+        return ticks;
+
+}
+
+/* High resolution sleep, originally made by Ilya Zakharevich */
+DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
+{
+  /* This is similar to DosSleep(), but has 8ms granularity in time-critical
+     threads even on Warp3. */
+  HEV     hevEvent1     = 0;   /* Event semaphore handle    */
+  HTIMER  htimerEvent1  = 0;   /* Timer handle              */
+  APIRET  rc            = NO_ERROR;  /* Return code               */
+  int ret = 1;
+  ULONG priority = 0, nesting;   /* Shut down the warnings */
+  PPIB pib;
+  PTIB tib;
+  char *e = NULL;
+  APIRET badrc;
+  int switch_priority = 50;
+
+  DosCreateEventSem(NULL,      /* Unnamed */
+                    &hevEvent1,  /* Handle of semaphore returned */
+                    DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */
+                    FALSE);      /* Semaphore is in RESET state  */
+
+  if (ms >= switch_priority)
+    switch_priority = 0;
+  if (switch_priority)
+  {
+    if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR)
+      switch_priority = 0;
+    else
+    {
+ /* In Warp3, to switch scheduling to 8ms step, one needs to do 
+    DosAsyncTimer() in time-critical thread.  On laters versions,
+    more and more cases of wait-for-something are covered.
+
+    It turns out that on Warp3fp42 it is the priority at the time
+    of DosAsyncTimer() which matters.  Let's hope that this works
+    with later versions too...  XXXX
+  */
+      priority = (tib->tib_ptib2->tib2_ulpri);
+      if ((priority & 0xFF00) == 0x0300) /* already time-critical */
+        switch_priority = 0;
+ /* Make us time-critical.  Just modifying TIB is not enough... */
+ /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/
+ /* We do not want to run at high priority if a signal causes us
+    to longjmp() out of this section... */
+      if (DosEnterMustComplete(&nesting))
+        switch_priority = 0;
+      else
+        DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
+    }
+  }
+
+  if ((badrc = DosAsyncTimer(ms,
+        (HSEM) hevEvent1, /* Semaphore to post        */
+        &htimerEvent1))) /* Timer handler (returned) */
+    e = "DosAsyncTimer";
+
+  if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300)
+  {
+ /* Nobody switched priority while we slept...  Ignore errors... */
+ /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */
+    if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0)))
+      rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0);
+  }
+  if (switch_priority)
+    rc = DosExitMustComplete(&nesting); /* Ignore errors */
+
+  /* The actual blocking call is made with "normal" priority.  This way we
+     should not bother with DosSleep(0) etc. to compensate for us interrupting
+     higher-priority threads.  The goal is to prohibit the system spending too
+     much time halt()ing, not to run us "no matter what". */
+  if (!e)     /* Wait for AsyncTimer event */
+    badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT);
+
+  if (e) ;    /* Do nothing */
+  else if (badrc == ERROR_INTERRUPT)
+    ret = 0;
+  else if (badrc)
+    e = "DosWaitEventSem";
+  if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */
+    e = "DosCloseEventSem";
+    badrc = rc;
+  }
+  if (e)
+  {
+    SDL_SetError("[SDL_Delay] : Had error in %s(), rc is 0x%x\n", e, badrc);
+  }
+}
+
+/* Data to handle a single periodic alarm */
+static int timer_alive = 0;
+static SDL_Thread *timer = NULL;
+
+static int RunTimer(void *unused)
+{
+        DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
+        while ( timer_alive ) {
+                if ( SDL_timer_running ) {
+                        SDL_ThreadedTimerCheck();
+                }
+                SDL_Delay(10);
+        }
+        return(0);
+}
+
+/* This is only called if the event thread is not running */
+int SDL_SYS_TimerInit(void)
+{
+        timer_alive = 1;
+        timer = SDL_CreateThread(RunTimer, NULL);
+        if ( timer == NULL )
+                return(-1);
+        return(SDL_SetTimerThreaded(1));
+}
+
+void SDL_SYS_TimerQuit(void)
+{
+        timer_alive = 0;
+        if ( timer ) {
+                SDL_WaitThread(timer, NULL);
+                timer = NULL;
+        }
+}
+
+int SDL_SYS_StartTimer(void)
+{
+        SDL_SetError("Internal logic error: OS/2 uses threaded timer");
+        return(-1);
+}
+
+void SDL_SYS_StopTimer(void)
+{
+        return;
+}
+
+