--- procps-2.0.11/proc/readproc.c.nptl 2002-11-06 21:51:57.000000000 +0100 +++ procps-2.0.11/proc/readproc.c 2003-02-20 10:20:07.000000000 +0100 @@ -87,12 +87,20 @@ sscanf(tmp, "State:\t%c", &P->state); } + tmp = strstr(S, "Tgid:"); + if (tmp) + sscanf(tmp, "Tgid:\t%d\n", &P->tgid); + else + P->tgid = 0; /* Tgid not supported by kernel */ + + tmp = strstr(S, "Pid:"); if (tmp) sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid); else fprintf(stderr, "Internal error!\n"); + tmp = strstr(S, "Uid:"); if (tmp) sscanf(tmp, @@ -172,7 +180,8 @@ "%lld " "%llu %llu %llu %llu %llu %llu " "%*s %*s %*s %*s " /* discard, no RT signals & Linux 2.1 used hex */ - "%llu %llu %llu %*d %d %llu %llu", + "%llu %llu %llu %*d %d %llu %llu " + "%llu %llu %llu %llu", /* threadgroup - utime stime cutime cstime */ &P->state, &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid, &P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, @@ -187,8 +196,18 @@ /* P->signal, P->blocked, P->sigignore, P->sigcatch, *//* can't use */ &P->wchan, &P->nswap, &P->cnswap /* , &P->exit_signal */ , &P->cpu, - &P->rtprio, &P->policy /* 2.5.18 */ + &P->rtprio, &P->policy, /* 2.5.18 */ + &P->group_utime, &P->group_stime, &P->group_cutime, &P->group_cstime /* NPTL */ ); + + if (num <= 34) { + /* Threadgroup data not availible, emulate */ + P->group_utime = P->utime; + P->group_stime = P->stime; + P->group_cutime = P->cutime; + P->group_cstime = P->cstime; + } + /* TODO: add &P->exit_signal support here, perhaps to identify Linux threads */ /* fprintf(stderr, "stat2proc converted %d fields.\n",num); */ @@ -355,7 +374,10 @@ matched = 1; } else { /* get next numeric /proc ent */ while ((ent = readdir(PT->procfs)) && - (*ent->d_name < '0' || *ent->d_name > '9')) ; + (*ent->d_name < '0' || *ent->d_name > '9') && + (Do(SKIPTHREADS) || + !(ent->d_name[0] == '.' && ent->d_name[1] >= '0' && ent->d_name[1] <= '9'))) + /* Skip entry */; if (!ent || !ent->d_name) return NULL; sprintf(path, "/proc/%s", ent->d_name); @@ -457,7 +479,10 @@ #define flags (PT->flags) while ((ent = readdir(PT->procfs)) && - (*ent->d_name < '0' || *ent->d_name > '9')) ; + (*ent->d_name < '0' || *ent->d_name > '9') && + (Do(SKIPTHREADS) || + !(ent->d_name[0] == '.' && ent->d_name[1] >= '0' && ent->d_name[1] <= '9'))) + /* Skip entry */; if (!ent || !ent->d_name) return NULL; sprintf(path, "/proc/%s", ent->d_name); @@ -473,18 +498,18 @@ if ((file2str(path, "stat", sbuf, sizeof sbuf)) == -1) goto next_proc; /* error reading /proc/#/stat */ stat2proc(sbuf, p); /* parse /proc/#/stat */ - - /* if (Do(FILLMEM)) {*//* read, parse /proc/#/statm */ - if ((file2str(path, "statm", sbuf, sizeof sbuf)) != -1) - statm2proc(sbuf, p); /* ignore statm errors here */ - /* } *//* statm fields just zero */ - + + if (Do(FILLMEM)) {/* read, parse /proc/#/statm */ + if ((file2str(path, "statm", sbuf, sizeof sbuf)) != -1) + statm2proc(sbuf, p); /* ignore statm errors here */ + } /* statm fields just zero */ + /* if (Do(FILLSTATUS)) { *//* read, parse /proc/#/status */ if ((file2str(path, "status", sbuf, sizeof sbuf)) != -1) { status2proc(sbuf, p, 0 /*FIXME*/); } /* }*/ - + /* some number->text resolving which is time consuming */ /* if (Do(FILLUSR)){ */ strncpy(p->euser, user_from_uid(p->euid), sizeof p->euser); @@ -499,15 +524,15 @@ /* }*/ /* }*/ - /* if (Do(FILLCMD)) *//* read+parse /proc/#/cmdline */ - p->cmdline = file2strvec(path, "cmdline"); - /* if (Do(FILLENV)) *//* read+parse /proc/#/environ */ - p->environ = file2strvec(path, "environ"); - /* if (Do(FILLWCHAN)) *//* read+parse /proc/#/wchan */ - if (file2str(path, "wchan", p->wchan_decoded, - sizeof(p->wchan_decoded)) < 0) - p->wchan_decoded[0] = '\0'; - + if (Do(FILLCMD)) /* read+parse /proc/#/cmdline */ + p->cmdline = file2strvec(path, "cmdline"); + if (Do(FILLENV)) /* read+parse /proc/#/environ */ + p->environ = file2strvec(path, "environ"); + if (Do(FILLWCHAN)) {/* read+parse /proc/#/wchan */ + if (file2str(path, "wchan", p->wchan_decoded, + sizeof(p->wchan_decoded)) < 0) + p->wchan_decoded[0] = '\0'; + } if (p->state == 'Z') /* fixup cmd for zombies */ strncat(p->cmd, " ", sizeof p->cmd); --- procps-2.0.11/proc/readproc.h.nptl 2002-11-06 21:51:57.000000000 +0100 +++ procps-2.0.11/proc/readproc.h 2003-02-20 10:20:07.000000000 +0100 @@ -117,11 +117,19 @@ session, /* session id */ tty, /* full device number of controlling terminal */ tpgid, /* terminal process group id */ + tgid, /* thread group id */ thread; /* is this a member of a thread group? */ unsigned int pcpu; /* %CPU usage (is not filled in by readproc!!!) */ char state; /* single-char code for process state (S=sleeping) */ + unsigned long long + group_cutime, /* thread group cumulative utime of proc + reaped children */ + group_cstime, /* thread group cumulative stime of proc + reaped children */ + group_utime, /* thread group user-mode CPU time accumulated by process */ + group_stime; /* thread group kernel-mode CPU time accumulated by proc */ + unsigned int + group_pcpu; /* thread group %CPU usage (is not filled in by readproc!!!) */ } proc_t; /* PROCTAB: data structure holding the persistent information readproc needs @@ -200,6 +208,8 @@ #define PROC_FILLBUG 0x3f /* No idea what we need */ #define PROC_FILLWCHAN 0x40 /* fill in wchan */ +#define PROC_SKIPTHREADS 0x80 /* Skip (NPTL) subthreads (tgid != pid) */ + /* Obsolete, consider only processes with one of the passed: */ #define PROC_PID 0x100 /* process id numbers ( 0 terminated) */ #define PROC_TTY 0x200 /* ctty device nos. ( 0 terminated) */ --- procps-2.0.11/ps/common.h.nptl 2002-10-01 19:53:49.000000000 +0200 +++ procps-2.0.11/ps/common.h 2003-02-20 10:20:07.000000000 +0100 @@ -140,7 +140,7 @@ #define SIGNAL 6 /* right in 9, or 16 if screen_cols>107 */ #define CUMUL 16 /* mark cumulative (Summed) headers with 'C' */ - + /********************** GENERAL TYPEDEF *******************/ /* Other fields that might be useful: @@ -183,6 +183,7 @@ int pad; int vendor; /* Vendor that invented this */ int flags; + int readproc_flags; int typecode; } format_node; @@ -195,6 +196,7 @@ const int pad; /* could be second width */ const int vendor; /* Where does this come from? */ const int flags; + const int readproc_flags; } format_struct; /* though ps-specific, needed by general file */ --- procps-2.0.11/ps/display.c.nptl 2002-11-08 08:00:34.000000000 +0100 +++ procps-2.0.11/ps/display.c 2003-02-20 10:20:07.000000000 +0100 @@ -247,6 +247,7 @@ { unsigned long total_time; unsigned long pcpu = 0; + unsigned long group_pcpu = 0; unsigned long seconds; if (buf == NULL) @@ -258,15 +259,41 @@ if (seconds) pcpu = ((long long) total_time * 1000 / Hertz) / seconds; buf->pcpu = (pcpu > 999) ? 999 : pcpu; + + + total_time = buf->group_utime + buf->group_stime; + if (include_dead_children) + total_time += (buf->group_cutime + buf->group_cstime); + if (seconds) + group_pcpu = ((long long) total_time * 1000 / Hertz) / seconds; + buf->group_pcpu = (group_pcpu > 999) ? 999 : group_pcpu; +} + +static int +get_readproc_flags(void) +{ + format_node *walk; + int flags; + + flags = 0; + walk = format_list; + while (walk) { + flags |= walk->readproc_flags; + walk = walk->next; + } + if (!show_threads) + flags |= PROC_SKIPTHREADS; + return flags; } + /***** just display */ static void simple_spew(void) { proc_t buf; PROCTAB *ptp; - ptp = openproc(PROC_FILLBUG); + ptp = openproc(get_readproc_flags()); memset(&buf, '#', sizeof (proc_t)); /* use "ps_" prefix to catch library mismatch */ while (ps_readproc(ptp, &buf)) { @@ -367,7 +394,7 @@ flag_threads(int pid) { unsigned int *pid_array; - int max = 1, parent, i; + int max = 1, parent, i, is_ntpl_thread; for (i = 0; i < pid; i++) { if (processes[i]->pid > max) @@ -384,40 +411,60 @@ pid_array[processes[i]->pid] = i + 1; for (i = 0; i < pid; i++) { - processes[i]->thread = 0; - if (processes[i]->ppid <= 1 - || pid_array[processes[i]->ppid] == 0) - continue; - parent = pid_array[processes[i]->ppid] - 1; - if (thread_group(processes[parent], processes[i])) - processes[i]->thread = 1; + is_ntpl_thread = processes[i]->tgid != 0 && processes[i]->tgid != processes[i]->pid; + processes[i]->thread = is_ntpl_thread; + + if (!is_ntpl_thread) { + /* Check for old-style LinuxThread or clone() threads: */ + if (processes[i]->ppid <= 1 + || pid_array[processes[i]->ppid] == 0) + continue; + parent = pid_array[processes[i]->ppid] - 1; + if (thread_group(processes[parent], processes[i])) + processes[i]->thread = 1; + } } /* * yield the master thread the CPU times from the child threads */ for (i = 0; i < pid; i++) { - if (!processes[i]->thread) - continue; - - parent = i; - do { - parent = pid_array[processes[parent]->ppid] - 1; - } while (processes[parent]->thread); - - processes[parent]->cstime += processes[i]->cstime; - processes[parent]->cstime += processes[i]->cstime; - processes[parent]->stime += processes[i]->stime; - processes[parent]->utime += processes[i]->utime; - processes[parent]->pcpu += processes[i]->pcpu; - - /* - * prevent a possible overflow due to bad accounting - */ - if (processes[parent]->pcpu > 999) - processes[parent]->pcpu = 999; + if (processes[i]->thread && + (processes[i]->tgid == 0 || + processes[i]->tgid == processes[i]->pid)) { + /* Non NTPL thread, need to manually compute thread stuff */ + parent = i; + do { + parent = pid_array[processes[parent]->ppid] - 1; + } while (processes[parent]->thread); + + processes[parent]->group_cstime += processes[i]->group_cstime; + processes[parent]->group_cutime += processes[i]->group_cutime; + processes[parent]->group_stime += processes[i]->group_stime; + processes[parent]->group_utime += processes[i]->group_utime; + processes[parent]->group_pcpu += processes[i]->group_pcpu; + + /* + * prevent a possible overflow due to bad accounting + */ + if (processes[parent]->group_pcpu > 999) + processes[parent]->group_pcpu = 999; + } } + /* Move threadgroup cpu info counters to normal ones, since + * we're not showing subthreads + */ + for (i = 0; i < pid; i++) { + if (!processes[i]->thread) { + processes[i]->cstime = processes[i]->group_cstime; + processes[i]->cutime = processes[i]->group_cutime; + processes[i]->stime = processes[i]->group_stime; + processes[i]->utime = processes[i]->group_utime; + processes[i]->pcpu = processes[i]->group_pcpu; + } + } + free(pid_array); } @@ -512,7 +559,7 @@ proc_t *retbuf; PROCTAB *ptp; int n = 0; /* number of processes & index into array */ - ptp = openproc(PROC_FILLBUG); + ptp = openproc(get_readproc_flags()); while ((retbuf = ps_readproc(ptp, NULL))) { fill_pcpu(retbuf); /* fill in %CPU */ if (want_this_proc(retbuf)) @@ -529,7 +576,8 @@ if (forest_type) prep_forest_sort(); - qsort(processes, n, sizeof (proc_t *), compare_two_procs); + if (sort_list) + qsort(processes, n, sizeof (proc_t *), compare_two_procs); if (forest_type) show_forest(n); else --- procps-2.0.11/ps/output.c.nptl 2002-11-10 18:10:36.000000000 +0100 +++ procps-2.0.11/ps/output.c 2003-02-20 10:20:07.000000000 +0100 @@ -1117,7 +1117,7 @@ {"addr", "ADDR", pr_nop, sr_nop, 4, 0, XXX, RIGHT}, {"alarm", "ALARM", pr_alarm, sr_it_real_value, 5, 0, LNX, RIGHT}, {"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, RIGHT}, - {"args", "COMMAND", pr_args, sr_nop, 16, 0, U98, UNLIMITED}, /*command */ + {"args", "COMMAND", pr_args, sr_nop, 16, 0, U98, UNLIMITED, ENV|CMD}, /*command */ {"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, SIGNAL}, /*sigmask */ {"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, RIGHT}, {"bsdstart", "START", pr_bsdstart, sr_nop, 6, 0, LNX, RIGHT}, @@ -1127,11 +1127,11 @@ {"class", "CLS", pr_policy, sr_nop, 5, 0, XXX, RIGHT}, {"cls", "-", pr_nop, sr_nop, 1, 0, HPU, RIGHT}, {"cmaj_flt", "-", pr_nop, sr_cmaj_flt, 1, 0, LNX, RIGHT}, - {"cmd", "CMD", pr_args, sr_cmd, 16, 0, DEC, UNLIMITED}, /*ucomm */ + {"cmd", "CMD", pr_args, sr_cmd, 16, 0, DEC, UNLIMITED, ENV|CMD}, /*ucomm */ {"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, RIGHT}, {"cnswap", "-", pr_nop, sr_cnswap, 1, 0, LNX, RIGHT}, - {"comm", "COMMAND", pr_comm, sr_nop, 16, 0, U98, UNLIMITED}, /*ucomm */ - {"command", "COMMAND", pr_args, sr_nop, 16, 0, XXX, UNLIMITED}, /*args */ + {"comm", "COMMAND", pr_comm, sr_nop, 16, 0, U98, UNLIMITED, ENV|CMD}, /*ucomm */ + {"command", "COMMAND", pr_args, sr_nop, 16, 0, XXX, UNLIMITED, ENV|CMD}, /*args */ {"cp", "CP", pr_cpu, sr_nop, 2, 0, DEC, RIGHT}, /* current cpu */ {"cpu", "CPU", pr_cpu, sr_nop, 3, 0, BSD, RIGHT}, /* current cpu */ {"cputime", "TIME", pr_time, sr_nop, 8, 0, DEC, RIGHT}, /*time */ @@ -1184,7 +1184,7 @@ {"m_lrs", "LRS", pr_nop, sr_lrs, 5, 0, LNx, RIGHT}, {"m_resident", "RES", pr_nop, sr_resident, 5, 0, LNx, RIGHT}, {"m_share", "SHRD", pr_nop, sr_share, 5, 0, LNx, RIGHT}, - {"m_size", "SIZE", pr_size, sr_size, 5, 0, LNx, RIGHT}, + {"m_size", "SIZE", pr_size, sr_size, 5, 0, LNx, RIGHT, MEM}, {"m_swap", "SWAP", pr_nop, sr_nop, 5, 0, LNx, RIGHT}, {"m_trs", "TRS", pr_trs, sr_trs, 5, 0, LNx, RIGHT}, {"maj_flt", "MAJFL", pr_majflt, sr_maj_flt, 6, 0, LNX, CUMUL | RIGHT}, @@ -1292,8 +1292,8 @@ {"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, LEFT}, {"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, LEFT}, {"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, RIGHT}, - {"ucmd", "CMD", pr_comm, sr_cmd, 16, 0, DEC, UNLIMITED}, /*ucomm */ - {"ucomm", "COMMAND", pr_comm, sr_nop, 16, 0, XXX, UNLIMITED}, /*comm */ + {"ucmd", "CMD", pr_comm, sr_cmd, 16, 0, DEC, UNLIMITED, ENV|CMD}, /*ucomm */ + {"ucomm", "COMMAND", pr_comm, sr_nop, 16, 0, XXX, UNLIMITED, ENV|CMD}, /*comm */ {"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, RIGHT}, {"uid_hack", "UID", pr_euser, sr_nop, 8, 0, XXX, USER}, {"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, RIGHT}, @@ -1311,7 +1311,7 @@ {"vm_stack", "STACK", pr_nop, sr_vm_stack, 5, 0, LNx, RIGHT}, {"vsize", "VSZ", pr_vsz, sr_vsize, 5, 0, DEC, RIGHT}, /*vsz */ {"vsz", "VSZ", pr_vsz, sr_vm_size, 5, 0, U98, RIGHT}, /*vsize */ - {"wchan", "WCHAN", pr_wchan, sr_wchan, 6, 0, XXX, WCHAN}, /* BSD n forces this to nwchan *//* was 10 wide */ + {"wchan", "WCHAN", pr_wchan, sr_wchan, 6, 0, XXX, WCHAN, PROC_FILLWCHAN}, /* BSD n forces this to nwchan *//* was 10 wide */ {"xstat", "XSTAT", pr_nop, sr_nop, 5, 0, BSD, RIGHT}, {"~", "-", pr_nop, sr_nop, 1, 0, LNX, RIGHT} /* NULL would ruin alphabetical order */ }; --- procps-2.0.11/ps/sortformat.c.nptl 2002-10-03 16:37:46.000000000 +0200 +++ procps-2.0.11/ps/sortformat.c 2003-02-20 10:20:07.000000000 +0100 @@ -57,6 +57,7 @@ thisnode->pad = fs->pad; thisnode->vendor = fs->vendor; thisnode->flags = fs->flags; + thisnode->readproc_flags = fs->readproc_flags; thisnode->next = NULL; return thisnode; } @@ -298,6 +299,7 @@ fnode->pad = 0; fnode->vendor = AIX; fnode->flags = 0; + fnode->readproc_flags = 0; fnode->next = NULL; } @@ -325,7 +327,7 @@ fs = search_format_array(spec); if (fs) { sort_node *thisnode; - thisnode = malloc(sizeof (format_node)); + thisnode = malloc(sizeof (sort_node)); thisnode->sr = fs->sr; thisnode->reverse = reverse; thisnode->next = NULL; @@ -746,6 +748,7 @@ fn->pad = 0; fn->vendor = AIX; /* yes, for SGI weirdness */ fn->flags = 0; + fn->readproc_flags = 0; fn->next = format_list; format_list = fn; } --- procps-2.0.11/top.c.nptl 2002-11-24 00:01:58.000000000 +0100 +++ procps-2.0.11/top.c 2003-02-20 12:08:39.000000000 +0100 @@ -1278,7 +1278,7 @@ flag_threads(proc_t ** processes) { unsigned int *pid_array; - int max = 1, i, parent; + int max = 1, i, parent, is_ntpl_thread; for (i = 0; processes[i]->pid != -1; i++) { if (processes[i]->pid > max) @@ -1290,41 +1290,58 @@ pid_array = malloc(sizeof (unsigned int) * (max + 1)); if (!pid_array) return; - memset(pid_array, 0, sizeof (unsigned int) * (max + 1)); for (i = 0; processes[i]->pid != -1; i++) pid_array[processes[i]->pid] = i + 1; for (i = 0; processes[i]->pid != -1; i++) { - processes[i]->thread = 0; - if (processes[i]->ppid <= 1 - || pid_array[processes[i]->ppid] == 0) - continue; - - parent = pid_array[processes[i]->ppid] - 1; - if (thread_group(processes[parent], processes[i])) - processes[i]->thread = 1; + is_ntpl_thread = processes[i]->tgid != 0 && processes[i]->tgid != processes[i]->pid; + processes[i]->thread = is_ntpl_thread; + + if (!is_ntpl_thread) { + /* Check for old-style LinuxThread or clone() threads: */ + if (processes[i]->ppid <= 1 + || pid_array[processes[i]->ppid] == 0) + continue; + parent = pid_array[processes[i]->ppid] - 1; + if (thread_group(processes[parent], processes[i])) + processes[i]->thread = 1; + } } /* * yield the master thread the CPU times from the child threads */ for (i = 0; processes[i]->pid != -1; i++) { - if (!processes[i]->thread) - continue; - - parent = i; - do { - parent = pid_array[processes[parent]->ppid] - 1; - } while (processes[parent]->thread); - - processes[parent]->cutime += processes[i]->cutime; - processes[parent]->cstime += processes[i]->cstime; - processes[parent]->utime += processes[i]->utime; - processes[parent]->stime += processes[i]->stime; + if (processes[i]->thread && + (processes[i]->tgid == 0 || + processes[i]->tgid == processes[i]->pid)) { + /* Non NTPL thread, need to manually compute thread stuff */ + parent = i; + do { + parent = pid_array[processes[parent]->ppid] - 1; + } while (processes[parent]->thread); + + processes[parent]->group_cstime += processes[i]->group_cstime; + processes[parent]->group_cutime += processes[i]->group_cutime; + processes[parent]->group_stime += processes[i]->group_stime; + processes[parent]->group_utime += processes[i]->group_utime; + } } + /* Move threadgroup cpu info counters to normal ones, since + * we're not showing subthreads + */ + for (i = 0; processes[i]->pid != -1; i++) { + if (!processes[i]->thread) { + processes[i]->cstime = processes[i]->group_cstime; + processes[i]->cutime = processes[i]->group_cutime; + processes[i]->stime = processes[i]->group_stime; + processes[i]->utime = processes[i]->group_utime; + } + } + free(pid_array); } @@ -1350,6 +1367,8 @@ PROC_FILLUSR | PROC_FILLWCHAN; if (monpids_index) proc_flags |= PROC_PID; + if (!show_threads) + proc_flags |= PROC_SKIPTHREADS; p_table = readproctab2(proc_flags, p_table, monpids); if (!show_threads) flag_threads(p_table); @@ -1368,6 +1387,9 @@ PUTP(top_clrtoeol); putchar('\n'); } + proc_flags &= ~PROC_SKIPTHREADS; + if (!show_threads) + proc_flags |= PROC_SKIPTHREADS; p_table = readproctab2(proc_flags, p_table, monpids); if (!show_threads) flag_threads(p_table); --- procps-2.0.11/w.c.nptl 2003-02-20 12:34:11.000000000 +0100 +++ procps-2.0.11/w.c 2003-02-20 12:41:43.000000000 +0100 @@ -299,7 +299,7 @@ fprintf(stderr, "warning: screen width %d suboptimal.\n", win.ws_col); - procs = readproctab(PROC_FILLCMD | PROC_FILLUSR); + procs = readproctab(PROC_FILLCMD | PROC_FILLUSR | PROC_SKIPTHREADS); if (header) { /* print uptime and headers */ print_uptime();