1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-29 04:51:28 +00:00

Rewrite keyboard and async I/O handling to improve performance and reduce dependency on async I/O signals (#392)

* Rewrite keyboard and async I/O handling to improve performance and reduce dependency on async I/O signals

Replaces the SIGIO handler, which used to process X events in the interrupt context, with
a stub routine that sets a flag to signal processing is required.
Actual event processing is moved to the main dispatch loop where Lisp periodic interrupts
are handled.

Removes the X connection file descriptor from the set of fds contributing to SIGIO events
and moves the processing of X events to where the Lisp periodic interrupt is handled in
the main dispatch loop.  This code is already guarded by a check for XPending() so can
be called regardless of whether any file descriptors are known to be ready.

Actual processing of async I/O events and X events are handled by procedures
process_io_events() and process_Xevents() respectively.  For the most part these are
a renaming of getsignaldata() and getXsignaldata().

The Lisp periodic timer (VTALRM) was set to operate with a 25000 us period (40 Hz),
but on modern hardware it is possible to run this timer with a period of 10000 us (100 Hz)

Incidentally, a bug was noted (and fixed) in the X event handling code for motion events:
Mouse motion without any keyboard activity should not add an entry to the keyboard event
ring buffer as these events do not represent a key state change.
Since the ring buffer is of limited size, when it is filled new events are ignored
until the buffered events are processed.  This resulted in the loss of a key/mouse button
transition (up or down) if the mouse was moved about "too much" between keyboard events.

A few incidental cleanups were also made:
  - KBDEventFlg initialization fixed (wrong semantic type)
  - Event_Req renamed to IO_Signalled (more appropriate name)
  - int_io_open() sets up process (self) to handle SIGIO generated by O_ASYNC operations
  - LOCK_X_EVENTS turned off since X library calls can no longer happen in an interrupt context

* Use of O_ASYNC must depend on the symbol being defined (looking at you, Cygwin)

* Add SA_RESTART flag to sigaction for SIGVTALRM periodic interrupt

* LOCK_X_UPDATE is no longer needed and should not be defined by default for Solaris in version.h
This commit is contained in:
Nick Briggs
2021-09-02 12:42:51 -07:00
committed by GitHub
parent c07618f55c
commit 377a6f3f47
36 changed files with 90 additions and 143 deletions

View File

@@ -133,10 +133,6 @@ extern DLword *DisplayRegion68k;
static struct timeval SelectTimeout = {0, 0};
#endif /* DOS */
#ifdef XWINDOW
extern volatile sig_atomic_t Event_Req;
#endif /* XWINDOW */
extern MISCSTATS *MiscStats;
LispPTR *LASTUSERACTION68k;
LispPTR *CLastUserActionCell68k;
@@ -187,7 +183,7 @@ LispPTR *MOUSECHORDTICKS68k;
/**NEW GLOBAL***-> will be moved***/
LispPTR *KEYBOARDEVENTQUEUE68k;
LispPTR *KEYBUFFERING68k;
int KBDEventFlg = NIL;
int KBDEventFlg = 0;
DLword *CTopKeyevent;
LispPTR DOBUFFEREDTRANSITION_index;
@@ -213,20 +209,12 @@ DLword ColorCursor_savebitmap[CURSORWIDTH / COLORPIXELS_IN_DLWORD * CURSORHEIGHT
/************************************************************************/
/* */
/* G E T S I G N A L D A T A */
/* */
/* Handler for the SIGIO interrupt, which happens */
/* 1. When a key transition happens */
/* 2. On mouse moves */
/* 3. When TCP input becomes available. */
/* 4. When a NIT ethernet packet becomes available. */
/* 5. When a console/log/stderr msg needs to be printed. */
/* */
/* */
/* */
/* */
/* */
/* p r o c e s s _ i o _ e v e n t s */
/* */
/* Periodically, or After a SIGIO interrupt which happens */
/* 1. When TCP input becomes available. */
/* 2. When a NIT ethernet packet becomes available. */
/* 3. When a console/log/stderr msg needs to be printed. */
/* */
/* */
/* Statics: LispReadFds A 32-bit vector with a 1 for each */
@@ -256,49 +244,16 @@ DLword ColorCursor_savebitmap[CURSORWIDTH / COLORPIXELS_IN_DLWORD * CURSORHEIGHT
/* */
/************************************************************************/
void getsignaldata(int sig)
void process_io_events()
{
#ifndef DOS
fd_set rfds, efds;
fd_set rfds;
u_int iflags;
int i;
#ifdef XWINDOW
#if defined(sun)
if (Event_Req) {
if (!XLocked++)
getXsignaldata(currentdsp);
else
XNeedSignal = 1;
Event_Req = FALSE;
XLocked--;
}
#endif
#endif /* XWINDOW */
/* #ifndef KBINT */
/* FD_COPY would be preferred but uses deprecated bcopy() on macOS. Why? */
memcpy(&rfds, &LispReadFds, sizeof(rfds));
memcpy(&efds, &LispReadFds, sizeof(efds));
/* label and ifs not needed if only keyboard on SIGIO */
getmore:
if (select(32, &rfds, NULL, &efds, &SelectTimeout) >= 0)
{
/* need to print out fd sets...
DBPRINT(("SIGIO: fd mask(r/e) = 0x%x/0x%x.\n", rfds, efds));
*/
#ifdef XWINDOW
if (FD_ISSET(ConnectionNumber(currentdsp->display_id), &rfds)) {
if (!XLocked)
getXsignaldata(currentdsp);
else
XNeedSignal = 1;
}
#endif /* XWINDOW */
if (select(32, &rfds, NULL, NULL, &SelectTimeout) > 0) {
#ifdef MAIKO_ENABLE_ETHERNET
if (ether_fd >= 0 && FD_ISSET(ether_fd, &rfds)) { /* Raw ethernet (NIT) I/O happened, so handle it. */
@@ -338,7 +293,7 @@ getmore:
}
/* #endif */
#endif /* DOS */
} /* end getsignaldata */
} /* end process_io_events */
/************************************************************************/

View File

@@ -253,7 +253,7 @@ rs232c_read() {
}
} else {
/*
* SIGIO handler getsignaldata and the successive
* SIGIO handler, process_io_events, and the successive
* rs232c_read has been called before Lisp prepares
* the next buffer. Turn on RS232C_remain_data to
* specify to read the remaining data after.

View File

@@ -87,9 +87,7 @@ extern DspInterface currentdsp;
int TIMEOUT_TIME; /* For file system timeout */
#ifdef XWINDOW
volatile sig_atomic_t Event_Req = FALSE;
#endif /* XWINDOW */
volatile sig_atomic_t IO_Signalled = FALSE;
static int gettime(int casep);
@@ -403,7 +401,7 @@ void update_timer() {
/* TIMER_INTERVAL usec ~ 20 per second. This should live in some
machine-configuration
file somewhere - it can be changed as the -t parameter to lisp*/
int TIMER_INTERVAL = 25000;
int TIMER_INTERVAL = 10000;
extern int LispWindowFd;
@@ -423,10 +421,6 @@ static void int_timer_service(int sig)
Irq_Stk_Check = 0;
Irq_Stk_End = 0;
#ifdef XWINDOW
Event_Req = TRUE;
#endif
}
/************************************************************************/
@@ -466,7 +460,7 @@ static void int_timer_init()
timer_action.sa_handler = int_timer_service;
sigemptyset(&timer_action.sa_mask);
timer_action.sa_flags = 0;
timer_action.sa_flags = SA_RESTART;
if (sigaction(SIGVTALRM, &timer_action, NULL) == -1) {
perror("sigaction: SIGVTALRM");
@@ -496,15 +490,10 @@ void int_io_open(int fd)
{
#ifdef DOS
/* would turn on DOS kbd signal handler here */
#elif KBINT
#elseif defined(O_ASYNC)
DBPRINT(("int_io_opening %d\n", fd));
if (fcntl(fd, F_SETOWN, getpid()) == -1) {
#ifdef DEBUG
perror("fcntl F_SETOWN ERROR");
#endif
};
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC) == -1) perror("fcntl F_SETFL error");
if (fcntl(fd, F_SETOWN, getpid()) == -1) perror("fcntl F_SETOWN error");
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC) == -1) perror("fcntl F_SETFL on error");
#endif
}
@@ -512,11 +501,27 @@ void int_io_close(int fd)
{
#ifdef DOS
/* Turn off signaller here */
#elif KBINT
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_ASYNC);
#elseif defined(O_ASYNC)
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_ASYNC) == -1) perror("fcntl_F_SETFL off error");
#endif
}
/************************************************************************/
/* */
/* i n t _ i o _ s e r v i c e */
/* */
/* Handle SIGIO */
/* */
/* */
/************************************************************************/
static void int_io_service(int sig)
{
Irq_Stk_Check = 0;
Irq_Stk_End = 0;
IO_Signalled = TRUE;
}
/************************************************************************/
/* */
/* i n t _ i o _ i n i t */
@@ -531,7 +536,7 @@ void int_io_close(int fd)
static void int_io_init() {
#ifndef DOS
struct sigaction io_action;
io_action.sa_handler = getsignaldata;
io_action.sa_handler = int_io_service;
sigemptyset(&io_action.sa_mask);
io_action.sa_flags = 0;
@@ -541,11 +546,6 @@ static void int_io_init() {
DBPRINT(("I/O interrupts enabled\n"));
}
#if defined(XWINDOW) && defined(I_SETSIG)
if (ioctl(ConnectionNumber(currentdsp->display_id), I_SETSIG, S_INPUT) < 0)
perror("ioctl on X fd - SETSIG for input handling failed");
#endif
#if defined(USE_DLPI)
DBPRINT(("INIT ETHER: Doing I_SETSIG.\n"));
if (ether_fd > 0)

View File

@@ -99,6 +99,7 @@
#include "ubf3defs.h"
#include "unwinddefs.h"
#include "vars3defs.h"
#include "xwinmandefs.h"
#include "z2defs.h"
#ifdef DOS
@@ -108,6 +109,8 @@ extern IOPAGE *IOPage68K;
extern KbdInterface currentkbd;
extern DspInterface currentdsp;
extern MouseInterface currentmouse;
#else
extern DspInterface currentdsp;
#endif /* DOS */
typedef struct conspage ConsPage;
@@ -141,11 +144,8 @@ register LispPTR tscache asm("bx");
#define PVARL PVar
#define IVARL IVar
#ifdef XWINDOW
extern volatile sig_atomic_t Event_Req; /* != 0 when it's time to check X events
on machines that don't get them reliably
(e.g. Suns running OpenWindows) */
#endif /* XWINDOW */
/* used by SIGIO signal handler to indicate I/O may be possible */
extern volatile sig_atomic_t IO_Signalled;
#ifdef PCTRACE
/* For keeping a trace table (ring buffer) of 100 last PCs */
@@ -1112,17 +1112,22 @@ check_interrupt:
Irq_Stk_End = (UNSIGNED)EndSTKP;
}
/* Check for an IRQ request */
/* This is a good time to process keyboard/mouse and ethernet I/O
* X events are not managed in the async/SIGIO code while
* raw ethernet, serial port, and socket connections are.
* If the system is configured with SIGIO handling we have a hint
* that allows us to cheaply skip if there's nothing to do
*/
process_Xevents(currentdsp);
if (IO_Signalled) {
IO_Signalled = FALSE;
process_io_events();
}
if ((Irq_Stk_End <= 0) || (Irq_Stk_Check <= 0) || need_irq) {
if (StkOffset_from_68K(CSTKPTR) > InterfacePage->stackbase) {
/* Interrupts not Disabled */
/* XXX: what on earth is this code trying to accomplish by calling
getsignaldata
*/
#if !defined(KBINT) || defined(OS4)
getsignaldata(0);
#endif
EXT;
update_timer();

View File

@@ -30,6 +30,7 @@
#include "adr68k.h"
#include "xinitdefs.h"
#include "dspifdefs.h"
#include "timerdefs.h"
#include "xbbtdefs.h"
#include "xlspwindefs.h"
#include "xwinmandefs.h"
@@ -65,7 +66,6 @@ Colormap Colors;
volatile sig_atomic_t XLocked = 0; /* non-zero while doing X ops, to avoid signals */
volatile sig_atomic_t XNeedSignal = 0; /* T if an X interrupt happened while XLOCK asserted */
extern fd_set LispReadFds;
/************************************************************************/
/* */
@@ -108,10 +108,6 @@ void lisp_Xexit(DspInterface dsp)
{
assert(Lisp_Xinitialized);
#if defined(I_SETSIG)
ioctl(ConnectionNumber(dsp->display_id), I_SETSIG, 0); /* so no interrupts happen during */
#endif
XLOCK;
XDestroySubwindows(dsp->display_id, dsp->LispWindow);
XDestroyWindow(dsp->display_id, dsp->LispWindow);
@@ -180,9 +176,6 @@ void Open_Display(DspInterface dsp)
{
assert(Lisp_Xinitialized == false);
FD_SET(ConnectionNumber(dsp->display_id), &LispReadFds);
fcntl(ConnectionNumber(dsp->display_id), F_SETOWN, getpid());
/****************************************************/
/* If debugging, set the X connection so that */
/* we run synchronized--so a debugger can */
@@ -200,7 +193,7 @@ void Open_Display(DspInterface dsp)
Create_LispWindow(dsp); /* Make the main window */
Lisp_Xinitialized = true;
init_Xevent(dsp); /* Turn on the intrpts. */
init_Xevent(dsp); /* Turn on the event reporting */
} /* end OpenDisplay */
/*********************************************************************/

View File

@@ -340,8 +340,8 @@ void DoRing() {
KBEVENT *kbevent;
TPRINT(("TRACE: DoRing()\n"));
do_ring:
/* DEL is not generally present on a Mac X keyboard, Ctrl-shift-ESC would be 18496 */
if (((*EmKbdAd268K) & 2113) == 0) { /*Ctrl-shift-NEXT*/
error("****** EMERGENCY Interrupt ******");
*EmKbdAd268K = KB_ALLUP; /*reset*/

View File

@@ -171,7 +171,7 @@ void beep_Xkeyboard(DspInterface dsp)
/************************************************************************/
/* */
/* g e t X s i g n a l d a t a */
/* p r o c e s s _ X e v e n t s */
/* */
/* Take X key/mouse events and turn them into Lisp events */
/* */
@@ -179,7 +179,7 @@ void beep_Xkeyboard(DspInterface dsp)
extern int Current_Hot_X, Current_Hot_Y; /* Cursor hotspot */
void getXsignaldata(DspInterface dsp)
void process_Xevents(DspInterface dsp)
{
XEvent report;
@@ -193,8 +193,6 @@ void getXsignaldata(DspInterface dsp)
(short)((report.xmotion.x + dsp->Visible.x) & 0xFFFF) - Current_Hot_X;
*EmCursorY68K = (*((DLword *)EmMouseY68K)) =
(short)((report.xmotion.y + dsp->Visible.y) & 0xFFFF) - Current_Hot_Y;
DoRing();
if ((KBDEventFlg) > 0) Irq_Stk_End = Irq_Stk_Check = 0;
break;
case KeyPress:
kb_trans(SUNLispKeyMap[(report.xkey.keycode) - KEYCODE_OFFSET], FALSE);
@@ -342,4 +340,4 @@ void getXsignaldata(DspInterface dsp)
Set_BitGravity(&report.xbutton, dsp, dsp->NWGrav, NorthWestGravity);
XFlush(dsp->display_id);
} /* end while */
} /* end getXsignaldata() */
} /* end process_Xevents */