diff options
Diffstat (limited to 'xc/test/xsuite/xtest/src/lib/block.c')
-rw-r--r-- | xc/test/xsuite/xtest/src/lib/block.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/xc/test/xsuite/xtest/src/lib/block.c b/xc/test/xsuite/xtest/src/lib/block.c new file mode 100644 index 000000000..f197cf912 --- /dev/null +++ b/xc/test/xsuite/xtest/src/lib/block.c @@ -0,0 +1,277 @@ +/* + * Copyright 1990, 1991 by the Massachusetts Institute of Technology and + * UniSoft Group Limited. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the names of MIT and UniSoft not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. MIT and UniSoft + * make no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * $XConsortium$ + */ + +#include "xtest.h" +#include "Xlib.h" +#include "Xutil.h" +#include "xtestlib.h" +#include "tet_api.h" +#include <setjmp.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> + +/* + * Possible child exit codes + */ +#define CHILD_EXIT_BLOCKING 0 +#define CHILD_EXIT_NOBLOCKING 1 +#define CHILD_EXIT_ERROR 2 + +/* + * passed as validresults argument to tet_fork + */ +#define CHILD_EXIT_MASK 0x3 + +/* + * how long child waits before generating event + */ +#define CHILD_SLEEP_TIME (5+(10*config.speedfactor)) + +/* + * how long parent waits before timing out + */ +#define TIMEOUT_TIME (30+(10*config.speedfactor)) + +static char block_file[] = BLOCK_FILE; +static jmp_buf jumptohere; + +/* + * Global variables corresponding to block() arguments. + * These are set by block() so that block_parent_proc() can access them. + */ +static Display *gdisplay; +static XEvent *gevent; +static Block_Info *ginfo; + +/* + * Status variable used to track problems encountered in block_parent_proc() + */ +static int parent_status; + +static void block_child_proc(); +static void block_parent_proc(); +static int blocker(); + +/* + * Used to test whether or not a procedure blocks. If event is NULL, + * then it is assumed that the delivery of any event is sufficient + * to unblock procedure. See block.man for more details. + */ +Status +block(display, event, info) +Display *display; +XEvent *event; +Block_Info *info; +{ + FILE *fp; + int exit_status; + + gdisplay = display; + gevent = event; + ginfo = info; + if (config.speedfactor < 1) { + delete("Unsupported speedfactor value: %d", config.speedfactor); + return(-1); + } + fp = fopen(block_file, "w"); + if (fp == (FILE *) NULL) { + delete("Could not create block file: %s", block_file); + return(-1); + } + if (setjmp(jumptohere)) { + delete("Timeout in block routine"); + (void) unlink(block_file); + return(-1); + } + parent_status = 1; + exit_status = tet_fork(block_child_proc, block_parent_proc, 0, CHILD_EXIT_MASK); + /* + * try removing block file just in case it still exists... + */ + (void) unlink(block_file); + /* + * check for problems in block_parent_proc + */ + if (parent_status == -1) + return(-1); + /* + * verify that we got the expected event + * do not verify for types with Ignore_Event_Return set + */ + if (!(info->p_type & Ignore_Event_Return)) { + if (event == (XEvent *) NULL) { + if (info->event_return.type != MappingNotify) { + delete("Unexpected event type: %s", eventname(info->event_return.type)); + return(-1); + } + } + else { + int err = 0; + +#define ER ((XAnyEvent *)(&(info->event_return))) +#define ES ((XAnyEvent *)event) + if (ER->type != ES->type) { + delete("expected %s, got %s", eventname(ES->type), eventname(ER->type)); + err++; + } + if (ER->send_event != True) { + delete("send_event not se in returned event"); + err++; + } + if (ER->window != ES->window) { + delete("wrong window, expected %d, got %d", ES->window, ER->window); + err++; + } + if (err) + return(-1); + } + } + switch (exit_status) { + default: + case CHILD_EXIT_ERROR: + delete("Error return from block's child"); + return(-1); + case CHILD_EXIT_BLOCKING: + return(1); + case CHILD_EXIT_NOBLOCKING: + return(0); + } + /*NOTREACHED*/ +} + +/*ARGSUSED*/ +static void +block_alarm(sig) +int sig; +{ + longjmp(jumptohere, 1); +} + +/* + * block_child_proc + */ +static void +block_child_proc() +{ + Display *display; + XAnyEvent *event = (XAnyEvent *) gevent; + + display = opendisplay(); + if (display == (Display *) NULL) + exit(CHILD_EXIT_ERROR); + sleep(CHILD_SLEEP_TIME); + if (access(block_file, F_OK)) + exit(CHILD_EXIT_NOBLOCKING); + if (gevent == (XEvent *) NULL) { + int retval; + unsigned char buf[512]; + + retval = XGetPointerMapping(display, buf, sizeof(buf)); + if (XSetPointerMapping(display, buf, retval) != MappingSuccess) + exit(CHILD_EXIT_ERROR); + } + else if (!XSendEvent(display, event->window, False, NoEventMask, gevent)) + exit(CHILD_EXIT_ERROR); + XCloseDisplay(display); + exit(CHILD_EXIT_BLOCKING); +} + +static void +block_parent_proc() +{ + (void) signal(SIGALRM, block_alarm); + alarm(TIMEOUT_TIME); + parent_status = blocker(gdisplay, ginfo); + alarm(0); + if (parent_status == -1) + return; + if (access(block_file, F_OK)) { + delete("Block file mysteriously disappeared: %s", block_file); + parent_status = -1; + return; + } + if (unlink(block_file)) { + /* + * return value of unlink() does not always indicate + * whether or not the file was removed...pc + */ + if (!access(block_file, F_OK)) { + delete("Block file could not be removed: %s", block_file); + parent_status = -1; + return; + } + } +} + +/* + * invoke the procedure which is being tested for blocking + * + * returns -1 on unexpected error + */ +static int +blocker(display, info) +Display *display; +Block_Info *info; +{ + _startcall(display); + if (isdeleted()) + return(-1); + switch (info->p_type) { + default: + delete("Unrecognized argument type in block: %x", info->p_type); + return(-1); + case XEventsQueued_Like: + info->int_return = (*(info->XEventsQueued_Like_Proc)) + (display, + info->XEventsQueued_Args.mode); + break; + case XPending_Like: + info->int_return = (*(info->XPending_Like_Proc)) + (display); + break; + case XIfEvent_Like: + case XPeekIfEvent_Like: + (*(info->XIfEvent_Like_Proc)) + (display, + &(info->event_return), + info->XIfEvent_Args.predicate, + info->XIfEvent_Args.arg); + break; + case XMaskEvent_Like: + (*(info->XMaskEvent_Like_Proc)) + (display, + info->XMaskEvent_Args.event_mask, + &(info->event_return)); + break; + case XNextEvent_Like: + case XPeekEvent_Like: + (*(info->XNextEvent_Like_Proc)) + (display, + &(info->event_return)); + break; + case XWindowEvent_Like: + (*(info->XWindowEvent_Like_Proc)) + (display, + info->XWindowEvent_Args.w, + info->XWindowEvent_Args.event_mask, + &(info->event_return)); + break; + } + _endcall(display); + return(0); +} |