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:
@@ -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 */
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
@@ -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.
|
||||
|
||||
50
src/timer.c
50
src/timer.c
@@ -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)
|
||||
|
||||
29
src/xc.c
29
src/xc.c
@@ -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();
|
||||
|
||||
|
||||
11
src/xinit.c
11
src/xinit.c
@@ -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 */
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user