wdvi

network DVI viewer
Log | Files | Refs

commit 7d978266916fbc463b2bffcefbc6a93cdae3d269
parent 1f4ced49814fdc750b5d7eb7be621d0457ae1098
Author: Kyle Milz <krwmilz@gmail.com>
Date:   Sat, 11 Sep 2021 15:41:29 +0000

remove signal handling

The only regressions i have noticed from this are
- the printing dialog output does not update
- drawing a page cannot be interrupted midway through a draw

This greatly simplifies the event loop, and removes one instance of
setjmp() and friends.

Diffstat:
Mdvi-draw.c | 30++----------------------------
Mevents.c | 468+++----------------------------------------------------------------------------
Mevents.h | 2--
Mspecial.c | 3---
Mspecial.h | 5-----
Mwdvi.1 | 8--------
Mxdvi.c | 6++----
7 files changed, 18 insertions(+), 504 deletions(-)

diff --git a/dvi-draw.c b/dvi-draw.c @@ -32,7 +32,7 @@ NOTE: #include "dvi-draw.h" /* drawing_mag */ #include "dvi-init.h" /* check_dvi_file() */ -#include "events.h" /* read_events(), do_color_change(), ... */ +#include "events.h" /* do_color_change(), ... */ #include "font.h" /* load_ft_font() XXX more */ #include "special.h" /* scan_special(), ... */ #include "util.h" /* xfopen(), snum() */ @@ -116,9 +116,6 @@ put_rule(x, y, w, h) { if (x < max_x && x + (int) w >= min_x && y < max_y && y + (int) h >= min_y) { - if (--event_counter == 0) - if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) - longjmp(canit_env, 1); if (fg_active != fg_current) do_color_change(); XFillRectangle(DISP, currwin.win, ruleGC, x - currwin.base_x, y - currwin.base_y, w ? w : 1, h ? h : 1); @@ -135,9 +132,6 @@ put_bitmap(bitmap, x, y) Printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y); if (x < max_x && x + (int) bitmap->w >= min_x && y < max_y && y + (int) bitmap->h >= min_y) { - if (--event_counter == 0) - if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) - longjmp(canit_env, 1); if (fg_active != fg_current) do_color_change(); image->width = bitmap->w; image->height = bitmap->h; @@ -168,10 +162,6 @@ put_image(g, x, y) if (x < max_x && x + img->width >= min_x && y < max_y && y + img->height >= min_y) { - if (--event_counter == 0) - if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) - longjmp(canit_env, 1); - if (g->fg != fg_current) /* if color change since last use */ shrink_glyph_grey(g); else if (fg_active != fg_current) /* if GCs need updating */ @@ -695,8 +685,6 @@ prescan(void) nextreportpage = current_page; } - if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE) break; - /* No calls to read_events() occur in this case. */ spcl_scan(scan_special); @@ -808,8 +796,6 @@ load_n_set_char(wide_ubyte cmd, wide_ubyte ch) #endif { if (!load_font(currinf.fontp)) { /* if not found */ - if (ev_flags & EV_GE_NEWDOC) /* if abort */ - longjmp(canit_env, 1); Fputs("Character(s) will be left blank.\n", stderr); currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char; #ifndef TEXXET @@ -1324,19 +1310,7 @@ draw_page() psfig_begun = False; drawing_mag = (currwin.win == alt.win); - /* NOTE: longjmp(canit_env) should not be done within read_events(). */ - if (!setjmp(canit_env)) - draw_part(current_frame = &frame0, dimconv); - else { /* if interrupted */ - /* If we were interrupted, put the expose event back, so that the - * region gets redrawn. The if statement is necessary because the - * magnifier may have been destroyed as part of the interrupt. */ - if (currwin.win == mane.win || currwin.win == alt.win) - expose(currwin.win == mane.win ? &mane : &alt, - min_x - currwin.base_x, min_y - currwin.base_y, - max_x - min_x, max_y - min_y); - ev_flags &= ~EV_MAG_GONE; - } + draw_part(current_frame = &frame0, dimconv); drawing_mag = False; dvi_pointer_frame = NULL; diff --git a/events.c b/events.c @@ -27,13 +27,9 @@ NOTE: \*========================================================================*/ -#include <sys/wait.h> /* waitpid, WNOHANG */ - #include <ctype.h> -#include <errno.h> #include <limits.h> /* abs() */ #include <math.h> /* pow() */ -#include <signal.h> #include <stdlib.h> /* free(), atoi(), atof(), exit(), abs() */ #include <X11/Xatom.h> @@ -54,10 +50,6 @@ NOTE: #include "xdvi.h" -#ifndef SIGPOLL -#define SIGPOLL SIGIO -#endif - #define MAGBORD 1 /* border size for magnifier */ /* @@ -76,13 +68,11 @@ static Position mag_x, mag_y, new_mag_x, new_mag_y; static int mag_conv_x, mag_conv_y; static Boolean dragcurs = False; -static sigset_t all_signals; - typedef void (*home_proc)(Boolean); typedef void (*mouse_proc)(XEvent *); +static void can_exposures(struct WindowRec *); void null_mouse(XEvent *); -static void xdvi_normal_exit(); mouse_proc mouse_motion = null_mouse; mouse_proc mouse_release = null_mouse; @@ -296,10 +286,6 @@ static short alt_stat; /* 1 = wait for expose, */ * Data for buffered events. */ -static volatile int event_freq = 70; -static void can_exposures(); - - #define gamma resource._gamma static void @@ -525,7 +511,7 @@ do_color_change() * Event-handling routines */ -void +static void expose(windowrec, x, y, w, h) struct WindowRec *windowrec; int x, y; @@ -866,11 +852,7 @@ ACTION(Act_minus) static ACTION(Act_quit) { - if (debug & DBG_EVENT) - puts(event_freq < 0 - ? "SIGPOLL is working" - : "no SIGPOLL signals received"); - xdvi_normal_exit(); + exit(1); } static @@ -1626,180 +1608,6 @@ handle_messages(widget, closure, event, cont) /* - * Interrupt system for receiving events. The program sets a flag - * whenever an event comes in, so that at the proper time (i.e., when - * reading a new dvi item), we can check incoming events to see if we - * still want to go on printing this page. This way, one can stop - * displaying a page if it is about to be erased anyway. We try to read - * as many events as possible before doing anything and base the next - * action on all events read. - * Note that the Xlib and Xt routines are not reentrant, so the most we - * can do is set a flag in the interrupt routine and check it later. - * Also, sometimes the interrupts are not generated (some systems only - * guarantee that SIGIO is generated for terminal files, and on the system - * I use, the interrupts are not generated if I use "(xdvi foo &)" instead - * of "xdvi foo"). Therefore, there is also a mechanism to check the - * event queue every 70 drawing operations or so. This mechanism is - * disabled if it turns out that the interrupts do work. - * For a fuller discussion of some of the above, see xlife in - * comp.sources.x. - */ - -/* - * Signal flags - */ - -/* This could be static volatile, but we want to avoid any optimizer bugs. */ -volatile unsigned int sig_flags = 0; - -#define SF_USR 1 -#define SF_ALRM 2 -#define SF_POLL 4 -#define SF_CHLD 8 -#define SF_TERM 16 - -static void do_sigterm(void); -static void do_sigchld(void); -static void do_sigpoll(void); -static void do_sigusr(void); - -#define SP0 do_sigusr /* these must be in the same order as SF_* */ -#define SP2 do_sigpoll -#define SP3 do_sigchld -#define SP4 do_sigterm /* highest priority */ - -typedef void (*signalproc)(void); - -static const signalproc flags_to_sigproc[32] - = {NULL, SP0, SP4, SP4, SP2, SP2, SP2, SP2, - SP3, SP3, SP3, SP3, SP3, SP3, SP3, SP3, - SP4, SP4, SP4, SP4, SP4, SP4, SP4, SP4, - SP4, SP4, SP4, SP4, SP4, SP4, SP4, SP4}; - -#undef SP0 -#undef SP2 -#undef SP3 -#undef SP4 - - -/* - * Signal routines. At the signal level, all we do is set flags. - */ - -/* ARGSUSED */ -static void -handle_sigpoll(signo) - int signo; -{ - event_counter = 1; - event_freq = -1; /* forget Plan B */ - sig_flags |= SF_POLL; -} - -/* ARGSUSED */ -static void -handle_sigterm(signo) - int signo; -{ - sig_flags |= SF_TERM; -} - -/* ARGSUSED */ -static void -handle_sigchld(signo) - int signo; -{ - sig_flags |= SF_CHLD; -} - -/* ARGSUSED */ -static void -handle_sigalrm(signo) - int signo; -{ - sig_flags |= SF_ALRM; -} - -/* ARGSUSED */ -static void -handle_sigusr(signo) - int signo; -{ - event_counter = 1; - sig_flags |= SF_USR; -} - - -/* - * enable_intr() - Called from main to set up the signal handlers. - */ - -void -enable_intr() { - int sock_fd = ConnectionNumber(DISP); - struct sigaction a; - - /* Subprocess handling, e.g., MakeTeXPK, fails on the Alpha without - this, because SIGPOLL interrupts the call of system(3), since OSF/1 - doesn't retry interrupted wait calls by default. From code by - maj@cl.cam.ac.uk. */ - a.sa_handler = handle_sigpoll; - (void) sigemptyset(&a.sa_mask); - (void) sigaddset(&a.sa_mask, SIGPOLL); - a.sa_flags = SA_RESTART; - sigaction(SIGPOLL, &a, NULL); - - prep_fd(sock_fd, False); - - a.sa_handler = handle_sigterm; - (void) sigemptyset(&a.sa_mask); - (void) sigaddset(&a.sa_mask, SIGINT); - (void) sigaddset(&a.sa_mask, SIGQUIT); - (void) sigaddset(&a.sa_mask, SIGTERM); - (void) sigaddset(&a.sa_mask, SIGHUP); - a.sa_flags = SA_RESETHAND; - sigaction(SIGINT, &a, NULL); - sigaction(SIGQUIT, &a, NULL); - sigaction(SIGTERM, &a, NULL); - sigaction(SIGHUP, &a, NULL); - - a.sa_handler = handle_sigchld; - (void) sigemptyset(&a.sa_mask); - (void) sigaddset(&a.sa_mask, SIGCHLD); - a.sa_flags = 0; - sigaction(SIGCHLD, &a, NULL); - - a.sa_handler = handle_sigalrm; - (void) sigemptyset(&a.sa_mask); - (void) sigaddset(&a.sa_mask, SIGALRM); - a.sa_flags = 0; - sigaction(SIGALRM, &a, NULL); - - a.sa_handler = handle_sigusr; - (void) sigemptyset(&a.sa_mask); - (void) sigaddset(&a.sa_mask, SIGUSR1); - a.sa_flags = 0; - sigaction(SIGUSR1, &a, NULL); - - (void) sigemptyset(&all_signals); - (void) sigaddset(&all_signals, SIGPOLL); - (void) sigaddset(&all_signals, SIGINT); - (void) sigaddset(&all_signals, SIGQUIT); - (void) sigaddset(&all_signals, SIGTERM); - (void) sigaddset(&all_signals, SIGHUP); - (void) sigaddset(&all_signals, SIGCHLD); - (void) sigaddset(&all_signals, SIGALRM); - (void) sigaddset(&all_signals, SIGUSR1); - -} - - -/* - * Mid-level signal handlers. These are called from within read_events(), - * and do the actual work appropriate for the given signal. - */ - -/* * Process-related routines. Call set_chld() to indicate that a given * child process should be watched for when it terminates. Call * clear_chld() to remove the process from the list. When the child @@ -1833,43 +1641,6 @@ clear_chld(cp) *cpp = cp->next; } -static void -do_sigchld() -{ - pid_t pid; - int status; - - sig_flags &= ~SF_CHLD; - - for (;;) { - pid = waitpid(-1, &status, WNOHANG); - if (pid == 0) break; - - if (pid != -1) { - struct xchild **cpp; - struct xchild *cp; - - for (cpp = &child_recs;;) { - cp = *cpp; - if (cp == NULL) - break; - if (cp->pid == pid) { - *cpp = cp->next; /* unlink it */ - (cp->proc)(status); - break; - } - cpp = &cp->next; - } - break; - } - - if (errno == EINTR) continue; - if (errno == ECHILD) break; - perror("xdvi: waitpid"); - break; - } -} - /* * File-related routines. Call set_io() to indicate that a given fd @@ -1932,122 +1703,8 @@ clear_io(ip) io_dirty = True; } -static void -do_sigpoll() -{ - struct xio *ip; - - sig_flags &= ~SF_POLL; - - if (io_dirty) { - struct pollfd *fp; - - if (num_fds > max_fds) { - if (fds != NULL) free(fds); - fds = xmalloc(num_fds * sizeof *fds); - max_fds = num_fds; - fds->fd = ConnectionNumber(DISP); - fds->events = POLLIN; - } - fp = fds + 1; - for (ip = iorecs; ip != NULL; ip = ip->next) { - fp->fd = ip->fd; - fp->events = ip->xio_events; - ip->pfd = fp; - ++fp; - } - io_dirty = False; - } - - for (;;) { - if (poll(fds + 1, num_fds - 1, 0) >= 0) - break; - - if (errno != EAGAIN && errno != EINTR) { - perror("xdvi: poll"); - return; - } - } - - for (ip = iorecs; ip != NULL; ip = ip->next) { - int revents = ip->pfd->revents; - - if (revents & POLLIN) (ip->read_proc)(); - if (revents & POLLOUT) (ip->write_proc)(); - } -} - - -/* - * Handle SIGUSR1 signal. Pretty straightforward. - */ - -static void -do_sigusr() -{ - sig_flags &= ~SF_USR; - if (dvi_file != NULL) { - Fclose(dvi_file); - dvi_file = NULL; - dvi_file_ready = False; - } - ev_flags |= EV_NEWDOC; -} - - -/* - * Handle termination signals. Kill child processes, if permitted. - * Otherwise, leave it up to the caller. This is the only place where - * the EV_TERM event flag is set, and it can only happen if there's an - * active non-killable process. This should only happen if read_events() - * is called from one of a very few select locations. - */ - -static void -do_sigterm() -{ - struct xchild *cp; - Boolean all_killed = True; - - sig_flags &= ~SF_TERM; - - /* loop through child processes */ - for (cp = child_recs; cp != NULL; cp = cp->next) - if (cp->killable) - kill(cp->pid, SIGKILL); - else - all_killed = False; - - if (all_killed) /* if all processes killed */ - exit(0); - - ev_flags |= EV_TERM; /* otherwise, let the caller handle it */ -} - -/* - * Set the flag so that termination occurs, via the above routine. - * This should be used in place of exit() when there may be a - * non-killable process running (e.g., anytime within read_events()). - */ - -static void -xdvi_normal_exit() -{ - sig_flags |= SF_TERM; -} - /* - * Since redrawing the screen is (potentially) a slow task, xdvi checks - * for incoming events while this is occurring. It does not register - * a work proc that draws and returns every so often, as the toolkit - * documentation suggests. Instead, it checks for events periodically - * (or not, if SIGPOLL can be used instead) and processes them in - * a subroutine called by the page drawing routine. This routine (below) - * checks to see if anything has happened and processes those events and - * signals. (Or, if it is called when there is no redrawing that needs - * to be done, it blocks until something happens.) - * * Ultimately, the goal is to have this be the only place in xdvi where * blocking occurs. * @@ -2059,123 +1716,26 @@ xdvi_normal_exit() */ unsigned int -read_events(ret_mask) - unsigned int ret_mask; +read_events(unsigned int ret_mask) { XEvent event; - for (;;) { - event_counter = event_freq; - /* - * The above line clears the flag indicating that an event is - * pending. So if an event comes in right now, the flag will be - * set again needlessly, but we just end up making an extra call. - * Also, be careful about destroying the magnifying glass while - * drawing on it. - */ - - if (event_freq < 0) { /* if SIGPOLL works */ - - if (!XtPending()) { - sigset_t oldsig; - - (void) sigprocmask(SIG_BLOCK, &all_signals, &oldsig); - for (;;) { - while (sig_flags) - flags_to_sigproc[sig_flags](); - - if (XtPending()) - break; - - if (ev_flags & ret_mask) { - (void) sigprocmask(SIG_SETMASK, &oldsig, - (sigset_t *) NULL); - return ev_flags; - } - (void) sigsuspend(&oldsig); - } - (void) sigprocmask(SIG_SETMASK, &oldsig, (sigset_t *) NULL); - } - } - else - { - for (;;) { - struct xio *ip; - - while (sig_flags) { - sigset_t oldsig; - - (void) sigprocmask(SIG_BLOCK, &all_signals, &oldsig); - - while (sig_flags) - flags_to_sigproc[sig_flags](); + for(;;) { - (void) sigprocmask(SIG_SETMASK, &oldsig, - (sigset_t *) NULL); - } - - if (XtPending()) - break; - - if (ev_flags & ret_mask) + if (!XtPending() && (ev_flags & ret_mask)) return ev_flags; - /* If a SIGUSR1 signal comes right now, then it will wait - until an X event or another SIGUSR1 signal arrives. */ - - if (io_dirty) { - struct pollfd *fp; - - if (num_fds > max_fds) { - if (fds != NULL) free(fds); - fds = xmalloc(num_fds * sizeof *fds); - max_fds = num_fds; - fds->fd = ConnectionNumber(DISP); - fds->events = POLLIN; - } - fp = fds + 1; - for (ip = iorecs; ip != NULL; ip = ip->next) { - fp->fd = ip->fd; - fp->events = ip->xio_events; - ip->pfd = fp; - ++fp; - } - io_dirty = False; - } + XtNextEvent(&event); - for (;;) { - if (poll(fds, num_fds, -1) >= 0) { - for (ip = iorecs; ip != NULL; ip = ip->next) { - int revents = ip->pfd->revents; - - if (revents & POLLIN) (ip->read_proc)(); - if (revents & POLLOUT) (ip->write_proc)(); - } - break; - } - - if (errno == EINTR) - break; - - if (errno != EAGAIN) { - perror("xdvi: poll"); - break; - } - } + if (resized) + get_geom(); + if (event.xany.window == alt.win && event.type == Expose) { + handle_expose((Widget) NULL, (XtPointer) &alt, &event, + (Boolean *) NULL); + continue; } - } - - - XtNextEvent(&event); - if (resized) get_geom(); - if (event.xany.window == alt.win && event.type == Expose) { - handle_expose((Widget) NULL, (XtPointer) &alt, &event, - (Boolean *) NULL); - continue; - } - (void) XtDispatchEvent(&event); - + XtDispatchEvent(&event); } } diff --git a/events.h b/events.h @@ -81,11 +81,9 @@ extern struct WindowRec mane, alt, currwin; #define EV_NOWAIT EV_GE_IDLE unsigned int ev_flags = EV_IDLE; -volatile int event_counter = 0; Bool compile_action(const char *, struct xdvi_action **); -void expose(struct WindowRec *, int, int, unsigned int, unsigned int); void do_color_change(void); void do_pages(void) __attribute__((__noreturn__)); void enable_intr(void); diff --git a/special.c b/special.c @@ -1181,7 +1181,6 @@ color_special(cp) scanned_page = scanned_page_color = scanned_page_reset = -1; ev_flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(canit_env, 1); } return; } @@ -1362,7 +1361,6 @@ applicationDoSpecial(cp) scanned_page = scanned_page_color = scanned_page_reset = -1; ev_flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(canit_env, 1); } return; } @@ -1374,7 +1372,6 @@ applicationDoSpecial(cp) scanned_page_color = scanned_page_reset = -1; ev_flags |= EV_NEWPAGE; /* force a redraw */ - longjmp(canit_env, 1); } return; } diff --git a/special.h b/special.h @@ -1,9 +1,5 @@ -#include <setjmp.h> - #include "data.h" /* struct rgb */ -jmp_buf canit_env; - /* * Used by the geometry-scanning routines. * It passes pointers to routines to be called at certain @@ -13,7 +9,6 @@ jmp_buf canit_env; struct geom_info { void (*geom_box) (struct geom_info *, long, long, long, long); void (*geom_special) (struct geom_info *, const char *); - jmp_buf done_env; void *geom_data; }; diff --git a/wdvi.1 b/wdvi.1 @@ -1012,14 +1012,6 @@ package, and the environment in the .B framed La\*(Te\&2e package. -.SH SIGNALS -When -.B wdvi -receives a -.SB SIGUSR1 -signal, it rereads the -.I dvi -file. .SH ENVIRONMENT .TP .SB DISPLAY diff --git a/xdvi.c b/xdvi.c @@ -81,7 +81,7 @@ NOTE: #include "default.h" /* default_dvi, default_dvi_len */ #include "dvi-init.h" /* init_dvi_file(), init_page() */ #include "dvi-draw.h" /* prescan() */ -#include "events.h" /* enable_intr(), compile_action(), ... */ +#include "events.h" /* compile_action(), ... */ #include "font-open.h" /* init_font_open() */ #include "util.h" /* xmalloc(), memicmp() */ #include "version.h" @@ -873,8 +873,6 @@ main(int argc, char **argv) if (visual->class != TrueColor) errx(1, "X visual not 'TrueColor' is not supported."); - enable_intr(); - /* * The default document is always available and simplifies startup * by giving inital window sizes and no error popups. @@ -883,7 +881,7 @@ main(int argc, char **argv) err(1, "fmemopen"); dvi_name = "default.dvi"; ev_flags |= EV_NEWDOC; - (void) read_events(EV_GE_NEWDOC); + read_events(EV_GE_NEWDOC); ev_flags &= ~EV_NEWDOC; if (resource.mfmode != NULL) {