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
)
32 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)
37 for(i
= 70; i
< tm
->tm_year
; ++i
)
39 result
+= is_leap(i
+ 1900) ? 366 : 365;
42 for(i
= 0; i
< tm
->tm_mon
; ++i
)
44 if(i
== 0 || i
== 2 || i
== 4 || i
== 6 || i
== 7 || i
== 9 || i
== 11) { result
+= 31; }
45 else if(i
== 3 || i
== 5 || i
== 8 || i
== 10) { result
+= 30; }
46 else if(is_leap(tm
->tm_year
+ 1900)) { result
+= 29; }
47 else { result
+= 28; }
50 result
+= tm
->tm_mday
- 1;
52 result
+= tm
->tm_hour
;
60 /* Drop-in replacement for gmtime_r as some plattforms strip the function from their libc. */
61 struct tm
*cs_gmtime_r(const time_t *timep
, struct tm
*r
)
63 static const int16_t daysPerMonth
[13] =
70 31 + 28 + 31 + 30 + 31,
71 31 + 28 + 31 + 30 + 31 + 30,
72 31 + 28 + 31 + 30 + 31 + 30 + 31,
73 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
74 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
75 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
76 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
77 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
81 time_t work
= * timep
% 86400;
82 r
->tm_sec
= work
% 60;
84 r
->tm_min
= work
% 60;
85 r
->tm_hour
= work
/ 60;
86 work
= * timep
/ 86400;
87 r
->tm_wday
= (4 + work
) % 7;
91 time_t k
= is_leap(i
) ? 366 : 365;
102 r
->tm_year
= i
- 1900;
106 if(is_leap(i
) && work
> 58)
110 r
->tm_mday
= 2; /* 29.2. */
115 for(i
= 11; i
&& daysPerMonth
[i
] > work
; --i
) { ; }
117 r
->tm_mday
+= work
- daysPerMonth
[i
];
121 /* Drop-in replacement for ctime_r as some plattforms strip the function from their libc. */
122 char *cs_ctime_r(const time_t *timep
, char *buf
)
125 localtime_r(timep
, &t
);
126 strftime(buf
, 26, "%c\n", &t
);
130 void cs_ftime(struct timeb
*tp
)
133 gettimeofday(&tv
, NULL
);
134 #if defined(CLOCKFIX)
135 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
/ 1000;
150 void cs_ftimeus(struct timeb
*tp
)
153 gettimeofday(&tv
, NULL
);
154 #if defined(CLOCKFIX)
155 if (tv
.tv_sec
> lasttime
.tv_sec
|| (tv
.tv_sec
== lasttime
.tv_sec
&& tv
.tv_usec
>= lasttime
.tv_usec
)) // check for time issues!
157 lasttime
= tv
; // register this valid time
162 settimeofday(&tv
, NULL
); // set time back to last known valid time
163 //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** \n");
166 tp
->time
= tv
.tv_sec
;
167 tp
->millitm
= tv
.tv_usec
;
170 void cs_sleepms(uint32_t msec
)
172 // does not interfere with signals like sleep and usleep do
173 struct timespec req_ts
;
174 req_ts
.tv_sec
= msec
/ 1000;
175 req_ts
.tv_nsec
= (msec
% 1000) * 1000000L;
176 int32_t olderrno
= errno
; // Some OS (especially MacOSX) seem to set errno to ETIMEDOUT when sleeping
179 /* Sleep for the time specified in req_ts. If interrupted by a
180 signal, place the remaining time left to sleep back into req_ts. */
181 int rval
= nanosleep (&req_ts
, &req_ts
);
184 break; // Completed the entire sleep time; all done.
186 else if (errno
== EINTR
)
188 continue; // Interrupted by a signal. Try again.
192 break; // Some other error; bail out.
198 void cs_sleepus(uint32_t usec
)
200 // does not interfere with signals like sleep and usleep do
201 struct timespec req_ts
;
202 req_ts
.tv_sec
= usec
/ 1000000;
203 req_ts
.tv_nsec
= (usec
% 1000000) * 1000L;
204 int32_t olderrno
= errno
; // Some OS (especially MacOSX) seem to set errno to ETIMEDOUT when sleeping
208 /* Sleep for the time specified in req_ts. If interrupted by a
209 signal, place the remaining time left to sleep back into req_ts. */
210 int rval
= nanosleep (&req_ts
, &req_ts
);
213 break; // Completed the entire sleep time; all done.
215 else if (errno
== EINTR
)
217 continue; // Interrupted by a signal. Try again.
221 break; // Some other error; bail out.
227 void add_ms_to_timespec(struct timespec
*timeout
, int32_t msec
)
230 int64_t nanosecs
, secs
;
231 const int64_t NANOSEC_PER_MS
= 1000000;
232 const int64_t NANOSEC_PER_SEC
= 1000000000;
234 nanosecs
= (int64_t) (msec
* NANOSEC_PER_MS
+ now
.tv_nsec
);
235 if (nanosecs
>= NANOSEC_PER_SEC
)
237 secs
= now
.tv_sec
+ (nanosecs
/ NANOSEC_PER_SEC
);
238 nanosecs
%= NANOSEC_PER_SEC
;
244 timeout
->tv_sec
= (long)secs
;
245 timeout
->tv_nsec
= (long)nanosecs
;
248 void add_ms_to_timeb(struct timeb
*tb
, int32_t ms
)
251 tb
->time
+= ms
/ 1000;
252 tb
->millitm
+= (ms
% 1000);
257 if(tb
->millitm
>= 1000)
264 int64_t add_ms_to_timeb_diff(struct timeb
*tb
, int32_t ms
)
267 add_ms_to_timeb(tb
, ms
);
269 return comp_timeb(tb
, &tb_now
);
272 #if defined(__UCLIBC__)
273 #define __UCLIBC_VER (__UCLIBC_MAJOR__ * 10000 + __UCLIBC_MINOR__ * 100 + __UCLIBC_SUBLEVEL__)
275 #define __UCLIBC_VER 999999
278 #if defined(__GLIBC__)
279 #define __GLIBCVER (__GLIBC__ * 100 + __GLIBC_MINOR__)
281 #define __GLIBCVER 9999
284 // Assume we have HAVE_pthread_condattr_setclock if CLOCK_MONOTONIC is defined
285 #if defined(CLOCKFIX) && defined(CLOCK_MONOTONIC)
286 #define HAVE_pthread_condattr_setclock 1
289 #if defined(HAVE_pthread_condattr_setclock)
290 // UCLIBC 0.9.31 does not have pthread_condattr_setclock
291 #if __UCLIBC_VER < 932
292 #undef HAVE_pthread_condattr_setclock
294 // glibc 2.3.6 in ppc old toolchain do not have pthread_condattr_setclock
296 #undef HAVE_pthread_condattr_setclock
298 // android's libc not have pthread_condattr_setclock
300 #undef HAVE_pthread_condattr_setclock
304 void __cs_pthread_cond_init(const char *n
, pthread_cond_t
*cond
)
306 pthread_condattr_t attr
;
307 SAFE_CONDATTR_INIT_R(&attr
, n
); // init condattr with defaults
309 #if defined(HAVE_pthread_condattr_setclock)
310 enum clock_type ctype
= cs_getclocktype();
311 SAFE_CONDATTR_SETCLOCK_R(&attr
, (ctype
== CLOCK_TYPE_MONOTONIC
) ? CLOCK_MONOTONIC
: CLOCK_REALTIME
, n
);
314 SAFE_COND_INIT_R(cond
, &attr
, n
); // init thread with right clock assigned
315 pthread_condattr_destroy(&attr
);
318 void __cs_pthread_cond_init_nolog(const char *n
, pthread_cond_t
*cond
)
320 pthread_condattr_t attr
;
321 SAFE_CONDATTR_INIT_NOLOG_R(&attr
, n
); // init condattr with defaults
323 #if defined(HAVE_pthread_condattr_setclock)
324 enum clock_type ctype
= cs_getclocktype();
325 SAFE_CONDATTR_SETCLOCK_NOLOG_R(&attr
, (ctype
== CLOCK_TYPE_MONOTONIC
) ? CLOCK_MONOTONIC
: CLOCK_REALTIME
, n
);
328 SAFE_COND_INIT_NOLOG_R(cond
, &attr
, n
); // init thread with right clock assigned
329 pthread_condattr_destroy(&attr
);
333 void sleepms_on_cond(const char *n
, pthread_mutex_t
*mutex
, pthread_cond_t
*cond
, uint32_t msec
)
336 add_ms_to_timespec(&ts
, msec
);
337 SAFE_MUTEX_LOCK_R(mutex
, n
);
338 SAFE_COND_TIMEDWAIT_R(cond
, mutex
, &ts
, n
); // sleep on sleep_cond
339 SAFE_MUTEX_UNLOCK_R(mutex
, n
);
342 void cs_pthread_cond_init(const char *n
, pthread_mutex_t
*mutex
, pthread_cond_t
*cond
)
344 SAFE_MUTEX_INIT_R(mutex
, NULL
, n
);
345 __cs_pthread_cond_init(n
, cond
);
348 void cs_pthread_cond_init_nolog(const char *n
, pthread_mutex_t
*mutex
, pthread_cond_t
*cond
)
350 SAFE_MUTEX_INIT_NOLOG_R(mutex
, NULL
, n
);
351 __cs_pthread_cond_init(n
, cond
);
354 enum clock_type
cs_getclocktype(void) {
355 if (clock_type
== CLOCK_TYPE_UNKNOWN
) {
357 cs_gettime(&ts
); // init clock type
362 time_t cs_walltime(struct timeb
*tp
)
364 // we dont need to fetch time again and calculate if oscam is already using realtimeclock!
365 if (clock_type
!= CLOCK_TYPE_MONOTONIC
)
372 gettimeofday(&tv
, NULL
);
373 int64_t skew
= tv
.tv_sec
- ts
.tv_sec
;
374 return(tp
->time
+ skew
);
377 /* Return real time clock value calculated based on cs_gettime(). Use this instead of time() */
382 return cs_walltime(&tb
);
386 #include <mach/clock.h>
387 #include <mach/mach.h>
390 void cs_gettime(struct timespec
*ts
)
393 gettimeofday(&tv
, NULL
);
394 #if defined(CLOCKFIX)
395 if (tv
.tv_sec
> lasttime
.tv_sec
|| (tv
.tv_sec
== lasttime
.tv_sec
&& tv
.tv_usec
>= lasttime
.tv_usec
)) // check for time issues!
397 lasttime
= tv
; // register this valid time
402 settimeofday(&tv
, NULL
); // set time back to last known valid time
403 //fprintf(stderr, "*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING, SYSTEMTIME SET TO LAST KNOWN VALID TIME **** \n");
406 ts
->tv_sec
= tv
.tv_sec
;
407 ts
->tv_nsec
= tv
.tv_usec
* 1000;
408 clock_type
= CLOCK_TYPE_REALTIME
;
411 #if !defined(CLOCKFIX) || (!defined(CLOCK_MONOTONIC) && !defined(__MACH__))
413 gettimeofday(&tv
, NULL
);
414 ts
->tv_sec
= tv
.tv_sec
;
415 ts
->tv_nsec
= tv
.tv_usec
* 1000;
416 clock_type
= CLOCK_TYPE_REALTIME
;
418 #elif defined (__MACH__)
419 // OS X does not have clock_gettime, use clock_get_time
422 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK
, &cclock
);
423 clock_get_time(cclock
, &mts
);
424 mach_port_deallocate(mach_task_self(), cclock
);
425 ts
->tv_sec
= mts
.tv_sec
;
426 ts
->tv_nsec
= mts
.tv_nsec
;
427 clock_type
= CLOCK_TYPE_REALTIME
;
429 if (clock_type
== CLOCK_TYPE_REALTIME
) // monotonic returned error
431 clock_gettime(CLOCK_REALTIME
, ts
);
434 int32_t ret
= clock_gettime(CLOCK_MONOTONIC
, ts
);
435 clock_type
= CLOCK_TYPE_MONOTONIC
;
436 if ((ret
< 0 && errno
== EINVAL
)) // Error fetching time from this source (Shouldn't happen on modern Linux)
438 clock_gettime(CLOCK_REALTIME
, ts
);
439 clock_type
= CLOCK_TYPE_REALTIME
;