RX: Avoid retrying calls on busy channels
[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 #include "afs/param.h"
15
16 #ifdef AFS_SUN59_ENV
17 #include <sys/time_impl.h>
18 #endif
19
20 #ifdef KERNEL
21 # ifndef UKERNEL
22 #  include "h/types.h"
23 #  include "h/time.h"
24 # else /* !UKERNEL */
25 #  include "afs/sysincludes.h"
26 #  include "afsincludes.h"
27 # endif /* !UKERNEL */
28 #else /* KERNEL */
29 # include <sys/time.h>
30 # ifdef HAVE_SIGNAL_H
31 #  include <signal.h>
32 # endif
33 # include <stdio.h>
34 # include <errno.h>
35 # include <stdlib.h>
36 #endif
37
38 #include "rx.h"
39 #include "rx_clock.h"
40
41 #if !defined(AFS_USE_GETTIMEOFDAY)
42 /*use this package only if gettimeofday is much much costlier than getitime */
43
44 #ifndef KERNEL
45
46 #define STARTVALUE 3600
47 static struct clock startvalue;
48 static struct clock relclock_epoch;   /* The elapsed time of the last itimer reset */
49
50 struct clock clock_now;         /* The last elapsed time ready by clock_GetTimer */
51
52 /* 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) */
53 int clock_haveCurrentTime;
54
55 int clock_nUpdates;             /* The actual number of clock updates */
56 static int clockInitialized = 0;
57
58 static void
59 clock_Sync(void)
60 {
61     struct itimerval itimer, otimer;
62     itimer.it_value.tv_sec = STARTVALUE;
63     itimer.it_value.tv_usec = 0;
64     itimer.it_interval.tv_sec = 0;
65     itimer.it_interval.tv_usec = 0;
66
67     signal(SIGALRM, SIG_IGN);
68     if (setitimer(ITIMER_REAL, &itimer, &otimer) != 0) {
69         osi_Panic("clock:  could not set interval timer; aborted(errno=%d)\n",
70                   errno);
71     }
72     if (relclock_epoch.usec + startvalue.usec >= otimer.it_value.tv_usec) {
73         relclock_epoch.sec = relclock_epoch.sec +
74             startvalue.sec - otimer.it_value.tv_sec;
75         relclock_epoch.usec = relclock_epoch.usec +
76             startvalue.usec - otimer.it_value.tv_usec;
77     } else {
78         relclock_epoch.sec = relclock_epoch.sec +
79             startvalue.sec - 1 - otimer.it_value.tv_sec;
80         relclock_epoch.usec = relclock_epoch.usec +
81             startvalue.usec + 1000000 - otimer.it_value.tv_usec;
82     }
83     if (relclock_epoch.usec >= 1000000)
84         relclock_epoch.usec -= 1000000, relclock_epoch.sec++;
85     /* the initial value of the interval timer may not be exactly the same
86      * as the arg passed to setitimer. POSIX allows the implementation to
87      * round it up slightly, and some nonconformant implementations truncate
88      * it */
89     getitimer(ITIMER_REAL, &itimer);
90     startvalue.sec = itimer.it_value.tv_sec;
91     startvalue.usec = itimer.it_value.tv_usec;
92 }
93
94 /* Initialize the clock */
95 void
96 clock_Init(void)
97 {
98     if (!clockInitialized) {
99         relclock_epoch.sec = relclock_epoch.usec = 0;
100         startvalue.sec = startvalue.usec = 0;
101         clock_Sync();
102         clockInitialized = 1;
103     }
104
105     clock_UpdateTime();
106 }
107
108 /* Make clock uninitialized. */
109 int
110 clock_UnInit(void)
111 {
112     clockInitialized = 0;
113     return 0;
114 }
115
116 /* 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 */
117 void
118 clock_UpdateTime(void)
119 {
120     struct itimerval itimer;
121     struct clock offset;
122     struct clock new;
123
124     getitimer(ITIMER_REAL, &itimer);
125
126     if (startvalue.usec >= itimer.it_value.tv_usec) {
127         offset.sec = startvalue.sec - itimer.it_value.tv_sec;
128         offset.usec = startvalue.usec - itimer.it_value.tv_usec;
129     } else {
130         /* The "-1" makes up for adding 1000000 usec, on the next line */
131         offset.sec = startvalue.sec - 1 - itimer.it_value.tv_sec;
132         offset.usec = startvalue.usec + 1000000 - itimer.it_value.tv_usec;
133     }
134     new.sec = relclock_epoch.sec + offset.sec;
135     new.usec = relclock_epoch.usec + offset.usec;
136     if (new.usec >= 1000000)
137         new.usec -= 1000000, new.sec++;
138     clock_now.sec = new.sec;
139     clock_now.usec = new.usec;
140     if (itimer.it_value.tv_sec < startvalue.sec / 2)
141         clock_Sync();
142     clock_haveCurrentTime = 1;
143     clock_nUpdates++;
144 }
145 #else /* KERNEL */
146 #endif /* KERNEL */
147
148 #endif /* AFS_USE_GETTIMEOFDAY */