2012-01-13 18 views
5

Tôi vừa theo dõi một vấn đề mà tôi phải đóng tất cả các tập tin mở cho tập lệnh Apache cgi của mình để tiếp tục. Tôi đã theo dõi vấn đề với Parse :: RecDescent.Cách tìm tập tin mở toàn cầu trong một chương trình perl

#!/usr/bin/env perl 

use strict; 
use warnings; 
use feature qw/say/; 
$|++; 

print "Content-Type: text/plain\n\n"; 

use Parse::RecDescent; 

say "$$: pre-fork: ". time; 

if(my $pid = fork) { 
    # parent 
    say "$$: return immediately: ". time; 
} 
else { 
    # child 
    say "$$: kicked off big process: ". time; 
    close STDIN; 
    close STDOUT; 
    close STDERR; 
    # close *{'Parse::RecDescent::ERROR'}; 
    sleep 5; 
} 

Câu hỏi của tôi là làm cách nào để tìm tất cả các tệp mở gói?

Tôi biết fileno sẽ trả lại bộ đếm cho một tệp mở. Có cách nào để thực hiện tra cứu ngược lại các mục này hoặc đóng các tập tin bằng bộ đếm fileno không?

Trả lời

8

Trên một số hệ thống, thư mục được trả về bởi "/proc/$$/fd/" chứa danh sách các bộ mô tả tệp đang mở. Bạn có thể sử dụng POSIX::close để đóng chúng.

# close all filehandles 
for (glob "/proc/$$/fd/*") { POSIX::close($1) if m{/(\d+)$}; } 
+0

Tôi thích sự đơn giản này. – CoffeeMonster

+2

@ikegami: Giới thiệu về cờ close-on-exec: Perl's 'open()' sẽ sử dụng giá trị '$^F' để xác định xem các tệp mới được mở có được đặt cờ đóng-on-exec hay không. '$^F' đại diện cho giá trị stdin, stdout, stderr" cutoff "- các bộ mô tả tập tin ở trên' $^F' nhận được bộ bit close-on-exec _at thời gian của 'open()' _. (Không phải 'exec()' thời gian.) Vì stdin, stdout và stderr được mở _before_ thực thi của tập lệnh, '$^F' sẽ không ảnh hưởng nếu chúng được đóng trong' exec() '. (Ngẫu nhiên, tôi đọc điều này có nghĩa là chỉ đóng 'STDIN',' STDOUT' và 'STDERR' là' $^F = 2' theo mặc định.) – sarnold

+0

@sarnold, Tuyệt vời khi nói về $^F. Đó là chút tôi đã mất tích. Bạn sẽ nghĩ rằng tôi muốn biết thêm về điều này kể từ khi tôi đã viết mã trong IPC :: Open3 mà đặt close-on-exec trên một xử lý! – ikegami

2

Bạn có thể đi xuống qua cây gói:

use strict; 
use warnings; 
use constant BREAK_DESCENT => {}; 

use Carp qw<croak>; 
use English qw<$EVAL_ERROR>; # [email protected] 

sub break_descent { 
    return BREAK_DESCENT if defined wantarray; 
    die BREAK_DESCENT; 
} 

sub _package_descend { 
    my ($package_name, $stash, $selector) = @_; 
    my $in_main  = $package_name =~ m/^(?:main)?::$/; 
    foreach my $name (keys %$stash) { 
     next if ($in_main and $name eq 'main::'); 
     my $full_name = $package_name . $name; 
     local $_  = do { no strict 'refs'; \*$full_name; }; 
     my $return 
      = $name =~ m/::$/ 
      ? _package_descend($full_name, *{$_}{HASH}, $selector) 
      : $selector->($package_name, $name => $_) 
      ; 
     return BREAK_DESCENT if (ref($return) and $return == BREAK_DESCENT); 
    } 
    return; 
} 

sub package_walk { 

    my ($package_name, $selector) 
     = @_ == 1 ? ('::', shift) 
     :   @_ 
     ; 

    $package_name .= '::' unless substr($package_name, -2) eq '::'; 
    local $EVAL_ERROR; 

    eval { 
     no strict 'refs'; 
     _package_descend($package_name, \%$package_name, $selector); 
    }; 

    return unless $EVAL_ERROR; 
    return if  do { no warnings 'numeric'; $EVAL_ERROR == BREAK_DESCENT; }; 

    say STDERR $EVAL_ERROR; 
    croak('Failed in selector!'); 
} 

package_walk(sub { 
    my ($pkg, $name) = @_; 
    #say "$pkg$name"; 
    # to not close handles in ::main:: 
    #return if $pkg =~ m/^(?:main)?::$/; 
    # use IO::Handle methods... 
    map { defined and $_->opened and $_->close } *{$_}{IO}; 
}); 
+0

