#!/usr/bin/perl

sub TIOCGWINSZ () { 0x5413; }
require "sys/ioctl.ph";

my $interval = 0.2;
my $width = 80;
my $height = 25;
sub sig_winch {
	-t STDIN and ioctl(STDIN, TIOCGWINSZ, $winsize)
	and ($height,$width) = unpack('S2',$winsize);
}
$SIG{'WINCH'} = \&sig_winch;
sig_winch();

print "\033[2J\n";

for (;;select '','','',$interval) {
	print "\033[1;1H";

	@ps = </proc/[0-9]*/stat>;
	$count = 0;
	foreach $f (@ps) {
		open(IN, '<', $f) or next;
		$p = <IN>;
		close(IN);
		next unless defined($p);
		($pid,$cmd,$stat) = split(' ',$p,4);
		$cmd =~ s/^\((.*)\)$/$1/;
		$sstat = substr($stat,0,1);
		next unless ($sstat eq 'D' or $recent_d{$pid});
		$recent_d{$pid}+= (($stat eq 'D') << 6) - 1;
		$f =~ s/stat$/stack/;
		if (open(IN, '<', $f)) {
			my $stack = '';
			while (defined($func = <IN>)) {
				chomp($func);
				$func =~ s/\[.*?\]\s//;
				$func =~ s/\/.*//;
				$stack.= ', '.$func;
				last if length($stack) > $width;
			}
			$rwidth = $width - 6 - 10 - length($stat) - 1;
			$stack = substr($stack,2,$rwidth);
			$stack_d{$pid} = $stack if ($sstat eq 'D' or !defined($stack_d{$pid}));
			$count++;
			$nl = substr("\n",$count == $height);
			printf("%5u %-9.9s %s %s\033[K$nl",
				$pid,$cmd,$stat,$stack_d{$pid});
			close(IN);
		} else {
			delete $recent_d{$pid};
			delete $stack_d{$pid};
			next;
		}
		last if ($count >= $height);
	}
	print "\033[0J";
	$| = 1;
	$| = 0;
}
