2015-08-19 10:30:00 +05:30
/*
* pids . c - task / thread / process related declarations for libproc
*
* Copyright ( C ) 1998 - 2005 Albert Cahalan
* Copyright ( C ) 2015 Craig Small < csmall @ enc . com . au >
* Copyright ( C ) 2015 Jim Warner < james . warner @ comcast . net >
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
//efine _GNU_SOURCE // for qsort_r
# include <ctype.h>
# include <errno.h>
# include <fcntl.h>
# include <limits.h>
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <proc/pids.h>
# include "procps-private.h"
2015-09-07 10:30:00 +05:30
# include "devname.h" // and a few headers for our
# include "readproc.h" // bridged libprocps support
# include "wchan.h" // ( maybe just temporary? )
2015-08-19 10:30:00 +05:30
//#define UNREF_RPTHASH // report on hashing, at uref time
2015-08-20 10:30:00 +05:30
//#define FPRINT_STACKS // enable validate_stacks output
2015-08-19 10:30:00 +05:30
# define FILL_ID_MAX 255 // upper limit for pid/uid fills
2015-08-20 10:30:00 +05:30
# define MEMORY_INCR 128 // amt by which allocations grow
2015-08-19 10:30:00 +05:30
2015-08-26 10:30:00 +05:30
# define READS_BEGUN (info->read) // a read is in progress
2015-08-19 10:30:00 +05:30
enum pids_item PROCPS_PIDS_logical_end = PROCPS_PIDS_noop + 1 ;
enum pids_item PROCPS_PIDS_physical_end = PROCPS_PIDS_noop + 2 ;
struct stacks_extent { // callers see a pids_stacks struct
struct pids_stack * * stacks ;
int ext_numitems ; // includes 'physical_end' delimiter
int ext_numstacks ;
struct stacks_extent * next ;
} ;
struct procps_pidsinfo {
int refcount ;
int maxitems ; // includes 'physical_end' delimiter
int curitems ; // includes 'logical_end' delimiter
enum pids_item * items ; // includes 'phy/log_end' delimiters
struct pids_stack * * anchor ; // reapable stacks (consolidated extents)
int alloc_total ; // number of above pointers allocated
int inuse_total ; // number of above pointers occupied
2015-09-10 10:30:00 +05:30
struct stacks_extent * extents ; // anchor for all resettable extents
2015-09-11 10:30:00 +05:30
struct stacks_extent * otherexts ; // anchor for single stack invariant extents
2015-08-19 10:30:00 +05:30
int history_yes ; // need historical data
struct history_info * hist ; // pointer to historical support data
int dirty_stacks ; // extents need dynamic storage clean
2015-08-26 10:30:00 +05:30
struct stacks_extent * read ; // an extent used for active reads
proc_t * ( * read_something ) ( PROCTAB * , proc_t * ) ; // readproc/readeither via which
2015-08-19 10:30:00 +05:30
unsigned pgs2k_shift ; // to convert some proc vaules
unsigned flags ; // the old library PROC_FILL flagss
PROCTAB * PT ; // the old library essential interface
struct pids_counts counts ; // counts for 'procps_pids_stacks_fill'
2015-08-20 10:30:00 +05:30
struct pids_reap reaped ; // counts + stacks for 'procps_pids_reap'
2015-08-19 10:30:00 +05:30
} ;
// ___ Results 'Set' Support ||||||||||||||||||||||||||||||||||||||||||||||||||
/* note: the vast majority of these 'set' functions have no need for
the procps_pidsinfo structure , but it ' s being passed to all
bacause of the CVT_set requirement & for future flexibility */
# define setNAME(e) set_results_ ## e
# define setDECL(e) static void setNAME(e) \
( struct procps_pidsinfo * I , struct pids_result * R , proc_t * P )
// convert pages to kib
# define CVT_set(e,t,x) setDECL(e) { \
R - > result . t = ( unsigned long ) ( P - > x ) < < I - > pgs2k_shift ; }
// strdup of a static char array
# define DUP_set(e,x) setDECL(e) { \
( void ) I ; R - > result . str = strdup ( P - > x ) ; }
// regular assignment copy
# define REG_set(e,t,x) setDECL(e) { \
( void ) I ; R - > result . t = P - > x ; }
// take ownership of a regular char* string
# define STR_set(e,x) setDECL(e) { \
( void ) I ; R - > result . str = P - > x ; P - > x = NULL ; }
// take ownership of a vectorized single string
2015-08-26 10:30:00 +05:30
# define STV_set(e,x) setDECL(e) { \
( void ) I ; R - > result . str = * P - > x ; P - > x = NULL ; }
// take ownership of true vectorized strings
2015-08-19 10:30:00 +05:30
# define VEC_set(e,x) setDECL(e) { \
2015-08-26 10:30:00 +05:30
( void ) I ; R - > result . strv = P - > x ; P - > x = NULL ; }
2015-08-19 10:30:00 +05:30
2015-09-09 10:30:00 +05:30
REG_set ( ADDR_END_CODE , ul_int , end_code )
REG_set ( ADDR_KSTK_EIP , ul_int , kstk_eip )
REG_set ( ADDR_KSTK_ESP , ul_int , kstk_esp )
REG_set ( ADDR_START_CODE , ul_int , start_code )
REG_set ( ADDR_START_STACK , ul_int , start_stack )
2015-08-19 10:30:00 +05:30
REG_set ( ALARM , sl_int , alarm )
2015-08-26 10:30:00 +05:30
STV_set ( CGROUP , cgroup )
VEC_set ( CGROUP_V , cgroup )
2015-08-19 10:30:00 +05:30
STR_set ( CMD , cmd )
2015-08-26 10:30:00 +05:30
STV_set ( CMDLINE , cmdline )
VEC_set ( CMDLINE_V , cmdline )
STV_set ( ENVIRON , environ )
VEC_set ( ENVIRON_V , environ )
2015-08-19 10:30:00 +05:30
REG_set ( EXIT_SIGNAL , s_int , exit_signal )
REG_set ( FLAGS , ul_int , flags )
REG_set ( FLT_MAJ , ul_int , maj_flt )
REG_set ( FLT_MAJ_C , ul_int , cmaj_flt )
REG_set ( FLT_MAJ_DELTA , ul_int , maj_delta )
REG_set ( FLT_MIN , ul_int , min_flt )
REG_set ( FLT_MIN_C , ul_int , cmin_flt )
REG_set ( FLT_MIN_DELTA , ul_int , min_delta )
REG_set ( ID_EGID , u_int , egid )
REG_set ( ID_EGROUP , str , egroup )
REG_set ( ID_EUID , u_int , euid )
REG_set ( ID_EUSER , str , euser )
REG_set ( ID_FGID , u_int , fgid )
REG_set ( ID_FGROUP , str , fgroup )
REG_set ( ID_FUID , u_int , fuid )
REG_set ( ID_FUSER , str , fuser )
REG_set ( ID_PGRP , s_int , pgrp )
REG_set ( ID_PID , s_int , tid )
REG_set ( ID_PPID , s_int , ppid )
REG_set ( ID_RGID , u_int , rgid )
REG_set ( ID_RGROUP , str , rgroup )
REG_set ( ID_RUID , u_int , ruid )
REG_set ( ID_RUSER , str , ruser )
REG_set ( ID_SESSION , s_int , session )
REG_set ( ID_SGID , u_int , sgid )
REG_set ( ID_SGROUP , str , sgroup )
REG_set ( ID_SUID , u_int , suid )
REG_set ( ID_SUSER , str , suser )
REG_set ( ID_TGID , s_int , tgid )
REG_set ( ID_TPGID , s_int , tpgid )
2015-08-26 10:30:00 +05:30
setDECL ( LXCNAME ) { ( void ) I ; R - > result . str = ( char * ) P - > lxcname ; }
2015-08-19 10:30:00 +05:30
REG_set ( MEM_CODE , sl_int , trs )
CVT_set ( MEM_CODE_KIB , ul_int , trs )
REG_set ( MEM_DATA , sl_int , drs )
CVT_set ( MEM_DATA_KIB , ul_int , drs )
REG_set ( MEM_DT , sl_int , dt )
REG_set ( MEM_LRS , sl_int , lrs )
REG_set ( MEM_RES , sl_int , resident )
CVT_set ( MEM_RES_KIB , ul_int , resident )
REG_set ( MEM_SHR , sl_int , share )
CVT_set ( MEM_SHR_KIB , ul_int , share )
REG_set ( MEM_VIRT , sl_int , size )
CVT_set ( MEM_VIRT_KIB , ul_int , size )
REG_set ( NICE , sl_int , nice )
REG_set ( NLWP , s_int , nlwp )
2015-09-03 18:02:19 +05:30
REG_set ( NS_IPC , ul_int , ns . ns [ 0 ] )
REG_set ( NS_MNT , ul_int , ns . ns [ 1 ] )
REG_set ( NS_NET , ul_int , ns . ns [ 2 ] )
REG_set ( NS_PID , ul_int , ns . ns [ 3 ] )
REG_set ( NS_USER , ul_int , ns . ns [ 4 ] )
REG_set ( NS_UTS , ul_int , ns . ns [ 5 ] )
2015-08-19 10:30:00 +05:30
REG_set ( OOM_ADJ , s_int , oom_adj )
REG_set ( OOM_SCORE , s_int , oom_score )
REG_set ( PRIORITY , s_int , priority )
REG_set ( PROCESSOR , u_int , processor )
REG_set ( RSS , sl_int , rss )
REG_set ( RSS_RLIM , ul_int , rss_rlim )
REG_set ( RTPRIO , ul_int , rtprio )
REG_set ( SCHED_CLASS , ul_int , sched )
STR_set ( SD_MACH , sd_mach )
STR_set ( SD_OUID , sd_ouid )
STR_set ( SD_SEAT , sd_seat )
STR_set ( SD_SESS , sd_sess )
STR_set ( SD_SLICE , sd_slice )
STR_set ( SD_UNIT , sd_unit )
STR_set ( SD_UUNIT , sd_uunit )
DUP_set ( SIGBLOCKED , blocked )
DUP_set ( SIGCATCH , sigcatch )
DUP_set ( SIGIGNORE , sigignore )
DUP_set ( SIGNALS , signal )
DUP_set ( SIGPENDING , _sigpnd )
REG_set ( STATE , s_ch , state )
STR_set ( SUPGIDS , supgid )
STR_set ( SUPGROUPS , supgrp )
setDECL ( TICS_ALL ) { ( void ) I ; R - > result . ull_int = P - > utime + P - > stime ; }
setDECL ( TICS_ALL_C ) { ( void ) I ; R - > result . ull_int = P - > utime + P - > stime + P - > cutime + P - > cstime ; }
REG_set ( TICS_DELTA , u_int , pcpu )
REG_set ( TICS_SYSTEM , ull_int , stime )
REG_set ( TICS_SYSTEM_C , ull_int , cstime )
REG_set ( TICS_USER , ull_int , utime )
REG_set ( TICS_USER_C , ull_int , cutime )
REG_set ( TIME_START , ull_int , start_time )
REG_set ( TTY , s_int , tty )
2015-09-07 10:30:00 +05:30
setDECL ( TTY_NAME ) { char buf [ 64 ] ; ( void ) I ; dev_to_tty ( buf , sizeof ( buf ) , P - > tty , P - > tid , ABBREV_DEV ) ; R - > result . str = strdup ( buf ) ; }
2015-08-19 10:30:00 +05:30
REG_set ( VM_DATA , ul_int , vm_data )
REG_set ( VM_EXE , ul_int , vm_exe )
REG_set ( VM_LIB , ul_int , vm_lib )
REG_set ( VM_LOCK , ul_int , vm_lock )
REG_set ( VM_RSS , ul_int , vm_rss )
REG_set ( VM_SIZE , ul_int , vm_size )
REG_set ( VM_STACK , ul_int , vm_stack )
REG_set ( VM_SWAP , ul_int , vm_swap )
setDECL ( VM_USED ) { ( void ) I ; R - > result . ul_int = P - > vm_swap + P - > vm_rss ; }
REG_set ( VSIZE_PGS , ul_int , vsize )
2015-09-09 10:30:00 +05:30
REG_set ( WCHAN_ADDR , ul_int , wchan )
2015-08-19 10:30:00 +05:30
setDECL ( WCHAN_NAME ) { ( void ) I ; R - > result . str = strdup ( lookup_wchan ( P - > tid ) ) ; }
2015-09-29 10:30:00 +05:30
setDECL ( extra ) { ( void ) I ; ( void ) R ; ( void ) P ; return ; }
2015-08-19 10:30:00 +05:30
setDECL ( noop ) { ( void ) I ; ( void ) R ; ( void ) P ; return ; }
setDECL ( logical_end ) { ( void ) I ; ( void ) R ; ( void ) P ; return ; }
setDECL ( physical_end ) { ( void ) I ; ( void ) R ; ( void ) P ; return ; }
# undef setDECL
# undef CVT_set
# undef DUP_set
# undef REG_set
# undef STR_set
2015-08-26 10:30:00 +05:30
# undef STV_set
2015-08-19 10:30:00 +05:30
# undef VEC_set
2015-08-26 10:30:00 +05:30
// ___ Free Storage Support |||||||||||||||||||||||||||||||||||||||||||||||||||
# define freNAME(e) free_results_ ## e
static void freNAME ( str ) ( struct pids_result * R ) {
if ( R - > result . str ) free ( ( void * ) R - > result . str ) ;
}
static void freNAME ( strv ) ( struct pids_result * R ) {
if ( R - > result . str & & * R - > result . strv ) free ( ( void * ) * R - > result . strv ) ;
}
2015-08-19 10:30:00 +05:30
// ___ Sorting Support ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
struct sort_parms {
int offset ;
enum pids_sort_order order ;
} ;
# define srtNAME(e) sort_results_ ## e
# define NUM_srt(T) static int srtNAME(T) ( \
const struct pids_stack * * A , const struct pids_stack * * B , struct sort_parms * P ) { \
const struct pids_result * a = ( * A ) - > head + P - > offset ; \
const struct pids_result * b = ( * B ) - > head + P - > offset ; \
2015-09-13 10:30:00 +05:30
return P - > order * ( a - > result . T - b - > result . T ) ; }
2015-08-19 10:30:00 +05:30
# define REG_srt(T) static int srtNAME(T) ( \
const struct pids_stack * * A , const struct pids_stack * * B , struct sort_parms * P ) { \
const struct pids_result * a = ( * A ) - > head + P - > offset ; \
const struct pids_result * b = ( * B ) - > head + P - > offset ; \
2015-09-13 10:30:00 +05:30
if ( a - > result . T > b - > result . T ) return P - > order > 0 ? 1 : - 1 ; \
if ( a - > result . T < b - > result . T ) return P - > order > 0 ? - 1 : 1 ; \
2015-08-19 10:30:00 +05:30
return 0 ; }
NUM_srt ( s_ch )
NUM_srt ( s_int )
NUM_srt ( sl_int )
REG_srt ( u_int )
REG_srt ( ul_int )
REG_srt ( ull_int )
static int srtNAME ( str ) (
const struct pids_stack * * A , const struct pids_stack * * B , struct sort_parms * P ) {
const struct pids_result * a = ( * A ) - > head + P - > offset ;
const struct pids_result * b = ( * B ) - > head + P - > offset ;
2015-09-13 10:30:00 +05:30
return P - > order * strcoll ( a - > result . str , b - > result . str ) ;
2015-08-19 10:30:00 +05:30
}
2015-08-26 10:30:00 +05:30
static int srtNAME ( strv ) (
const struct pids_stack * * A , const struct pids_stack * * B , struct sort_parms * P ) {
const struct pids_result * a = ( * A ) - > head + P - > offset ;
const struct pids_result * b = ( * B ) - > head + P - > offset ;
if ( ! a - > result . strv | | ! b - > result . strv ) return 0 ;
2015-09-13 10:30:00 +05:30
return P - > order * strcoll ( ( * a - > result . strv ) , ( * b - > result . strv ) ) ;
2015-08-26 10:30:00 +05:30
}
2015-09-07 10:30:00 +05:30
static int srtNAME ( strvers ) (
const struct pids_stack * * A , const struct pids_stack * * B , struct sort_parms * P ) {
const struct pids_result * a = ( * A ) - > head + P - > offset ;
const struct pids_result * b = ( * B ) - > head + P - > offset ;
2015-09-13 10:30:00 +05:30
return P - > order * strverscmp ( a - > result . str , b - > result . str ) ;
2015-09-07 10:30:00 +05:30
}
2015-08-19 10:30:00 +05:30
static int srtNAME ( noop ) (
const struct pids_stack * * A , const struct pids_stack * * B , enum pids_item * O ) {
( void ) A ; ( void ) B ; ( void ) O ;
return 0 ;
}
# undef NUM_srt
# undef REG_srt
// ___ Controlling Table ||||||||||||||||||||||||||||||||||||||||||||||||||||||
// from either 'stat' or 'status' (preferred)
# define f_either PROC_SPARE_1
# define f_grp PROC_FILLGRP
# define f_lxc PROC_FILL_LXC
# define f_ns PROC_FILLNS
# define f_oom PROC_FILLOOM
# define f_stat PROC_FILLSTAT
# define f_statm PROC_FILLMEM
# define f_status PROC_FILLSTATUS
# define f_systemd PROC_FILLSYSTEMD
# define f_usr PROC_FILLUSR
2015-08-28 10:30:00 +05:30
// these next three will yield true verctorized strings
2015-08-26 10:30:00 +05:30
# define v_arg PROC_FILLARG
# define v_cgroup PROC_FILLCGROUP
# define v_env PROC_FILLENV
2015-08-28 10:30:00 +05:30
// remaining are compound flags, yielding a single string (maybe vectorized)
2015-08-19 10:30:00 +05:30
# define x_cgroup PROC_EDITCGRPCVT | PROC_FILLCGROUP // just 1 str
# define x_cmdline PROC_EDITCMDLCVT | PROC_FILLARG // just 1 str
# define x_environ PROC_EDITENVRCVT | PROC_FILLENV // just 1 str
# define x_ogroup PROC_FILLSTATUS | PROC_FILLGRP
# define x_ouser PROC_FILLSTATUS | PROC_FILLUSR
# define x_supgrp PROC_FILLSTATUS | PROC_FILLSUPGRP
typedef void ( * SET_t ) ( struct procps_pidsinfo * , struct pids_result * , proc_t * ) ;
2015-08-26 10:30:00 +05:30
typedef void ( * FRE_t ) ( struct pids_result * ) ;
2015-08-19 10:30:00 +05:30
typedef int ( * QSR_t ) ( const void * , const void * , void * ) ;
# define RS(e) (SET_t)setNAME(e)
2015-08-26 10:30:00 +05:30
# define FF(e) (FRE_t)freNAME(e)
2015-08-19 10:30:00 +05:30
# define QS(t) (QSR_t)srtNAME(t)
/*
* Need it be said ?
* This table must be kept in the exact same order as
* those ' enum pids_item ' guys ! */
static struct {
2015-08-26 10:30:00 +05:30
SET_t setsfunc ; // the actual result setting routine
2015-08-19 10:30:00 +05:30
unsigned oldflags ; // PROC_FILLxxxx flags for this item
2015-08-26 10:30:00 +05:30
FRE_t freefunc ; // free function for strings storage
QSR_t sortfunc ; // sort cmp func for a specific type
2015-08-20 10:30:00 +05:30
int needhist ; // a result requires history support
2015-08-19 10:30:00 +05:30
} Item_table [ ] = {
2015-08-26 10:30:00 +05:30
/* setsfunc oldflags freefunc sortfunc needhist
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2015-09-09 10:30:00 +05:30
{ RS ( ADDR_END_CODE ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( ADDR_KSTK_EIP ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( ADDR_KSTK_ESP ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( ADDR_START_CODE ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( ADDR_START_STACK ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
2015-08-26 10:30:00 +05:30
{ RS ( ALARM ) , f_stat , NULL , QS ( sl_int ) , 0 } ,
{ RS ( CGROUP ) , x_cgroup , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( CGROUP_V ) , v_cgroup , FF ( strv ) , QS ( strv ) , 0 } ,
{ RS ( CMD ) , f_either , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( CMDLINE ) , x_cmdline , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( CMDLINE_V ) , v_arg , FF ( strv ) , QS ( strv ) , 0 } ,
{ RS ( ENVIRON ) , x_environ , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( ENVIRON_V ) , v_env , FF ( strv ) , QS ( strv ) , 0 } ,
{ RS ( EXIT_SIGNAL ) , f_stat , NULL , QS ( s_int ) , 0 } ,
{ RS ( FLAGS ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( FLT_MAJ ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( FLT_MAJ_C ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( FLT_MAJ_DELTA ) , f_stat , NULL , QS ( ul_int ) , + 1 } ,
{ RS ( FLT_MIN ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( FLT_MIN_C ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( FLT_MIN_DELTA ) , f_stat , NULL , QS ( ul_int ) , + 1 } ,
{ RS ( ID_EGID ) , 0 , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_EGROUP ) , f_grp , NULL , QS ( str ) , 0 } ,
{ RS ( ID_EUID ) , 0 , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_EUSER ) , f_usr , NULL , QS ( str ) , 0 } ,
{ RS ( ID_FGID ) , f_status , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_FGROUP ) , x_ogroup , NULL , QS ( str ) , 0 } ,
{ RS ( ID_FUID ) , f_status , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_FUSER ) , x_ouser , NULL , QS ( str ) , 0 } ,
{ RS ( ID_PGRP ) , f_stat , NULL , QS ( s_int ) , 0 } ,
{ RS ( ID_PID ) , 0 , NULL , QS ( s_int ) , 0 } ,
{ RS ( ID_PPID ) , f_either , NULL , QS ( s_int ) , 0 } ,
{ RS ( ID_RGID ) , f_status , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_RGROUP ) , x_ogroup , NULL , QS ( str ) , 0 } ,
{ RS ( ID_RUID ) , f_status , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_RUSER ) , x_ouser , NULL , QS ( str ) , 0 } ,
{ RS ( ID_SESSION ) , f_stat , NULL , QS ( s_int ) , 0 } ,
{ RS ( ID_SGID ) , f_status , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_SGROUP ) , x_ogroup , NULL , QS ( str ) , 0 } ,
{ RS ( ID_SUID ) , f_status , NULL , QS ( u_int ) , 0 } ,
{ RS ( ID_SUSER ) , x_ouser , NULL , QS ( str ) , 0 } ,
{ RS ( ID_TGID ) , f_status , NULL , QS ( s_int ) , 0 } ,
{ RS ( ID_TPGID ) , f_stat , NULL , QS ( s_int ) , 0 } ,
{ RS ( LXCNAME ) , f_lxc , NULL , QS ( str ) , 0 } ,
{ RS ( MEM_CODE ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_CODE_KIB ) , f_statm , NULL , QS ( ul_int ) , 0 } ,
{ RS ( MEM_DATA ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_DATA_KIB ) , f_statm , NULL , QS ( ul_int ) , 0 } ,
{ RS ( MEM_DT ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_LRS ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_RES ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_RES_KIB ) , f_statm , NULL , QS ( ul_int ) , 0 } ,
{ RS ( MEM_SHR ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_SHR_KIB ) , f_statm , NULL , QS ( ul_int ) , 0 } ,
{ RS ( MEM_VIRT ) , f_statm , NULL , QS ( sl_int ) , 0 } ,
{ RS ( MEM_VIRT_KIB ) , f_statm , NULL , QS ( ul_int ) , 0 } ,
{ RS ( NICE ) , f_stat , NULL , QS ( sl_int ) , 0 } ,
{ RS ( NLWP ) , f_either , NULL , QS ( s_int ) , 0 } ,
{ RS ( NS_IPC ) , f_ns , NULL , QS ( ul_int ) , 0 } ,
{ RS ( NS_MNT ) , f_ns , NULL , QS ( ul_int ) , 0 } ,
{ RS ( NS_NET ) , f_ns , NULL , QS ( ul_int ) , 0 } ,
{ RS ( NS_PID ) , f_ns , NULL , QS ( ul_int ) , 0 } ,
{ RS ( NS_USER ) , f_ns , NULL , QS ( ul_int ) , 0 } ,
{ RS ( NS_UTS ) , f_ns , NULL , QS ( ul_int ) , 0 } ,
{ RS ( OOM_ADJ ) , f_oom , NULL , QS ( s_int ) , 0 } ,
{ RS ( OOM_SCORE ) , f_oom , NULL , QS ( s_int ) , 0 } ,
{ RS ( PRIORITY ) , f_stat , NULL , QS ( s_int ) , 0 } ,
{ RS ( PROCESSOR ) , f_stat , NULL , QS ( u_int ) , 0 } ,
{ RS ( RSS ) , f_stat , NULL , QS ( sl_int ) , 0 } ,
{ RS ( RSS_RLIM ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( RTPRIO ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( SCHED_CLASS ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
{ RS ( SD_MACH ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SD_OUID ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SD_SEAT ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SD_SESS ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SD_SLICE ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SD_UNIT ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SD_UUNIT ) , f_systemd , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SIGBLOCKED ) , f_status , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SIGCATCH ) , f_status , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SIGIGNORE ) , f_status , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SIGNALS ) , f_status , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SIGPENDING ) , f_status , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( STATE ) , f_either , NULL , QS ( s_ch ) , 0 } ,
{ RS ( SUPGIDS ) , f_status , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( SUPGROUPS ) , x_supgrp , FF ( str ) , QS ( str ) , 0 } ,
{ RS ( TICS_ALL ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TICS_ALL_C ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TICS_DELTA ) , f_stat , NULL , QS ( u_int ) , + 1 } ,
{ RS ( TICS_SYSTEM ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TICS_SYSTEM_C ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TICS_USER ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TICS_USER_C ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TIME_START ) , f_stat , NULL , QS ( ull_int ) , 0 } ,
{ RS ( TTY ) , f_stat , NULL , QS ( s_int ) , 0 } ,
2015-09-07 10:30:00 +05:30
{ RS ( TTY_NAME ) , f_stat , FF ( str ) , QS ( strvers ) , 0 } ,
2015-08-26 10:30:00 +05:30
{ RS ( VM_DATA ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_EXE ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_LIB ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_LOCK ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_RSS ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_SIZE ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_STACK ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_SWAP ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VM_USED ) , f_status , NULL , QS ( ul_int ) , 0 } ,
{ RS ( VSIZE_PGS ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
2015-09-09 10:30:00 +05:30
{ RS ( WCHAN_ADDR ) , f_stat , NULL , QS ( ul_int ) , 0 } ,
2015-08-26 10:30:00 +05:30
{ RS ( WCHAN_NAME ) , 0 , FF ( str ) , QS ( str ) , 0 } ,
2015-09-29 10:30:00 +05:30
{ RS ( extra ) , 0 , NULL , QS ( ull_int ) , 0 } ,
2015-08-26 10:30:00 +05:30
{ RS ( noop ) , 0 , NULL , QS ( noop ) , 0 } ,
{ RS ( logical_end ) , 0 , NULL , QS ( noop ) , 0 } ,
{ RS ( physical_end ) , 0 , NULL , QS ( noop ) , 0 }
2015-08-19 10:30:00 +05:30
} ;
# undef RS
2015-08-26 10:30:00 +05:30
# undef FF
2015-08-19 10:30:00 +05:30
# undef QS
# undef setNAME
2015-08-26 10:30:00 +05:30
# undef freNAME
# undef srtNAME
2015-08-19 10:30:00 +05:30
//#undef f_either // needed later
# undef f_grp
# undef f_lxc
# undef f_ns
# undef f_oom
//#undef f_stat // needed later
# undef f_statm
//#undef f_status // needed later
# undef f_systemd
# undef f_usr
2015-08-26 10:30:00 +05:30
# undef v_arg
# undef v_cgroup
# undef v_env
2015-08-19 10:30:00 +05:30
# undef x_cgroup
# undef x_cmdline
# undef x_environ
# undef x_ogroup
# undef x_ouser
# undef x_supgrp
// ___ History Support Private Functions ||||||||||||||||||||||||||||||||||||||
// ( stolen from top when he wasn't looking ) -------------------------------
# define HHASH_SIZE 1024
# define _HASH_PID_(K) (K & (HHASH_SIZE - 1))
# define Hr(x) info->hist->x // 'hist ref', minimize stolen impact
typedef unsigned long long TIC_t ;
typedef struct HST_t {
TIC_t tics ; // last frame's tics count
unsigned long maj , min ; // last frame's maj/min_flt counts
int pid ; // record 'key'
int lnk ; // next on hash chain
} HST_t ;
struct history_info {
int num_tasks ; // used as index (tasks tallied)
int HHist_siz ; // max number of HST_t structs
HST_t * PHist_sav ; // alternating 'old/new' HST_t anchors
HST_t * PHist_new ;
int HHash_one [ HHASH_SIZE ] ; // the actual hash tables
int HHash_two [ HHASH_SIZE ] ; // (accessed via PHash_sav/PHash_new)
int HHash_nul [ HHASH_SIZE ] ; // an 'empty' hash table image
int * PHash_sav ; // alternating 'old/new' hash tables
int * PHash_new ; // (aka. the 'one/two' actual tables)
} ;
static void config_history (
struct procps_pidsinfo * info )
{
int i ;
for ( i = 0 ; i < HHASH_SIZE ; i + + ) // make the 'empty' table image
Hr ( HHash_nul [ i ] ) = - 1 ;
memcpy ( Hr ( HHash_one ) , Hr ( HHash_nul ) , sizeof ( Hr ( HHash_nul ) ) ) ;
memcpy ( Hr ( HHash_two ) , Hr ( HHash_nul ) , sizeof ( Hr ( HHash_nul ) ) ) ;
Hr ( PHash_sav ) = Hr ( HHash_one ) ; // alternating 'old/new' hash tables
Hr ( PHash_new ) = Hr ( HHash_two ) ;
} // end: config_history
static inline HST_t * histget (
struct procps_pidsinfo * info ,
int pid )
{
int V = Hr ( PHash_sav [ _HASH_PID_ ( pid ) ] ) ;
while ( - 1 < V ) {
if ( Hr ( PHist_sav [ V ] . pid ) = = pid )
return & Hr ( PHist_sav [ V ] ) ;
V = Hr ( PHist_sav [ V ] . lnk ) ; }
return NULL ;
} // end: histget
static inline void histput (
struct procps_pidsinfo * info ,
unsigned this )
{
int V = _HASH_PID_ ( Hr ( PHist_new [ this ] . pid ) ) ;
Hr ( PHist_new [ this ] . lnk ) = Hr ( PHash_new [ V ] ) ;
Hr ( PHash_new [ V ] = this ) ;
} // end: histput
# undef _HASH_PID_
static int make_hist (
struct procps_pidsinfo * info ,
proc_t * p )
{
2015-08-20 10:30:00 +05:30
# define nSLOT info->hist->num_tasks
2015-08-19 10:30:00 +05:30
TIC_t tics ;
HST_t * h ;
2015-08-20 10:30:00 +05:30
if ( nSLOT + 1 > = Hr ( HHist_siz ) ) {
Hr ( HHist_siz ) + = MEMORY_INCR ;
2015-08-19 10:30:00 +05:30
Hr ( PHist_sav ) = realloc ( Hr ( PHist_sav ) , sizeof ( HST_t ) * Hr ( HHist_siz ) ) ;
Hr ( PHist_new ) = realloc ( Hr ( PHist_new ) , sizeof ( HST_t ) * Hr ( HHist_siz ) ) ;
2015-08-28 10:30:00 +05:30
if ( ! Hr ( PHist_sav ) | | ! Hr ( PHist_new ) )
2015-08-19 10:30:00 +05:30
return - ENOMEM ;
}
2015-08-20 10:30:00 +05:30
Hr ( PHist_new [ nSLOT ] . pid ) = p - > tid ;
Hr ( PHist_new [ nSLOT ] . tics ) = tics = ( p - > utime + p - > stime ) ;
Hr ( PHist_new [ nSLOT ] . maj ) = p - > maj_flt ;
Hr ( PHist_new [ nSLOT ] . min ) = p - > min_flt ;
2015-08-19 10:30:00 +05:30
2015-08-20 10:30:00 +05:30
histput ( info , nSLOT ) ;
2015-08-19 10:30:00 +05:30
if ( ( h = histget ( info , p - > tid ) ) ) {
tics - = h - > tics ;
2015-08-28 10:30:00 +05:30
p - > pcpu = tics ;
2015-08-19 10:30:00 +05:30
p - > maj_delta = p - > maj_flt - h - > maj ;
p - > min_delta = p - > min_flt - h - > min ;
}
2015-08-20 10:30:00 +05:30
nSLOT + + ;
2015-08-19 10:30:00 +05:30
return 0 ;
2015-08-20 10:30:00 +05:30
# undef nSLOT
2015-08-19 10:30:00 +05:30
} // end: make_hist
static inline void toggle_history (
struct procps_pidsinfo * info )
{
void * v ;
v = Hr ( PHist_sav ) ;
Hr ( PHist_sav ) = Hr ( PHist_new ) ;
Hr ( PHist_new ) = v ;
v = Hr ( PHash_sav ) ;
Hr ( PHash_sav ) = Hr ( PHash_new ) ;
Hr ( PHash_new ) = v ;
memcpy ( Hr ( PHash_new ) , Hr ( HHash_nul ) , sizeof ( Hr ( HHash_nul ) ) ) ;
info - > hist - > num_tasks = 0 ;
} // end: toggle_history
# ifdef UNREF_RPTHASH
static void unref_rpthash (
struct procps_pidsinfo * info )
{
int i , j , pop , total_occupied , maxdepth , maxdepth_sav , numdepth
2015-08-20 10:30:00 +05:30
, cross_foot , sz = HHASH_SIZE * ( int ) sizeof ( int )
, hsz = ( int ) sizeof ( HST_t ) * Hr ( HHist_siz ) ;
2015-08-19 10:30:00 +05:30
int depths [ HHASH_SIZE ] ;
for ( i = 0 , total_occupied = 0 , maxdepth = 0 ; i < HHASH_SIZE ; i + + ) {
int V = Hr ( PHash_new [ i ] ) ;
j = 0 ;
if ( - 1 < V ) {
+ + total_occupied ;
while ( - 1 < V ) {
V = Hr ( PHist_new [ V ] . lnk ) ;
if ( - 1 < V ) j + + ;
}
}
depths [ i ] = j ;
if ( maxdepth < j ) maxdepth = j ;
}
maxdepth_sav = maxdepth ;
fprintf ( stderr ,
2015-08-20 10:30:00 +05:30
" \n History Memory Costs: "
" \n \t HST_t size = %d, total allocated = %d, "
" \n \t thus PHist_new & PHist_sav consumed %dk (%d) total bytes. "
2015-08-19 10:30:00 +05:30
" \n "
2015-08-20 10:30:00 +05:30
" \n \t Two hash tables provide for %d entries each + 1 extra 'empty' image, "
" \n \t thus %dk (%d) bytes per table for %dk (%d) total bytes. "
" \n "
" \n \t Grand total = %dk (%d) bytes. "
" \n "
" \n Hash Results Report: "
2015-08-19 10:30:00 +05:30
" \n \t Total hashed = %d "
" \n \t Level-0 hash entries = %d (%d%% occupied) "
" \n \t Max Depth = %d "
" \n \n "
2015-08-20 10:30:00 +05:30
, ( int ) sizeof ( HST_t ) , Hr ( HHist_siz )
, hsz / 1024 , hsz
, HHASH_SIZE
, sz / 1024 , sz , ( sz * 3 ) / 1024 , sz * 3
, ( hsz + ( sz * 3 ) ) / 1024 , hsz + ( sz * 3 )
2015-08-19 10:30:00 +05:30
, info - > hist - > num_tasks
, total_occupied , ( total_occupied * 100 ) / HHASH_SIZE
2015-08-20 10:30:00 +05:30
, maxdepth ) ;
2015-08-19 10:30:00 +05:30
if ( total_occupied ) {
for ( pop = total_occupied , cross_foot = 0 ; maxdepth ; maxdepth - - ) {
for ( i = 0 , numdepth = 0 ; i < HHASH_SIZE ; i + + )
if ( depths [ i ] = = maxdepth ) + + numdepth ;
fprintf ( stderr ,
" \t %5d (%3d%%) hash table entries at depth %d \n "
2015-08-20 10:30:00 +05:30
, numdepth , ( numdepth * 100 ) / total_occupied , maxdepth ) ;
2015-08-19 10:30:00 +05:30
pop - = numdepth ;
cross_foot + = numdepth ;
if ( 0 = = pop & & cross_foot = = total_occupied ) break ;
}
if ( pop ) {
2015-08-20 10:30:00 +05:30
fprintf ( stderr , " \t %5d (%3d%%) unchained entries (at depth 0) \n "
2015-08-19 10:30:00 +05:30
, pop , ( pop * 100 ) / total_occupied ) ;
cross_foot + = pop ;
}
fprintf ( stderr ,
" \t ----- \n "
" \t %5d total entries occupied \n " , cross_foot ) ;
2015-08-20 10:30:00 +05:30
if ( maxdepth_sav > 1 ) {
2015-08-19 10:30:00 +05:30
fprintf ( stderr , " \n PIDs at max depth: " ) ;
for ( i = 0 ; i < HHASH_SIZE ; i + + )
if ( depths [ i ] = = maxdepth_sav ) {
j = Hr ( PHash_new [ i ] ) ;
fprintf ( stderr , " \n \t pos %4d: %05d " , i , Hr ( PHist_new [ j ] . pid ) ) ;
while ( - 1 < j ) {
j = Hr ( PHist_new [ j ] . lnk ) ;
if ( - 1 < j ) fprintf ( stderr , " , %05d " , Hr ( PHist_new [ j ] . pid ) ) ;
}
}
fprintf ( stderr , " \n " ) ;
}
}
} // end: unref_rpthash
# endif // UNREF_RPTHASH
2015-08-28 10:30:00 +05:30
# undef Hr
2015-08-19 10:30:00 +05:30
# undef HHASH_SIZE
// ___ Standard Private Functions |||||||||||||||||||||||||||||||||||||||||||||
static inline void assign_results (
struct procps_pidsinfo * info ,
struct pids_stack * stack ,
proc_t * p )
{
struct pids_result * this = stack - > head ;
for ( ; ; ) {
enum pids_item item = this - > item ;
if ( item > = PROCPS_PIDS_logical_end )
break ;
2015-08-26 10:30:00 +05:30
Item_table [ item ] . setsfunc ( info , this , p ) ;
info - > dirty_stacks | = Item_table [ item ] . freefunc ? 1 : 0 ;
2015-08-19 10:30:00 +05:30
+ + this ;
}
return ;
} // end: assign_results
static inline void cleanup_stack (
struct pids_result * p ,
int depth )
{
int i ;
for ( i = 0 ; i < depth ; i + + ) {
if ( p - > item < PROCPS_PIDS_noop ) {
2015-08-26 10:30:00 +05:30
if ( Item_table [ p - > item ] . freefunc )
Item_table [ p - > item ] . freefunc ( p ) ;
2015-09-01 10:30:00 +05:30
p - > result . ull_int = 0 ;
2015-08-19 10:30:00 +05:30
}
+ + p ;
}
} // end: cleanup_stack
static inline void cleanup_stacks_all (
struct procps_pidsinfo * info )
{
struct stacks_extent * ext = info - > extents ;
int i ;
while ( ext ) {
for ( i = 0 ; ext - > stacks [ i ] ; i + + )
cleanup_stack ( ext - > stacks [ i ] - > head , info - > maxitems ) ;
ext = ext - > next ;
} ;
info - > dirty_stacks = 0 ;
} // end: cleanup_stacks_all
2015-09-10 10:30:00 +05:30
/*
* This routine exists in case we ever want to offer something like
* ' static ' or ' invarient ' results stacks . By unsplicing an extent
* from the info anchor it will be isolated from future reset / free . */
static struct stacks_extent * extent_cut (
2015-08-19 10:30:00 +05:30
struct procps_pidsinfo * info ,
struct stacks_extent * ext )
{
struct stacks_extent * p = info - > extents ;
if ( ext ) {
if ( ext = = p ) {
info - > extents = p - > next ;
2015-09-10 10:30:00 +05:30
return ext ;
2015-08-19 10:30:00 +05:30
}
do {
if ( ext = = p - > next ) {
p - > next = p - > next - > next ;
2015-09-10 10:30:00 +05:30
return ext ;
2015-08-19 10:30:00 +05:30
}
p = p - > next ;
} while ( p ) ;
}
2015-09-10 10:30:00 +05:30
return NULL ;
} // end: extent_cut
static int extent_free (
struct procps_pidsinfo * info ,
struct stacks_extent * ext )
{
if ( extent_cut ( info , ext ) ) {
free ( ext ) ;
return 0 ;
}
2015-08-19 10:30:00 +05:30
return - 1 ;
2015-09-10 10:30:00 +05:30
} // end: extent_free
2015-08-19 10:30:00 +05:30
2015-08-20 10:30:00 +05:30
static inline int items_check_failed (
2015-08-19 10:30:00 +05:30
int maxitems ,
enum pids_item * items )
{
int i ;
2015-08-30 10:30:00 +05:30
/* if an enum is passed instead of an address of one or more enums, ol' gcc
* will silently convert it to an address ( possibly NULL ) . only clang will
* offer any sort of warning like the following :
*
* warning : incompatible integer to pointer conversion passing ' int ' to parameter of type ' enum pids_item * '
* if ( procps_pids_new ( & info , 3 , PROCPS_PIDS_noop ) < 0 )
* ^ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
if ( maxitems < 1
2015-09-01 10:30:00 +05:30
| | ( void * ) items < ( void * ) 0x8000 ) // twice as big as our largest enum
2015-08-30 10:30:00 +05:30
return - 1 ;
2015-08-19 10:30:00 +05:30
for ( i = 0 ; i < maxitems ; i + + ) {
2015-08-28 10:30:00 +05:30
// a pids_item is currently unsigned, but we'll protect our future
2015-08-19 10:30:00 +05:30
if ( items [ i ] < 0 )
return - 1 ;
if ( items [ i ] > PROCPS_PIDS_noop ) {
return - 1 ;
}
}
return 0 ;
} // end: items_check_failed
static inline void libflags_set (
struct procps_pidsinfo * info )
{
int i ;
info - > flags = info - > history_yes = 0 ;
for ( i = 0 ; i < info - > curitems ; i + + ) {
info - > flags | = Item_table [ info - > items [ i ] ] . oldflags ;
2015-08-20 10:30:00 +05:30
info - > history_yes | = Item_table [ info - > items [ i ] ] . needhist ;
2015-08-19 10:30:00 +05:30
}
if ( info - > flags & f_either ) {
if ( ! ( info - > flags & f_stat ) )
info - > flags | = f_status ;
}
return ;
} // end: libflags_set
static inline void oldproc_close (
struct procps_pidsinfo * info )
{
if ( info - > PT ! = NULL ) {
closeproc ( info - > PT ) ;
info - > PT = NULL ;
}
return ;
} // end: oldproc_close
static inline int oldproc_open (
struct procps_pidsinfo * info ,
2015-09-06 10:30:00 +05:30
unsigned supp_flgs ,
2015-08-19 10:30:00 +05:30
. . . )
{
va_list vl ;
int * ids ;
if ( info - > PT = = NULL ) {
va_start ( vl , supp_flgs ) ;
ids = va_arg ( vl , int * ) ;
va_end ( vl ) ;
if ( NULL = = ( info - > PT = openproc ( info - > flags | supp_flgs , ids ) ) )
return 0 ;
}
return 1 ;
} // end: oldproc_open
static inline struct pids_result * stack_itemize (
struct pids_result * p ,
int depth ,
enum pids_item * items )
{
struct pids_result * p_sav = p ;
int i ;
for ( i = 0 ; i < depth ; i + + ) {
p - > item = items [ i ] ;
p - > result . ull_int = 0 ;
+ + p ;
}
return p_sav ;
} // end: stack_itemize
static inline int tally_proc (
struct procps_pidsinfo * info ,
struct pids_counts * counts ,
proc_t * p )
{
switch ( p - > state ) {
case ' R ' :
+ + counts - > running ;
break ;
case ' S ' :
case ' D ' :
+ + counts - > sleeping ;
break ;
case ' T ' :
+ + counts - > stopped ;
break ;
case ' Z ' :
+ + counts - > zombied ;
break ;
default : // keep gcc happy
break ;
}
+ + counts - > total ;
if ( info - > history_yes )
return ! make_hist ( info , p ) ;
return 1 ;
} // end: tally_proc
2015-08-20 10:30:00 +05:30
# ifdef FPRINT_STACKS
2015-08-19 10:30:00 +05:30
static void validate_stacks (
void * stacks ,
const char * who )
{
# include <stdio.h>
static int once = 0 ;
struct stacks_extent * ext = ( struct stacks_extent * ) stacks ;
int i , t , x , n = 0 ;
fprintf ( stderr , " %s: called by '%s' \n " , __func__ , who ) ;
fprintf ( stderr , " %s: ext_numitems = %d, ext_numstacks = %d, extents = %p, next = %p \n " , __func__ , ext - > ext_numitems , ext - > ext_numstacks , ext , ext - > next ) ;
fprintf ( stderr , " %s: stacks_extent results excluding the end-of-stack element ... \n " , __func__ ) ;
for ( x = 0 ; NULL ! = ext - > stacks [ x ] ; x + + ) {
struct pids_stack * h = ext - > stacks [ x ] ;
struct pids_result * r = h - > head ;
fprintf ( stderr , " %s: v[%03d] = %p, h = %p, fill_id #%-5u " , __func__ , x , h , r , ( unsigned ) h - > fill_id ) ;
for ( i = 0 ; r - > item < PROCPS_PIDS_logical_end ; i + + , r + + )
;
t = i + 1 ;
fprintf ( stderr , " - found %d elements for stack %d \n " , i , n ) ;
+ + n ;
}
if ( ! once ) {
fprintf ( stderr , " %s: found %d total stack(s), each %d bytes (including eos) \n " , __func__ , x , ( int ) ( sizeof ( struct pids_stack ) + ( sizeof ( struct pids_result ) * t ) ) ) ;
fprintf ( stderr , " %s: sizeof(struct pids_stack) = %d \n " , __func__ , ( int ) sizeof ( struct pids_stack ) ) ;
fprintf ( stderr , " %s: sizeof(struct pids_result) = %d \n " , __func__ , ( int ) sizeof ( struct pids_result ) ) ;
fprintf ( stderr , " %s: sizeof(struct stacks_extent) = %d \n " , __func__ , ( int ) sizeof ( struct stacks_extent ) ) ;
once = 1 ;
}
fputc ( ' \n ' , stderr ) ;
return ;
} // end: validate_stacks
2015-08-20 10:30:00 +05:30
# endif
2015-08-19 10:30:00 +05:30
// ___ Public Functions |||||||||||||||||||||||||||||||||||||||||||||||||||||||
2015-09-11 10:30:00 +05:30
PROCPS_EXPORT struct pids_stack * fatal_proc_unmounted (
struct procps_pidsinfo * info ,
int return_self )
{
static proc_t self ;
struct stacks_extent * ext ;
// this is very likely the *only* newlib function where the
// context (procps_pidsinfo) of NULL will ever be permitted
look_up_our_self ( & self ) ;
if ( ! return_self )
return NULL ;
if ( info = = NULL
| | ! ( ext = ( struct stacks_extent * ) procps_pids_stacks_alloc ( info , 1 ) )
| | ! extent_cut ( info , ext ) )
return NULL ;
ext - > next = info - > otherexts ;
info - > otherexts = ext ;
assign_results ( info , ext - > stacks [ 0 ] , & self ) ;
return ext - > stacks [ 0 ] ;
} // end: fatal_proc_unmounted
2015-08-19 10:30:00 +05:30
/*
* procps_pids_new ( ) :
*
* @ info : location of returned new structure
*
* Returns : 0 on success < 0 on failure
*/
PROCPS_EXPORT int procps_pids_new (
struct procps_pidsinfo * * info ,
int maxitems ,
enum pids_item * items )
{
struct procps_pidsinfo * p ;
int pgsz ;
if ( info = = NULL | | * info ! = NULL )
return - EINVAL ;
if ( items_check_failed ( maxitems , items ) )
return - EINVAL ;
if ( ! ( p = calloc ( 1 , sizeof ( struct procps_pidsinfo ) ) ) )
return - ENOMEM ;
// allow for our PROCPS_PIDS_physical_end
if ( ! ( p - > items = calloc ( ( maxitems + 1 ) , sizeof ( enum pids_item ) ) ) ) {
free ( p ) ;
return - ENOMEM ;
}
if ( ! ( p - > hist = calloc ( ( maxitems + 1 ) , sizeof ( struct history_info ) ) ) ) {
free ( p - > items ) ;
free ( p ) ;
return - ENOMEM ;
}
memcpy ( p - > items , items , sizeof ( enum pids_item ) * maxitems ) ;
p - > items [ maxitems ] = PROCPS_PIDS_physical_end ;
p - > curitems = p - > maxitems = maxitems + 1 ;
libflags_set ( p ) ;
pgsz = getpagesize ( ) ;
while ( pgsz > 1024 ) { pgsz > > = 1 ; p - > pgs2k_shift + + ; }
config_history ( p ) ;
p - > refcount = 1 ;
* info = p ;
return 0 ;
} // end: procps_pids_new
2015-08-26 10:30:00 +05:30
PROCPS_EXPORT struct pids_stack * procps_pids_read_next (
struct procps_pidsinfo * info )
{
static proc_t task ; // static for initial zeroes + later dynamic free(s)
if ( info = = NULL | | ! READS_BEGUN )
return NULL ;
if ( info - > dirty_stacks ) {
cleanup_stack ( info - > read - > stacks [ 0 ] - > head , info - > maxitems ) ;
info - > dirty_stacks = 0 ;
}
if ( NULL = = info - > read_something ( info - > PT , & task ) )
return NULL ;
assign_results ( info , info - > read - > stacks [ 0 ] , & task ) ;
return info - > read - > stacks [ 0 ] ;
} // end: procps_pids_read_next
PROCPS_EXPORT int procps_pids_read_open (
struct procps_pidsinfo * info ,
enum pids_reap_type which )
{
if ( info = = NULL | | READS_BEGUN )
return - EINVAL ;
if ( ! info - > maxitems & & ! info - > curitems )
return - EINVAL ;
if ( which ! = PROCPS_REAP_TASKS_ONLY & & which ! = PROCPS_REAP_THREADS_TOO )
return - EINVAL ;
if ( ! ( info - > read = ( struct stacks_extent * ) procps_pids_stacks_alloc ( info , 1 ) ) )
return - ENOMEM ;
if ( ! oldproc_open ( info , 0 ) )
return - 1 ;
info - > read_something = which ? readeither : readproc ;
return 0 ;
} // end: procps_pids_read_open
PROCPS_EXPORT int procps_pids_read_shut (
struct procps_pidsinfo * info )
{
int rc ;
if ( info = = NULL | | ! READS_BEGUN )
return - EINVAL ;
oldproc_close ( info ) ;
2015-09-10 10:30:00 +05:30
rc = extent_free ( info , info - > read ) ;
2015-08-26 10:30:00 +05:30
info - > read = NULL ;
return rc ;
} // end: procps_pids_read_shut
2015-08-19 10:30:00 +05:30
/* procps_pids_reap():
*
* Harvest all the available tasks / threads and provide the result
* stacks along with a summary of the information gathered .
*
* Returns : pointer to a pids_reap struct on success , NULL on error .
*/
PROCPS_EXPORT struct pids_reap * procps_pids_reap (
struct procps_pidsinfo * info ,
enum pids_reap_type which )
{
# define n_alloc info->alloc_total
# define n_inuse info->inuse_total
static proc_t task ; // static for initial zeroes + later dynamic free(s)
2015-08-26 10:30:00 +05:30
proc_t * ( * reap_something ) ( PROCTAB * , proc_t * ) ;
2015-08-19 10:30:00 +05:30
struct pids_stacks * ext ;
2015-08-28 10:30:00 +05:30
int n_save ;
2015-08-19 10:30:00 +05:30
2015-08-26 10:30:00 +05:30
if ( info = = NULL | | READS_BEGUN )
2015-08-26 10:30:00 +05:30
return NULL ;
if ( ! info - > maxitems & & ! info - > curitems )
return NULL ;
if ( which ! = PROCPS_REAP_TASKS_ONLY & & which ! = PROCPS_REAP_THREADS_TOO )
return NULL ;
2015-08-28 10:30:00 +05:30
n_save = n_alloc ;
2015-08-26 10:30:00 +05:30
2015-08-19 10:30:00 +05:30
if ( ! info - > anchor ) {
2015-08-20 10:30:00 +05:30
if ( ( ! ( info - > anchor = calloc ( sizeof ( void * ) , MEMORY_INCR ) ) )
| | ( ! ( info - > reaped . stacks = calloc ( sizeof ( void * ) , MEMORY_INCR ) ) )
| | ( ! ( ext = procps_pids_stacks_alloc ( info , MEMORY_INCR ) ) ) )
2015-08-19 10:30:00 +05:30
return NULL ;
2015-08-20 10:30:00 +05:30
memcpy ( info - > anchor , ext - > stacks , sizeof ( void * ) * MEMORY_INCR ) ;
n_save = info - > alloc_total = MEMORY_INCR ;
2015-08-19 10:30:00 +05:30
}
if ( info - > dirty_stacks )
cleanup_stacks_all ( info ) ;
2015-08-20 10:30:00 +05:30
memset ( & info - > reaped . counts , 0 , sizeof ( struct pids_counts ) ) ;
2015-08-19 10:30:00 +05:30
if ( ! oldproc_open ( info , 0 ) )
return NULL ;
toggle_history ( info ) ;
2015-08-26 10:30:00 +05:30
reap_something = which ? readeither : readproc ;
2015-08-19 10:30:00 +05:30
for ( n_inuse = 0 ; ; n_inuse + + ) {
if ( n_inuse = = n_alloc ) {
2015-08-20 10:30:00 +05:30
n_alloc + = MEMORY_INCR ;
if ( ( ! ( info - > anchor = realloc ( info - > anchor , sizeof ( void * ) * n_alloc ) ) )
| | ( ! ( ext = procps_pids_stacks_alloc ( info , MEMORY_INCR ) ) ) )
2015-08-19 10:30:00 +05:30
return NULL ;
2015-08-20 10:30:00 +05:30
memcpy ( info - > anchor + n_inuse , ext - > stacks , sizeof ( void * ) * MEMORY_INCR ) ;
2015-08-19 10:30:00 +05:30
}
2015-08-26 10:30:00 +05:30
if ( NULL = = reap_something ( info - > PT , & task ) )
2015-08-19 10:30:00 +05:30
break ;
2015-08-28 10:30:00 +05:30
if ( ! tally_proc ( info , & info - > reaped . counts , & task ) ) {
oldproc_close ( info ) ;
2015-08-19 10:30:00 +05:30
return NULL ;
2015-08-28 10:30:00 +05:30
}
2015-08-19 10:30:00 +05:30
assign_results ( info , info - > anchor [ n_inuse ] , & task ) ;
}
oldproc_close ( info ) ;
if ( n_save ! = n_alloc
2015-08-20 10:30:00 +05:30
& & ! ( info - > reaped . stacks = realloc ( info - > reaped . stacks , sizeof ( void * ) * n_alloc ) ) )
2015-08-19 10:30:00 +05:30
return NULL ;
2015-08-20 10:30:00 +05:30
memcpy ( info - > reaped . stacks , info - > anchor , sizeof ( void * ) * n_alloc ) ;
return & info - > reaped ;
2015-08-19 10:30:00 +05:30
# undef n_alloc
# undef n_inuse
} // end: procps_pids_reap
PROCPS_EXPORT int procps_pids_ref (
struct procps_pidsinfo * info )
{
if ( info = = NULL )
return - EINVAL ;
info - > refcount + + ;
return info - > refcount ;
} // end: procps_pids_ref
PROCPS_EXPORT int procps_pids_reset (
struct procps_pidsinfo * info ,
int newmaxitems ,
enum pids_item * newitems )
{
struct stacks_extent * ext ;
int i ;
if ( info = = NULL )
return - EINVAL ;
/* disallow (for now?) absolute increases in stacks size
( users must ' unref ' and then ' new ' to achieve that ) */
if ( newmaxitems + 1 > info - > maxitems )
return - EINVAL ;
if ( items_check_failed ( newmaxitems , newitems ) )
return - EINVAL ;
2015-08-20 10:30:00 +05:30
/* shame on this caller, they didn't change anything. and unless they have
altered the depth of the stacks we ' re not gonna change anything either ! */
2015-08-19 10:30:00 +05:30
if ( info - > curitems = = newmaxitems + 1
& & ! memcmp ( info - > items , newitems , sizeof ( enum pids_item ) * newmaxitems ) )
return 0 ;
if ( info - > dirty_stacks )
cleanup_stacks_all ( info ) ;
memcpy ( info - > items , newitems , sizeof ( enum pids_item ) * newmaxitems ) ;
info - > items [ newmaxitems ] = PROCPS_PIDS_logical_end ;
// account for above PROCPS_PIDS_logical_end
info - > curitems = newmaxitems + 1 ;
ext = info - > extents ;
while ( ext ) {
for ( i = 0 ; ext - > stacks [ i ] ; i + + )
stack_itemize ( ext - > stacks [ i ] - > head , info - > curitems , info - > items ) ;
2015-08-20 10:30:00 +05:30
# ifdef FPRINT_STACKS
2015-08-19 10:30:00 +05:30
validate_stacks ( ext , __func__ ) ;
2015-08-20 10:30:00 +05:30
# endif
2015-08-19 10:30:00 +05:30
ext = ext - > next ;
} ;
libflags_set ( info ) ;
return 0 ;
} // end: procps_pids_reset
/*
* procps_pids_stacks_alloc ( ) :
*
* Allocate and initialize one or more stacks each of which is anchored in an
* associated pids_stack structure ( which may include extra user space ) .
*
* All such stacks will will have their result structures properly primed with
* ' items ' , while the result itself will be zeroed .
*
* Returns an array of pointers representing the ' heads ' of each new stack .
*/
PROCPS_EXPORT struct pids_stacks * procps_pids_stacks_alloc (
struct procps_pidsinfo * info ,
int maxstacks )
{
struct stacks_extent * p_blob ;
struct pids_stack * * p_vect ;
struct pids_stack * p_head ;
size_t vect_size , head_size , list_size , blob_size ;
void * v_head , * v_list ;
int i ;
if ( info = = NULL | | info - > items = = NULL )
return NULL ;
if ( maxstacks < 1 )
return NULL ;
vect_size = sizeof ( void * ) * maxstacks ; // address vectors themselves
vect_size + = sizeof ( void * ) ; // plus NULL delimiter
head_size = sizeof ( struct pids_stack ) ; // a head struct
list_size = sizeof ( struct pids_result ) * info - > maxitems ; // a results stack
blob_size = sizeof ( struct stacks_extent ) ; // the extent anchor itself
blob_size + = vect_size ; // all vectors + delim
blob_size + = head_size * maxstacks ; // all head structs
blob_size + = list_size * maxstacks ; // all results stacks
/* note: all memory is allocated in a single blob, facilitating a later free().
as a minimum , it ' s important that the result structures themselves always be
contiguous for any given stack ( just as they are when defined statically ) . */
if ( NULL = = ( p_blob = calloc ( 1 , blob_size ) ) )
return NULL ;
p_blob - > next = info - > extents ;
info - > extents = p_blob ;
p_blob - > stacks = ( void * ) p_blob + sizeof ( struct stacks_extent ) ;
p_vect = p_blob - > stacks ;
v_head = ( void * ) p_vect + vect_size ;
v_list = v_head + ( head_size * maxstacks ) ;
for ( i = 0 ; i < maxstacks ; i + + ) {
p_head = ( struct pids_stack * ) v_head ;
p_head - > head = stack_itemize ( ( struct pids_result * ) v_list , info - > curitems , info - > items ) ;
p_blob - > stacks [ i ] = p_head ;
v_list + = list_size ;
v_head + = head_size ;
}
p_blob - > ext_numitems = info - > maxitems ;
p_blob - > ext_numstacks = maxstacks ;
2015-08-20 10:30:00 +05:30
# ifdef FPRINT_STACKS
2015-08-19 10:30:00 +05:30
validate_stacks ( p_blob , __func__ ) ;
2015-08-20 10:30:00 +05:30
# endif
2015-08-19 10:30:00 +05:30
return ( struct pids_stacks * ) p_blob ;
} // end: procps_pids_stacks_alloc
PROCPS_EXPORT int procps_pids_stacks_dealloc (
struct procps_pidsinfo * info ,
struct pids_stacks * * these )
{
struct stacks_extent * ext ;
2015-08-26 10:30:00 +05:30
int rc ;
2015-08-19 10:30:00 +05:30
if ( info = = NULL | | these = = NULL )
return - EINVAL ;
if ( ( * these ) - > stacks = = NULL | | ( * these ) - > stacks [ 0 ] = = NULL )
return - EINVAL ;
ext = ( struct stacks_extent * ) ( * these ) ;
2015-09-10 10:30:00 +05:30
rc = extent_free ( info , ext ) ;
2015-08-19 10:30:00 +05:30
* these = NULL ;
return rc ;
} // end: procps_pids_stacks_dealloc
PROCPS_EXPORT struct pids_counts * procps_pids_stacks_fill (
struct procps_pidsinfo * info ,
struct pids_stacks * these ,
int maxstacks ,
enum pids_fill_type which )
{
static proc_t task ; // static for initial zeroes + later dynamic free(s)
unsigned ids [ FILL_ID_MAX + 1 ] ;
int i ;
2015-08-26 10:30:00 +05:30
if ( info = = NULL | | these = = NULL | | READS_BEGUN )
2015-08-19 10:30:00 +05:30
return NULL ;
if ( these - > stacks = = NULL | | these - > stacks [ 0 ] = = NULL )
return NULL ;
if ( which ! = PROCPS_FILL_PID & & which ! = PROCPS_FILL_UID )
return NULL ;
if ( maxstacks < 1 | | maxstacks > FILL_ID_MAX )
return NULL ;
for ( i = 0 ; i < maxstacks ; i + + ) {
if ( these - > stacks [ i ] = = NULL )
break ;
ids [ i ] = these - > stacks [ i ] - > fill_id ;
}
ids [ i ] = 0 ;
if ( info - > dirty_stacks )
cleanup_stacks_all ( info ) ;
memset ( & info - > counts , 0 , sizeof ( struct pids_counts ) ) ;
if ( ! oldproc_open ( info , which , ids , i ) )
return NULL ;
toggle_history ( info ) ;
for ( i = 0 ; i < maxstacks ; i + + ) {
if ( these - > stacks [ i ] = = NULL )
break ;
if ( ! readproc ( info - > PT , & task ) )
break ;
if ( ! tally_proc ( info , & info - > counts , & task ) ) {
oldproc_close ( info ) ;
return NULL ;
}
assign_results ( info , these - > stacks [ i ] , & task ) ;
}
oldproc_close ( info ) ;
2015-08-20 10:30:00 +05:30
# ifdef FPRINT_STACKS
2015-08-19 10:30:00 +05:30
validate_stacks ( these , __func__ ) ;
2015-08-20 10:30:00 +05:30
# endif
2015-08-19 10:30:00 +05:30
return & info - > counts ;
} // end: procps_pids_stacks_fill
/*
* procps_pids_stacks_sort ( ) :
*
* Sort stacks anchored in the passed pids_stack pointers array
* based on the designated sort enumerator and specified order .
*
* Returns those same addresses sorted .
*
* Note : all of the stacks must be homogeneous ( of equal length and content ) .
*/
PROCPS_EXPORT struct pids_stack * * procps_pids_stacks_sort (
struct procps_pidsinfo * info ,
2015-08-20 10:30:00 +05:30
struct pids_stack * stacks [ ] ,
2015-08-19 10:30:00 +05:30
int numstacked ,
enum pids_item sort ,
enum pids_sort_order order )
{
struct sort_parms parms ;
struct pids_result * p ;
int offset ;
if ( info = = NULL | | stacks = = NULL )
return NULL ;
2015-08-28 10:30:00 +05:30
// a pids_item is currently unsigned, but we'll protect our future
2015-08-19 10:30:00 +05:30
if ( sort < 0 | | sort > PROCPS_PIDS_noop )
return NULL ;
2015-09-28 10:30:00 +05:30
if ( order ! = PROCPS_SORT_ASCEND & & order ! = PROCPS_SORT_DESCEND )
2015-08-19 10:30:00 +05:30
return NULL ;
if ( numstacked < 2 )
return stacks ;
offset = 0 ;
p = stacks [ 0 ] - > head ;
for ( ; ; ) {
if ( p - > item = = sort )
break ;
+ + offset ;
if ( offset > = info - > curitems )
return NULL ;
if ( p - > item > PROCPS_PIDS_noop )
return NULL ;
+ + p ;
}
parms . offset = offset ;
parms . order = order ;
2015-08-26 10:30:00 +05:30
qsort_r ( stacks , numstacked , sizeof ( void * ) , ( QSR_t ) Item_table [ p - > item ] . sortfunc , & parms ) ;
2015-08-19 10:30:00 +05:30
return stacks ;
} // end: procps_pids_stacks_sort
PROCPS_EXPORT int procps_pids_unref (
struct procps_pidsinfo * * info )
{
if ( info = = NULL | | * info = = NULL )
return - EINVAL ;
( * info ) - > refcount - - ;
if ( ( * info ) - > refcount = = 0 ) {
# ifdef UNREF_RPTHASH
unref_rpthash ( * info ) ;
# endif
if ( ( * info ) - > extents ) {
cleanup_stacks_all ( * info ) ;
do {
struct stacks_extent * p = ( * info ) - > extents ;
( * info ) - > extents = ( * info ) - > extents - > next ;
free ( p ) ;
} while ( ( * info ) - > extents ) ;
}
2015-09-11 10:30:00 +05:30
if ( ( * info ) - > otherexts ) {
struct stacks_extent * nextext , * ext = ( * info ) - > otherexts ;
while ( ext ) {
nextext = ext - > next ;
cleanup_stack ( ext - > stacks [ 0 ] - > head , ext - > ext_numitems ) ;
free ( ext ) ;
ext = nextext ;
} ;
}
2015-08-20 10:30:00 +05:30
if ( ( * info ) - > reaped . stacks )
free ( ( * info ) - > reaped . stacks ) ;
2015-08-19 10:30:00 +05:30
if ( ( * info ) - > anchor )
free ( ( * info ) - > anchor ) ;
if ( ( * info ) - > items )
free ( ( * info ) - > items ) ;
if ( ( * info ) - > hist ) {
free ( ( * info ) - > hist - > PHist_sav ) ;
free ( ( * info ) - > hist - > PHist_new ) ;
free ( ( * info ) - > hist ) ;
}
free ( * info ) ;
* info = NULL ;
return 0 ;
}
return ( * info ) - > refcount ;
} // end: procps_pids_unref