Date: Wed, 19 Mar 2008 13:32:01 GMT From: "Christian S.J. Peron" <csjp@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 138092 for review Message-ID: <200803191332.m2JDW1YA043967@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=138092 Change 138092 by csjp@ibm01 on 2008/03/19 13:31:55 Fix an interesting scenario which is the result of using SIGALARM for timer events. The delivery of the signal perfectly coincided with the timeout associated with the bpf descriptor, resulting in select(2) being interrupted constantly before it could time out. Subsequently, packets could never be processed in this case. To work around this, we query the timer before each call to select, and we we are interrupted, we adjust the timeout to compensate for the interruption. So, if we schedule a 10 second timeout, and get interrupted 5 seconds in, we will adjust the next timeout to 5 seconds. Affected files ... .. //depot/projects/zcopybpf/src/contrib/libpcap/pcap-bpf.c#25 edit .. //depot/projects/zcopybpf/src/contrib/libpcap/pcap-int.h#8 edit Differences ... ==== //depot/projects/zcopybpf/src/contrib/libpcap/pcap-bpf.c#25 (text+ko) ==== @@ -197,9 +197,12 @@ { struct bpf_zbuf bz; struct timeval tv; + struct timespec cur; fd_set r_set; int data, r; + int tmout, expire; +#define TSTOMILLI(ts) (((ts)->tv_sec * 1000) + ((ts)->tv_nsec / 1000000)) /* * Start out by seeing whether anything is waiting by checking the * next shared memory buffer for data. @@ -207,27 +210,57 @@ data = pcap_next_zbuf_shm(p, cc); if (data) return (data); - + /* + * If a previous sleep was interrupted due to signal delivery, make + * sure that the timeout gets adjusted accordingly. This requires + * that we analyze when the timeout should be been expired, and + * subtract the current time from that. If after this operation, + * our timeout is less then or equal to zero, handle it like a + * regular timeout. + */ + tmout = p->to_ms; + if (tmout) + (void) clock_gettime(CLOCK_MONOTONIC, &cur); + if (p->interrupted && p->to_ms) { + expire = TSTOMILLI(&p->firstsel) + p->to_ms; + tmout = expire - TSTOMILLI(&cur); + if (tmout <= 0) { + p->interrupted = 0; + data = pcap_next_zbuf_shm(p, cc); + if (data) + return (data); + if (ioctl(p->fd, BIOCROTZBUF, &bz) < 0) { + (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "BIOCROTZBUF: %s", strerror(errno)); + return (-1); + } + return (pcap_next_zbuf_shm(p, cc)); + } + } /* * No data in the buffer, so must use select() to wait for data or * the next timeout. */ FD_ZERO(&r_set); FD_SET(p->fd, &r_set); - if (p->to_ms != 0) { - tv.tv_sec = p->to_ms / 1000; - tv.tv_usec = (p->to_ms * 1000) % 1000000; + if (tmout != 0) { + tv.tv_sec = tmout / 1000; + tv.tv_usec = (tmout * 1000) % 1000000; } r = select(p->fd + 1, &r_set, NULL, NULL, p->to_ms != 0 ? &tv : NULL); - if (r < 0 && errno == EINTR) + if (r < 0 && errno == EINTR) { + if (!p->interrupted && p->to_ms) { + p->interrupted = 1; + p->firstsel = cur; + } return (0); - else if (r < 0) { + } else if (r < 0) { (void) snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "select: %s", strerror(errno)); return (-1); } - + p->interrupted = 0; /* * Check again for data, which may exist now that we've either been * woken up as a result of data or timed out. Try the "there's data" ==== //depot/projects/zcopybpf/src/contrib/libpcap/pcap-int.h#8 (text+ko) ==== @@ -192,6 +192,8 @@ u_int zbufsize; u_int timeout; u_int zerocopy; + u_int interrupted; + struct timespec firstsel; /* * If there's currently a buffer being actively processed, then it is
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200803191332.m2JDW1YA043967>