Can you undo change in sig_dispatch_pending() ?

Oleg Volkov oleg@unicorn.kiev.ua
Thu Nov 1 15:26:00 GMT 2007


Christopher Faylor wrote:

> However, if you think that this check can be put back then it seems like
> the next logical step is to remove the sig_dispatch_pending from readv
> and writev.

Perhaps subsequent steps will be to remove sig_dispatch_pending() from
other syscalls. It doesn't seem to me these steps are logical.

> If you have tests for this then you can either try removing the
> sig_dispatch_pending entirely and see how that works or you can generate
> data showing how often the sigq.start.next test is triggered and report
> the results here.
>
>> I'd like to understand what you meant by that more.  Did you mean how
>> often does it avoid the needless thread ping pong, or how often does it
>> actually invoke it?  I assume the latter as the performance data clearly
>> indicates the former is very frequent.
>
> I mean how many times
>
>   if (!sigq.next)
>      return;
>
>  /* this code */
>
> is executed.

I have prepared a test, which shows that `sigq.start.next' can be zero and
non-zero when sig_dispatch_pending() is called from writev(). This test is
for cygwin1.dll version 1.5.24-2. To run this test you first need to ensure
that DEBUGGING macro is defined, modify the line in sig_dispatch_pending(),
so `sigq.start.next' will be checked:

  if (exit_state || &_my_tls == _sig_tls || !sigq.start.next)

and add the following line in writev() before the call to
sig_dispatch_pending():

  syscall_printf  ("writev (%d, %p, %d): entry", fd, iov, iovcnt);

Test program is given below.

  #include <fcntl.h>
  #include <signal.h>
  #include <stdio.h>
  #include <unistd.h>
  #include <w32api/windows.h>  // for Sleep()

  void sighndlr(int sig)
  {
  }

  int main(int argc, char **argv)
  {
    char c=0;
    int fd, pid=getpid();
    time_t tstart;
    sigset_t sset;
    struct sigaction act;
    if ((fd=open("tstsig.bin",
                 O_CREAT|O_WRONLY|O_TRUNC,
                 0666))<0) {
      perror("open()");
      return 1;
    }
    sigemptyset(&sset);
    act.sa_handler=sighndlr;
    act.sa_mask=sset;
    act.sa_flags=SA_NOMASK;
    sigaction(SIGUSR1,&act,0);
    if (fork()==-1) {
      perror("fork()");
      return 1;
    }
    tstart=time(0);
    while (time(0)<tstart+5) {  // repeat for ~5 secs in
      kill(pid,SIGUSR1);        //      child and parent
      write(fd,&c,1);
      Sleep(0);
    }
    return 0;
  }

Invoke this program using `strace test_program >dump' command.
Then use commands:

  grep -c "sig_dispatch_pending:" dump
    # to see the total number of calls to sig_dispatch_pending();
    # on my computer it is ~3000; this number includes calls from
    # both write() and kill();

  grep -c flushing dump
    # to see the number of calls to sig_dispatch_pending() when
    # `sigq.start.next' is non-zero; on my computer it is ~450;

  grep -B1 flushing dump | less
    # to ensure that sig_dispatch_pending() sometimes flushes
    # signals when is called from writev();

  grep -B1 sigq | less
    # to ensure that there are calls to sig_dispatch_pending()
    # from writev() when `sigq.start.next' is zero.



More information about the Cygwin-developers mailing list