Merge branch 'newtop'

This commit is contained in:
Jan Görig 2011-05-25 11:05:04 +02:00
commit c3b7310149
14 changed files with 4502 additions and 4061 deletions

19
.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
free
kill
pgrep
pkill
pmap
proc/.depend
proc/libproc-3.2.8.so
ps/ps
pwdx
skill
slabtop
snice
sysctl
tload
top
uptime
vmstat
w
watch

View File

@ -1,545 +1,328 @@
Credit for this belongs to: This file summarizes changes to the top program and supporting documentation
Jim / James C. Warner, <warnerjc@worldnet.att.net> introduced on March 31, 2011.
---------------------------------- Contents:
DOCUMENT Changes
Ok, ok, I yield -- most of what follows has been removed from the manual page INTERNAL Improvements
and packaged separately as this README (hey, it was only TEMPORARY insanity). EXTERNAL Improvements
BUGS Previously Fixed and Preserved
Of course, that means that now absolutely nobody will ever read it. BUGS Newly/Nearly Fixed
BUGS/WISH-LISTS That Should Go Bye-bye
This is probably a good thing... BUGS FIXED You Didn't Know You Had
OTHER Changes, Hopefully They Won't Bite You
BENCHMARKS
## Table of Contents ---------------------------------------------------##
# the only darn thing that wasn't in the man page
CUSTOMIZING the Sources DOCUMENT Changes =========================================================
# the following carry their original topic numbers . The entire file was cleaned up, standardized and expanded to include:
DIFFERENCES / New Features - a new section "2. SUMMARY Display" added for symmetry with Fields
Interface Etiquette - nine new fields were added to section "3a. DESCRIPTIONS of Fields"
Expanded Configurable Display Support - a new section "3b. MANAGING Fields" replaced the obsolete section
Enhanced Field/Column Management "2b. SELECTING and ORDERING Columns"
Customization Flexibility - section "5c. SCROLLING a Window" was added for that new feature
NOTES and Rantings
The top Binary . I don't know when the explanations for CODE and DATA were changed to
Comparing Performance show 'virtual' memory, but I think there's a reason their alternate
Cost of Stuff names contain the word 'resident'. Thus they were changed back to
The top Sources say 'physical memory'.
EXAMPLES of Windows
The 'A' Mode Command Toggle . And as I indicated in a previous email, the former string identifier
STACKIN' & WHACKIN' Windows 'ME' was restored as were the 'h' key/command conventions (vs. <h>).
ALL TOGETHER Now, Window(s)
Oops, the 'h' key/command conventions remain restored, but subsequent
testing revealed problems with the .ME string identifier. Thus, it was
## CUSTOMIZING the Sources ---------------------------------------------## changed to .WE (along with the companion .Me/.We id).
Listed below are the conditionals available should you wish to recompile . Also previously mentioned, the 'man2html' program translates top.1 to
this top. The author's favorite is: PRETEND4CPUS. HTML with near perfect fidelity. I take that to mean there should be
no problems with the top.1 source on most other platforms.
That's the #define allowing you to simulate an SMP environment, and
(perhaps) impress your friends. It's currently set to display four To further improve translation to HTML, several .Bd and .Ed macros
separate CPUs, but could easily be changed. were added to preserve literal (fixed width) spacing.
Caution: do NOT use this provision in an effort to impress someone
who truly possesses such a machine! The fact that all 4 INTERNAL Improvements ====================================================
CPUs show the same dynamic results will likely have the . The old restriction of 26 fields has been lifted. With this new-top
opposite effect. 100+ fields are now possible. It currently supports up to 55, of
which 35 are in use. Adding a new field is almost too easy.
//#define ATEOJ_REPORT /* report a bunch of stuff, at end-of-job */ . Task row construction has been considerably improved -- both from
//#define CASEUP_HEXES /* show any hex values in upper case */ a programming perspective and a performance perspective.
//#define CASEUP_SCALE /* show scaled time/num suffix upper case */
//#define CASEUP_SUMMK /* show memory summary kilobytes with 'K' */ . The column highlighting costs for sort field visibility were
//#define POSIX_CMDLIN /* use '[ ]' for kernel threads, not '( )' */ virtually eliminated.
//#define PRETEND2_5_X /* pretend we're linux 2.5.x (for IO-wait) */
//#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */ An optional define (USE_X_COLHDR) can be enabled to completely
//#define PRETENDNOCAP /* use a terminal without essential caps */ eliminate any costs associated with the 'x' command toggle.
//#define SORT_SUPRESS /* *attempt* to reduce qsort overhead */
//#define STDOUT_IOLBF /* disable our own stdout _IOFBF override */ . The management of the HST_t structures, used for %cpu calculations,
//#define USE_LIB_STA3 /* use lib status (3 ch) vs. proc_t (1 ch) */ was optimized with a hashing scheme. Thus the need for a qsort then
//#define WARN_NOT_SMP /* restrict '1' & 'I' commands to true smp */ a binary search in each frame was completely eliminated.
An optional define can restore the former qsort/bsearch approach but
## 6. DIFFERENCES / New Features ---------------------------------------## with an internal inlined binary search function offering substantially
The following summarizes differences between this top and your better performance than the old top.
former top. It was originally based on procps-2.0.7. However,
except for the separate/summary CPU toggle, all of these differ- . This far more capable new-top executable is no larger than old top.
ences also apply through procps-2.0.10.
. The above combine to produce substantially improved performance
6a. Interface Etiquette whose details are documented below under BENCHMARKS.
-*- Input and output are far more carefully implemented in
this top. You won't be subjected to 4 - 5 'Unknown command'
messages should you press the wrong key. EXTERNAL Improvements ====================================================
. Field management has been completely redesigned. It's now embodied
-*- You need suffer a confirmation message only when the results on a single screen where display-ability, position and sort selection
of a command are not obvious by their effects on the display. can be handled in one place -- for all windows at one time!
-*- The Help screen will no longer overflow, even when running This function is dependent on cursor motion keys and should a device
with a 24 row xterm (vt100). not have the customary arrow keys, alternatives are provided and
documented under "Operation" near the beginning of the man page.
-*- The fields selection/ordering screens do not carelessly
destroy important information through unintended line wraps. . The following new fields have been added:
Group Id
-*- Should you narrow a xterm window to less than 80 columns Minor Page Faults
while this top is running, you will not be left with an Number of Threads
utterly worthless, embarrassing display. Process Group Id
Real User Id
6b. Expanded Configurable Display Support Saved User Id
-*- In an SMP environment, you can choose between a summary dis- Saved User Name
play or you may show each cpu separately. No longer must Session Id
this choice be irrevocably made at startup. Tty Process Group Id
-*- There are new fields and with this top, any field is . Scrolling keys now allow one to move the view of any window vertically
selectable for sorting. Plus, your sorted column can be or horizontally to reveal any desired task or column. Previously, only
instantly reversed with just a single keystroke. some tasks were viewable even with reversible, selectable sort columns.
-*- You may optionally apply 2 distinct types of highlighting to Each of the four windows is capable of maintaining its own scrolled
running tasks and/or sorted columns. With this top, you'll coordinates and an optional toggle ('C') displays a message aiding
be able to instantly spot running tasks and always know the navigation within the available tasks and displayable fields.
current sort field.
. User interactive line oriented input now provides for true line
-*- While you could continue to use the more familiar (and editing supported by these new keys:
boring) monochrome display, you might want to try this top's Left/Right arrow keys, Delete key, Backspace and
new color display. You can even create your own unique col- Home/End keys (likely limited to xterm, not terminal)
ors used in summaries, messages, headings and tasks, each of
which can be made persistent until you choose to change them. . User filtering via the -u | -U interactive commands is now window
based which means that different windows could be used to filter
-*- Up to four separate windows can be displayed simultaneously, different users.
giving you four separate ways to sort and view the tasks cur-
rently cluttering up your system. You could have one view by . Signal handling has been normalized and is now consistent regardless
pids, another by cpu usage, yet another showing memory con- of the particular top screen a user may have been using.
sumption. You get the idea...
. The 'i' toggle now shows any task that has used *some* cpu since the
-*- Each window comes with pre-configured (but user configurable) last screen update. It's no longer limited to just running tasks.
fields and you can size each window individually.
. The summary area 'task states' line now reflects either 'Threads'
-*- Virtually every one of this top's options (summaries, fields, or 'Tasks' depending on the -H toggle.
colors, sorted column, etc.) is separately configurable for
each of those four windows.
BUGS Previously Fixed and Preserved ======================================
Heck, you can even change a window's name, if you don't care ( but not necessarily literally)
for top's choices. Your changes will be reflected not only . 228822, suspending top leaves xterm in slightly messed-up state
when you're in what top calls alternate-display mode but also . 256376, segfaults, if the xterm is to small
on his special new 'Windows' help screen. . 320289, segv on sigwinch
. 351065, wrong highlight 1st column (escape characters displayed)
-*- And, [ ** Drum-Roll + Ta-Da ** ] with just one keystroke you . 358724, accepts extra numeric args
can quickly switch between full-screen and multiple window . 378695, seg fault if "/proc" is not mounted
modes! Or, with a different keystroke, toggle a single win- . 426782, UID field is too narrow
dow Off for now, then On again later!! . 458986, should check xterm for EOF/EIO
. 459890, Irix mode should use %#4.1f when threads shown
6c. Enhanced Field/Column Management
-*- Many Field/Column names have been changed to make them more
intuitive, more self-descriptive. And with this top you BUGS Newly/Nearly Fixed ==================================================
won't be fooled with field choices that are "not yet imple- . 225542, 'Unknown command' message blocks further commands
mented". The message is now displayed using usleep for 1.25 seconds, instead
of the former full 2 seconds. And while it still blocks further
-*- Task memory statistics are more meaningful and more accurate. commands, the delay is much more tolerable.
-*- You'll finally have complete display integrity regardless of Can we consider this bug 'nearly' fixed?
field selections, their order or screen width. And that
means the command column no longer need be kept as the right- . 410292, interface error when using backspace
most field, lest your screen turn to <bleep> when all the Full line editing was added but could be disabled via a #define.
following columns get misaligned. And via that define, even under basic termios support, the backspace
problem was cured.
6d. Customization Flexibility
-*- You have complete program naming freedom with no internal . 567509, top idle command ('i') not working for threaded programs
ties to a specific personal configuration file. Symbolic Since the 'i' command now reflects tasks that have used *some* cpu,
links could be used to establish different configuration and is no longer dependent on an 'R' state, I *believe/hope* this
files reflecting the different personalities of your cus- bug has been swatted.
tomized "tops", under whatever aliases you've used.
Thus, you could have an alias for running top in 'Batch BUGS/WISH-LISTS That Should Go Bye-bye ===================================
mode', another for when you work from the Linux console and . 340751, wish for hostname to benefit multiple top sessions
maybe a third used with X-Windows. All of that, yet still Craig's suggestion regarding symlinks is the perfect solution.
just a single binary image! How dare Craig say that the solution was "not ideal" !
-*- All of your configuration choices can be preserved in a per- . 586497, wish for graceful degradation on small screen sizes
sonal configuration file, including any changes made on a This objective could be accomplished by setting up 2 symlinks for
per-window basis. Thus, once you personalize things they top, personalizing them for the 2 tiny phone displays, then writing
remain personalized until you decide to change them again. the respective configuration files.
This top has been completely cured of:
i-cant-remember-so-please-do-that-all-over-again I shudder at the programming effort suggested by Paul. And when it
( and again, and again ... ) was done you'd find everybody else would have different criteria.
The bottom line is this: if you save your configuration
before quitting top, upon restart the display will appear BUGS FIXED You Didn't Know You Had =======================================
exactly as you left it. And that means you no longer have to . Without amplifying the dirty details, the long standing occasionally
keep top running until-the-end-of-time (ok, a long time reported display corruption, and an unreported source of performance
anyway), lest your customizations go bye-bye. degradation, has been eliminated. The cure is in the elimination of
the Pseudo_cols variable and the improved PUFF macro.
## 7. NOTES and Rantings -----------------------------------------------## . Line oriented input was not sensitive to screen width. Thus a user
7a. The top Binary could hold down any key and ultimately line wrap, overwriting the
To whom it may (should) concern: this top, even with its vastly columns header and the entire screen. New top prevents this.
expanded capabilities, is only slightly larger than the old top.
Were it not for extensive help text and additional sort callbacks, . User filtering (-u|-U) via a user ID (not name) now validates that
it would be smaller. number. The old-top just made sure it was numeric, then blindly
Throw source carelessly at objectives, it will displayed no matching users (i.e. an empty window).
produce equally careless machine instructions.
example: (num_pages - an_address)/1024 == duh? . The threads toggle ('H') is no longer window based but more properly
kicker: document result as broken, due to elf! applies to all windows. The previous implementation produced the
---------------------------------------------- following aberration if multiple windows were being shown:
I know you're out there, are you getting this? . -H would be acknowledged and applied to all visible windows
. keying 'a' or 'w' would silently turn it off
Now, as for all those new capabilities like colors and windows and . then keying -H would turn it back on, but the user expected off
highlighting, you'd expect this top to be the "mother of all pigs"
compared to old top -- right? . If you hit ^Z on any help or fields screen to suspend old-top, after
issuing 'fg' you would then be left with a seemingly hung application
Yea, with this top expect following piglets: inviting ^C. In truth, one could recover with the space bar, but that
. A smaller virtual image and resident footprint was far from intuitive.
. Slightly fewer major page faults
. A large reduction in minor page faults for SMP . The old-top consistently writes 1 extra byte for each task row or 1
. The same or better response time byte too few for columns headers, depending on your perspective.
. The same or even less CPU costs The new top writes the same number of bytes for each.
Ideally any comparison of the old and new top should be against . By failing to clear to eol, old top left the display in a terrible
the same libproc format (32-bit or 64-bit tics) and run in a true state after exiting a 'fields' screen when only a few columns were
or simulated SMP environment (producing separate CPU stats). This being displayed.
latter requirement will coax old top into handling his own
'/proc/stat' access -- something this top always does, but with . The old-top used a zero value for the L_NONE library flag which could
less cost. cause repeated rebuilding of columns headers with each frame. In truth,
this was not likely to happen in real life since only two fields actually
7b. Comparing Performance used that flag. However, if it did happen, performance could be degraded
Even with equivalent libraries and '/proc/stat' access, it's dif- by 800%.
ficult to accurately compare tops using their own displays.
Results for these cpu-intensive programs (who frequently exceed
their time-slice) generally show a wide disparity in %CPU. This OTHER Changes, Hopefully They Won't Bite You =============================
is due to differing call patterns, kernel preemptions and the tim- . The undocumented TOPRC environment variable is no longer supported.
ing of process snapshots. For slightly better results, start each Any similar need can be met through a symlink alias.
program with the following commands:
./old-top -d 0.5 . The use of environment variables to override terminal size is now
nice -n-10 ./new-top -d 0.4 off by default but could be enabled through '#define TTYGETENVYES'.
While actually putting this top at a performance disadvantage, the . The global 'bold enable' toggle is active by default and thus agrees
higher scheduling priority and staggered timing will periodically with the documentation. It's been wrong ever since Al's wholesale
yield a somewhat truer picture. You could even reverse those 'cosmetic' changes in procps-3.2.2.
roles and get similar results.
. Task defaults now show bold (not reverse) and row highlighting.
The most consistent performance results will be obtained 'off- This agrees with what was always stated in the documentation.
line', using your shell's time pipe or the time program itself.
And even in a single processor environment or without equivalent . The 'H' toggle (thread mode) is not persistent. Persistence can be
libraries, total cpu costs (user time + system time) are similar. achieved with a simple shell script employing the -H switch.
However, this top's cpu costs ARE influenced by the capabilities . Then 'g' and 'G' commands were reversed to reflect their likely use.
you choose to exploit, even if they don't SEEM to be reflected in
such timings. So let's examine some...
BENCHMARKS ===============================================================
7c. Cost of Stuff Tested as root with nice -10 and using only common fields
Colors Cost -- Nada (almost). ( on a pretty old, slow laptop under Debian Lenny )
Once the terminfo strings are built (at and during a user's but rcfiles specified identical sort fields and identical
behest) they are SAVED with each window's stuff. And while settings for the 'B', 'b', 'x' and 'y' toggles (even though
there will be extra tty escape sequences transmitted because of the defaults are not necessarily identical).
colors, it makes no difference which 'char *' is actually used.
In every case new-top outperforms old-top, but I've shown %
Highlighting Cost -- Nada (maybe), or blame it on Rio. improvements for only the most significant. Those cases mostly
On second thought, let's blame it on the user. involve colors with both row & column highlighting. I suggested
above that the highlighting cost was virtually eliminated in
For row highlighting, there is only the cost of those extra tty new-top, and these tests bare that out.
escape sequences (same as for colors). For column highlight-
ing, there is a fairly significant cost associated with column Note the much smaller differences for new-top between the 24x80
transition management combined with even more tty output. window results and full screen (but don't mix apples_terminal
These increased costs are incurred on every task display row. with oranges_xterm). This is a reflection of the simplification
of task row construction, also mentioned above.
Sooo... hey USER -- do NOT highlight COLUMNS. You shouldn't
need a constant visual reminder of your chosen sort field. It's always been the case that any top in an xterm outperforms
However, if you forget which field top is sorting it can serve that top under the terminal application, even when the xterm
as a quick visual reminder. provides additional rows and columns. It's true below with
Gnome and it was true nine years ago under KDE.
Windows Cost -- Nada (if just 1 window).
If more than 1 window, almost certainly NOT Nada so blame it on ----------------------------------------------------------
reality. Colors are not an issue, but those sort fields are. The following comparisons were run with:
100 tasks & 160 threads
If we could trust the user to always select the same 'c' state, -d0 -n5000
'S' state and sort field (hey, why ya got multiple windows then new-top old-top
user, huh?) AND if we can trust someone to recompile top with a xterm 24x80
#define enabled, then we could achieve 'Nada'. a 1 win, lflgs_none 11.2 secs 51.8 secs + 462.6%
1 win, default 61.0 secs 66.8 secs
Ok, not likely, so we're gonna' be doing multiple sorts. BUT, 1 win, colors w/ x+y 61.3 secs 83.0 secs + 135.4%
it may not be as bad as it sounds. Those sorts involve point- 1 win, thread mode 88.3 secs 94.2 secs
ers only. And, that's as good as it gets ! (right Mr. N?) b 1 win, every field on 99.7 secs 106.0 secs
1 win, cmdline 71.2 secs 76.6 secs
7d. The top Sources 4 wins, defaults 101.3 secs 107.2 secs
top.h 4 wins, colors w/ x+y 101.5 secs 122.8 secs + 121.0%
Unlike his predecessor, this top has a proper header file. It
contains ONLY declarations, NOT definitions. And there are xterm, full screen (53x170)
several conditionals present to help with further customiza- a 1 win, lflgs_none 15.9 secs 54.2 secs + 340.9%
tions and experimentation. All are Off by default. 1 win, default 70.0 secs 73.2 secs
1 win, colors w/ x+y 69.4 secs 131.3 secs + 189.2%
top.c 1 win, thread mode 97.6 secs 102.6 secs
Hopefully proves that source code needn't be a disorganized, c 1 win, every field on 122.1 secs 128.1 secs
misaligned MESS. And, WHO says a source listing shouldn't 1 win, cmdline 80.8 secs 83.7 secs
occasionally make you SMILE? Why, top.c even does a darn good 4 wins, defaults 111.4 secs 115.8 secs
job of following the suggestions in a document hardly anybody 4 wins, colors w/ x+y 112.0 secs 172.9 secs + 154.4%
seems to observe.
terminal 24x80
the Linus Torvalds CodingStyle guidelines ... a 1 win, lflgs_none 8.9 secs 58.6 secs + 658.4%
-*- -*- -*- on indentation + etc. -*- -*- -*- 1 win, default 70.1 secs 80.3 secs
well almost all, except for those stinkin'... 1 win, colors w/ x+y 70.6 secs 157.3 secs + 222.8%
1 win, thread mode 104.7 secs 120.5 secs
I suppose even Linus Torvalds is entitled to err now and again. b 1 win, every field on 111.2 secs 134.5 secs
How so you say? Tabs, me' bucko, stinkin' tabs! That, plus the 1 win, cmdline 83.8 secs 94.5 secs
simplistic position regarding indentation espoused in that other- 4 wins, defaults 125.6 secs 146.7 secs
wise excellent document. 4 wins, colors w/ x+y 125.6 secs 206.9 secs + 176.7%
-*- Rant On, and on -*- terminal, full screen (39x125)
Let's compare two approaches to the tab/indentation issue with a a 1 win, lflgs_none 9.1 secs 60.6 secs + 665.9%
small code sample using tabs then spaces. This snippet happens to 1 win, default 74.3 secs 88.0 secs
be the key to top's use of dynamic colors on many static screens, 1 win, colors w/ x+y 73.9 secs 314.5 secs + 425.6%
while also ensuring screen width isn't exceeded so as to avoid 1 win, thread mode 113.0 secs 140.9 secs
line wraps. We'll view just the first 40 columns, assuming one b 1 win, every field on 117.7 secs 154.9 secs
wishes to occasionally provide comments to the right of actual 1 win, cmdline 87.4 secs 107.2 secs
code (you do, don't you?). 4 wins, defaults 139.1 secs 166.7 secs
4 wins, colors w/ x+y 157.3 secs 423.2 secs + 269.0%
Then YOU decide which approach makes the most SENSE!
----------------------------------------------------------
Stinkin' Tabs versus Spaces: the Linus way The following comarisons were run with:
Hey, where'd my +----+----1----+----2----+----3----+----4+ 300 tasks & 360 threads
many code lines | while (*sub_beg) { : -d0 -n3000
up-and-gone-to? | switch (*sub_end: new-top old-top
| case 0: : xterm, full screen (53x170)
Gosh, wonder if | \ Tabs Induced / : a 1 win, lflgs_none 14.3 secs 79.0 secs + 552.4%
Linus expects a | case 1: : 1 win, default 101.1 secs 104.5 secs
fellow to stick | + WASTE-Lands! + case 5: : 1 win, colors w/ x+y 101.3 secs 140.0 secs + 138.2%
his comments on | : 1 win, thread mode 120.1 secs 123.1 secs
the left side?! | + Not a Living + : c 1 win, every field on 179.8 secs 185.6 secs
| : 1 win, cmdline 124.9 secs 132.8 secs
Ever see source | + line-of-code + : 4 wins, defaults 174.8 secs 179.2 secs
with not enough | : 4 wins, colors w/ x+y 175.0 secs 215.2 secs + 123.0%
whitespace; and | / To Be Found! \ :
this is better? | default:: terminal, full screen (39x125)
| : a 1 win, lflgs_none 12.3 secs 98.5 secs + 800.8%
Oh lookie here, \ } : 1 win, default 117.4 secs 134.0 secs
there's just a hint of REAL code! ----> if (0 >= room) b: 1 win, colors w/ x+y 111.6 secs 296.1 secs + 265.3%
/ } /* end: while 'subtrin: 1 win, thread mode 141.3 secs 155.3 secs
+----------------------------------------+ b 1 win, every field on 197.7 secs 204.8 secs
1 win, cmdline 143.9 secs 157.3 secs
Spaces versus Stinkin' Tabs: the other way 4 wins, defaults 204.0 secs 226.2 secs
+----+----1----+----2----+----3----+----4+ 4 wins, colors w/ x+y 216.9 secs 434.5 secs + 200.3%
Wow, now this is | while (*sub_beg) { :
Visible hackin'! | switch (*sub_end) { : . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
| case 0: :
Hmmm, wonder how | *(sub_end + 1) = '\0'; : notes:
many programmers | case 1: case 2: case 3: case: a these results represent the library flags L_NONE zero value and
read those lines | case 5: case 6: case 7: case: thus the hidden cost of rebuilding column headers w/ every frame
from the LEFT to | cap = Curwin->captab[(int: b while every common field was turned on, not all fields could be
the RIGHT? This | *sub_end = '\0'; : displayed due to limited screen width
"innovation" may | PUTP("%s%.*s%s", cap, roo: c only in a full screen xterm window could all common fields
possibly benefit | room -= (sub_end - sub_be: actually be displayed
those particular | sub_beg = ++sub_end; :
kinds of people, | break; :
you agree? Duh! | default: :
| ++sub_end; :
AND, there might | } :
even be room for | if (0 >= room) break; :
unseen comments! | } /* end: while 'subtrings' */ :
+----------------------------------------+
Gosh, I just don't KNOW -- it's such a TOUGH choice...
Oh you Stinkin' Tabs: correspondence, Who-Cares; documentation,
Oh-Alright; even scripts, Well-If-You-Must. But you have NO place
within the code-space of MY C-source listing! So be gone
already!!
In Summation...
- If you want to use tabs to the right of the code, go-for-it.
But PLEASE, not ever in the C-source code-space, thank-you-
kindly. Just use three little ol' spaces (exactly 3, no-more,
no-less) where you WOULD have stuck a stinkin' tab.
We'll get far more READABLE files, much less WAISTED precious
horizontal space, more consistent CURSORS and on, and ON, AND
ON! Plus, without those awful *the-devil's-own-handiwork*, the
aforementioned document need NEVER speak of their EVILS again.
- Lastly, since SPACES (not stinkin' tabs) are SO beneficial,
maybe we should use just a few more of 'em. Some of those C-
thingies are VERY sensitive -- they don't like being TOUCHED
by any other syntax element! Which ones? Why these guys:
braces, reserved words and binary operators
( it's the TRUTH, they told me themselves )
It's so EASY to keep 'em HAPPY! And lo-and-behold, the combi-
nation of <sp>thingy<sp> turns out to be a darn effective bug
repellent, too. So much so, one can actually code while
TOTALLY NUDE yet still avoid them ol' bug-bytes (sic-sic)!
step
down_from
me_punctilious
soap-box_once_again
[1 +5 +5 +5 = huh?]
## 4c. EXAMPLES of Windows ---------------------------------------------##
-*- The 'A' Mode Command Toggle -*-
Here's what you'll see when you first invoke the alternate-display
mode interactive command.
This particular display was produce on a VT100 xterm, with only 24
rows. All four task displays are visible, but they could not be sized
the same. Available lines are parceled out in the fairest way possi-
ble so the last two task displays have an extra line each.
Notice the 'current' window name in the summary area -- it's been
emphasized because the associated task display is visible. Since
1:Def has a task area, the full range of interactive commands would be
at your disposal. But remember, many of those commands will apply
only to window 1:Def.
+--------------------------------------+
1:Def name is bold, |1:Def - 15:46:37 up 16:25, 9 users, :
thus all commands |Tasks: 76 total, 1 running, 75 sle:
will be available. |Cpu(s): 0.7% user, 1.3% system, :
|Mem: 126588k total, 123688k used,:
|Swap: 265032k total, 8232k used,:
|______________________________________:
Tough luck windows |1__PID_USER______PR__NI_%CPU____TIME+_:
#1 & 2 - you lost | 7343 jtwm 16 0 0.9 0:00.59:
one line each -- | 7339 jtwm 9 0 0.0 0:00.02:
guess you'll just |__7337_root_______9___0__0.0___0:01.30:
have to learn how |2__PID__PPID_Command____________TIME+_:
to live with it. | 997 952 kdeinit 17:59.59:
| 1115 952 kdeinit 2:16.47:
|__1803__1116_led_______________1:55.30:
|3__PID_%MEM__VIRT_SWAP__RES_CODE_DATA_:
The #3 & #4 windows | 4634 12.3 15620 0 15m 860 14m :
better not gloat | 7337 11.3 14396 92 13m 36 13m :
over 1 extra line. | 923 10.6 30524 16m 13m 1120 12m :
That user could yet |___991__7.2__9492__316_9176___12_9164_:
sock 'em with the |4_UID_USER_____GROUP____TTY________PID:
'n' command and | 43 xfs xfs ? 806:
take those lines, | 0 ykde users pts/7 5561:
plus others, away! | 0 wgnome users pts/7 5560:
| 0 root root pts/7 5325:
+--------------------------------------+
So, what say we start applying some of those "full range of interac-
tive commands"?
Onward + Downward...
-*- STACKIN' & WHACKIN' Windows -*-
Whoa, hold on mate. Someone has already whacked these windows. See,
there are no task areas for windows 1:Def and 4:Usr. Well, we can at
least retrace their steps...
Here's what was done, after issuing the 'A' command and entering
alternate-display mode.
1) When #1 was the 'current' window, '-' was pressed,
toggling Off the associated task display
( if 'l t m' had been applied to its summary, too )
( then there'll be only a msg line when 'current' )
2) Then the 'w' key was struck to cycle backward,
making 4:Usr the 'current' window
(could have used 'a a a', if one likes to type)
3) Then step #1 was repeated, and bye-bye window #4
4) Finally, window #2 was made the 'current' window
( Q. how many keystrokes were used? )
( A. minimum of 2: 'a a' or 'w w'. )
+--------------------------------------+
No 'l','t','m','1' |2:Top - 15:48:35 up 16:27, 9 users, :
commands have been |Tasks: 75 total, 1 running, 74 sle:
issued here, |Cpu(s): 2.0% user, 0.7% system, :
but... |Mem: 126588k total, 123712k used,:
|Swap: 265032k total, 8232k used,:
|______________________________________:
#2's been changed; |2__PID__PPID_Command____________TIME+_:
user applied a 'c' | 997 952 kdeinit: konsol 18:00.70:
command (when it | 1115 952 kdeinit: konsol 2:16.47:
was current) - now | 1803 1116 led tiptop.HELP 1:55.30:
shows cmd lines vs. | 923 922 X :0 1:09.60:
program names; | 973 1 klaptopdaemon 0:59.63:
still seems to be | 981 952 /usr/bin/artsd 0:48.63:
sorted on TIME+ | 987 1 kdeinit: kdeskt 0:24.34:
though |___991_____1_kdeinit:_kicker___0:04.59:
|3__PID_%MEM__VIRT_SWAP__RES_CODE_DATA_:
This #3 guy appears | 4634 12.3 15620 0 15m 860 14m :
to still be running | 7337 11.3 14396 92 13m 36 13m :
with the supplied | 923 10.6 30544 16m 13m 1120 12m :
defaults, but no | 991 7.2 9492 316 9176 12 9164 :
telling what damage | 7329 7.0 9036 140 8896 36 8860 :
might have been | 1115 6.9 8956 160 8796 36 8760 :
done to it's | 987 6.4 8668 524 8144 20 8124 :
summary info stuff | 1131 6.4 8268 144 8124 36 8088 :
+--------------------------------------+
And that's what brought us to this current state. No, wait. Oh
lordy, will you look at that -- someone has changed the name of win-
dow #2 from 'Job' to 'Top'!
How'd they do that? Well, they just issued the 'g' interactive com-
mand, of course. That command is available whenever alternate-display
mode is active and always impacts just the 'current' window. Gosh,
you can even issue the 'g' command when 'l' has toggled Off the very
summary area line containing the window name!
Almost Done...
-*- ALL TOGETHER Now, Window(s) -*-
Here, the window 1:Def task display has been toggled Off but it
remains the 'current' window. Since there is no task area, many com-
mands will be restricted. However, the commands ('l', 't', 'm', '1')
affecting the summary area, as well as some other global commands
('k', 'Z', etc.), would still be active.
Notice that the Mem and Swap lines are not shown. This means that the
loser (oops, user) has, in fact, issued the 'm' command! Now, if you
were to cycle the 'current' window with the 'a' or 'w' commands, the
task display would remain the same (except possibly growing/shrinking
slightly) but the summary area would change periodically.
The comments to the left of the image provide additional insights into
how things came to be. Note especially the comments for window 4:Usr
-- the one with some empty rows...
1:Def no highlight, +--------------------------------------+
thus disabled cmds: |1:Def - 15:50:32 up 16:29, 9 users, :
b,i,n,u,x,y, etc. |Tasks: 75 total, 2 running, 73 sle:
& m = lost Mem/Swap |Cpu(s): 10.6% user, 0.0% system, :
|______________________________________:
2:Job was very busy: |2__PID__PPID_Command____________TIME+_:
'n' cmd, w/ 7 tasks | 80 1 ( khubd ) 0:00.00:
'c' cmd, cmd line | 6 0 ( kreclaimd ) 0:00.00:
'O' cmd, sort cmd | 9 1 ( mdrecoveryd ) 0:00.00:
'R' cmd, sort bkwd | 11358 1 /bin/bash/ /usr 0:00.00:
'x' cmd, hi column | 1297 1 /sbin/mingetty 0:00.00:
(when 2 WAS current) | 683 1 xinetd -stayali 0:00.00:
|___836_____1_login_--_root_____0:00.00:
3:Mem has altered |3__PID_%MEM__VIRT_SWAP__RES_CODE_DATA_:
some std defaults: | 4634 12.3 15620 0 15m 860 14m :
'y' turned Off | 7337 11.3 14396 92 13m 36 13m :
'x' turned On | 923 10.6 30544 16m 13m 1120 12m :
(when 3 WAS current) | 991 7.2 9492 316 9176 12 9164 :
|__7329__7.0__9036__140_8896___36_8860_:
Huh? 4:Usr has some |4_UID_USER_____GROUP____TTY________PID:
blank rows! ? ? ? ? | 0 jtwm root pts/2 5561:
Aha, the 'i' command | 0 root root ? 5560:
applied (when 4 WAS | :
current); could be | :
reversed with '=', | :
when 4 IS current! +--------------------------------------+
Ok now, how about that 'current' window 1:Def and its unseen tasks?
At any time, you can quickly retrieve lost tasks in a number of ways:
1) Press '-', toggling just the 'current' window
2) Press '_', toggling all visible/invisible windows
( 1:Def is the only window currently not shown )
( afterward, it'll be the only window showing! )
* 3) Press '+', forcing all task displays to become visible
4) Press 'A' to return to full-screen mode,
with only 1:Def tasks shown and without a window name
Now that should be enough ways of getting a task area visible again to
satisfy almost any user, don't ya think?
Note: Use #3 above when you've messed up your screen beyond
redemption. The four task displays will reappear, nice and even.
They will also have retained any customizations you had previously
applied, except for the 'i' (idle tasks) and 'n' (max tasks) com-
mands.
That's It ! Piece of Cake !! Enjoy them there windows !!!

