Bug 13075

Summary: signal is not posted for async I/O on raw devices
Product: Base System Reporter: kwchen <kwchen>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 3.2-RELEASE   
Hardware: Any   
OS: Any   

Description kwchen 1999-08-11 14:40:01 UTC
The following program (~60 lines) does not get a SIGUSR1 when used with a raw device,
but does get the signal with a block device. It will wait forever for a
signal (pause()); doing "kill -30 <pid>" from shell prompt will cause it
to execute sigusr1() and display the data it just read and the data seemed
correct.

BTW, how do I identify a specific AIO job with each signal? Are signals
queued in FreeBSD? Thanks very much.

#include <stdio.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <time.h>
#include <aio.h>

aiocb_t         myaiocb;
siginfo_t       siginfo;
char            buf[10240];

sig_t
sigusr1(int signo)
{
        int i;
        printf("in sigusr1(), signo = %d\n", signo);
        printf("aio_error(myaiocb): %d\n", aio_error(&myaiocb));
#if 0
        printf("aio buffer after read: %s\n", buf);
        for (i = 0; i < 500; i++) printf(" %c", buf[i]);
        printf("\n");
}

main(argc, argv)
int     argc;
char**  argv;
{
        int rtn;
        int fd;

        /* signal is not posted on raw partition, but okay on block device */
        fd = open("/dev/rwd0s4e", O_RDONLY);
        /* fd = open("/dev/wd0s4e", O_RDONLY);  this works. */
        if (fd < 0) {
                perror("open failed");
                exit(1);
        }
        printf("open succeeded ...\n");
        signal(SIGUSR1, (sig_t) sigusr1);
        myaiocb.aio_fildes = fd;
        myaiocb.aio_buf = buf;
        myaiocb.aio_nbytes = 2048;

        myaiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
        myaiocb.aio_sigevent.sigev_signo = SIGUSR1;
        myaiocb.aio_sigevent.sigev_value.sival_int = 123;

        printf("calling aio_read ...\n");
        rtn = aio_read(&myaiocb);
        if (rtn < 0) {
                perror("aio_read failed");
                exit(1);
        }
        printf("aio_read succeeded\n");

        /* normally get EINPROGRESS */
        printf("aio_error(myaiocb): %d\n", aio_error(&myaiocb));

        pause();
}

How-To-Repeat: The above program will wait forever for a signal.
Comment 1 cmsedore 1999-09-15 18:55:09 UTC
Here's a patch that should fix the problem.  Warning: this patch comes from
my own version of vfs_aio.c (no differences exist between my code and the
code modified below, except that which is expressed below, so no
incompatibilities should arise).  This may cause problems because line
offsets are significantly different, and I had to hand edit the last patch
chunk to eliminate a bunch of followon stuff.  

*************** lio_listio(struct proc *p, struct lio_li
*** 1930,1944 ****
   * to do so from a timeout routine, but *not* from an interrupt routine.
   */
  static void
! process_signal(void *ljarg)
  {
!       struct aio_liojob *lj = ljarg;
!       if (lj->lioj_signal.sigev_notify == SIGEV_SIGNAL) {
!               if (lj->lioj_queue_count == lj->lioj_queue_finished_count) {
!                       psignal(lj->lioj_ki->kaio_p,
lj->lioj_signal.sigev_signo);
!                       lj->lioj_flags |= LIOJ_SIGNAL_POSTED;
                }
        }
  }

  /*
--- 2062,2086 ----
   * to do so from a timeout routine, but *not* from an interrupt routine.
   */
  static void
! process_signal(void *aioj)
  {
!       struct aiocblist *aiocbe = aioj;
!       struct aio_liojob *lj = aiocbe->lio;
!       struct aiocb *cb = &aiocbe->uaiocb;
!
!       if (lj) {
!               if (lj->lioj_signal.sigev_notify == SIGEV_SIGNAL) {
!                       if (lj->lioj_queue_count ==
lj->lioj_queue_finished_count) {
!                               psignal(lj->lioj_ki->kaio_p,
lj->lioj_signal.sigev_signo);
!                               lj->lioj_flags |= LIOJ_SIGNAL_POSTED;
!                       }
                }
        }
+
+       if (cb->aio_sigevent.sigev_notify == SIGEV_SIGNAL) {
+               psignal(aiocbe->userproc,cb->aio_sigevent.sigev_signo);
+       }
+
  }

  /*
*************** aio_physwakeup(bp)
*** 1986,1992 ****
                                if ((lj->lioj_flags &
(LIOJ_SIGNAL|LIOJ_SIGNAL_POSTED)) ==
                                        LIOJ_SIGNAL) {
                                        lj->lioj_flags |=
LIOJ_SIGNAL_POSTED;
!                                       timeout(process_signal, lj, 0);
                                }
                        }
                }
--- 2128,2134 ----
                                if ((lj->lioj_flags &
(LIOJ_SIGNAL|LIOJ_SIGNAL_POSTED)) ==
                                        LIOJ_SIGNAL) {
                                        lj->lioj_flags |=
LIOJ_SIGNAL_POSTED;
!                                       timeout(process_signal, aiocbe, 0);
                                }
                        }
                }
*************** aio_physwakeup(bp)
*** 2004,2010 ****
--- 2146,2154 ----
                                ki->kaio_flags &= ~KAIO_WAKEUP;
                                wakeup(p);
                        }
+
+               }
+
+               if (aiocbe->uaiocb. aio_sigevent.sigev_notify ==
SIGEV_SIGNAL) {
+                       timeout(process_signal, aiocbe, 0);
                }
        }
        splx(s);
  }
Comment 2 Jason Evans freebsd_committer freebsd_triage 2000-01-14 18:58:51 UTC
State Changed
From-To: open->closed

Fixed, along with kern/12053.