2019-05-27 09:55:13 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-08-09 16:31:30 +04:00
/*
* Controller of read / write threads for virtio - trace
*
* Copyright ( C ) 2012 Hitachi , Ltd .
* Created by Yoshihiro Yunomae < yoshihiro . yunomae . ez @ hitachi . com >
* Masami Hiramatsu < masami . hiramatsu . pt @ hitachi . com >
*/
# define _GNU_SOURCE
# include <fcntl.h>
# include <poll.h>
# include <signal.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include "trace-agent.h"
# define HOST_MSG_SIZE 256
# define EVENT_WAIT_MSEC 100
static volatile sig_atomic_t global_signal_val ;
bool global_sig_receive ; /* default false */
bool global_run_operation ; /* default false*/
/* Handle SIGTERM/SIGINT/SIGQUIT to exit */
static void signal_handler ( int sig )
{
global_signal_val = sig ;
}
int rw_ctl_init ( const char * ctl_path )
{
int ctl_fd ;
ctl_fd = open ( ctl_path , O_RDONLY ) ;
if ( ctl_fd = = - 1 ) {
pr_err ( " Cannot open ctl_fd \n " ) ;
goto error ;
}
return ctl_fd ;
error :
exit ( EXIT_FAILURE ) ;
}
static int wait_order ( int ctl_fd )
{
struct pollfd poll_fd ;
int ret = 0 ;
while ( ! global_sig_receive ) {
poll_fd . fd = ctl_fd ;
poll_fd . events = POLLIN ;
ret = poll ( & poll_fd , 1 , EVENT_WAIT_MSEC ) ;
if ( global_signal_val ) {
global_sig_receive = true ;
pr_info ( " Receive interrupt %d \n " , global_signal_val ) ;
/* Wakes rw-threads when they are sleeping */
if ( ! global_run_operation )
pthread_cond_broadcast ( & cond_wakeup ) ;
ret = - 1 ;
break ;
}
if ( ret < 0 ) {
pr_err ( " Polling error \n " ) ;
goto error ;
}
if ( ret )
break ;
} ;
return ret ;
error :
exit ( EXIT_FAILURE ) ;
}
/*
* contol read / write threads by handling global_run_operation
*/
void * rw_ctl_loop ( int ctl_fd )
{
ssize_t rlen ;
char buf [ HOST_MSG_SIZE ] ;
int ret ;
/* Setup signal handlers */
signal ( SIGTERM , signal_handler ) ;
signal ( SIGINT , signal_handler ) ;
signal ( SIGQUIT , signal_handler ) ;
while ( ! global_sig_receive ) {
ret = wait_order ( ctl_fd ) ;
if ( ret < 0 )
break ;
rlen = read ( ctl_fd , buf , sizeof ( buf ) ) ;
if ( rlen < 0 ) {
pr_err ( " read data error in ctl thread \n " ) ;
goto error ;
}
if ( rlen = = 2 & & buf [ 0 ] = = ' 1 ' ) {
/*
* If host writes ' 1 ' to a control path ,
* this controller wakes all read / write threads .
*/
global_run_operation = true ;
pthread_cond_broadcast ( & cond_wakeup ) ;
pr_debug ( " Wake up all read/write threads \n " ) ;
} else if ( rlen = = 2 & & buf [ 0 ] = = ' 0 ' ) {
/*
* If host writes ' 0 ' to a control path , read / write
* threads will wait for notification from Host .
*/
global_run_operation = false ;
pr_debug ( " Stop all read/write threads \n " ) ;
} else
pr_info ( " Invalid host notification: %s \n " , buf ) ;
}
return NULL ;
error :
exit ( EXIT_FAILURE ) ;
}