View File

@ -50,13 +50,6 @@ static int escape_str_utf8(char *restrict dst, const char *restrict src, int buf
my_cells++; my_cells++;
my_bytes++; my_bytes++;
} else if (len==1) {
/* non-multibyte */
*(dst++) = isprint(*src) ? *src : '?';
src++;
my_cells++;
my_bytes++;
} else if (!iswprint(wc)) { } else if (!iswprint(wc)) {
/* multibyte - no printable */ /* multibyte - no printable */
*(dst++) = '?'; *(dst++) = '?';
@ -98,7 +91,7 @@ static int escape_str_utf8(char *restrict dst, const char *restrict src, int buf
} }
//fprintf(stdout, "cells: %d\n", my_cells); //fprintf(stdout, "cells: %d\n", my_cells);
} }
*(dst++) = '\0'; *dst = '\0';
// fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells); // fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells);
@ -114,14 +107,14 @@ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *m
int my_cells = 0; int my_cells = 0;
int my_bytes = 0; int my_bytes = 0;
const char codes[] = const char codes[] =
"Z-------------------------------" "Z..............................."
"********************************" "||||||||||||||||||||||||||||||||"
"********************************" "||||||||||||||||||||||||||||||||"
"*******************************-" "|||||||||||||||||||||||||||||||."
"--------------------------------" "????????????????????????????????"
"********************************" "????????????????????????????????"
"********************************" "????????????????????????????????"
"********************************"; "????????????????????????????????";
#if (__GNU_LIBRARY__ >= 6) #if (__GNU_LIBRARY__ >= 6)
static int utf_init=0; static int utf_init=0;
@ -131,9 +124,10 @@ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *m
char *enc = nl_langinfo(CODESET); char *enc = nl_langinfo(CODESET);
utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1; utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1;
} }
if (utf_init==1) if (utf_init==1 && MB_CUR_MAX>1) {
/* UTF8 locales */ /* UTF8 locales */
return escape_str_utf8(dst, src, bufsize, maxcells); return escape_str_utf8(dst, src, bufsize, maxcells);
}
#endif #endif
if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale
@ -143,12 +137,12 @@ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *m
break; break;
c = (unsigned char) *(src++); c = (unsigned char) *(src++);
if(!c) break; if(!c) break;
if(codes[c]=='-') c='?'; if(codes[c]!='|') c=codes[c];
my_cells++; my_cells++;
my_bytes++; my_bytes++;
*(dst++) = c; *(dst++) = c;
} }
*(dst++) = '\0'; *dst = '\0';
*maxcells -= my_cells; *maxcells -= my_cells;
return my_bytes; // bytes of text, excluding the NUL return my_bytes; // bytes of text, excluding the NUL
@ -214,3 +208,16 @@ int escape_command(char *restrict const outbuf, const proc_t *restrict const pp,
outbuf[end] = '\0'; outbuf[end] = '\0';
return end; // bytes, not including the NUL return end; // bytes, not including the NUL
} }
/////////////////////////////////////////////////
// copy an already 'escaped' string,
// using the traditional escape.h calling conventions
int escaped_copy(char *restrict dst, const char *restrict src, int bufsize, int *maxroom){
int n;
if (bufsize > *maxroom+1) bufsize = *maxroom+1;
n = snprintf(dst, bufsize, "%s", src);
if (n >= bufsize) n = bufsize-1;
*maxroom -= n;
return n;
}

