File Coverage

ulib/clock.c
Criterion Covered Total %
statement 82 98 83.6
branch 44 66 66.6
condition n/a
subroutine n/a
pod n/a
total 126 164 76.8


line stmt bran cond sub pod time code
1             #ifdef __cplusplus
2             extern "C" {
3             #endif
4              
5             #include "ulib/clock.h"
6             #include "ulib/chacha.h"
7             #include "ulib/gettime.h"
8              
9             #ifdef __cplusplus
10             }
11             #endif
12              
13             #ifdef USE_WIN32_NATIVE
14             /* #define getpid() _getpid() */
15             #define ftruncate(a,b) _chsize(a,b)
16             /* typedef U32 mode_t; */
17             #endif
18             #undef open
19              
20             #define state_fd UCXT.clock_state_fd
21             #define state_f UCXT.clock_state_f
22             #define adjustment UCXT.clock_adj
23             #define last UCXT.clock_last
24             #define clock_seq UCXT.clock_seq
25             #define myU2time UCXT.myU2time
26             #define prev_clock_reg UCXT.clock_prev_reg
27             #define defer_100ns UCXT.clock_defer_100ns
28             #define pathlen UCXT.clock_pathlen
29              
30             /* called at boot */
31 156           void uu_clock_init(pUCXT) {
32 156           state_fd = -3;
33 156           state_f = NULL;
34 156           pathlen.path = NULL;
35 156           pathlen.len = 0;
36 156           adjustment = 0;
37 156           last.tv_sec = 0;
38 156           last.tv_usec = 0;
39 156           prev_clock_reg = 0;
40 156           defer_100ns = 0;
41             /* clock_seq uninit */
42 156           }
43              
44 6           void uu_clock_getpath(pUCXT, struct_pathlen_t *sp) {
45 6           Copy(&pathlen, sp, 1, struct_pathlen_t);
46 6           }
47              
48 20           void uu_clock_setpath(pUCXT, struct_pathlen_t *sp) {
49 20 100         if (pathlen.path)
50 11           Safefree(pathlen.path);
51 20           Copy(sp, &pathlen, 1, struct_pathlen_t);
52 20 100         if (state_fd >= 0)
53 8           fclose(state_f);
54 20           state_fd = -3;
55 20           }
56              
57             /* returns 100ns intervals since unix epoch.
58             * since gettimeofday() is in 1usec intervals,
59             * last digit is simulated via adjustment.
60             */
61 471           IV uu_clock(pUCXT, U64 *ret_clock_reg, U16 *ret_clock_seq) {
62             struct timeval tv;
63             mode_t save_umask;
64             int len;
65             UV ptod[2];
66             U64 clock_reg;
67             #ifdef HAVE_LSTAT
68             struct stat statbuf;
69             #endif
70              
71             /* state_fd:
72             * -4 cannot create
73             * -3 untried
74             * -2 symlink
75             * -1 can create
76             * >=0 open
77             */
78 471 100         if (state_fd == -3) {
79             #ifdef HAVE_LSTAT
80 79 100         if (lstat(pathlen.path, &statbuf) < 0) { /* this covers EINTR too.. ugh */
81 76 100         if (errno == ENOENT)
82 8           state_fd = -1;
83             else
84 68           state_fd = -4;
85             }
86 3 100         else if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
87 1           state_fd = -2;
88             }
89             else {
90             #endif
91 2           state_fd = open(pathlen.path, O_RDWR);
92 2 50         if (state_fd < 0 && errno == ENOENT)
    0          
93 0           state_fd = -1; /* can create */
94 2 50         else if (state_fd >= 0) {
95             #ifdef HAVE_LSTAT
96 2           state_f = NULL;
97 2 50         if ((lstat(pathlen.path, &statbuf) == 0) && ((statbuf.st_mode & S_IFMT) != S_IFLNK))
    50          
98             #endif
99 2           state_f = fdopen(state_fd, "r+");
100 2 50         if (!state_f) {
101 0           close(state_fd);
102 0           state_fd = -2;
103             }
104             }
105             #ifdef HAVE_LSTAT
106             }
107             #endif
108             }
109              
110 471 100         if (state_fd >= 0) {
111             unsigned int cl;
112             unsigned long tv1, tv2;
113             int a;
114              
115 2           rewind(state_f);
116              
117 2 100         if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", &cl, &tv1, &tv2, &a) == 4) {
118 1           clock_seq = cl & 0x3fff;
119 1           last.tv_sec = tv1;
120 1           last.tv_usec = tv2;
121 1           adjustment = a;
122             }
123             }
124              
125             /* gettimeofday(&tv, 0); */
126 471           (*myU2time)(aTHX_ (UV*)&ptod);
127 471           tv.tv_sec = (long)ptod[0];
128 471           tv.tv_usec = (long)ptod[1];
129              
130 471 100         if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
    50          
