help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Help-smalltalk] non-blocking pipe read issue


From: Derek Zhou
Subject: [Help-smalltalk] non-blocking pipe read issue
Date: Thu, 2 Feb 2012 04:02:36 -0800
User-agent: Mutt/1.5.20 (2009-06-14)

Hi all,
I think there is a bug in the async reading of a pipe. Here is a example:
mkfifo a2b
mkfifo b2a
a.st:

f1 := File name: 'a2b'.
f2 := File name: 'b2a'.
aWriter := f1 writeStream.
bReader := f2 readStream.
counter := 0.
[
    aWriter nextPutAll: 'hello'; nl.
    aWriter flush.
    bReader nextLine.
    counter := counter + 1.
    (counter \\ 10000) = 0 ifTrue: [
    Transcript nextPutAll: '%1 times' % {counter}; nl ] ] repeat.

b.st:

f1 := File name: 'a2b'.
f2 := File name: 'b2a'.
aReader := f1 readStream.
bWriter := f2 writeStream.
counter := 0.
[
    aReader nextLine.
    bWriter nextPutAll: 'hello'; nl.
    bWriter flush.
    counter := counter + 1.
    (counter \\ 10000) = 0 ifTrue: [
    Transcript nextPutAll: '%1 times' % {counter}; nl ] ] repeat.

If I run the 2 scripts in 2 windows they will hang after a short
while. and sending them SIGIO will unblock them. The test is done in gst 3.2.4.

The work around is to override isPipe in FileDescriptor so it always return 
false then the problem goes away. Obviously that totally disable async IO
behavior so IO will block the whole gst.

My theory:
gst try hard not to do blocking io. so for pipe it first poll it, if there is 
no data it will setup sigio and suspend. However, if data come in after poll 
return but before the sigsuspend, it will hang. 

libgst/sysdep/posix/events.c:

RETSIGTYPE
file_polling_handler (int sig)
{
  if (num_used_pollfds > 0)
    {
      _gst_disable_interrupts (true);
      _gst_async_call (async_signal_polled_files, NULL);
      _gst_enable_interrupts (true);
    }

  _gst_set_signal_handler (sig, file_polling_handler);
  _gst_wakeup ();
}

...
  set_file_interrupt (fd, file_polling_handler);

  /* Now check if I/O was made possible while setting up our machinery...
     If so, exit; otherwise, wait on the semaphore and the SIGIO
     will wake us up.  */

  result = _gst_sync_file_polling (fd, cond);
  if (result == 0)
    {
      if (!head)
        head = new;
      else
        *p_tail_next = new;
      p_tail_next = &new->next;

      num_used_pollfds++;
      _gst_register_oop (semaphoreOOP);
      _gst_sync_wait (semaphoreOOP);
    }
  else
    xfree (new);
...

Although it does a second poll after the sig handler setup trying to catch 
this possibility, the data could still come in after the second poll but 
before the _gst_sync_wait. The sig handler will trigger but it does not 
prevent the process going to sleep.

>From the look of it the problem is not limited to pipes, the same could
happen to sockets as well.

Possible fixes:
* block SIGIO until the process is really asleep in an atomic operation.
However I don't know how. 
 
I hate signals. 

Derek




reply via email to

[Prev in Thread] Current Thread [Next in Thread]