View File

@ -17,6 +17,7 @@ EXTERN_C_BEGIN
extern int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t n, int *cells); extern int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t n, int *cells);
extern int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *maxcells); extern int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *maxcells);
extern int escape_command(char *restrict const outbuf, const proc_t *restrict const pp, int bytes, int *cells, unsigned flags); extern int escape_command(char *restrict const outbuf, const proc_t *restrict const pp, int bytes, int *cells, unsigned flags);
extern int escaped_copy(char *restrict dst, const char *restrict src, int bufsize, int *maxroom);
EXTERN_C_END EXTERN_C_END
#endif #endif

View File

@ -6,7 +6,7 @@ global:
__cyg_profile_func_enter; __cyg_profile_func_exit; main; __cyg_profile_func_enter; __cyg_profile_func_exit; main;
readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command; readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command;
escape_str; escape_strlist; escape_str; escape_strlist; escaped_copy; read_cmdline;
openproc; closeproc; openproc; closeproc;
tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan; tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan;
display_version; procps_version; linux_version_code; display_version; procps_version; linux_version_code;

View File

@ -12,6 +12,7 @@
#include "version.h" #include "version.h"
#include "readproc.h" #include "readproc.h"
#include "alloc.h" #include "alloc.h"
#include "escape.h"
#include "pwcache.h" #include "pwcache.h"
#include "devname.h" #include "devname.h"
#include "procps.h" #include "procps.h"
@ -365,6 +366,19 @@ LEAVE(0x220);
} }
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
#ifdef OOMEM_ENABLE
static void oomscore2proc(const char* S, proc_t *restrict P)
{
sscanf(S, "%d", &P->oom_score);
}
static void oomadj2proc(const char* S, proc_t *restrict P)
{
sscanf(S, "%d", &P->oom_adj);
}
#endif
///////////////////////////////////////////////////////////////////////
// Reads /proc/*/stat files, being careful not to trip over processes with // Reads /proc/*/stat files, being careful not to trip over processes with
// names like ":-) 1 2 3 4 5 6". // names like ":-) 1 2 3 4 5 6".
@ -514,13 +528,15 @@ static char** file2strvec(const char* directory, const char* what) {
return ret; return ret;
} }
// warning: interface may change // this is the former under utilized 'read_cmdline', which has been
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){ // generalized in support of these new libproc flags:
// PROC_EDITCGRPCVT, PROC_EDITCMDLCVT
static int read_unvectored(char *restrict const dst, unsigned sz, unsigned pid, const char *what, char sep) {
char name[32]; char name[32];
int fd; int fd;
unsigned n = 0; unsigned n = 0;
dst[0] = '\0';
snprintf(name, sizeof name, "/proc/%u/cmdline", pid); snprintf(name, sizeof name, "/proc/%u/%s", pid, what);
fd = open(name, O_RDONLY); fd = open(name, O_RDONLY);
if(fd==-1) return 0; if(fd==-1) return 0;
for(;;){ for(;;){
@ -530,23 +546,86 @@ int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){
break; break;
} }
n += r; n += r;
if(n==sz) break; // filled the buffer if(n==sz) { // filled the buffer
--n; // make room for '\0'
break;
}
if(r==0) break; // EOF if(r==0) break; // EOF
} }
close(fd); close(fd);
if(n){ if(n){
int i; int i=n;
if(n==sz) n--; while(i--)
dst[n] = '\0'; if(dst[i]=='\n' || dst[i]=='\0') dst[i]=sep;
i=n;
while(i--){
int c = dst[i];
if(c<' ' || c>'~') dst[i]=' ';
}
} }
dst[n] = '\0';
return n; return n;
} }
static char** vectorize_this_str (const char* src) {
#define pSZ (sizeof(char*))
char *cpy, **vec;
int adj, tot;
tot = strlen(src) + 1; // prep for our vectors
adj = (pSZ-1) - ((tot + pSZ-1) & (pSZ-1)); // calc alignment bytes
cpy = xcalloc(NULL, tot + adj + (2 * pSZ)); // get new larger buffer
snprintf(cpy, tot, "%s", src); // duplicate their string
vec = (char**)(cpy + tot + adj); // prep pointer to pointers
*vec = cpy; // point 1st vector to string
*(vec+1) = NULL; // null ptr 'list' delimit
return vec; // ==> free(*vec) to dealloc
#undef pSZ
}
// This routine reads /proc/#/cgroup for a single task.
// It is similar to file2strvec except we filter and concatenate
// the data into a single string represented as a single vector.
static void fill_cgroup_cvt (proc_t *restrict p) {
#define vMAX ( sizeof(dbuf) - (int)(dst - dbuf) )
char sbuf[1024], dbuf[1024];
char *src, *dst, *grp, *eob;
int tot, x, whackable_int = sizeof(dbuf);
*(dst = dbuf) = '\0'; // empty destination
tot = read_unvectored(sbuf, sizeof(sbuf), p->tid, "cgroup", '\0');
for (src = sbuf, eob = sbuf + tot; src < eob; src += x) {
x = 1; // loop assist
if (!*src) continue;
x = strlen((grp = src));
if ('/' == grp[x - 1]) continue; // skip empty root cgroups
#if 0
grp += strspn(grp, "0123456789:"); // jump past group number
#endif
dst += snprintf(dst, vMAX, "%s", (dst > dbuf) ? "," : "");
dst += escape_str(dst, grp, vMAX, &whackable_int);
}
p->cgroup = vectorize_this_str(dbuf[0] ? dbuf : "-");
#undef vMAX
}
// This routine reads /proc/#/cmdline for the designated task, "escapes"
// the result into a single string represented as a single vector and
// guarantees the caller a valid proc_t.cmdline pointer.
static void fill_cmdline_cvt (proc_t *restrict p) {
#define uFLG ( ESC_BRACKETS | ESC_DEFUNCT )
char sbuf[2048], dbuf[2048];
int whackable_int = sizeof(dbuf);
if (read_unvectored(sbuf, sizeof(sbuf), p->tid, "cmdline", ' '))
escape_str(dbuf, sbuf, sizeof(dbuf), &whackable_int);
else
escape_command(dbuf, p, sizeof(dbuf), &whackable_int, uFLG);
p->cmdline = vectorize_this_str(dbuf);
#undef uFLG
}
// warning: interface may change
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid) {
return read_unvectored(dst, sz, pid, "cmdline", ' ');
}
/* These are some nice GNU C expression subscope "inline" functions. /* These are some nice GNU C expression subscope "inline" functions.
* The can be used with arbitrary types and evaluate their arguments * The can be used with arbitrary types and evaluate their arguments
* exactly once. * exactly once.
@ -628,21 +707,37 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons
} }
} }
if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */ if (unlikely(flags & PROC_FILLENV)) /* read /proc/#/environ */
p->cmdline = file2strvec(path, "cmdline"); p->environ = file2strvec(path, "environ");
else
p->cmdline = NULL;
if (unlikely(flags & PROC_FILLENV)) /* read+parse /proc/#/environ */
p->environ = file2strvec(path, "environ");
else else
p->environ = NULL; p->environ = NULL;
if(linux_version_code>=LINUX_VERSION(2,6,24) && (flags & PROC_FILLCGROUP)) if (flags & (PROC_FILLCOM|PROC_FILLARG)) { /* read /proc/#/cmdline */
p->cgroup = file2strvec(path, "cgroup"); /* read /proc/#/cgroup */ if (flags & PROC_EDITCMDLCVT)
else fill_cmdline_cvt(p);
p->cgroup = NULL; else
p->cmdline = file2strvec(path, "cmdline");
} else
p->cmdline = NULL;
if ((flags & PROC_FILLCGROUP) /* read /proc/#/cgroup, if possible */
&& linux_version_code >= LINUX_VERSION(2,6,24)) {
if (flags & PROC_EDITCGRPCVT)
fill_cgroup_cvt(p);
else
p->cgroup = file2strvec(path, "cgroup");
} else
p->cgroup = NULL;
#ifdef OOMEM_ENABLE
if (unlikely(flags & PROC_FILLOOM)) {
if (likely( file2str(path, "oom_score", sbuf, sizeof sbuf) != -1 ))
oomscore2proc(sbuf, p);
if (likely( file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1 ))
oomadj2proc(sbuf, p);
}
#endif
return p; return p;
next_proc: next_proc:
return NULL; return NULL;