131 73           cc_rand16(aUCXT, &clock_seq);
132 73           clock_seq &= 0x3fff;
133              
134 73           last.tv_sec = tv.tv_sec - 1;
135 73           last.tv_usec = tv.tv_usec;
136             }
137              
138 471 50         if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) {
    100          
    50          
139 0           clock_seq = (clock_seq+1) & 0x3fff;
140 0           adjustment = 0;
141 0           last = tv;
142             }
143 471 100         else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) {
    50          
144 0 0         if (adjustment >= MAX_ADJUSTMENT) {
145 0           clock_seq = (clock_seq+1) & 0x3fff;
146 0           adjustment = 0;
147             }
148             else {
149 0           adjustment++;
150             }
151             }
152             else {
153 471           adjustment = 0;
154 471           last = tv;
155             }
156              
157 471           clock_reg = tv.tv_usec*10 + adjustment;
158 471           clock_reg += ((U64)tv.tv_sec)*10000000;
159             /* *clock_reg += (((U64)0x01b21dd2) << 32) + 0x13814000; */
160              
161 471 100         if ((clock_reg - prev_clock_reg) >= defer_100ns) {
162 470 100         if (state_fd == -1) { /* can create */
163             #ifdef HAVE_LSTAT
164 7 50         if ((lstat(pathlen.path, &statbuf) == 0) && ((statbuf.st_mode & S_IFMT) == S_IFLNK))
    0          
165 0           state_fd = -2;
166             else {
167             #endif
168 7           save_umask = umask(0);
169 7           state_fd = open(pathlen.path, O_RDWR|O_CREAT, 0660);
170 7 50         if (state_fd < 0)
171 0           state_fd = -4;
172 7           (void) umask(save_umask);
173 7 50         if (state_fd >= 0) {
174             #ifdef HAVE_LSTAT
175 7           state_f = NULL;
176 7 50         if ((lstat(pathlen.path, &statbuf) == 0) && ((statbuf.st_mode & S_IFMT) != S_IFLNK))
    50          
177             #endif
178 7           state_f = fdopen(state_fd, "r+");
179 7 50         if (!state_f) {
180 0           close(state_fd);
181 0           state_fd = -2;
182             }
183             }
184             #ifdef HAVE_LSTAT
185             }
186             #endif
187             }
188              
189 470 100         if (state_fd > 0) {
190 9           rewind(state_f);
191 9           len = fprintf(state_f,
192             "clock: %04x tv: %016lu %08lu adj: %08d\n",
193 9           clock_seq, (unsigned long)last.tv_sec,
194 9           (unsigned long)last.tv_usec, adjustment);
195 9           fflush(state_f);
196 9 50         if (ftruncate(state_fd, len) < 0) {
197 0           fprintf(state_f, " \n");
198 0           fflush(state_f);
199             }
200 9           rewind(state_f);
201             }
202             }
203              
204 471           prev_clock_reg = clock_reg;
205              
206             /* *clock_high = clock_reg >> 32; */
207             /* *clock_low = (U32)clock_reg; */
208 471           *ret_clock_reg = clock_reg;
209 471           *ret_clock_seq = clock_seq;
210 471           return 0;
211             }
212              
213             /* ex:set ts=2 sw=2 itab=spaces: */