Skip to content
Snippets Groups Projects
Commit faedb9d7 authored by deuce's avatar deuce
Browse files

Use SIGIO for signal-driven user input. Now, using SIGALRM and SIGIO

allows all the advantages of the Win32 threaded model with about half the
calories.
parent ba6673d1
No related branches found
No related tags found
No related merge requests found
...@@ -73,7 +73,11 @@ ...@@ -73,7 +73,11 @@
#include "OpenDoor.h" #include "OpenDoor.h"
#ifdef ODPLAT_NIX #ifdef ODPLAT_NIX
#include <sys/types.h>
#include <unistd.h>
#include <signal.h> #include <signal.h>
#include <fcntl.h>
#include <errno.h>
#endif #endif
#include "ODCore.h" #include "ODCore.h"
#include "ODGen.h" #include "ODGen.h"
...@@ -108,7 +112,8 @@ static void ODKrnlTimeUpdate(void); ...@@ -108,7 +112,8 @@ static void ODKrnlTimeUpdate(void);
static void ODKrnlChatCleanup(void); static void ODKrnlChatCleanup(void);
static void ODKrnlChatMode(void); static void ODKrnlChatMode(void);
#ifdef ODPLAT_NIX #ifdef ODPLAT_NIX
void sig_run_kernel(int sig); static void sig_run_kernel(int sig);
static void sig_get_char(int sig);
#endif #endif
/* Functions specific to the multithreaded implementation of the kernel. */ /* Functions specific to the multithreaded implementation of the kernel. */
...@@ -187,7 +192,7 @@ tODResult ODKrnlInitialize(void) ...@@ -187,7 +192,7 @@ tODResult ODKrnlInitialize(void)
/* Run kernel on SIGALRM (Every 1 second) */ /* Run kernel on SIGALRM (Every 1 second) */
act.sa_handler=sig_run_kernel; act.sa_handler=sig_run_kernel;
act.sa_flags=0; act.sa_flags=SA_RESTART;
sigemptyset(&(act.sa_mask)); sigemptyset(&(act.sa_mask));
sigaction(SIGALRM,&act,NULL); sigaction(SIGALRM,&act,NULL);
itv.it_interval.tv_sec=1; itv.it_interval.tv_sec=1;
...@@ -195,6 +200,28 @@ tODResult ODKrnlInitialize(void) ...@@ -195,6 +200,28 @@ tODResult ODKrnlInitialize(void)
itv.it_value.tv_sec=0; itv.it_value.tv_sec=0;
itv.it_value.tv_usec=250000; itv.it_value.tv_usec=250000;
setitimer(ITIMER_REAL,&itv,NULL); setitimer(ITIMER_REAL,&itv,NULL);
/* Make sure SIGALRM is unblocked */
sigemptyset(&block);
sigaddset(&block,SIGALRM);
sigprocmask(SIG_UNBLOCK,&block,NULL);
/* Make stdin signal driven. */
act.sa_handler=sig_get_char;
act.sa_flags=0;
sigemptyset(&(act.sa_mask));
sigaction(SIGIO,&act,NULL);
/* Make sure SIGIO is unblocked */
sigemptyset(&block);
sigaddset(&block,SIGIO);
sigprocmask(SIG_UNBLOCK,&block,NULL);
/* Have SIGIO signales delivered to this process */
fcntl(0,F_SETOWN,getpid());
/* Enable SIGIO when read possible on stdin */
fcntl(0,F_SETFL,fcntl(0,F_GETFL)|O_ASYNC);
#endif #endif
/* Initialize time of next status update and next time deduction. */ /* Initialize time of next status update and next time deduction. */
...@@ -354,12 +381,14 @@ ODAPIDEF void ODCALL od_kernel(void) ...@@ -354,12 +381,14 @@ ODAPIDEF void ODCALL od_kernel(void)
} }
} }
#ifndef ODPLAT_NIX /* On *nix, this is handled by a signal */
/* Loop, obtaining any new characters from the serial port and */ /* Loop, obtaining any new characters from the serial port and */
/* adding them to the common local/remote input queue. */ /* adding them to the common local/remote input queue. */
while(ODComGetByte(hSerialPort, &ch, FALSE) == kODRCSuccess) while(ODComGetByte(hSerialPort, &ch, FALSE) == kODRCSuccess)
{ {
ODKrnlHandleReceivedChar(ch, TRUE); ODKrnlHandleReceivedChar(ch, TRUE);
} }
#endif
} }
#ifdef ODPLAT_DOS #ifdef ODPLAT_DOS
...@@ -1590,17 +1619,32 @@ static void ODKrnlChatCleanup(void) ...@@ -1590,17 +1619,32 @@ static void ODKrnlChatCleanup(void)
#endif #endif
} }
#ifdef ODPLAT_NIX
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* sig_run_kernel(sig) *** PRIVATE FUNCTION *** * sig_run_kernel(sig) *** PRIVATE FUNCTION ***
* *
* Runs od_kernel() on a SIGALRM * Runs od_kernel() on a SIGALRM
* *
*/ */
#ifdef ODPLAT_NIX static void sig_run_kernel(int sig)
void sig_run_kernel(int sig)
{ {
od_kernel(); od_kernel();
} }
#endif
/* ----------------------------------------------------------------------------
* sig_run_kernel(sig) *** PRIVATE FUNCTION ***
*
* Runs od_kernel() on a SIGALRM
*
*/
static void sig_get_char(int sig)
{
static char ch;
/* Loop, obtaining any new characters from the serial port and */
/* adding them to the common local/remote input queue. */
while(ODComGetByte(hSerialPort, &ch, FALSE) == kODRCSuccess)
{
ODKrnlHandleReceivedChar(ch, TRUE);
}
}
#endif
...@@ -660,16 +660,20 @@ void ODTimerWaitForElapse(tODTimer *pTimer) ...@@ -660,16 +660,20 @@ void ODTimerWaitForElapse(tODTimer *pTimer)
} }
#elif defined(ODPLAT_NIX) #elif defined(ODPLAT_NIX)
gettimeofday(&tv,NULL); /* This is timing sensitive and *MUST* wait regardless of 100% CPU or signals */
tv.tv_sec -= pTimer->Start.tv_sec; while(1) {
tv.tv_usec -= pTimer->Start.tv_usec; gettimeofday(&tv,NULL);
if(tv.tv_usec < 0) { tv.tv_sec -= (pTimer->Start.tv_sec + pTimer->Duration/1000);
tv.tv_sec--; tv.tv_usec -= (pTimer->Start.tv_usec + ((pTimer->Duration*1000)%1000000));
tv.tv_usec += 1000000; if(tv.tv_usec < 0) {
tv.tv_sec--;
tv.tv_usec += 1000000;
}
if(tv.tv_sec<0 || tv.tv_usec<0)
return;
if(!select(0,NULL,NULL,NULL,&tv))
break;
} }
if(tv.tv_sec<0 || tv.tv_usec<0)
return;
select(0,NULL,NULL,NULL,&tv);
#else /* !ODPLAT_DOS */ #else /* !ODPLAT_DOS */
{ {
/* Under other platforms, timer resolution is high enough that we can */ /* Under other platforms, timer resolution is high enough that we can */
...@@ -779,7 +783,7 @@ ODAPIDEF void ODCALL od_sleep(tODMilliSec Milliseconds) ...@@ -779,7 +783,7 @@ ODAPIDEF void ODCALL od_sleep(tODMilliSec Milliseconds)
{ {
#ifdef ODPLAT_NIX #ifdef ODPLAT_NIX
struct timeval tv; struct timeval tv;
fd_set in; struct timeval start;
#endif #endif
/* Log function entry if running in trace mode. */ /* Log function entry if running in trace mode. */
TRACE(TRACE_API, "od_sleep()"); TRACE(TRACE_API, "od_sleep()");
...@@ -811,16 +815,33 @@ ODAPIDEF void ODCALL od_sleep(tODMilliSec Milliseconds) ...@@ -811,16 +815,33 @@ ODAPIDEF void ODCALL od_sleep(tODMilliSec Milliseconds)
#endif /* ODPLAT_WIN32 */ #endif /* ODPLAT_WIN32 */
#ifdef ODPLAT_NIX #ifdef ODPLAT_NIX
FD_ZERO(&in);
tv.tv_sec=Milliseconds/1000;
tv.tv_usec=(Milliseconds%1000)*1000;
if(Milliseconds==0) { if(Milliseconds==0) {
tv.tv_usec=1000; /* Prevent 100% CPU *only* no delay is actually required here */
FD_SET(0,&in); tv.tv_sec=0;
tv.tv_usec=1;
select(0,NULL,NULL,NULL,&tv);
}
else {
gettimeofday(&start,NULL);
start.tv_sec += Milliseconds/1000;
start.tv_usec += (Milliseconds*1000)%1000000;
while(1) {
/* This is timing sensitive and *MUST* wait for at least Milliseconds regardless of 100% CPU or signals */
gettimeofday(&tv,NULL);
tv.tv_sec -= (start.tv_sec + Milliseconds/1000);
tv.tv_usec -= (start.tv_usec + ((Milliseconds*1000)%1000000));
if(tv.tv_usec < 0) {
tv.tv_sec--;
tv.tv_usec += 1000000;
}
if(tv.tv_sec<0 || tv.tv_usec<0)
break;
if(!select(0,NULL,NULL,NULL,&tv))
break;
}
} }
if(select(1,Milliseconds?NULL:&in,NULL,NULL,&tv)>0)
od_kernel();
#endif #endif
OD_API_EXIT(); OD_API_EXIT();
......
Note that OpenDoors installs signal handlers and *REQUIRES* that they be called
for the following signals:
SIGALRM - Drives the od_kernel
SIGIO - Drives user input
If you install your own handles, be absolutely sure that they call the old
handlers as well.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment