I have a problem mixing Gambit C's process ports and Xlib. I got this problem in version 4 beta 20, but could still reproduce it in a freshly built v4.1.2. I thought I'd bounce it here just to make sure I haven't missed something obvious, before submitting a bug report.
The reproduction steps are:
- Write an app that
- Opens a child process with default arguments (only the path).
- In the child process,
- prints something to (current-error-port).
- write-u8 some data to standard output (i.e., back to the main process).
- Execute that app from an X terminal.
- Close the app window.
- Try to type stuff in the X terminal.
What you type after that is not displayed in the terminal. Your input is recognized and processed by the terminal, but you can't see it.
I could reproduce this in two Debian Linux boxes with different (NVidia vs ATI) proprietary X servers. To make sure this is a problem with Gambit and not Xlib, I have made an (I believe) equivalent pure C program, which doesn't misbehave.
I could not reproduce this without involving X Windows. The error does still happen if the X Windows app exits gracefully (i.e., by advertising WM_DELETE_WINDOW protocol and closing the window on receipt of the appropriate ClientMessage,) but only if you print to standard error before opening the window or while it is live. The error doesn't happen if you print to standard error only after closing the window, just before exiting the process.
Here is the minimal Gambit program that I could find that will display the error:
--- main.scm ---
(let ((p (open-process "./child")))
(letrec
((loop
(lambda ()
(let ((evt-type (read-u8 p)))
(display "got ")
(display evt-type)
(newline)
(if (eqv? evt-type #!eof)
(void)
(loop))))))
(loop)))
(display "Main says bye!")
(newline)
--- child.scm ---
(c-declare #<<c-declare-end
#include <X11/Xlib.h>
Display* dpy;
int scr;
Window win;
XEvent event;
c-declare-end
)
(define open-window
(c-lambda () unsigned-long #<<c-lambda-end
dpy = XOpenDisplay(NULL);
scr = DefaultScreen(dpy);
win = XCreateSimpleWindow(dpy,
RootWindow(dpy, scr),
0, 0,
300, 300,
0,
BlackPixel(dpy, scr),
WhitePixel(dpy, scr));
XSelectInput(dpy,
win,
ExposureMask | ButtonPressMask | StructureNotifyMask);
XMapWindow(dpy, win);
___result = win;
c-lambda-end
))
(define next-event
(c-lambda () int #<<c-lambda-end
XNextEvent(dpy, &event);
___result = event.type;
c-lambda-end
))
;; !!! If you comment out the following lines, !!!
;; !!! the error doesn't happen. !!!
(display "Child says hello!" (current-error-port))
(newline (current-error-port))
(open-window)
(letrec
((loop
(lambda ()
(write-u8 (next-event))
(force-output)
(loop))))
(loop))
--- to test the above ---
#!/usr/bin/env sh
gsc -link child.scm && \
gcc -lX11 -lgambc child.c child_.c -o child && \
gsi main.scm
The following is the equivalent C program that doesn't misbehave (if you try it put it in a separate directory):
--- main.c ---
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
FILE* fp;
int evt;
fp = popen("./child", "r");
do {
evt = getc(fp);
printf("got %d\n", evt);
} while (evt != -1);
printf("Main says bye!\n");
return 0;
}
--- child.c ---
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
int main(int argc, char** argv) {
Display* dpy;
int scr;
Window win;
XEvent event;
fprintf(stderr, "Here we go!\n");
dpy = XOpenDisplay(NULL);
scr = DefaultScreen(dpy);
win = XCreateSimpleWindow(dpy,
RootWindow(dpy, scr),
0, 0,
300, 300,
0,
BlackPixel(dpy, scr),
WhitePixel(dpy, scr));
XSelectInput(dpy,
win,
ExposureMask | ButtonPressMask | StructureNotifyMask);
XMapWindow(dpy, win);
for (;;) {
XNextEvent(dpy, &event);
putchar(event.type);
fflush(stdout);
}
return 0;
}
--- to test the above ---
#!/usr/bin/env sh
gcc main.c -o main && \
gcc -lX11 child.c -o child && \
./main
Regards,
Esteban.