Điều đó sẽ không tìm thấy xử lý trên stack, trong từ vựng, vv Anh ấy đang cố gắng để đóng tất cả các xử lý. Tôi đã hy vọng sẽ thấy một bài viết đề cập đến gần-on-exec. Tôi không biết đủ về nó. – ikegami

+0

@ikegami Không có nghĩa là để được đầy đủ, chỉ cần trả lời những điều sau đây: "Câu hỏi của tôi là làm thế nào để tôi tìm thấy tất cả mở * gói * tập tin?" Các phạm vi từ vựng khép kín không phải là vấn đề khi Perl dọn dẹp những thứ đó cho bạn, nhưng trong các biến gói ... Tôi sẽ thêm một cái gì đó cho điều đó. – Axeman

+0

Không, xử lý bằng từ vựng không bị đóng cửa cho bạn ở đây. Anh ấy muốn làm những thứ trong đứa trẻ trước khi rời khỏi. – ikegami

2

gì về trọng trên toàn cầu open với một phiên bản mà giữ một danh sách của tất cả các xử lý nó tạo ra? Một cái gì đó như thế này có thể là một sự khởi đầu:

use Scalar::Util 'weaken'; 
use Symbol(); 
my @handles; 
BEGIN { 
    *CORE::GLOBAL::open = sub (*;[email protected]) { 
     if (defined $_[0] and not ref $_[0]) { 
      splice @_, 0, 1, Symbol::qualify_to_ref($_[0]) 
     } 
     my $ret = 
      @_ == 1 ? CORE::open $_[0] : 
      @_ == 2 ? CORE::open $_[0], $_[1] : 
         CORE::open $_[0], $_[1], @_[2 .. $#_]; 
     if ($ret) { 
      push @handles, $_[0]; 
      weaken $handles[-1]; 
     } 
     $ret 
    } 
} 

sub close_all_handles { 
    $_ and eval {close $_} for @handles 
} 

open FH, $0; 

say scalar <FH>; # prints "use Scalar::Util 'weaken';" 

close_all_handles; 

say scalar <FH>; # error: readline() on closed file handle 

Điều này sẽ nắm bắt tất cả các xử lý toàn cầu, nhưng không bao giờ được làm sạch (do tham chiếu vòng tròn hoặc các lý do khác).

Nếu bạn đặt ghi đè này (khối BEGIN) trước khi gọi tới use Parse::RecDescent thì nó sẽ ghi đè các cuộc gọi đến open mà mô-đun tạo ra.

+0

Có một trình xử lý tập tin xử lý cũng sẽ hoạt động tốt :) – CoffeeMonster

1

Tôi đã kết thúc bằng đề xuất @ ikegami nhưng tôi đã quan tâm đến phương pháp @ Axeman. Đây là một phiên bản đơn giản.

# Find all file-handles in packages. 
my %seen; 
sub recurse { 
    no strict 'refs'; 
    my $package = shift or return; 
    return if $seen{$package}++; 

    for my $part (sort keys %{$package}) { 
     if (my $fileno = fileno($package.$part)) { 
      print $package.$part." => $fileno\n"; 
     } 
    } 
    for my $part (grep /::/, sort keys %{$package}) { 
     (my $sub_pkg = $package.$part) =~ s/main:://; 
     recurse($sub_pkg); 
    } 
} 
recurse('main::'); 
3

Khi theo dõi xuống các chi tiết gần-on-exec cho sự tò mò Ikegami, tôi nghĩ rằng tôi thấy rằng tất cả các bạn cần làm là gần STDIN, STDOUT, và STDERR mình nếu bạn chỉ đơn giản là thực hiện một tiến trình khác:

$SYSTEM_FD_MAX 
    $^F  The maximum system file descriptor, ordinarily 2. 
      System file descriptors are passed to exec()ed 
      processes, while higher file descriptors are not. 
      Also, during an open(), system file descriptors are 
      preserved even if the open() fails. (Ordinary file 
      descriptors are closed before the open() is 
      attempted.) The close-on-exec status of a file 
      descriptor will be decided according to the value of 
      $^F when the corresponding file, pipe, or socket was 
      opened, not the time of the exec(). 

Tất nhiên, nếu tác vụ lâu dài của bạn không yêu cầu cuộc gọi execve(2) để chạy, thì cờ close-on-exec sẽ không giúp bạn gì cả. Tất cả phụ thuộc vào những gì sleep 5 là một stand-in cho.

Các vấn đề liên quan