@ -27,6 +27,16 @@ in the source distribution for its full text.
# include <sys/types.h>
# include <fcntl.h>
# ifdef HAVE_DELAYACCT
# include <netlink/attr.h>
# include <netlink/netlink.h>
# include <netlink/genl/genl.h>
# include <netlink/genl/ctrl.h>
# include <netlink/socket.h>
# include <netlink/msg.h>
# include <linux/taskstats.h>
# endif
/*{
# include "ProcessList.h"
@ -72,6 +82,10 @@ typedef struct LinuxProcessList_ {
CPUData * cpus ;
TtyDriver * ttyDrivers ;
# ifdef HAVE_DELAYACCT
struct nl_sock * netlink_socket ;
int netlink_family ;
# endif
} LinuxProcessList ;
# ifndef PROCDIR
@ -192,6 +206,21 @@ static void LinuxProcessList_initTtyDrivers(LinuxProcessList* this) {
this - > ttyDrivers = ttyDrivers ;
}
# ifdef HAVE_DELAYACCT
static void LinuxProcessList_initNetlinkSocket ( LinuxProcessList * this ) {
this - > netlink_socket = nl_socket_alloc ( ) ;
if ( this - > netlink_socket = = NULL ) {
return ;
}
if ( nl_connect ( this - > netlink_socket , NETLINK_GENERIC ) < 0 ) {
return ;
}
this - > netlink_family = genl_ctrl_resolve ( this - > netlink_socket , TASKSTATS_GENL_NAME ) ;
}
# endif
ProcessList * ProcessList_new ( UsersTable * usersTable , Hashtable * pidWhiteList , uid_t userId ) {
LinuxProcessList * this = xCalloc ( 1 , sizeof ( LinuxProcessList ) ) ;
ProcessList * pl = & ( this - > super ) ;
@ -199,6 +228,10 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui
LinuxProcessList_initTtyDrivers ( this ) ;
# ifdef HAVE_DELAYACCT
LinuxProcessList_initNetlinkSocket ( this ) ;
# endif
// Update CPU count:
FILE * file = fopen ( PROCSTATFILE , " r " ) ;
if ( file = = NULL ) {
@ -234,6 +267,12 @@ void ProcessList_delete(ProcessList* pl) {
}
free ( this - > ttyDrivers ) ;
}
# ifdef HAVE_DELAYACCT
if ( this - > netlink_socket ) {
nl_close ( this - > netlink_socket ) ;
nl_socket_free ( this - > netlink_socket ) ;
}
# endif
free ( this ) ;
}
@ -552,6 +591,75 @@ static void LinuxProcessList_readOomData(LinuxProcess* process, const char* dirn
fclose ( file ) ;
}
# ifdef HAVE_DELAYACCT
static int handleNetlinkMsg ( struct nl_msg * nlmsg , void * linuxProcess ) {
struct nlmsghdr * nlhdr ;
struct nlattr * nlattrs [ TASKSTATS_TYPE_MAX + 1 ] ;
struct nlattr * nlattr ;
struct taskstats * stats ;
int rem ;
unsigned long long int timeDelta ;
LinuxProcess * lp = ( LinuxProcess * ) linuxProcess ;
nlhdr = nlmsg_hdr ( nlmsg ) ;
if ( genlmsg_parse ( nlhdr , 0 , nlattrs , TASKSTATS_TYPE_MAX , NULL ) < 0 ) {
return NL_SKIP ;
}
if ( ( nlattr = nlattrs [ TASKSTATS_TYPE_AGGR_PID ] ) | | ( nlattr = nlattrs [ TASKSTATS_TYPE_NULL ] ) ) {
stats = nla_data ( nla_next ( nla_data ( nlattr ) , & rem ) ) ;
assert ( lp - > super . pid = = stats - > ac_pid ) ;
timeDelta = ( stats - > ac_etime * 1000 - lp - > delay_read_time ) ;
# define BOUNDS(x) isnan(x) ? 0.0 : (x > 100) ? 100.0 : x;
# define DELTAPERC(x,y) BOUNDS((float) (x - y) / timeDelta * 100);
lp - > cpu_delay_percent = DELTAPERC ( stats - > cpu_delay_total , lp - > cpu_delay_total ) ;
lp - > blkio_delay_percent = DELTAPERC ( stats - > blkio_delay_total , lp - > blkio_delay_total ) ;
lp - > swapin_delay_percent = DELTAPERC ( stats - > swapin_delay_total , lp - > swapin_delay_total ) ;
# undef DELTAPERC
# undef BOUNDS
lp - > swapin_delay_total = stats - > swapin_delay_total ;
lp - > blkio_delay_total = stats - > blkio_delay_total ;
lp - > cpu_delay_total = stats - > cpu_delay_total ;
lp - > delay_read_time = stats - > ac_etime * 1000 ;
}
return NL_OK ;
}
static void LinuxProcessList_readDelayAcctData ( LinuxProcessList * this , LinuxProcess * process ) {
struct nl_msg * msg ;
if ( nl_socket_modify_cb ( this - > netlink_socket , NL_CB_VALID , NL_CB_CUSTOM , handleNetlinkMsg , process ) < 0 ) {
return ;
}
if ( ! ( msg = nlmsg_alloc ( ) ) ) {
return ;
}
if ( ! genlmsg_put ( msg , NL_AUTO_PID , NL_AUTO_SEQ , this - > netlink_family , 0 , NLM_F_REQUEST , TASKSTATS_CMD_GET , TASKSTATS_VERSION ) ) {
nlmsg_free ( msg ) ;
}
if ( nla_put_u32 ( msg , TASKSTATS_CMD_ATTR_PID , process - > super . pid ) < 0 ) {
nlmsg_free ( msg ) ;
}
if ( nl_send_sync ( this - > netlink_socket , msg ) < 0 ) {
process - > swapin_delay_percent = - 1LL ;
process - > blkio_delay_percent = - 1LL ;
process - > cpu_delay_percent = - 1LL ;
return ;
}
if ( nl_recvmsgs_default ( this - > netlink_socket ) < 0 ) {
return ;
}
}
# endif
static void setCommand ( Process * process , const char * command , int len ) {
if ( process - > comm & & process - > commLen > = len ) {
strncpy ( process - > comm , command , len + 1 ) ;
@ -750,6 +858,10 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, const char*
}
}
# ifdef HAVE_DELAYACCT
LinuxProcessList_readDelayAcctData ( this , lp ) ;
# endif
# ifdef HAVE_CGROUP
if ( settings - > flags & PROCESS_FLAG_LINUX_CGROUP )
LinuxProcessList_readCGroupFile ( lp , dirname , name ) ;