2021-01-15 13:12:18 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2020 Intel Corporation
* Author : Johannes Berg < johannes @ sipsolutions . net >
*/
2021-08-02 23:40:31 +03:00
# include <stdbool.h>
2021-01-15 13:12:18 +01:00
# include <os.h>
# include <errno.h>
# include <sched.h>
# include <unistd.h>
# include <kern_util.h>
# include <sys/select.h>
# include <stdio.h>
# include <sys/timerfd.h>
# include "rtc.h"
static int uml_rtc_irq_fds [ 2 ] ;
void uml_rtc_send_timetravel_alarm ( void )
{
unsigned long long c = 1 ;
CATCH_EINTR ( write ( uml_rtc_irq_fds [ 1 ] , & c , sizeof ( c ) ) ) ;
}
int uml_rtc_start ( bool timetravel )
{
int err ;
if ( timetravel ) {
int err = os_pipe ( uml_rtc_irq_fds , 1 , 1 ) ;
if ( err )
goto fail ;
} else {
uml_rtc_irq_fds [ 0 ] = timerfd_create ( CLOCK_REALTIME , TFD_CLOEXEC ) ;
if ( uml_rtc_irq_fds [ 0 ] < 0 ) {
err = - errno ;
goto fail ;
}
/* apparently timerfd won't send SIGIO, use workaround */
sigio_broken ( uml_rtc_irq_fds [ 0 ] ) ;
err = add_sigio_fd ( uml_rtc_irq_fds [ 0 ] ) ;
if ( err < 0 ) {
close ( uml_rtc_irq_fds [ 0 ] ) ;
goto fail ;
}
}
return uml_rtc_irq_fds [ 0 ] ;
fail :
uml_rtc_stop ( timetravel ) ;
return err ;
}
int uml_rtc_enable_alarm ( unsigned long long delta_seconds )
{
struct itimerspec it = {
. it_value = {
. tv_sec = delta_seconds ,
} ,
} ;
if ( timerfd_settime ( uml_rtc_irq_fds [ 0 ] , 0 , & it , NULL ) )
return - errno ;
return 0 ;
}
void uml_rtc_disable_alarm ( void )
{
uml_rtc_enable_alarm ( 0 ) ;
}
void uml_rtc_stop ( bool timetravel )
{
if ( timetravel )
os_close_file ( uml_rtc_irq_fds [ 1 ] ) ;
else
ignore_sigio_fd ( uml_rtc_irq_fds [ 0 ] ) ;
os_close_file ( uml_rtc_irq_fds [ 0 ] ) ;
}