From owner-p4-projects@FreeBSD.ORG Wed Mar 19 13:32:02 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2B6C3106567B; Wed, 19 Mar 2008 13:32:02 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DF715106564A for ; Wed, 19 Mar 2008 13:32:01 +0000 (UTC) (envelope-from csjp@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id D1C648FC27 for ; Wed, 19 Mar 2008 13:32:01 +0000 (UTC) (envelope-from csjp@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m2JDW1b5043969 for ; Wed, 19 Mar 2008 13:32:01 GMT (envelope-from csjp@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m2JDW1YA043967 for perforce@freebsd.org; Wed, 19 Mar 2008 13:32:01 GMT (envelope-from csjp@freebsd.org) Date: Wed, 19 Mar 2008 13:32:01 GMT Message-Id: <200803191332.m2JDW1YA043967@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to csjp@freebsd.org using -f From: "Christian S.J. Peron" To: Perforce Change Reviews Cc: Subject: PERFORCE change 138092 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 19 Mar 2008 13:32:02 -0000 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