Skip Menu |

This queue is for tickets about the Proc-ProcessTable CPAN distribution.

Report information
The Basics
Id: 56852
Status: rejected
Priority: 0/
Queue: Proc-ProcessTable

People
Owner: Nobody in particular
Requestors: kohts [...] yandex-team.ru
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.45
Fixed in: (no value)



Subject: unusable on linux
Proc::ProcessTable is totally unusable on Linux (even not speaking about other tickets in RT queue about this). I have a daemon which regularly (once per several seconds) makes Proc::ProcessTable->new()->table call. After running for some tens of hours (10-30) daemon can no longer get sockets with socketpair() call (fcntl call fails with "Bad file descriptor") and then my process disappears from running processes (with nothing useful in dmesg and syslog). To work around I've created a function which populates process table from /proc -- if you need this code, drop me a message, I will post it.
Sure I'm interested in the code. I can't understand your message without it, primarily because I've worked in a project which communicates via sockets and had massive use of Proc::ProcessTable under Linux and AIX. Jens
Show quoted text
> Sure I'm interested in the code. I can't understand > your message without it, primarily because > I've worked in a project which communicates > via sockets and had massive use of Proc::ProcessTable > under Linux and AIX. > > Jens
Here's the code (excerpts from the daemon): package psProcess; sub pid { my ($self) = @_; return $self->{'pid'}; } sub ppid { my ($self) = @_; return $self->{'ppid'}; } sub pgrp { my ($self) = @_; return $self->{'pgid'}; } sub pgid { my ($self) = @_; return $self->{'pgid'}; } sub cmndline { my ($self) = @_; return $self->{'cmd'}; } package main; sub get_process_table { my $ptable; # Proc::ProcessTable has some leaks on linux # which leads to process dying if ($^O eq 'linux') { $ptable = []; my $i = 0; my $dummy; my $open_res; while (!($open_res = opendir($dummy, "/proc")) && $i < 3) { sleep 1; $i++; } if (!$open_res) { psSnake::die("unable to read /proc"); } my @all_entries; $i = 0; while (scalar(@all_entries) < 3 && $i < 3) { @all_entries = readdir($dummy); sleep 1 if $i > 0; $i++; } close($dummy); # . + .. eq 2 if (scalar(@all_entries) < 3) { psSnake::die("/proc is not mounted"); } my $read_may_fail = sub { my ($filename) = @_; my $filecontent; if (open F, $filename) { { local $/ = undef; $filecontent = <F>; } close F; } return $filecontent; }; foreach my $e (sort @all_entries) { my $pid_dir = "/proc/$e"; next if $e eq '.' || $e eq '..'; next if $e !~ /^\d+$/o; next if ! -d $pid_dir; my $cmd = $read_may_fail->("$pid_dir/cmdline"); $cmd =~ s/\0/ /goi if $cmd; my $stat = $read_may_fail->("$pid_dir/stat"); next unless $stat; my @stat_arr = split(" ", $stat); next if ! scalar(@stat_arr) > 5; if (!$cmd) { $cmd = $stat_arr[1]; if ($cmd) { $cmd =~ s/[\(\)]//goi; $cmd = "[" . $cmd . "]"; } } my $ppid = $stat_arr[3]; my $pgid = $stat_arr[4]; next if ! $cmd; next if ! $ppid =~ /^\d+$/o; next if ! $pgid =~ /^\d+$/o; my $p = { 'pid' => $e, 'ppid' => $ppid, 'pgid' => $pgid, 'cmd' => $cmd, }; bless ($p, 'psProcess'); push (@{$ptable}, $p); } return $ptable; } else { my $r = code_may_fail(sub {return Proc::ProcessTable->new()->table}, {'tries' => 3}); if (!$r->{'result'}) { psSnake::die("unable to get process table: " . $r->{'warn'}); } $ptable = $r->{'result'}; } my $i = 0; while (scalar(@{$ptable}) < 2 && $i < 3) { $i++; sleep 1; $ptable = get_process_table(); } if (scalar(@{$ptable}) < 2) { psSnake::die("unable to read process table"); } return $ptable; }
Hi I started to fix some of the issues of Proc::ProcessTable, Jonathan Swartz created a repo on github for it: https://github.com/jonswar/perl-proc-processtable While wading through this bug report, I discovered that you call the sub "get_process_table()" inside itself, thus creating a recursive call. Is this intentional? Given @{$ptable} is indeed < 2 in while (scalar(@{$ptable}) < 2 && $i < 3) { , you would call "get_process_table()" infinitely till the whole thing blows up. Cheers, Joachim Am Mo 26. Apr 2010, 05:31:46, http://lj.rossia.org/~nit/ schrieb: Show quoted text
>
> > Sure I'm interested in the code. I can't understand > > your message without it, primarily because > > I've worked in a project which communicates > > via sockets and had massive use of Proc::ProcessTable > > under Linux and AIX. > > > > Jens
> > Here's the code (excerpts from the daemon): > > package psProcess; > sub pid { my ($self) = @_; return $self->{'pid'}; } > sub ppid { my ($self) = @_; return $self->{'ppid'}; } > sub pgrp { my ($self) = @_; return $self->{'pgid'}; } > sub pgid { my ($self) = @_; return $self->{'pgid'}; } > sub cmndline { my ($self) = @_; return $self->{'cmd'}; } > > package main; > sub get_process_table { > my $ptable; > > # Proc::ProcessTable has some leaks on linux > # which leads to process dying > if ($^O eq 'linux') { > $ptable = []; > > my $i = 0; > > my $dummy; > my $open_res; > while (!($open_res = opendir($dummy, "/proc")) && $i < 3) { > sleep 1; > $i++; > } > if (!$open_res) { > psSnake::die("unable to read /proc"); > } > > my @all_entries; > $i = 0; > while (scalar(@all_entries) < 3 && $i < 3) { > @all_entries = readdir($dummy); > sleep 1 if $i > 0; > $i++; > } > close($dummy); > > # . + .. eq 2 > if (scalar(@all_entries) < 3) { > psSnake::die("/proc is not mounted"); > } > > my $read_may_fail = sub { > my ($filename) = @_; > my $filecontent; > if (open F, $filename) { > { local $/ = undef; $filecontent = <F>; } > close F; > } > return $filecontent; > }; > > foreach my $e (sort @all_entries) { > my $pid_dir = "/proc/$e"; > > next if $e eq '.' || $e eq '..'; > next if $e !~ /^\d+$/o; > next if ! -d $pid_dir; > > my $cmd = $read_may_fail->("$pid_dir/cmdline"); > $cmd =~ s/\0/ /goi if $cmd; > > my $stat = $read_may_fail->("$pid_dir/stat"); > next unless $stat; > > my @stat_arr = split(" ", $stat); > next if ! scalar(@stat_arr) > 5; > > if (!$cmd) { > $cmd = $stat_arr[1]; > > if ($cmd) { > $cmd =~ s/[\(\)]//goi; > $cmd = "[" . $cmd . "]"; > } > } > > my $ppid = $stat_arr[3]; > my $pgid = $stat_arr[4]; > > next if ! $cmd; > next if ! $ppid =~ /^\d+$/o; > next if ! $pgid =~ /^\d+$/o; > > my $p = { > 'pid' => $e, > 'ppid' => $ppid, > 'pgid' => $pgid, > 'cmd' => $cmd, > }; > > bless ($p, 'psProcess'); > push (@{$ptable}, $p); > } > > return $ptable; > } > else { > my $r = code_may_fail(sub {return Proc::ProcessTable->new()- >table}, > {'tries' => 3}); > > if (!$r->{'result'}) { > psSnake::die("unable to get process table: " . $r->{'warn'}); > } > > $ptable = $r->{'result'}; > } > > my $i = 0; > while (scalar(@{$ptable}) < 2 && $i < 3) { > $i++; > sleep 1; > $ptable = get_process_table(); > } > > if (scalar(@{$ptable}) < 2) { > psSnake::die("unable to read process table"); > } > > return $ptable; > }