2006-01-19 04:42:42 +03:00
/*
2015-11-02 19:16:37 +03:00
* Copyright ( C ) 2015 Anton Ivanov ( aivanov @ { brocade . com , kot - begemot . co . uk } )
* Copyright ( C ) 2015 Thomas Meyer ( thomas @ m3y3r . de )
* Copyright ( C ) 2012 - 2014 Cisco Systems
2007-10-16 12:26:54 +04:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike { addtoit , linux . intel } . com )
2006-01-19 04:42:42 +03:00
* Licensed under the GPL
*/
2007-10-16 12:26:54 +04:00
# include <stddef.h>
# include <errno.h>
# include <signal.h>
2006-01-19 04:42:42 +03:00
# include <time.h>
2005-04-17 02:20:36 +04:00
# include <sys/time.h>
2012-10-08 06:27:32 +04:00
# include <kern_util.h>
# include <os.h>
2015-11-02 19:16:37 +03:00
# include <string.h>
# include <timer-internal.h>
2006-01-19 04:42:42 +03:00
2015-11-02 19:16:37 +03:00
static timer_t event_high_res_timer = 0 ;
2006-09-26 10:33:05 +04:00
2015-11-02 19:16:37 +03:00
static inline long long timeval_to_ns ( const struct timeval * tv )
{
return ( ( long long ) tv - > tv_sec * UM_NSEC_PER_SEC ) +
tv - > tv_usec * UM_NSEC_PER_USEC ;
2006-01-19 04:42:42 +03:00
}
2015-11-02 19:16:37 +03:00
static inline long long timespec_to_ns ( const struct timespec * ts )
2007-10-16 12:27:25 +04:00
{
2015-11-02 19:16:37 +03:00
return ( ( long long ) ts - > tv_sec * UM_NSEC_PER_SEC ) +
ts - > tv_nsec ;
}
2007-10-16 12:27:25 +04:00
2015-11-02 19:16:37 +03:00
long long os_persistent_clock_emulation ( void ) {
struct timespec realtime_tp ;
2007-10-16 12:27:25 +04:00
2015-11-02 19:16:37 +03:00
clock_gettime ( CLOCK_REALTIME , & realtime_tp ) ;
return timespec_to_ns ( & realtime_tp ) ;
2007-10-16 12:27:25 +04:00
}
2007-10-16 12:27:27 +04:00
/**
2015-11-02 19:16:37 +03:00
* os_timer_create ( ) - create an new posix ( interval ) timer
2007-10-16 12:27:27 +04:00
*/
2015-11-02 19:16:37 +03:00
int os_timer_create ( void * timer ) {
timer_t * t = timer ;
if ( t = = NULL ) {
t = & event_high_res_timer ;
}
if ( timer_create (
CLOCK_MONOTONIC ,
NULL ,
t ) = = - 1 ) {
return - 1 ;
}
return 0 ;
2007-10-16 12:27:27 +04:00
}
2015-11-02 19:16:37 +03:00
int os_timer_set_interval ( void * timer , void * i )
2006-01-19 04:42:42 +03:00
{
2015-11-02 19:16:37 +03:00
struct itimerspec its ;
unsigned long long nsec ;
timer_t * t = timer ;
struct itimerspec * its_in = i ;
2007-10-16 12:26:54 +04:00
2015-11-02 19:16:37 +03:00
if ( t = = NULL ) {
t = & event_high_res_timer ;
}
2007-10-16 12:27:22 +04:00
2015-11-02 19:16:37 +03:00
nsec = UM_NSEC_PER_SEC / UM_HZ ;
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
if ( its_in ! = NULL ) {
its . it_value . tv_sec = its_in - > it_value . tv_sec ;
its . it_value . tv_nsec = its_in - > it_value . tv_nsec ;
} else {
its . it_value . tv_sec = 0 ;
its . it_value . tv_nsec = nsec ;
}
2005-04-17 02:20:36 +04:00
2015-11-02 19:16:37 +03:00
its . it_interval . tv_sec = 0 ;
its . it_interval . tv_nsec = nsec ;
2005-04-17 02:20:36 +04:00
2015-11-02 19:16:37 +03:00
if ( timer_settime ( * t , 0 , & its , NULL ) = = - 1 ) {
return - errno ;
}
2005-04-17 02:20:36 +04:00
2007-12-01 23:16:29 +03:00
return 0 ;
2007-11-29 03:21:51 +03:00
}
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
/**
* os_timer_remain ( ) - returns the remaining nano seconds of the given interval
* timer
* Because this is the remaining time of an interval timer , which correspondends
* to HZ , this value can never be bigger than one second . Just
* the nanosecond part of the timer is returned .
* The returned time is relative to the start time of the interval timer .
* Return an negative value in an error case .
*/
long os_timer_remain ( void * timer )
2008-05-13 01:02:00 +04:00
{
2015-11-02 19:16:37 +03:00
struct itimerspec its ;
timer_t * t = timer ;
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
if ( t = = NULL ) {
t = & event_high_res_timer ;
}
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
if ( timer_gettime ( t , & its ) = = - 1 ) {
return - errno ;
}
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
return its . it_value . tv_nsec ;
}
2008-05-13 01:02:00 +04:00
2019-05-06 15:39:37 +03:00
int os_timer_one_shot ( unsigned long ticks )
2015-11-02 19:16:37 +03:00
{
struct itimerspec its ;
unsigned long long nsec ;
unsigned long sec ;
2008-06-06 09:46:10 +04:00
2015-11-02 19:16:37 +03:00
nsec = ( ticks + 1 ) ;
sec = nsec / UM_NSEC_PER_SEC ;
nsec = nsec % UM_NSEC_PER_SEC ;
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
its . it_value . tv_sec = nsec / UM_NSEC_PER_SEC ;
its . it_value . tv_nsec = nsec ;
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
its . it_interval . tv_sec = 0 ;
its . it_interval . tv_nsec = 0 ; // we cheat here
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
timer_settime ( event_high_res_timer , 0 , & its , NULL ) ;
return 0 ;
2008-05-13 01:02:00 +04:00
}
2015-11-02 19:16:37 +03:00
/**
* os_timer_disable ( ) - disable the posix ( interval ) timer
* Returns the remaining interval timer time in nanoseconds
*/
long long os_timer_disable ( void )
2008-05-13 01:02:00 +04:00
{
2015-11-02 19:16:37 +03:00
struct itimerspec its ;
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
memset ( & its , 0 , sizeof ( struct itimerspec ) ) ;
timer_settime ( event_high_res_timer , 0 , & its , & its ) ;
return its . it_value . tv_sec * UM_NSEC_PER_SEC + its . it_value . tv_nsec ;
2007-11-29 03:21:51 +03:00
}
2015-11-02 19:16:37 +03:00
long long os_vnsecs ( void )
2007-11-29 03:21:51 +03:00
{
2015-11-02 19:16:37 +03:00
struct timespec ts ;
2008-06-06 09:46:10 +04:00
2015-11-02 19:16:37 +03:00
clock_gettime ( CLOCK_PROCESS_CPUTIME_ID , & ts ) ;
return timespec_to_ns ( & ts ) ;
}
2007-11-29 03:21:51 +03:00
2015-11-02 19:16:37 +03:00
long long os_nsecs ( void )
{
struct timespec ts ;
2007-11-29 03:21:51 +03:00
2015-11-02 19:16:37 +03:00
clock_gettime ( CLOCK_MONOTONIC , & ts ) ;
return timespec_to_ns ( & ts ) ;
2007-11-29 03:21:51 +03:00
}
2015-11-02 19:16:37 +03:00
/**
* os_idle_sleep ( ) - sleep for a given time of nsecs
* @ nsecs : nanoseconds to sleep
*/
void os_idle_sleep ( unsigned long long nsecs )
2006-01-19 04:42:42 +03:00
{
2007-11-29 03:21:51 +03:00
struct timespec ts ;
2015-11-02 19:16:37 +03:00
if ( nsecs < = 0 ) {
return ;
}
2008-05-13 01:02:00 +04:00
2015-11-02 19:16:37 +03:00
ts = ( ( struct timespec ) {
. tv_sec = nsecs / UM_NSEC_PER_SEC ,
. tv_nsec = nsecs % UM_NSEC_PER_SEC
} ) ;
2006-01-19 04:42:42 +03:00
2015-11-02 19:16:37 +03:00
/*
* Relay the signal if clock_nanosleep is interrupted .
*/
if ( clock_nanosleep ( CLOCK_MONOTONIC , 0 , & ts , NULL ) ) {
2008-05-13 01:02:00 +04:00
deliver_alarm ( ) ;
2015-11-02 19:16:37 +03:00
}
2006-01-19 04:42:42 +03:00
}