Killing processes - dead or alive

For discussions about programming, programming questions/advice, and projects that don't really have anything to do with Puppy.
Post Reply
Message
Author
User avatar
MochiMoppel
Posts: 2084
Joined: Wed 26 Jan 2011, 09:06
Location: Japan

Killing processes - dead or alive

#1 Post by MochiMoppel »

Inspired by some recent threads on how to kill zombie processes and by a question on how to use Xdialog for killing processes I became curious if Xdialog can be used as a simple process killer.

Though Xdialog doesn't have a multicolumn list function and seems ill equipped for the task it's possible. Processes are sorted by starting time and also show their status (zombies would show as 'Z'). Some properties (the important PPID and the sometimes lengthy ARGS) are difficult to display in the main list and therefore went into the help line at the bottom, which functions like a tooltip.

So far, so good. Still I was puzzled when I saw the result. The script takes the output of the ps command, pipes it to sort and then to awk. What I still don't understand: When ps outputs a list of current processes, the following sort and awk processes haven't started yet. How can they be already included in the list? Trying to kill them results in an error since - like zombies - they are already dead.
#!/bin/bash
IFS=$'\n'
while : ;do
PSLIST=$(ps -eo pid,start,stat,comm,ppid,args | sort -rk2 | awk '{ print $1 "\n" $2 "\t\t" $3 "\t\t" $4 "\nPPID:"$5,"ARGS:"substr($0, index($0,$6)) }' )
RESULT=$(Xdialog --stdout --ok-label " kill -9 " --item-help --menubox "Processes (sorted by STARTED)" 400x300 0 $PSLIST)
case $? in
0 ) ERR=$(kill -9 $RESULT 2>&1) || { ERR=${ERR##*:} ; Xdialog --msgbox "ERROR:\n$ERR" x ;};;
* ) break ;;
esac
done
I can avoid such deadish processes from appearing in the list when I split the pipe chain into 3 separate variable assignments:

Code: Select all

PSLIST=$( ps -eo pid,start,stat,comm,ppid,args)
PSLIST=$( echo -n "$PSLIST" | sort -rk2)
PSLIST=$( echo -n "$PSLIST" | awk '{ print $1 "\n" $2 "\t\t" $3 "\t\t" $4 "\nPPID:"$5,"ARGS:"substr($0, index($0,$6)) }')
Takes 10 millisecond more than a pipe chain, but the list now looks right. Still I would like to understand what happened in the first case.
Attachments
mm_processkiller.png
Xdialogs using a) pipe chain and b) separate variables
(52.05 KiB) Downloaded 356 times
Last edited by MochiMoppel on Fri 22 Jul 2016, 06:43, edited 1 time in total.

some1
Posts: 117
Joined: Thu 17 Jan 2013, 11:07

#2 Post by some1 »

When ps outputs a list of current processes, the following sort and awk processes haven't started yet. How can they be already included in the list? Trying to kill them results in an error since - like zombies - they are already dead.
Some indicative comments:
1) when the command is read by the shell -(script run/enter pressed in terminal)
rescheduling of the systems tasklist is "triggered"
2) /proc/pidX/ is pointers to the stateinfo in the tasklist
3) ps gets info from /proc
4) /proc contains info of how the system intends to honor
your request in 1)
lets assume the tasklist has adjusted to this execution-order:
ps,sort,awk
5) ps runs - gathers information on the _scheduled_ state -
and will include information on sort and awk.
6) Timewise - every process triggered in 1) - will likely be
non-existent when you see the output.
So yes - whatever we do - we act on possibly out-dated information.
----
Suggestion:
1) get the pid of your killerscript
2) in the awk: filter-out anything that have your killerscript PID
and anything that have a PPID=killerscript PID

User avatar
MochiMoppel
Posts: 2084
Joined: Wed 26 Jan 2011, 09:06
Location: Japan

#3 Post by MochiMoppel »

Many thanks,some1, for your valuable comments. I now understand what's going on. Interesting stuff.
some1 wrote:Suggestion:
1) get the pid of your killerscript
That's easier said than done. There might be 2. The first is alive and well and shouldn't be filtered. Only the second is dead, but retrieving its PID is not trivial.
I find it easier to remove the last n lines from the ps output (PIDs 22203-22206 in first example). Depending on code there might only be 1 line to remove: ps's own PID (PID 21942 in 2nd example).

