2 #include "oscam-time.h"
4 static enum clock_type clock_type
= CLOCK_TYPE_UNKNOWN
;
7 struct timeval lasttime
; // holds previous time to detect systemtime adjustments due to eg transponder change on dvb receivers
10 int64_t comp_timeb(struct timeb
*tpa
, struct timeb
*tpb
)
12 return (int64_t)(((int64_t)(tpa
->time
- tpb
->time
) * 1000ull) + ((int64_t) tpa
->millitm
- (int64_t) tpb
->millitm
));
15 int64_t comp_timebus(struct timeb
*tpa
, struct timeb
*tpb
)
17 return (int64_t)(((int64_t)(tpa
->time
- tpb
->time
) * 1000000ull) + ((int64_t) tpa
->millitm
- (int64_t) tpb
->millitm
));
20 /* Checks if year is a leap year. If so, 1 is returned, else 0. */
21 static int8_t is_leap(unsigned int y
)
23 return (y
% 4) == 0 && ((y
% 100) != 0 || (y
% 400) == 0);
26 /* Drop-in replacement for timegm function as some plattforms strip the function from their libc.. */
27 time_t cs_timegm(struct tm
*tm
)
31 if(tm
->tm_mon
> 12 || tm
->tm_mon
< 0 || tm
->tm_mday
> 31 || tm
->tm_min
> 60 || tm
->tm_sec
> 60 || tm
->tm_hour
> 24)
33 for(i
= 70; i
< tm
->tm_year
; ++i
)
35 result
+= is_leap(i
+ 1900) ? 366 : 365;
37 for(i
= 0; i
< tm
->tm_mon
; ++i
)
39 if(i
== 0 || i
== 2 || i
== 4 || i
== 6 || i
== 7 || i
== 9 || i
== 11) { result
+= 31; }
40 else if(i
== 3 || i
== 5 || i
== 8 || i
== 10) { result
+= 30; }
41 else if(is_leap(tm
->tm_year
+ 1900)) { result
+= 29; }
42 else { result
+= 28; }
44 result
+= tm
->tm_mday
- 1;
46 result
+= tm
->tm_hour
;
54 /* Drop-in replacement for gmtime_r as some plattforms strip the function from their libc. */
55 struct tm
*cs_gmtime_r(const time_t *timep
, struct tm
*r
)
57 static const int16_t daysPerMonth
[13] = { 0,
62 31 + 28 + 31 + 30 + 31,
63 31 + 28 + 31 + 30 + 31 + 30,
64 31 + 28 + 31 + 30 + 31 + 30 + 31,
65 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
66 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
67 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
68 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
69 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
72 time_t work
= * timep
% 86400;
73 r
->tm_sec
= work
% 60;
75 r
->tm_min
= work
% 60;
76 r
->tm_hour
= work
/ 60;
77 work
= * timep
/ 86400;
78 r
->tm_wday
= (4 + work
) % 7;
81 time_t k
= is_leap(i
) ? 366 : 365;
87 r
->tm_year
= i
- 1900;
90 if(is_leap(i
) && work
> 58)
93 { r
->tm_mday
= 2; } /* 29.2. */
96 for(i
= 11; i
&& daysPerMonth
[i
] > work
; --i
)
99 r
->tm_mday
+= work
- daysPerMonth
[i
];
103 /* Drop-in replacement for ctime_r as some plattforms strip the function from their libc. */
104 char *cs_ctime_r(const time_t *timep
, char *buf
)
107 localtime_r(timep
, &t
);
108 strftime(buf
, 26, "%c\n", &t
);
112 void cs_ftime(struct timeb
*tp
)
115 gettimeofday(&tv
, NULL
);
116 #if defined(CLOCKFIX)
117 if (tv
.tv_sec
> lasttime
.tv_sec
|| (tv
.tv_sec
== lasttime
.tv_sec
&& tv
.tv_usec
>= lasttime
.tv_usec
)){ // check for time issues!
118 lasttime
= tv
; // register this valid time
123 settimeofday(&tv
, NULL
); // set time back to last known valid time
124 //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** \n");
127 tp
->time
= tv
.tv_sec
;
128 tp
->millitm
= tv
.tv_usec
/ 1000;
131 void cs_ftimeus(struct timeb
*tp
)
134 gettimeofday(&tv
, NULL
);
135 #if defined(CLOCKFIX)
136 if (tv
.tv_sec
> lasttime
.tv_sec
|| (tv
.tv_sec
== lasttime
.tv_sec
&& tv
.tv_usec
>= lasttime
.tv_usec
)){ // check for time issues!
137 lasttime
= tv
; // register this valid time
142 settimeofday(&tv
, NULL
); // set time back to last known valid time
143 //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** \n");
146 tp
->time
= tv
.tv_sec
;
147 tp
->millitm
= tv
.tv_usec
;
150 void cs_sleepms(uint32_t msec
)
152 //does not interfere with signals like sleep and usleep do
153 struct timespec req_ts
;
154 req_ts
.tv_sec
= msec
/ 1000;
155 req_ts
.tv_nsec
= (msec
% 1000) * 1000000L;
156 int32_t olderrno
= errno
; // Some OS (especially MacOSX) seem to set errno to ETIMEDOUT when sleeping
159 /* Sleep for the time specified in req_ts. If interrupted by a
160 signal, place the remaining time left to sleep back into req_ts. */
161 int rval
= nanosleep (&req_ts
, &req_ts
);
163 break; // Completed the entire sleep time; all done.
164 else if (errno
== EINTR
)
165 continue; // Interrupted by a signal. Try again.
167 break; // Some other error; bail out.
172 void cs_sleepus(uint32_t usec
)
174 //does not interfere with signals like sleep and usleep do
175 struct timespec req_ts
;
176 req_ts
.tv_sec
= usec
/ 1000000;
177 req_ts
.tv_nsec
= (usec
% 1000000) * 1000L;
178 int32_t olderrno
= errno
; // Some OS (especially MacOSX) seem to set errno to ETIMEDOUT when sleeping
181 /* Sleep for the time specified in req_ts. If interrupted by a
182 signal, place the remaining time left to sleep back into req_ts. */
183 int rval
= nanosleep (&req_ts
, &req_ts
);
185 break; // Completed the entire sleep time; all done.
186 else if (errno
== EINTR
)
187 continue; // Interrupted by a signal. Try again.
189 break; // Some other error; bail out.
194 void add_ms_to_timespec(struct timespec
*timeout
, int32_t msec
)
197 int64_t nanosecs
, secs
;
198 const int64_t NANOSEC_PER_MS
= 1000000;
199 const int64_t NANOSEC_PER_SEC
= 1000000000;
201 nanosecs
= (int64_t) (msec
* NANOSEC_PER_MS
+ now
.tv_nsec
);
202 if (nanosecs
>= NANOSEC_PER_SEC
){
203 secs
= now
.tv_sec
+ (nanosecs
/ NANOSEC_PER_SEC
);
204 nanosecs
%= NANOSEC_PER_SEC
;
209 timeout
->tv_sec
= (long)secs
;
210 timeout
->tv_nsec
= (long)nanosecs
;
213 void add_ms_to_timeb(struct timeb
*tb
, int32_t ms
)
216 tb
->time
+= ms
/ 1000;
217 tb
->millitm
+= (ms
% 1000);
222 if(tb
->millitm
>= 1000)
229 int64_t add_ms_to_timeb_diff(struct timeb
*tb
, int32_t ms
)
232 add_ms_to_timeb(tb
, ms
);
234 return comp_timeb(tb
, &tb_now
);
237 #if defined(__UCLIBC__)
238 # define __UCLIBC_VER (__UCLIBC_MAJOR__ * 10000 + __UCLIBC_MINOR__ * 100 + __UCLIBC_SUBLEVEL__)
240 # define __UCLIBC_VER 999999
243 #if defined(__GLIBC__)
244 # define __GLIBCVER (__GLIBC__ * 100 + __GLIBC_MINOR__)
246 # define __GLIBCVER 9999
249 // Assume we have HAVE_pthread_condattr_setclock if CLOCK_MONOTONIC is defined
250 #if defined(CLOCKFIX) && defined(CLOCK_MONOTONIC)
251 #define HAVE_pthread_condattr_setclock 1
254 #if defined(HAVE_pthread_condattr_setclock)
255 // UCLIBC 0.9.31 does not have pthread_condattr_setclock
256 # if __UCLIBC_VER < 932
257 # undef HAVE_pthread_condattr_setclock
259 // glibc 2.3.6 in ppc old toolchain do not have pthread_condattr_setclock
260 # if __GLIBCVER < 204
261 # undef HAVE_pthread_condattr_setclock
263 // android's libc not have pthread_condattr_setclock
265 # undef HAVE_pthread_condattr_setclock
269 void __cs_pthread_cond_init(const char *n
, pthread_cond_t
*cond
)
271 pthread_condattr_t attr
;
272 SAFE_CONDATTR_INIT_R(&attr
, n
); // init condattr with defaults
274 #if defined(HAVE_pthread_condattr_setclock)
275 enum clock_type ctype
= cs_getclocktype();
276 SAFE_CONDATTR_SETCLOCK_R(&attr
, (ctype
== CLOCK_TYPE_MONOTONIC
) ? CLOCK_MONOTONIC
: CLOCK_REALTIME
, n
);
279 SAFE_COND_INIT_R(cond
, &attr
, n
); // init thread with right clock assigned
280 pthread_condattr_destroy(&attr
);
283 void __cs_pthread_cond_init_nolog(const char *n
, pthread_cond_t
*cond
)
285 pthread_condattr_t attr
;
286 SAFE_CONDATTR_INIT_NOLOG_R(&attr
, n
); // init condattr with defaults
288 #if defined(HAVE_pthread_condattr_setclock)
289 enum clock_type ctype
= cs_getclocktype();
290 SAFE_CONDATTR_SETCLOCK_NOLOG_R(&attr
, (ctype
== CLOCK_TYPE_MONOTONIC
) ? CLOCK_MONOTONIC
: CLOCK_REALTIME
, n
);
293 SAFE_COND_INIT_NOLOG_R(cond
, &attr
, n
); // init thread with right clock assigned
294 pthread_condattr_destroy(&attr
);
298 void sleepms_on_cond(const char *n
, pthread_mutex_t
*mutex
, pthread_cond_t
*cond
, uint32_t msec
)
301 add_ms_to_timespec(&ts
, msec
);
302 SAFE_MUTEX_LOCK_R(mutex
, n
);
303 SAFE_COND_TIMEDWAIT_R(cond
, mutex
, &ts
, n
); // sleep on sleep_cond
304 SAFE_MUTEX_UNLOCK_R(mutex
, n
);
307 void cs_pthread_cond_init(const char *n
, pthread_mutex_t
*mutex
, pthread_cond_t
*cond
)
309 SAFE_MUTEX_INIT_R(mutex
, NULL
, n
);
310 __cs_pthread_cond_init(n
, cond
);
313 void cs_pthread_cond_init_nolog(const char *n
, pthread_mutex_t
*mutex
, pthread_cond_t
*cond
)
315 SAFE_MUTEX_INIT_NOLOG_R(mutex
, NULL
, n
);
316 __cs_pthread_cond_init(n
, cond
);
319 enum clock_type
cs_getclocktype(void) {
320 if (clock_type
== CLOCK_TYPE_UNKNOWN
) {
322 cs_gettime(&ts
); // init clock type
327 time_t cs_walltime(struct timeb
*tp
)
329 // we dont need to fetch time again and calculate if oscam is already using realtimeclock!
330 if (clock_type
!= CLOCK_TYPE_MONOTONIC
)
337 gettimeofday(&tv
, NULL
);
338 int64_t skew
= tv
.tv_sec
- ts
.tv_sec
;
339 return(tp
->time
+ skew
);
342 /* Return real time clock value calculated based on cs_gettime(). Use this instead of time() */
347 return cs_walltime(&tb
);
351 #include <mach/clock.h>
352 #include <mach/mach.h>
355 void cs_gettime(struct timespec
*ts
)
358 gettimeofday(&tv
, NULL
);
359 #if defined(CLOCKFIX)
360 if (tv
.tv_sec
> lasttime
.tv_sec
|| (tv
.tv_sec
== lasttime
.tv_sec
&& tv
.tv_usec
>= lasttime
.tv_usec
)){ // check for time issues!
361 lasttime
= tv
; // register this valid time
366 settimeofday(&tv
, NULL
); // set time back to last known valid time
367 //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** \n");
370 ts
->tv_sec
= tv
.tv_sec
;
371 ts
->tv_nsec
= tv
.tv_usec
* 1000;
372 clock_type
= CLOCK_TYPE_REALTIME
;
375 #if !defined(CLOCKFIX) || (!defined(CLOCK_MONOTONIC) && !defined(__MACH__))
377 gettimeofday(&tv
, NULL
);
378 ts
->tv_sec
= tv
.tv_sec
;
379 ts
->tv_nsec
= tv
.tv_usec
* 1000;
380 clock_type
= CLOCK_TYPE_REALTIME
;
382 #elif defined (__MACH__)
383 // OS X does not have clock_gettime, use clock_get_time
386 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK
, &cclock
);
387 clock_get_time(cclock
, &mts
);
388 mach_port_deallocate(mach_task_self(), cclock
);
389 ts
->tv_sec
= mts
.tv_sec
;
390 ts
->tv_nsec
= mts
.tv_nsec
;
391 clock_type
= CLOCK_TYPE_REALTIME
;
393 if (clock_type
== CLOCK_TYPE_REALTIME
) { // monotonic returned error
394 clock_gettime(CLOCK_REALTIME
, ts
);
397 int32_t ret
= clock_gettime(CLOCK_MONOTONIC
, ts
);
398 clock_type
= CLOCK_TYPE_MONOTONIC
;
399 if ((ret
< 0 && errno
== EINVAL
)){ // Error fetching time from this source (Shouldn't happen on modern Linux)
400 clock_gettime(CLOCK_REALTIME
, ts
);
401 clock_type
= CLOCK_TYPE_REALTIME
;