View File

@ -111,8 +111,9 @@ typedef struct proc_t {
cmin_flt, // stat cumulative min_flt of process and child processes cmin_flt, // stat cumulative min_flt of process and child processes
cmaj_flt; // stat cumulative maj_flt of process and child processes cmaj_flt; // stat cumulative maj_flt of process and child processes
char char
**environ, // (special) environment string vector (/proc/#/environ) **environ, // (special) environment string vector (/proc/#/environ)
**cmdline; // (special) command line string vector (/proc/#/cmdline) **cmdline, // (special) command line string vector (/proc/#/cmdline)
**cgroup; // (special) cgroup string vector (/proc/#/cgroup)
char char
// Be compatible: Digital allows 16 and NT allows 14 ??? // Be compatible: Digital allows 16 and NT allows 14 ???
euser[P_G_SZ], // stat(),status effective user name euser[P_G_SZ], // stat(),status effective user name
@ -140,7 +141,11 @@ typedef struct proc_t {
tpgid, // stat terminal process group id tpgid, // stat terminal process group id
exit_signal, // stat might not be SIGCHLD exit_signal, // stat might not be SIGCHLD
processor; // stat current (or most recent?) CPU processor; // stat current (or most recent?) CPU
char **cgroup; // cgroup current cgroup, looks like a classic filepath #ifdef OOMEM_ENABLE
int
oom_score, // oom_score (badness for OOM killer)
oom_adj; // oom_adj (adjustment to OOM score)
#endif
} proc_t; } proc_t;
// PROCTAB: data structure holding the persistent information readproc needs // PROCTAB: data structure holding the persistent information readproc needs
@ -239,6 +244,7 @@ extern proc_t * get_proc_stats(pid_t pid, proc_t *p);
#define PROC_FILLWCHAN 0x0080 // look up WCHAN name #define PROC_FILLWCHAN 0x0080 // look up WCHAN name
#define PROC_FILLARG 0x0100 // alloc and fill in `cmdline' #define PROC_FILLARG 0x0100 // alloc and fill in `cmdline'
#define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup` #define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup`
#define PROC_FILLOOM 0x0400 // alloc and fill in oom_score, oom_adj
#define PROC_LOOSE_TASKS 0x2000 // threat threads as if they were processes #define PROC_LOOSE_TASKS 0x2000 // threat threads as if they were processes
@ -246,6 +252,9 @@ extern proc_t * get_proc_stats(pid_t pid, proc_t *p);
#define PROC_PID 0x1000 // process id numbers ( 0 terminated) #define PROC_PID 0x1000 // process id numbers ( 0 terminated)
#define PROC_UID 0x4000 // user id numbers ( length needed ) #define PROC_UID 0x4000 // user id numbers ( length needed )
#define PROC_EDITCGRPCVT 0x10000 // edit `cgroup' as single vector
#define PROC_EDITCMDLCVT 0x20000 // edit `cmdline' as single vector
// it helps to give app code a few spare bits // it helps to give app code a few spare bits
#define PROC_SPARE_1 0x01000000 #define PROC_SPARE_1 0x01000000
#define PROC_SPARE_2 0x02000000 #define PROC_SPARE_2 0x02000000

