Author: ian
Date: Fri Feb 15 18:30:32 2013
New Revision: 246845
URL: http://svnweb.freebsd.org/changeset/base/246845

Log:
  Add PPS_CANWAIT support for time_pps_fetch().  This adds support for all three
  blocking modes described in section 3.4.3 of RFC 2783, allowing the caller
  to retrieve the most recent values without blocking, to block for a specified
  time, or to block forever.
  
  Reviewed by:  discussion on hackers@

Modified:
  head/sys/kern/kern_tc.c

Modified: head/sys/kern/kern_tc.c
==============================================================================
--- head/sys/kern/kern_tc.c     Fri Feb 15 17:22:57 2013        (r246844)
+++ head/sys/kern/kern_tc.c     Fri Feb 15 18:30:32 2013        (r246845)
@@ -1446,6 +1446,50 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO,
  * RFC 2783 PPS-API implementation.
  */
 
+static int
+pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps)
+{
+       int err, timo;
+       pps_seq_t aseq, cseq;
+       struct timeval tv;
+
+       if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
+               return (EINVAL);
+
+       /*
+        * If no timeout is requested, immediately return whatever values were
+        * most recently captured.  If timeout seconds is -1, that's a request
+        * to block without a timeout.  WITNESS won't let us sleep forever
+        * without a lock (we really don't need a lock), so just repeatedly
+        * sleep a long time.
+        */
+       if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) {
+               if (fapi->timeout.tv_sec == -1)
+                       timo = 0x7fffffff;
+               else {
+                       tv.tv_sec = fapi->timeout.tv_sec;
+                       tv.tv_usec = fapi->timeout.tv_nsec / 1000;
+                       timo = tvtohz(&tv);
+               }
+               aseq = pps->ppsinfo.assert_sequence;
+               cseq = pps->ppsinfo.clear_sequence;
+               while (aseq == pps->ppsinfo.assert_sequence &&
+                   cseq == pps->ppsinfo.clear_sequence) {
+                       err = tsleep(pps, PCATCH, "ppsfch", timo);
+                       if (err == EWOULDBLOCK && fapi->timeout.tv_sec == -1) {
+                               continue;
+                       } else if (err != 0) {
+                               return (err);
+                       }
+               }
+       }
+
+       pps->ppsinfo.current_mode = pps->ppsparam.mode;
+       fapi->pps_info_buf = pps->ppsinfo;
+
+       return (0);
+}
+
 int
 pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
 {
@@ -1485,13 +1529,7 @@ pps_ioctl(u_long cmd, caddr_t data, stru
                return (0);
        case PPS_IOC_FETCH:
                fapi = (struct pps_fetch_args *)data;
-               if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
-                       return (EINVAL);
-               if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec)
-                       return (EOPNOTSUPP);
-               pps->ppsinfo.current_mode = pps->ppsparam.mode;
-               fapi->pps_info_buf = pps->ppsinfo;
-               return (0);
+               return (pps_fetch(fapi, pps));
 #ifdef FFCLOCK
        case PPS_IOC_FETCH_FFCOUNTER:
                fapi_ffc = (struct pps_fetch_ffc_args *)data;
@@ -1540,7 +1578,7 @@ pps_ioctl(u_long cmd, caddr_t data, stru
 void
 pps_init(struct pps_state *pps)
 {
-       pps->ppscap |= PPS_TSFMT_TSPEC;
+       pps->ppscap |= PPS_TSFMT_TSPEC | PPS_CANWAIT;
        if (pps->ppscap & PPS_CAPTUREASSERT)
                pps->ppscap |= PPS_OFFSETASSERT;
        if (pps->ppscap & PPS_CAPTURECLEAR)
@@ -1680,6 +1718,9 @@ pps_event(struct pps_state *pps, int eve
                hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
        }
 #endif
+
+       /* Wakeup anyone sleeping in pps_fetch().  */
+       wakeup(pps);
 }
 
 /*
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to