(resent from xemacs-patches)
Try this with your XEmacs:
* start a console XEmacs using `xemacs -nw';
* create an X frame using `M-x make-frame-on-display RET DISPLAY RET';
* close the X frame using the X "kill" facility.
For me, XEmacs exits without printing anything, instead of just
shutting down the X frame. This is, of course, a manifestation of the
infamous "XEmacs-dies-along-with-the-X-server" syndrome. Fiddling
with `x-seppuku-on-epipe', the only related variable, makes XEmacs
exit even sooner, all without proper autosaving. In fact, setting
`x-seppuku-on-epipe' is "required" on some systems because not using
it confuses the hell out of Xlib.
Problem summary: when XEmacs loses connection to the X server,
x_IO_error_handler() is called. The function enqueues an event to
wipe out the offending console at an appropriate time, and returns.
The "returns" part is wrong, because it either confuses Xlib, or makes
it exit right away or when the next X event is processed.
The right solution is for x_IO_error_handler to throw to top level
without ever returning to Xlib. However, this leaves the (very real)
possibility of bogus X events sitting in the Xt event queue and
crashing XEmacs at the first opportunity. Because of this,
x_IO_error_handler() needs to set a device->being_deleted flag, and
the functions in event-Xt.c that handle raw X events need to check the
flag and ignore the events coming from devices on which it is set.
This obviates the need for `x-seppuku-on-epipe'.
This wisdom is the result of a two-day investigation followed by an
email/voice discussion with Ben. Eventually I've written the patch
below, to be applied to 21.1 (the patch is applicable to 21.0, but
this is far from "critical bugfix"). I would like gnuclient users to
apply the patch and let me know if it fixes the
XEmacs-dies-along-with-the-X-server problem.
1998-08-28 Hrvoje Niksic <hniksic(a)srce.hr>
* event-Xt.c (emacs_Xt_mapping_action): Check for device being
deleted.
(x_event_to_emacs_event): Ditto.
(emacs_Xt_handle_focus_event): Ditto.
(emacs_Xt_handle_magic_event): Ditto.
* console-x.h (struct x_device): New flag being_deleted.
(DEVICE_X_BEING_DELETED): New macro.
* device-x.c (x_IO_error_handler): Throw to top-level instead of
returning. Before doing that, set the being_deleted flag on the
device.
1998-08-27 Hrvoje Niksic <hniksic(a)srce.hr>
* device-x.c (x-seppuku-on-epipe): Removed.
--- src/device-x.c.orig Wed Aug 26 20:27:44 1998
+++ src/device-x.c Fri Aug 28 04:23:56 1998
@@ -62,9 +62,6 @@
Lisp_Object Qx_error;
Lisp_Object Qinit_pre_x_win, Qinit_post_x_win;
-/* $B@ZJ"(B, n. Japanese ritual suicide. */
-int x_seppuku_on_epipe;
-
/* The application class of Emacs. */
Lisp_Object Vx_emacs_application_class;
@@ -880,10 +877,8 @@
Lisp_Object dev;
struct device *d = get_device_from_display_1 (disp);
- if (d)
- XSETDEVICE (dev, d);
- else
- dev = Qnil;
+ assert (d != NULL);
+ XSETDEVICE (dev, d);
if (NILP (find_nonminibuffer_frame_not_on_device (dev)))
{
@@ -903,31 +898,24 @@
{
warn_when_safe
(Qx, Qcritical,
- "I/O Error %d (%s) on display connection \"%s\"\n"
- " after %lu requests (%lu known processed) with "
- "%d events remaining.\n",
+ "I/O Error %d (%s) on display connection\n"
+ " \"%s\" after after %lu requests (%lu known processed)\n"
+ " with %d events remaining.\n"
+ " Throwing to top level.\n",
errno, strerror (errno), DisplayString (disp),
NextRequest (disp) - 1, LastKnownRequestProcessed (disp),
QLength (disp));
}
+ /* According to X specs, we should not return from this function, or
+ Xlib might just decide to exit(). So we mark the offending
+ console for deletion and throw to top level. */
if (d)
enqueue_magic_eval_event (io_error_delete_device, dev);
+ DEVICE_X_BEING_DELETED (d) = 1;
+ Fthrow (Qtop_level, Qnil);
- /* CvE, July 16, 1996, XEmacs 19.14 */
- /* Test for broken pipe error, which indicates X-server has gone down */
- if (errno == EPIPE && x_seppuku_on_epipe)
- {
- /* Most probably X-server has gone down: Avoid infinite loop by just */
- /* exiting */
- /* slb: This sounds really, really dangerous to do by default, so */
- /* I'm adding a guard to avoid doing this as default behavior */
- stderr_out( "\n\nXEmacs exiting on broken pipe (errno %d, %s)\n",
- errno, strerror(errno));
- exit(errno);
- }
-
- return 0;
+ RETURN_NOT_REACHED (0);
}
DEFUN ("x-debug-mode", Fx_debug_mode, 1, 2, 0, /*
@@ -1733,14 +1721,6 @@
just reside in C.
*/ );
Vx_initial_argv_list = Qnil;
-
- DEFVAR_BOOL ("x-seppuku-on-epipe", &x_seppuku_on_epipe /*
-When non-nil, terminate XEmacs immediately on SIGPIPE from the X server.
-XEmacs doesn't terminate properly on some systems.
-When this variable is non-nil, XEmacs will commit immediate suicide
-when it gets a sigpipe from the X Server.
-*/ );
- x_seppuku_on_epipe = 0;
#if defined(MULE) && (defined(LWLIB_MENUBARS_MOTIF) || defined(HAVE_XIM) || defined (USE_XFONTSET))
DEFVAR_LISP ("x-app-defaults-directory", &Vx_app_defaults_directory /*
--- src/device.c.orig Fri Aug 28 03:42:11 1998
+++ src/device.c Fri Aug 28 03:42:12 1998
@@ -817,6 +817,9 @@
void
io_error_delete_device (Lisp_Object device)
{
+ /* Note: it's the console that should get deleted, but
+ delete_device_internal() contains a hack that also deletes the
+ console when called from this function. */
delete_device_internal (XDEVICE (device), 1, 0, 1);
}
--- src/console-x.h.orig Fri Aug 28 03:44:44 1998
+++ src/console-x.h Fri Aug 28 03:49:21 1998
@@ -70,6 +70,9 @@
/* The X connection of this device. */
Display *display;
+ /* Set by x_IO_error_handler(). */
+ int being_deleted;
+
/* Xt application info. */
Widget Xt_app_shell;
@@ -184,6 +187,7 @@
#define FRAME_X_DISPLAY(f) (DEVICE_X_DISPLAY (XDEVICE (f->device)))
#define DEVICE_X_DISPLAY(d) (DEVICE_X_DATA (d)->display)
+#define DEVICE_X_BEING_DELETED(d) (DEVICE_X_DATA (d)->being_deleted)
#define DEVICE_X_VISUAL(d) (DEVICE_X_DATA (d)->visual)
#define DEVICE_X_DEPTH(d) (DEVICE_X_DATA (d)->depth)
#define DEVICE_X_COLORMAP(d) (DEVICE_X_DATA (d)->device_cmap)
--- src/event-Xt.c.orig Fri Aug 28 03:53:15 1998
+++ src/event-Xt.c Fri Aug 28 03:56:52 1998
@@ -658,6 +658,9 @@
emacs_Xt_mapping_action (Widget w, XEvent* event)
{
struct device *d = get_device_from_display (event->xany.display);
+
+ if (DEVICE_X_BEING_DELETED (d))
+ return;
#if 0
/* nyet. Now this is handled by Xt. */
XRefreshKeyboardMapping (&event->xmapping);
@@ -923,6 +926,10 @@
struct device *d = get_device_from_display (display);
struct x_device *xd = DEVICE_X_DATA (d);
+ if (DEVICE_X_BEING_DELETED (d))
+ /* #### Uh, is this 0 correct? */
+ return 0;
+
set_last_server_timestamp (d, x_event);
switch (x_event->type)
@@ -1335,14 +1342,17 @@
void
emacs_Xt_handle_focus_event (XEvent *event)
{
+ struct device *d = get_device_from_display (event->xany.display);
+ struct frame *f;
+
+ if (DEVICE_X_BEING_DELETED (d))
+ return;
+
/*
* It's curious that we're using x_any_window_to_frame() instead
* of x_window_to_frame(). I don't know what the impact of this is.
*/
-
- struct frame *f =
- x_any_window_to_frame (get_device_from_display (event->xany.display),
- event->xfocus.window);
+ f = x_any_window_to_frame (d, event->xfocus.window);
if (!f)
/* focus events are sometimes generated just before
a frame is destroyed. */
@@ -1509,7 +1519,7 @@
XEvent *event = &emacs_event->event.magic.underlying_x_event;
struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
- if (!FRAME_LIVE_P (f))
+ if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
return;
switch (event->type)
--
Hrvoje Niksic <hniksic(a)srce.hr> | Student at FER Zagreb, Croatia
--------------------------------+--------------------------------
"Silence!" cries Freydag. "I did not call thee in for a consultation!"
"They are my innards! I will not have them misread by a poseur!"