View File

@ -24,7 +24,9 @@
#include <netinet/in.h> /* htons */ #include <netinet/in.h> /* htons */
#endif #endif
#ifndef OOMEM_ENABLE
long smp_num_cpus; /* number of CPUs */ long smp_num_cpus; /* number of CPUs */
#endif
#define BAD_OPEN_MESSAGE \ #define BAD_OPEN_MESSAGE \
"Error: /proc must be mounted\n" \ "Error: /proc must be mounted\n" \
@ -180,7 +182,11 @@ static void old_Hertz_hack(void){
setlocale(LC_NUMERIC, savelocale); setlocale(LC_NUMERIC, savelocale);
jiffies = user_j + nice_j + sys_j + other_j; jiffies = user_j + nice_j + sys_j + other_j;
seconds = (up_1 + up_2) / 2; seconds = (up_1 + up_2) / 2;
#ifndef OOMEM_ENABLE
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus ); h = (unsigned)( (double)jiffies/seconds/smp_num_cpus );
#else
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus() );
#endif
/* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */ /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
switch(h){ switch(h){
case 9 ... 11 : Hertz = 10; break; /* S/390 (sometimes) */ case 9 ... 11 : Hertz = 10; break; /* S/390 (sometimes) */
@ -246,10 +252,34 @@ static int check_for_privs(void){
return !!rc; return !!rc;
} }
#ifdef OOMEM_ENABLE
long smp_num_cpus(void)
{
static long _smp_num_cpus=-1; /* number of CPUs */
if (_smp_num_cpus != -1)
return(_smp_num_cpus);
// ought to count CPUs in /proc/stat instead of relying
// on glibc, which foolishly tries to parse /proc/cpuinfo
//
// SourceForge has an old Alpha running Linux 2.2.20 that
// appears to have a non-SMP kernel on a 2-way SMP box.
// _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512
// _SC_NPROCESSORS_ONLN returns 1, which should work OK
_smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if(_smp_num_cpus<1) _smp_num_cpus=1; /* SPARC glibc is buggy */
return(_smp_num_cpus);
}
#endif
static void init_libproc(void) __attribute__((constructor)); static void init_libproc(void) __attribute__((constructor));
static void init_libproc(void){ static void init_libproc(void){
have_privs = check_for_privs(); have_privs = check_for_privs();
init_Linux_version(); /* Must be called before we check code */ init_Linux_version(); /* Must be called before we check code */
#ifndef OOMEM_ENABLE
// ought to count CPUs in /proc/stat instead of relying // ought to count CPUs in /proc/stat instead of relying
// on glibc, which foolishly tries to parse /proc/cpuinfo // on glibc, which foolishly tries to parse /proc/cpuinfo
// //
@ -259,7 +289,7 @@ static void init_libproc(void){
// _SC_NPROCESSORS_ONLN returns 1, which should work OK // _SC_NPROCESSORS_ONLN returns 1, which should work OK
smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN); smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if(smp_num_cpus<1) smp_num_cpus=1; /* SPARC glibc is buggy */ if(smp_num_cpus<1) smp_num_cpus=1; /* SPARC glibc is buggy */
#endif
if(linux_version_code > LINUX_VERSION(2, 4, 0)){ if(linux_version_code > LINUX_VERSION(2, 4, 0)){
Hertz = find_elf_note(AT_CLKTCK); Hertz = find_elf_note(AT_CLKTCK);
if(Hertz!=NOTE_NOT_FOUND) return; if(Hertz!=NOTE_NOT_FOUND) return;

View File

@ -7,7 +7,11 @@
EXTERN_C_BEGIN EXTERN_C_BEGIN
extern unsigned long long Hertz; /* clock tick frequency */ extern unsigned long long Hertz; /* clock tick frequency */
#ifndef OOMEM_ENABLE
extern long smp_num_cpus; /* number of CPUs */ extern long smp_num_cpus; /* number of CPUs */
#else
extern long smp_num_cpus(void); /* number of CPUs */
#endif
extern int have_privs; /* boolean, true if setuid or similar */ extern int have_privs; /* boolean, true if setuid or similar */
#if 0 #if 0

View File

@ -224,6 +224,7 @@ static unsigned task_format_needs;
#define needs_for_format (proc_format_needs|task_format_needs) #define needs_for_format (proc_format_needs|task_format_needs)
#define PROC_ONLY_FLAGS (PROC_FILLENV|PROC_FILLARG|PROC_FILLCOM|PROC_FILLMEM|PROC_FILLCGROUP) #define PROC_ONLY_FLAGS (PROC_FILLENV|PROC_FILLARG|PROC_FILLCOM|PROC_FILLMEM|PROC_FILLCGROUP)
/***** munge lists and determine openproc() flags */ /***** munge lists and determine openproc() flags */
static void lists_and_needs(void){ static void lists_and_needs(void){
check_headers(); check_headers();
@ -283,11 +284,12 @@ static void lists_and_needs(void){
} }
if(!unix_f_option){ if(!unix_f_option){
proc_format_needs &= ~PROC_FILLCOM; proc_format_needs &= ~PROC_FILLCOM;
proc_format_needs |= PROC_EDITCMDLCVT;
needs_for_sort &= ~PROC_FILLCOM; needs_for_sort &= ~PROC_FILLCOM;
} }
// convert ARG to COM as a standard // convert ARG to COM as a standard
if(proc_format_needs & PROC_FILLARG){ if(proc_format_needs & PROC_FILLARG){
proc_format_needs |= PROC_FILLCOM; proc_format_needs |= (PROC_FILLCOM | PROC_EDITCMDLCVT);
proc_format_needs &= ~PROC_FILLARG; proc_format_needs &= ~PROC_FILLARG;
} }
if(bsd_e_option){ if(bsd_e_option){

View File

@ -331,8 +331,11 @@ Modifications to the arguments are not shown.
// FIXME: some of these may hit the guard page in forest mode // FIXME: some of these may hit the guard page in forest mode
/* "command" is the same thing: long unless c */ /*
static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp){ * "args", "cmd", "command" are all the same: long unless c
* "comm", "ucmd", "ucomm" are all the same: short unless -f
* ( determinations are made in display.c, we just deal with results ) */
static int pr_argcom(char *restrict const outbuf, const proc_t *restrict const pp){
char *endp = outbuf; char *endp = outbuf;
unsigned flags; unsigned flags;
int rightward=max_rightward; int rightward=max_rightward;
@ -342,84 +345,30 @@ static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp)
endp += fh; endp += fh;
rightward -= fh; rightward -= fh;
} }
if(bsd_c_option) flags = ESC_DEFUNCT; if(pp->cmdline)
else flags = ESC_DEFUNCT | ESC_BRACKETS | ESC_ARGS; endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward);
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, flags); else
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT);
if(bsd_e_option && rightward>1){ if(bsd_e_option && rightward>1) {
const char **env = (const char**)pp->environ; if(pp->environ && *pp->environ)
if(env && *env){ endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward);
*endp++ = ' ';
rightward--;
endp += escape_strlist(endp, env, OUTBUF_SIZE, &rightward);
}
} }
//return endp - outbuf; //return endp - outbuf;
return max_rightward-rightward; return max_rightward-rightward;
} }
static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) { static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) {
char *endp = outbuf;
int rightward = max_rightward; int rightward = max_rightward;
if(pp->cgroup) { if(pp->cgroup) {
char **pcgroup = pp->cgroup; escaped_copy(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward);
return max_rightward-rightward;
while(*pcgroup != NULL) {
//Skip root cgroups
if(!**pcgroup || (*pcgroup)[strlen(*pcgroup)-1] == '/') {
pcgroup++;
continue;
}
//Skip initial cgroup number
char *ccgroup = strchr(*pcgroup, ':');
if(ccgroup == NULL)
ccgroup = *pcgroup;
else
ccgroup++;
if(endp != outbuf)
endp += escape_str(endp, ";", OUTBUF_SIZE, &rightward);
endp += escape_str(endp, ccgroup, OUTBUF_SIZE, &rightward);
pcgroup++;
}
} }
else
if(endp == outbuf)
return pr_nop(outbuf,pp); return pr_nop(outbuf,pp);
return (int)(endp-outbuf);
} }
/* "ucomm" is the same thing: short unless -f */
static int pr_comm(char *restrict const outbuf, const proc_t *restrict const pp){
char *endp = outbuf;
unsigned flags;
int rightward=max_rightward;
if(forest_prefix){
int fh = forest_helper(outbuf);
endp += fh;
rightward -= fh;
}
if(unix_f_option) flags = ESC_DEFUNCT | ESC_BRACKETS | ESC_ARGS;
else flags = ESC_DEFUNCT;
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, flags);
if(bsd_e_option && rightward>1){
const char **env = (const char**)pp->environ;
if(env && *env){
*endp++ = ' ';
rightward--;
endp += escape_strlist(endp, env, OUTBUF_SIZE, &rightward);
}
}
//return endp - outbuf;
return max_rightward-rightward;
}
/* Non-standard, from SunOS 5 */ /* Non-standard, from SunOS 5 */
static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){ static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){
char *endp = outbuf; char *endp = outbuf;
@ -1292,7 +1241,7 @@ static int pr_t_left2(char *restrict const outbuf, const proc_t *restrict const
#define GRP PROC_FILLGRP /* gid_t -> group names */ #define GRP PROC_FILLGRP /* gid_t -> group names */
#define WCH PROC_FILLWCHAN /* do WCHAN lookup */ #define WCH PROC_FILLWCHAN /* do WCHAN lookup */
#define CGRP PROC_FILLCGROUP /* read cgroup */ #define CGRP PROC_FILLCGROUP | PROC_EDITCGRPCVT /* read cgroup */
/* TODO /* TODO
* pull out annoying BSD aliases into another table (to macro table?) * pull out annoying BSD aliases into another table (to macro table?)
* add sorting functions here (to unify names) * add sorting functions here (to unify names)
@ -1320,7 +1269,7 @@ static const format_struct format_array[] = {
{"addr_1", "ADDR", pr_nop, sr_nop, 1, 0, LNX, AN|LEFT}, {"addr_1", "ADDR", pr_nop, sr_nop, 1, 0, LNX, AN|LEFT},
{"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT}, {"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT},
{"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, PO|RIGHT}, {"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, PO|RIGHT},
{"args", "COMMAND", pr_args, sr_cmd, 27, ARG, U98, PO|UNLIMITED}, /*command*/ {"args", "COMMAND", pr_argcom, sr_cmd, 27, ARG, U98, PO|UNLIMITED}, /*command*/
{"atime", "TIME", pr_time, sr_nop, 8, 0, SOE, ET|RIGHT}, /*cputime*/ /* was 6 wide */ {"atime", "TIME", pr_time, sr_nop, 8, 0, SOE, ET|RIGHT}, /*cputime*/ /* was 6 wide */
{"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, TO|SIGNAL}, /*sigmask*/ {"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, TO|SIGNAL}, /*sigmask*/
{"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, TO|RIGHT}, {"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, TO|RIGHT},
@ -1332,11 +1281,11 @@ static const format_struct format_array[] = {
{"class", "CLS", pr_class, sr_sched, 3, 0, XXX, TO|LEFT}, {"class", "CLS", pr_class, sr_sched, 3, 0, XXX, TO|LEFT},
{"cls", "CLS", pr_class, sr_sched, 3, 0, HPU, TO|RIGHT}, /*says HPUX or RT*/ {"cls", "CLS", pr_class, sr_sched, 3, 0, HPU, TO|RIGHT}, /*says HPUX or RT*/
{"cmaj_flt", "-", pr_nop, sr_cmaj_flt, 1, 0, LNX, AN|RIGHT}, {"cmaj_flt", "-", pr_nop, sr_cmaj_flt, 1, 0, LNX, AN|RIGHT},
{"cmd", "CMD", pr_args, sr_cmd, 27, ARG, DEC, PO|UNLIMITED}, /*ucomm*/ {"cmd", "CMD", pr_argcom, sr_cmd, 27, ARG, DEC, PO|UNLIMITED}, /*ucomm*/
{"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, AN|RIGHT}, {"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, AN|RIGHT},
{"cnswap", "-", pr_nop, sr_nop, 1, 0, LNX, AN|RIGHT}, {"cnswap", "-", pr_nop, sr_nop, 1, 0, LNX, AN|RIGHT},
{"comm", "COMMAND", pr_comm, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/ {"comm", "COMMAND", pr_argcom, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/
{"command", "COMMAND", pr_args, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/ {"command", "COMMAND", pr_argcom, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/
{"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT}, {"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT},
{"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/ {"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/
{"cpu", "CPU", pr_nop, sr_nop, 3, 0, BSD, AN|RIGHT}, /* FIXME ... HP-UX wants this as the CPU number for SMP? */ {"cpu", "CPU", pr_nop, sr_nop, 3, 0, BSD, AN|RIGHT}, /* FIXME ... HP-UX wants this as the CPU number for SMP? */
@ -1516,8 +1465,8 @@ static const format_struct format_array[] = {
{"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT}, {"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT},
{"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, PO|LEFT}, {"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, PO|LEFT},
{"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT}, {"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT},
{"ucmd", "CMD", pr_comm, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/ {"ucmd", "CMD", pr_argcom, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/
{"ucomm", "COMMAND", pr_comm, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/ {"ucomm", "COMMAND", pr_argcom, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/
{"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT}, {"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT},
{"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER}, {"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER},
{"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT}, {"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT},

1499
top.1

File diff suppressed because it is too large Load Diff

4920
top.c

File diff suppressed because it is too large Load Diff

911
top.h

File diff suppressed because it is too large Load Diff