some1
Posts: 117
Joined: Thu 17 Jan 2013, 11:07

#4 Post by some1 »

About my suggestion above:
I had this in mind:
awk -v pid="$$" '!($1==pid||$2==pid){<printcode>}'

but overlooked,that you run in a subshell $( )

the ps-tree looks something like this:

main
\_subshell i.e. $( )
-- \ps
-- |sort
-- |awk

the piping ps|sort|awk implies that the ps-output contains ps,sort,awk
its desired to exclude subshell,ps,sort,awk from the final output

$$ gives us the pid of main/script
its global,can be read anywhere in the subshells
$BASHPID is local to a shell
i.e.
in main: $$==$BASHPID
elsewhere: $$!=$BASHPID

so in subshell we do PID=$BASHPID
PID is global to the kid-shells,
can be read by a child
is persistent i.e. a saved $BASHPID
this PID will be the pid of the childs parent,
will be the PPID
--------------------------------
In production-code:
the sort bungles the line-order - but the fieldsplitting
stays intact - so after the sorting we may have something like this:

F*CK:This could be read as a TABLE - with some imagination :)

-- field 1=$1 field 5=$5
-- ps-PID-- ps-PPID
----------------------------------------------
-- whatever .............................
-- pid ? subshell
-- ? pid awk
-- ? pid sort
-- ? pid ps
-- whatever .............................

We filter out the lines with pid either in $1 or in $5 by doing this:
Pseudocode:

PSLIST=$(PID=$BASHPID;<ps|sort>| awk -v pid=$PID '($1!=pid&&pid!=$5){<printcode>}')

Note: That way we can filter-out kids-and parent with rather limited
knowledge of the ps-tree.One may call it a special-case,ad-hoc solution.
A more general awk-walk fetching a subtree - needs more code ---
The codeposition of sort - probably to get your smart Xdialog-tooltip -
comes with a price too - if you want to shred more levels -i.e. exclude
the script-pid $$ from the output.
As is -using $BASHPID - you can save 10 ms .Be happy with that :)
-------
-------
A minor thing:
I have a vague notion - that the format of STARTED -
can change to date-format
1) Perhaps when bridging midnight
2) Perhaps when older than a 24-hour period
If so - that might affect the sorting.
As said - a notion.
--------
some hours later:
Just corrected a few typos.

The mentioning of PPID above refers to ps-header-naming.

Bash has an inbuilt $PPID,which gives the parent to the script
I dont think $PPID is relevant in this context.

---

User avatar
MochiMoppel
Posts: 2084
Joined: Wed 26 Jan 2011, 09:06
Location: Japan

#5 Post by MochiMoppel »

some1 wrote:We filter out the lines with pid either in $1 or in $5 by doing this:
Pseudocode:
PSLIST=$(PID=$BASHPID;<ps|sort>| awk -v pid=$PID '($1!=pid&&pid!=$5){<printcode>}')
Good idea, but why not then simply filter all processes younger than the main script? That's what I currently use:
PSLIST=$(<ps> | awk '$1<='"$$"'{<printcode>}')

I also agree with your notion about STARTED. I get much better results with (reverse) sorting PID instead of STARTED. And I now entrust the sorting to ps ( --sort=-pid ). Saves another process. :wink:

This all is a proof-of-concept. Apart from dead processes I also filter kernel threads (kworker etc., the stuff that I definitely don't want to kill manually). And I did the same thing using yad and like the benefit of multiple selection and sorting on any column, but nothing beats the speed and simplicity of Xdialog :lol:

EDITED 2 DAYS LATER: My briliant idea didn't last long :cry: I now see that pid numbers are not always assigned in sequential order. Newer pids not necessarily have a higher value. Today my killerscript's pid is only 4-digit (see screenshot), which also makes sorting of pids in either direction useless.

I'll adopt your $BASHPID idea and also revert to sorting of STARTED. I padded pids and ppids with zeros to right align them and to defeat Xdialog's lack of monospace font support. The kill command ignores leading zeros
Attachments
processkiller_sorted_filtered.png
(16.83 KiB) Downloaded 183 times

Post Reply