I found it. It is due to a race condition in the Xt timeout code. This
condition is triggered more easily in the D&D code as there only Xt
events are processed not XEmacs ones. Basically there too many ques
involved. The NT people need to look at there code whether they copied
the bug.
Don't ya love race conditions?
Jan
The scenario:
1. A timeout/wakeup gets setup and put on 'pending_timeouts' and
'pending_timeout_list'.
2. The Xt_timeout_call back function is called. This does NOT generate
a timeout event directly but moves the timeout from
pending_timeouts to completed_timeouts.
3. Xemacs calls event_stream_disable_wakeup this removes the id from
'pending_timeout_list' and calls Xt_remove_timeout.
4. Xt_remove_timeout scans pending_timeouts, finds nothing and
returns.
5. time passes.
6. The event code starts converting all completed_timeouts into Emacs
events and crashes in event_stream_signal_wakup because the
timeout can no longer be found in pending_timeout_list.
The fix:
Make Xt_remove_timeout also remove the timeout from the completed list
for Emacs it is as if the timeout never happened.
The recipe:
Eval
(defun plokker (&rest r)
(message "plok"))
(add-hook 'post-command-hook
(lambda () (start-itimer "plok" 'plokker 1 nil t)))
((lambda nil (start-itimer "plok" (quote plokker) 1 nil t)))
and start dragging from XEmacs to XEmacs.
The bug at work:
Allocated: 36 /* Timer 36 is allocated */
InList 36 /* Put in pending_time_out_list */
Called back: 36 /* callback is called for it ->
completed_timouts */
Unlist 36 /* disable wakeup, remove from pending_timeout_lis
Preremove 36 (Pending 1) /* Xt_remove_timeout,
1 = !pending_timouts, do nothing
Normal sequence (no callback in between)
Allocated: 37
InList 37
Unlist 37
Preremove 37 (Pending 0) /* pending timeouts nonempty
Removed: 4377440 /* Now the timeout is removed
Allocated: 38
InList 38
Completed: 36 /* Converting completed_timouts in events */
Looking up: 36 (0) /* Lookup in resignal_wakeup */
Fatal error: assertion failed, file event-stream.c, line 1214, !NILP (rest)
The Changelog:
1998-06-18 Jan Vroonhof <vroonhof(a)math.ethz.ch>
* event-Xt.c (emacs_Xt_remove_timeout): Also remove timeout from
completed_timeouts. The timer could have expired.
The Patch:
Index: event-Xt.c
===================================================================
RCS file: /usr/CVSroot/XEmacs/xemacs-20/src/event-Xt.c,v
retrieving revision 1.40
diff -u -u -r1.40 event-Xt.c
--- event-Xt.c 1998/05/14 04:46:24 1.40
+++ event-Xt.c 1998/06/18 20:23:58
@@ -1685,28 +1685,58 @@
{
struct Xt_timeout *timeout, *t2;
+ timeout = NULL;
+
/* Find the timeout on the list of pending ones, if it's still there. */
- if (!pending_timeouts) return;
- if (id == pending_timeouts->id)
+ if (pending_timeouts)
{
- timeout = pending_timeouts;
- pending_timeouts = pending_timeouts->next;
+ if (id == pending_timeouts->id)
+ {
+ timeout = pending_timeouts;
+ pending_timeouts = pending_timeouts->next;
+ }
+ else
+ {
+ t2 = pending_timeouts;
+ while (t2->next && t2->next->id != id) t2 = t2->next;
+ if ( t2->next) /*found it */
+ {
+ timeout = t2->next;
+ t2->next = t2->next->next;
+ }
+ }
+ /* if it was pending, we have removed it from the list */
+ if (timeout)
+ XtRemoveTimeOut (timeout->interval_id);
}
- else
+
+ /* It could be that the Xt call back was already called but we didn't convert
+ into an Emacs event yet */
+ if (!timeout && completed_timeouts)
{
- t2 = pending_timeouts;
- while (t2->next && t2->next->id != id) t2 = t2->next;
- if (! t2->next) return;
- timeout = t2->next;
- t2->next = t2->next->next;
+ /* Code duplication! */
+ if (id == completed_timeouts->id)
+ {
+ timeout = completed_timeouts;
+ completed_timeouts = completed_timeouts->next;
+ }
+ else
+ {
+ t2 = completed_timeouts;
+ while (t2->next && t2->next->id != id) t2 = t2->next;
+ if ( t2->next) /*found it */
+ {
+ timeout = t2->next;
+ t2->next = t2->next->next;
+ }
+ }
}
- /* At this point, we've found the thing on the list of pending timeouts,
- and removed it.
- */
-
- XtRemoveTimeOut (timeout->interval_id);
- Blocktype_free (the_Xt_timeout_blocktype, timeout);
+ /* If we found the thing on the lists of timeouts,
+ and removed it, deallocate
+ */
+ if (timeout)
+ Blocktype_free (the_Xt_timeout_blocktype, timeout);
}
static void
Show replies by date