Comment 11 for bug 291373

Revision history for this message
Dominique Pellé (dominique-pelle) wrote :

Thanks for the stack traces. That looks very useful.

I've been able to reproduce this bug only twice so far. It's very rare on
my machine but it did happen.

From your stack trace, I suppose that we can't assume that kill(0, SIGTSTP);
is handled immediately (i.e. it's asynchronous) even though signal is sent to
ouselves. So if the signal is handled after if (!sigcont_received) but before pause();
then we call pause() and we then wait for a signal that will never come anymore
(which would hangs vim until we press CTRL-C.

If so, we should not call pause() here. Yielding the CPU (sleep(0)) should
be enough to have the signal handled when process is rescheduled since
we sent it to ourselves.

Can anybody confirm that the following patch fixes to bug? It works for me
but since bug was very hard to reproduce on my machine it would be
interesting to get feedback for other people, especially on Solaris since old
code had a comment for Solaris.

Index: os_unix.c
===================================================================
RCS file: /cvsroot/vim/vim7/src/os_unix.c,v
retrieving revision 1.90
diff -c -r1.90 os_unix.c
*** os_unix.c 22 Feb 2009 01:52:46 -0000 1.90
--- os_unix.c 22 Feb 2009 14:05:50 -0000
***************
*** 1122,1133 ****
      sigcont_received = FALSE;
  # endif
      kill(0, SIGTSTP); /* send ourselves a STOP signal */
! # ifdef _REENTRANT
! /* When we didn't suspend immediately in the kill(), do it now. Happens
! * on multi-threaded Solaris. */
! if (!sigcont_received)
! pause();
! # endif

  # ifdef FEAT_TITLE
      /*
--- 1122,1144 ----
      sigcont_received = FALSE;
  # endif
      kill(0, SIGTSTP); /* send ourselves a STOP signal */
! /*
! * Wait for the STOP signal to be handled. It generally happens
! * immediately since signal is sent to ourselves, but somehow not
! * all the time. Do not call pause() because there would be race
! * condition which would hang Vim if signal happened in between the
! * test of sigcont_received and the call to pause(). If signal is
! * not yet received, call sleep(0) to just yield CPU. Signal should
! * then be received. If still not received, sleep 1, 2, 3 ms.
! * Don't bother waiting further if signal is not received after
! * 1+2+3+4 ms.
! */
! {
! long wait;
! for (wait = 0; !sigcont_received && wait <= 3L; wait++)
! /* Loop is not entered most of the time */
! mch_delay(wait, FALSE);
! }

  # ifdef FEAT_TITLE
      /*