library: allow duplicated results for <pids> interface

Ok, here is that rather major internal redesign hinted
at in the three previous commits. Its need was quickly
revealed after adapting top then attempting to display
newly added 'CGNAME' fields and an existing 'CGROUPS'.

That very quickly generated a SEGV. And the reason was
just as quickly recognized. Both fields relied on that
proc_t.cgroup member yet whichever result structure is
first in a stack is the one which assumes ownership of
of the vectored sting by resetting its cgroup to NULL.

So this commit introduces reference counting for a few
of the fields in the proc_t. Specifically there are 17
entries in the Item_table dealing with strings/vectors
where ownership is transferred to newlib. Now whenever
such fields are represented more than once in a stack,
the strings will be duplicated instead of transferred.
In this way we can generally remain optimized avoiding
string copies, yet still accommodate them when needed.

There's an exception to this scheme: those true string
vectors (CGROUP_V, CMDLINE_V and ENVIRON_V). When such
fields are duplicated in a stack the result structures
beyond the first will be set to NULL, which the caller
will (should) already be equipped to deal with anyway.

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2015-10-13 00:00:00 -05:00 committed by Craig Small
parent cfd47f710a
commit 88489be542

View File

@ -55,6 +55,15 @@
enum pids_item PROCPS_PIDS_logical_end = PROCPS_PIDS_noop + 1; enum pids_item PROCPS_PIDS_logical_end = PROCPS_PIDS_noop + 1;
enum pids_item PROCPS_PIDS_physical_end = PROCPS_PIDS_noop + 2; enum pids_item PROCPS_PIDS_physical_end = PROCPS_PIDS_noop + 2;
// these represent the proc_t fields whose storage cannot be managed
// optimally if they are ever referenced more than once in any stack
enum rel_ref {
ref_CGROUP, ref_CGROUP_V, ref_CMD, ref_CMDLINE,
ref_CMDLINE_V, ref_ENVIRON, ref_ENVIRON_V, ref_SD_MACH,
ref_SD_OUID, ref_SD_SEAT, ref_SD_SESS, ref_SD_SLICE,
ref_SD_UNIT, ref_SD_UUNIT, ref_SUPGIDS, ref_SUPGROUPS,
MAXIMUM_ref
};
struct stacks_extent { struct stacks_extent {
struct pids_stack **stacks; struct pids_stack **stacks;
@ -90,37 +99,44 @@ struct procps_pidsinfo {
PROCTAB *PT; // the old library essential interface PROCTAB *PT; // the old library essential interface
unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations
unsigned long long boot_seconds; // for TIME_ELAPSED calculation unsigned long long boot_seconds; // for TIME_ELAPSED calculation
int ref_counts[MAXIMUM_ref]; // ref counts for special string fields
}; };
// ___ Results 'Set' Support |||||||||||||||||||||||||||||||||||||||||||||||||| // ___ Results 'Set' Support ||||||||||||||||||||||||||||||||||||||||||||||||||
/* note: the vast majority of these 'set' functions have no need for static char **dupstrvecs (char **pvec) {
the procps_pidsinfo structure, but it's being passed to all /* maybe someday we'll actually duplicate these string vectors but,
because of the CVT_set requirement & for future flexibility */ for now, let's just gently tell the user 'thanks, but no thanks'
( remember, that user was already provided with one valid copy ) */
return NULL;
}
#define setNAME(e) set_results_ ## e #define setNAME(e) set_results_ ## e
#define setDECL(e) static void setNAME(e) \ #define setDECL(e) static void setNAME(e) \
(struct procps_pidsinfo *I, struct pids_result *R, proc_t *P) (struct procps_pidsinfo *I, struct pids_result *R, proc_t *P)
// convert pages to kib // convert pages to kib
#define CVT_set(e,t,x) setDECL(e) { \ #define CVT_set(e,t,x) setDECL(e) { \
R->result. t = (unsigned long)(P-> x) << I -> pgs2k_shift; } R->result. t = (unsigned long)(P-> x) << I -> pgs2k_shift; }
// strdup of a static char array // strdup of a static char array
#define DUP_set(e,x) setDECL(e) { \ #define DUP_set(e,x) setDECL(e) { \
(void)I; R->result.str = strdup(P-> x); } (void)I; R->result.str = strdup(P-> x); }
// regular assignment copy // regular assignment copy
#define REG_set(e,t,x) setDECL(e) { \ #define REG_set(e,t,x) setDECL(e) { \
(void)I; R->result. t = P-> x; } (void)I; R->result. t = P-> x; }
// take ownership of a regular char* string // take ownership of a regular char* string if possible, else duplicate
#define STR_set(e,x) setDECL(e) { \ #define STR_set(e,x) setDECL(e) { \
(void)I; R->result.str = P-> x; P-> x = NULL; } if (I->ref_counts[ref_ ## e] > 1) R->result.str = strdup(P-> x); \
// take ownership of a vectorized single string else { R->result.str = P-> x; P-> x = NULL; } }
// take ownership of a vectorized single string if possible, else duplicate
#define STV_set(e,x) setDECL(e) { \ #define STV_set(e,x) setDECL(e) { \
(void)I; R->result.str = *P-> x; P-> x = NULL; } if (I->ref_counts[ref_ ## e] > 1) R->result.str = strdup(*P-> x); \
// take ownership of true vectorized strings else { R->result.str = *P-> x; P-> x = NULL; } }
// take ownership of true vectorized strings if possible, else return NULL
#define VEC_set(e,x) setDECL(e) { \ #define VEC_set(e,x) setDECL(e) { \
(void)I; R->result.strv = P-> x; P-> x = NULL; } if (I->ref_counts[ref_ ## e] > 1) R->result.strv = dupstrvecs(P-> x); \
else { R->result.strv = P-> x; P-> x = NULL; } }
REG_set(ADDR_END_CODE, ul_int, end_code) REG_set(ADDR_END_CODE, ul_int, end_code)
REG_set(ADDR_KSTK_EIP, ul_int, kstk_eip) REG_set(ADDR_KSTK_EIP, ul_int, kstk_eip)
@ -370,126 +386,127 @@ static struct {
FRE_t freefunc; // free function for strings storage FRE_t freefunc; // free function for strings storage
QSR_t sortfunc; // sort cmp func for a specific type QSR_t sortfunc; // sort cmp func for a specific type
int needhist; // a result requires history support int needhist; // a result requires history support
int refcount; // the result needs reference counts
} Item_table[] = { } Item_table[] = {
/* setsfunc oldflags freefunc sortfunc needhist /* setsfunc oldflags freefunc sortfunc needhist refcount
--------------------- ---------- --------- ------------ -------- */ --------------------- ---------- --------- ------------ -------- ------------- */
{ RS(ADDR_END_CODE), f_stat, NULL, QS(ul_int), 0 }, { RS(ADDR_END_CODE), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(ADDR_KSTK_EIP), f_stat, NULL, QS(ul_int), 0 }, { RS(ADDR_KSTK_EIP), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(ADDR_KSTK_ESP), f_stat, NULL, QS(ul_int), 0 }, { RS(ADDR_KSTK_ESP), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(ADDR_START_CODE), f_stat, NULL, QS(ul_int), 0 }, { RS(ADDR_START_CODE), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(ADDR_START_STACK), f_stat, NULL, QS(ul_int), 0 }, { RS(ADDR_START_STACK), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(ALARM), f_stat, NULL, QS(sl_int), 0 }, { RS(ALARM), f_stat, NULL, QS(sl_int), 0, -1 },
{ RS(CGNAME), x_cgroup, FF(str), QS(str), 0 }, { RS(CGNAME), x_cgroup, FF(str), QS(str), 0, ref_CGROUP }, // refcount: diff result, same source
{ RS(CGROUP), x_cgroup, FF(str), QS(str), 0 }, { RS(CGROUP), x_cgroup, FF(str), QS(str), 0, ref_CGROUP }, // refcount: diff result, same source
{ RS(CGROUP_V), v_cgroup, FF(strv), QS(strv), 0 }, { RS(CGROUP_V), v_cgroup, FF(strv), QS(strv), 0, ref_CGROUP_V },
{ RS(CMD), f_either, FF(str), QS(str), 0 }, { RS(CMD), f_either, FF(str), QS(str), 0, ref_CMD },
{ RS(CMDLINE), x_cmdline, FF(str), QS(str), 0 }, { RS(CMDLINE), x_cmdline, FF(str), QS(str), 0, ref_CMDLINE },
{ RS(CMDLINE_V), v_arg, FF(strv), QS(strv), 0 }, { RS(CMDLINE_V), v_arg, FF(strv), QS(strv), 0, ref_CMDLINE_V },
{ RS(ENVIRON), x_environ, FF(str), QS(str), 0 }, { RS(ENVIRON), x_environ, FF(str), QS(str), 0, ref_ENVIRON },
{ RS(ENVIRON_V), v_env, FF(strv), QS(strv), 0 }, { RS(ENVIRON_V), v_env, FF(strv), QS(strv), 0, ref_ENVIRON_V },
{ RS(EXIT_SIGNAL), f_stat, NULL, QS(s_int), 0 }, { RS(EXIT_SIGNAL), f_stat, NULL, QS(s_int), 0, -1 },
{ RS(FLAGS), f_stat, NULL, QS(ul_int), 0 }, { RS(FLAGS), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(FLT_MAJ), f_stat, NULL, QS(ul_int), 0 }, { RS(FLT_MAJ), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(FLT_MAJ_C), f_stat, NULL, QS(ul_int), 0 }, { RS(FLT_MAJ_C), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(FLT_MAJ_DELTA), f_stat, NULL, QS(ul_int), +1 }, { RS(FLT_MAJ_DELTA), f_stat, NULL, QS(ul_int), +1, -1 },
{ RS(FLT_MIN), f_stat, NULL, QS(ul_int), 0 }, { RS(FLT_MIN), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(FLT_MIN_C), f_stat, NULL, QS(ul_int), 0 }, { RS(FLT_MIN_C), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(FLT_MIN_DELTA), f_stat, NULL, QS(ul_int), +1 }, { RS(FLT_MIN_DELTA), f_stat, NULL, QS(ul_int), +1, -1 },
{ RS(ID_EGID), 0, NULL, QS(u_int), 0 }, // free w/ simple_read... { RS(ID_EGID), 0, NULL, QS(u_int), 0, -1 }, // oldflags: free w/ simple_read...
{ RS(ID_EGROUP), f_grp, NULL, QS(str), 0 }, { RS(ID_EGROUP), f_grp, NULL, QS(str), 0, -1 },
{ RS(ID_EUID), 0, NULL, QS(u_int), 0 }, // free w/ simple_read... { RS(ID_EUID), 0, NULL, QS(u_int), 0, -1 }, // oldflags: free w/ simple_read...
{ RS(ID_EUSER), f_usr, NULL, QS(str), 0 }, { RS(ID_EUSER), f_usr, NULL, QS(str), 0, -1 },
{ RS(ID_FGID), f_status, NULL, QS(u_int), 0 }, { RS(ID_FGID), f_status, NULL, QS(u_int), 0, -1 },
{ RS(ID_FGROUP), x_ogroup, NULL, QS(str), 0 }, { RS(ID_FGROUP), x_ogroup, NULL, QS(str), 0, -1 },
{ RS(ID_FUID), f_status, NULL, QS(u_int), 0 }, { RS(ID_FUID), f_status, NULL, QS(u_int), 0, -1 },
{ RS(ID_FUSER), x_ouser, NULL, QS(str), 0 }, { RS(ID_FUSER), x_ouser, NULL, QS(str), 0, -1 },
{ RS(ID_PGRP), f_stat, NULL, QS(s_int), 0 }, { RS(ID_PGRP), f_stat, NULL, QS(s_int), 0, -1 },
{ RS(ID_PID), 0, NULL, QS(s_int), 0 }, // free w/ simple_nextpid { RS(ID_PID), 0, NULL, QS(s_int), 0, -1 }, // oldflags: free w/ simple_nextpid
{ RS(ID_PPID), f_either, NULL, QS(s_int), 0 }, { RS(ID_PPID), f_either, NULL, QS(s_int), 0, -1 },
{ RS(ID_RGID), f_status, NULL, QS(u_int), 0 }, { RS(ID_RGID), f_status, NULL, QS(u_int), 0, -1 },
{ RS(ID_RGROUP), x_ogroup, NULL, QS(str), 0 }, { RS(ID_RGROUP), x_ogroup, NULL, QS(str), 0, -1 },
{ RS(ID_RUID), f_status, NULL, QS(u_int), 0 }, { RS(ID_RUID), f_status, NULL, QS(u_int), 0, -1 },
{ RS(ID_RUSER), x_ouser, NULL, QS(str), 0 }, { RS(ID_RUSER), x_ouser, NULL, QS(str), 0, -1 },
{ RS(ID_SESSION), f_stat, NULL, QS(s_int), 0 }, { RS(ID_SESSION), f_stat, NULL, QS(s_int), 0, -1 },
{ RS(ID_SGID), f_status, NULL, QS(u_int), 0 }, { RS(ID_SGID), f_status, NULL, QS(u_int), 0, -1 },
{ RS(ID_SGROUP), x_ogroup, NULL, QS(str), 0 }, { RS(ID_SGROUP), x_ogroup, NULL, QS(str), 0, -1 },
{ RS(ID_SUID), f_status, NULL, QS(u_int), 0 }, { RS(ID_SUID), f_status, NULL, QS(u_int), 0, -1 },
{ RS(ID_SUSER), x_ouser, NULL, QS(str), 0 }, { RS(ID_SUSER), x_ouser, NULL, QS(str), 0, -1 },
{ RS(ID_TGID), 0, NULL, QS(s_int), 0 }, // free w/ simple_nextpid { RS(ID_TGID), 0, NULL, QS(s_int), 0, -1 }, // oldflags: free w/ simple_nextpid
{ RS(ID_TPGID), f_stat, NULL, QS(s_int), 0 }, { RS(ID_TPGID), f_stat, NULL, QS(s_int), 0, -1 },
{ RS(LXCNAME), f_lxc, NULL, QS(str), 0 }, { RS(LXCNAME), f_lxc, NULL, QS(str), 0, -1 },
{ RS(MEM_CODE), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_CODE), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_CODE_KIB), f_statm, NULL, QS(ul_int), 0 }, { RS(MEM_CODE_KIB), f_statm, NULL, QS(ul_int), 0, -1 },
{ RS(MEM_DATA), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_DATA), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_DATA_KIB), f_statm, NULL, QS(ul_int), 0 }, { RS(MEM_DATA_KIB), f_statm, NULL, QS(ul_int), 0, -1 },
{ RS(MEM_DT), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_DT), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_LRS), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_LRS), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_RES), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_RES), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_RES_KIB), f_statm, NULL, QS(ul_int), 0 }, { RS(MEM_RES_KIB), f_statm, NULL, QS(ul_int), 0, -1 },
{ RS(MEM_SHR), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_SHR), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_SHR_KIB), f_statm, NULL, QS(ul_int), 0 }, { RS(MEM_SHR_KIB), f_statm, NULL, QS(ul_int), 0, -1 },
{ RS(MEM_VIRT), f_statm, NULL, QS(sl_int), 0 }, { RS(MEM_VIRT), f_statm, NULL, QS(sl_int), 0, -1 },
{ RS(MEM_VIRT_KIB), f_statm, NULL, QS(ul_int), 0 }, { RS(MEM_VIRT_KIB), f_statm, NULL, QS(ul_int), 0, -1 },
{ RS(NICE), f_stat, NULL, QS(sl_int), 0 }, { RS(NICE), f_stat, NULL, QS(sl_int), 0, -1 },
{ RS(NLWP), f_either, NULL, QS(s_int), 0 }, { RS(NLWP), f_either, NULL, QS(s_int), 0, -1 },
{ RS(NS_IPC), f_ns, NULL, QS(ul_int), 0 }, { RS(NS_IPC), f_ns, NULL, QS(ul_int), 0, -1 },
{ RS(NS_MNT), f_ns, NULL, QS(ul_int), 0 }, { RS(NS_MNT), f_ns, NULL, QS(ul_int), 0, -1 },
{ RS(NS_NET), f_ns, NULL, QS(ul_int), 0 }, { RS(NS_NET), f_ns, NULL, QS(ul_int), 0, -1 },
{ RS(NS_PID), f_ns, NULL, QS(ul_int), 0 }, { RS(NS_PID), f_ns, NULL, QS(ul_int), 0, -1 },
{ RS(NS_USER), f_ns, NULL, QS(ul_int), 0 }, { RS(NS_USER), f_ns, NULL, QS(ul_int), 0, -1 },
{ RS(NS_UTS), f_ns, NULL, QS(ul_int), 0 }, { RS(NS_UTS), f_ns, NULL, QS(ul_int), 0, -1 },
{ RS(OOM_ADJ), f_oom, NULL, QS(s_int), 0 }, { RS(OOM_ADJ), f_oom, NULL, QS(s_int), 0, -1 },
{ RS(OOM_SCORE), f_oom, NULL, QS(s_int), 0 }, { RS(OOM_SCORE), f_oom, NULL, QS(s_int), 0, -1 },
{ RS(PRIORITY), f_stat, NULL, QS(s_int), 0 }, { RS(PRIORITY), f_stat, NULL, QS(s_int), 0, -1 },
{ RS(PROCESSOR), f_stat, NULL, QS(u_int), 0 }, { RS(PROCESSOR), f_stat, NULL, QS(u_int), 0, -1 },
{ RS(RSS), f_stat, NULL, QS(sl_int), 0 }, { RS(RSS), f_stat, NULL, QS(sl_int), 0, -1 },
{ RS(RSS_RLIM), f_stat, NULL, QS(ul_int), 0 }, { RS(RSS_RLIM), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(RTPRIO), f_stat, NULL, QS(ul_int), 0 }, { RS(RTPRIO), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(SCHED_CLASS), f_stat, NULL, QS(ul_int), 0 }, { RS(SCHED_CLASS), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(SD_MACH), f_systemd, FF(str), QS(str), 0 }, { RS(SD_MACH), f_systemd, FF(str), QS(str), 0, ref_SD_MACH },
{ RS(SD_OUID), f_systemd, FF(str), QS(str), 0 }, { RS(SD_OUID), f_systemd, FF(str), QS(str), 0, ref_SD_OUID },
{ RS(SD_SEAT), f_systemd, FF(str), QS(str), 0 }, { RS(SD_SEAT), f_systemd, FF(str), QS(str), 0, ref_SD_SEAT },
{ RS(SD_SESS), f_systemd, FF(str), QS(str), 0 }, { RS(SD_SESS), f_systemd, FF(str), QS(str), 0, ref_SD_SESS },
{ RS(SD_SLICE), f_systemd, FF(str), QS(str), 0 }, { RS(SD_SLICE), f_systemd, FF(str), QS(str), 0, ref_SD_SLICE },
{ RS(SD_UNIT), f_systemd, FF(str), QS(str), 0 }, { RS(SD_UNIT), f_systemd, FF(str), QS(str), 0, ref_SD_UNIT },
{ RS(SD_UUNIT), f_systemd, FF(str), QS(str), 0 }, { RS(SD_UUNIT), f_systemd, FF(str), QS(str), 0, ref_SD_UUNIT },
{ RS(SIGBLOCKED), f_status, FF(str), QS(str), 0 }, { RS(SIGBLOCKED), f_status, FF(str), QS(str), 0, -1 },
{ RS(SIGCATCH), f_status, FF(str), QS(str), 0 }, { RS(SIGCATCH), f_status, FF(str), QS(str), 0, -1 },
{ RS(SIGIGNORE), f_status, FF(str), QS(str), 0 }, { RS(SIGIGNORE), f_status, FF(str), QS(str), 0, -1 },
{ RS(SIGNALS), f_status, FF(str), QS(str), 0 }, { RS(SIGNALS), f_status, FF(str), QS(str), 0, -1 },
{ RS(SIGPENDING), f_status, FF(str), QS(str), 0 }, { RS(SIGPENDING), f_status, FF(str), QS(str), 0, -1 },
{ RS(STATE), f_either, NULL, QS(s_ch), 0 }, { RS(STATE), f_either, NULL, QS(s_ch), 0, -1 },
{ RS(SUPGIDS), f_status, FF(str), QS(str), 0 }, { RS(SUPGIDS), f_status, FF(str), QS(str), 0, ref_SUPGIDS },
{ RS(SUPGROUPS), x_supgrp, FF(str), QS(str), 0 }, { RS(SUPGROUPS), x_supgrp, FF(str), QS(str), 0, ref_SUPGROUPS },
{ RS(TICS_ALL), f_stat, NULL, QS(ull_int), 0 }, { RS(TICS_ALL), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TICS_ALL_C), f_stat, NULL, QS(ull_int), 0 }, { RS(TICS_ALL_C), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TICS_DELTA), f_stat, NULL, QS(u_int), +1 }, { RS(TICS_DELTA), f_stat, NULL, QS(u_int), +1, -1 },
{ RS(TICS_SYSTEM), f_stat, NULL, QS(ull_int), 0 }, { RS(TICS_SYSTEM), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TICS_SYSTEM_C), f_stat, NULL, QS(ull_int), 0 }, { RS(TICS_SYSTEM_C), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TICS_USER), f_stat, NULL, QS(ull_int), 0 }, { RS(TICS_USER), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TICS_USER_C), f_stat, NULL, QS(ull_int), 0 }, { RS(TICS_USER_C), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TIME_ALL), f_stat, NULL, QS(ull_int), 0 }, { RS(TIME_ALL), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TIME_ELAPSED), f_stat, NULL, QS(ull_int), 0 }, { RS(TIME_ELAPSED), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TIME_START), f_stat, NULL, QS(ull_int), 0 }, { RS(TIME_START), f_stat, NULL, QS(ull_int), 0, -1 },
{ RS(TTY), f_stat, NULL, QS(s_int), 0 }, { RS(TTY), f_stat, NULL, QS(s_int), 0, -1 },
{ RS(TTY_NAME), f_stat, FF(str), QS(strvers), 0 }, { RS(TTY_NAME), f_stat, FF(str), QS(strvers), 0, -1 },
{ RS(TTY_NUMBER), f_stat, FF(str), QS(strvers), 0 }, { RS(TTY_NUMBER), f_stat, FF(str), QS(strvers), 0, -1 },
{ RS(VM_DATA), f_status, NULL, QS(ul_int), 0 }, { RS(VM_DATA), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_EXE), f_status, NULL, QS(ul_int), 0 }, { RS(VM_EXE), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_LIB), f_status, NULL, QS(ul_int), 0 }, { RS(VM_LIB), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_LOCK), f_status, NULL, QS(ul_int), 0 }, { RS(VM_LOCK), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_RSS), f_status, NULL, QS(ul_int), 0 }, { RS(VM_RSS), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_SIZE), f_status, NULL, QS(ul_int), 0 }, { RS(VM_SIZE), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_STACK), f_status, NULL, QS(ul_int), 0 }, { RS(VM_STACK), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_SWAP), f_status, NULL, QS(ul_int), 0 }, { RS(VM_SWAP), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VM_USED), f_status, NULL, QS(ul_int), 0 }, { RS(VM_USED), f_status, NULL, QS(ul_int), 0, -1 },
{ RS(VSIZE_PGS), f_stat, NULL, QS(ul_int), 0 }, { RS(VSIZE_PGS), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(WCHAN_ADDR), f_stat, NULL, QS(ul_int), 0 }, { RS(WCHAN_ADDR), f_stat, NULL, QS(ul_int), 0, -1 },
{ RS(WCHAN_NAME), 0, FF(str), QS(str), 0 }, // tid already free { RS(WCHAN_NAME), 0, FF(str), QS(str), 0, -1 }, // oldflags: tid already free
{ RS(extra), 0, NULL, QS(ull_int), 0 }, { RS(extra), 0, NULL, QS(ull_int), 0, -1 },
{ RS(noop), 0, NULL, QS(noop), 0 }, { RS(noop), 0, NULL, QS(noop), 0, -1 },
{ RS(logical_end), 0, NULL, QS(noop), 0 }, { RS(logical_end), 0, NULL, QS(noop), 0, -1 },
{ RS(physical_end), 0, NULL, QS(noop), 0 } { RS(physical_end), 0, NULL, QS(noop), 0, -1 }
}; };
#undef RS #undef RS
@ -858,12 +875,15 @@ static inline int items_check_failed (
static inline void libflags_set ( static inline void libflags_set (
struct procps_pidsinfo *info) struct procps_pidsinfo *info)
{ {
int i; int i, n;
memset (info->ref_counts, 0, sizeof(info->ref_counts));
info->flags = info->history_yes = 0; info->flags = info->history_yes = 0;
for (i = 0; i < info->curitems; i++) { for (i = 0; i < info->curitems; i++) {
info->flags |= Item_table[info->items[i]].oldflags; info->flags |= Item_table[info->items[i]].oldflags;
info->history_yes |= Item_table[info->items[i]].needhist; info->history_yes |= Item_table[info->items[i]].needhist;
n = Item_table[info->items[i]].refcount;
if (n > -1) ++info->ref_counts[n];
} }
if (info->flags & f_either) { if (info->flags & f_either) {
if (!(info->flags & f_stat)) if (!(info->flags & f_stat))