rx-rw-locking-20081024
[openafs.git] / src / rx / rx_clock.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* Elapsed time package */
11 /* See rx_clock.h for calling conventions */
12
13 #include <afsconfig.h>
14 #ifdef  KERNEL
15 #include "afs/param.h"
16 #else
17 #include <afs/param.h>
18 #endif
19
20 #ifdef AFS_SUN59_ENV
21 #include <sys/time_impl.h>
22 #endif
23
24 RCSID
25     ("$Header$");
26
27 #ifdef KERNEL
28 #ifndef UKERNEL
29 #include "rx/rx_clock.h"
30 #include "h/types.h"
31 #include "h/time.h"
32 #else /* !UKERNEL */
33 #include "afs/sysincludes.h"
34 #include "afsincludes.h"
35 #include "rx/rx_internal.h"
36 #include "rx/rx.h"
37 #include "rx/rx_clock.h"
38 #endif /* !UKERNEL */
39 #else /* KERNEL */
40 #include <sys/time.h>
41 #ifdef HAVE_SIGNAL_H
42 #include <signal.h>
43 #endif
44 #include <stdio.h>
45 #include <errno.h>
46 #include <stdlib.h>
47 #include "rx_internal.h"
48 #include "rx.h"
49 #include "rx_clock.h"
50 #endif
51
52 #if !defined(AFS_USE_GETTIMEOFDAY)
53 /*use this package only if gettimeofday is much much costlier than getitime */
54
55 #ifndef KERNEL
56
57 #define STARTVALUE 3600
58 static struct clock startvalue;
59 static struct clock relclock_epoch;   /* The elapsed time of the last itimer reset */
60
61 struct clock clock_now;         /* The last elapsed time ready by clock_GetTimer */
62
63 /* This is set to 1 whenever the time is read, and reset to 0 whenever clock_NewTime is called.  This is to allow the caller to control the frequency with which the actual time is re-evaluated (an expensive operation) */
64 int clock_haveCurrentTime;
65
66 int clock_nUpdates;             /* The actual number of clock updates */
67 static int clockInitialized = 0;
68
69 static void
70 clock_Sync(void)
71 {
72     struct itimerval itimer, otimer;
73     itimer.it_value.tv_sec = STARTVALUE;
74     itimer.it_value.tv_usec = 0;
75     itimer.it_interval.tv_sec = 0;
76     itimer.it_interval.tv_usec = 0;
77
78     signal(SIGALRM, SIG_IGN);
79     if (setitimer(ITIMER_REAL, &itimer, &otimer) != 0) {
80         fprintf(stderr, "clock:  could not set interval timer; \
81                                 aborted(errno=%d)\n", errno);
82         fflush(stderr);
83         exit(1);
84     }
85     if (relclock_epoch.usec + startvalue.usec >= otimer.it_value.tv_usec) {
86         relclock_epoch.sec = relclock_epoch.sec +
87             startvalue.sec - otimer.it_value.tv_sec;
88         relclock_epoch.usec = relclock_epoch.usec +
89             startvalue.usec - otimer.it_value.tv_usec;
90     } else {
91         relclock_epoch.sec = relclock_epoch.sec +
92             startvalue.sec - 1 - otimer.it_value.tv_sec;
93         relclock_epoch.usec = relclock_epoch.usec +
94             startvalue.usec + 1000000 - otimer.it_value.tv_usec;
95     }
96     if (relclock_epoch.usec >= 1000000)
97         relclock_epoch.usec -= 1000000, relclock_epoch.sec++;
98     /* the initial value of the interval timer may not be exactly the same
99      * as the arg passed to setitimer. POSIX allows the implementation to
100      * round it up slightly, and some nonconformant implementations truncate
101      * it */
102     getitimer(ITIMER_REAL, &itimer);
103     startvalue.sec = itimer.it_value.tv_sec;
104     startvalue.usec = itimer.it_value.tv_usec;
105 }
106
107 /* Initialize the clock */
108 void
109 clock_Init(void)
110 {
111     if (!clockInitialized) {
112         relclock_epoch.sec = relclock_epoch.usec = 0;
113         startvalue.sec = startvalue.usec = 0;
114         clock_Sync();
115         clockInitialized = 1;
116     }
117
118     clock_UpdateTime();
119 }
120
121 /* Make clock uninitialized. */
122 int
123 clock_UnInit(void)
124 {
125     clockInitialized = 0;
126     return 0;
127 }
128
129 /* Compute the current time.  The timer gets the current total elapsed time since startup, expressed in seconds and microseconds.  This call is almost 200 usec on an APC RT */
130 void
131 clock_UpdateTime(void)
132 {
133     struct itimerval itimer;
134     struct clock offset;
135     struct clock new;
136
137     getitimer(ITIMER_REAL, &itimer);
138
139     if (startvalue.usec >= itimer.it_value.tv_usec) {
140         offset.sec = startvalue.sec - itimer.it_value.tv_sec;
141         offset.usec = startvalue.usec - itimer.it_value.tv_usec;
142     } else {
143         /* The "-1" makes up for adding 1000000 usec, on the next line */
144         offset.sec = startvalue.sec - 1 - itimer.it_value.tv_sec;
145         offset.usec = startvalue.usec + 1000000 - itimer.it_value.tv_usec;
146     }
147     new.sec = relclock_epoch.sec + offset.sec;
148     new.usec = relclock_epoch.usec + offset.usec;
149     if (new.usec >= 1000000)
150         new.usec -= 1000000, new.sec++;
151     clock_now.sec = new.sec;
152     clock_now.usec = new.usec;
153     if (itimer.it_value.tv_sec < startvalue.sec / 2)
154         clock_Sync();
155     clock_haveCurrentTime = 1;
156     clock_nUpdates++;
157 }
158 #else /* KERNEL */
159 #endif /* KERNEL */
160
161 #endif /* AFS_USE_GETTIMEOFDAY */