在 Perl 模块中使用 sigtrap,如何在对象上下文中接收到陷阱?

发布于 2024-12-08 02:53:45 字数 590 浏览 0 评论 0原文

在我的模块的 BEGIN 部​​分中有以下内容:

use sigtrap qw(handler shutdown normal-signals);
use sigtrap qw(die untrapped normal-signals stack-trace any error-signals);

但是当 sigtrap 捕获 INT 等时...我在关闭子中得到的内容仅包含陷阱而不包含对象句柄。没有$self。

sub shutdown {
    my $sig = shift || 'Nothing';   
    print "Got signal: $sig\n";
    exit;
}

简单地返回

Got signal: INT

My DESTROY get 在此之后立即调用并可以访问对象句柄,但因为我在关闭时无法访问该句柄,所以我无法存储它并且不知道信号是什么。

我需要知道我遇到了什么陷阱,以便我的 DESTROY 方法可以记录导致关闭的原因。

也许 sigtrap 不是这里的最佳选择。欢迎提出意见。

Have the following in my module's BEGIN section:

use sigtrap qw(handler shutdown normal-signals);
use sigtrap qw(die untrapped normal-signals stack-trace any error-signals);

But when sigtrap catches INT,etc.. what I get in my shutdown sub only contains the trap and not the object handle. No $self.

sub shutdown {
    my $sig = shift || 'Nothing';   
    print "Got signal: $sig\n";
    exit;
}

simply returns

Got signal: INT

My DESTROY get's called right on time after this and has access to the object handle, but because I didn't have access to the handle in my shutdown, I couldn't store it and have no idea what the signal was.

I need to know what trap I got so my DESTROY method can log what caused the shutdown.

Perhaps sigtrap isn't the best choice here. Opinions welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

高速公鹿 2024-12-15 02:53:45

我检查了 sigtrap,它不是专门的 OO 模块,如果你想要的话要将其用作一个,您可能需要使用闭包而不是对象方法。

所以你可以像这样定义你的类:

package SigHandler;

sub new { 
    my $class = shift;
    return bless { @_ }, $class;
}

sub on_signal_int { 
    my $self = shift;
    ...
}

sub get_handler { 
    my $self       = shift;
    my @other_args = shift;
    ...
    return sub { 
        my $sig = shift;
        if ( $sig == INT ) { 
            return $self->on_signal_int();
        }
    };
}

然后像这样调用它:

use handler => SigHandler->new->get_handler, 'normal-signals';

I checked sigtrap, it's not specifically an OO module, if you want to use it as one, you may need to use a closure instead of an object method.

So you might define your class like so:

package SigHandler;

sub new { 
    my $class = shift;
    return bless { @_ }, $class;
}

sub on_signal_int { 
    my $self = shift;
    ...
}

sub get_handler { 
    my $self       = shift;
    my @other_args = shift;
    ...
    return sub { 
        my $sig = shift;
        if ( $sig == INT ) { 
            return $self->on_signal_int();
        }
    };
}

And then call it like so:

use handler => SigHandler->new->get_handler, 'normal-signals';
旧话新听 2024-12-15 02:53:45

Perl 的信号处理程序(包括使用 sigtrap 设置的信号处理程序)是程序级别的,而不是对象级别的。因此,当 perl 调用处理程序时,它没有任何对象可以传递给您。

如果您想在收到信号时清理一堆对象,则需要对模块进行编码以跟踪它创建的对象。然后,当您收到信号时,您可以遍历这些对象并执行任何销毁方法。

像这样的事情应该让你开始:

{package Test;
    use Scalar::Util 'weaken';
    use sigtrap handler => \&cleanup, 'normal-signals';

    my %objects;

    sub new {
        my ($class, $msg) = @_;
        my $self = [$msg];
        bless $self, $class;
        weaken($objects{$self} = $self);  # prevent memory leak
        $self
    }

    sub cleanup {
        my ($sig) = @_;
        say "cleanup on $sig";
        defined and $_->DESTROY for values %objects;
        exit;
    }

    sub DESTROY {
        my ($self) = @_;
        if (@$self) {
            say "DESTROY $self @$self";
            @$self = ();
            delete $objects{$self}
        }
    }

}

{my $obj1 = Test->new('out of scope')}

my $obj2 = Test->new('in scope');

1 while 1;

运行时:

$ perl so.pl
DESTROY Test=ARRAY(0x899150) out of scope
^Ccleanup on INT
DESTROY Test=ARRAY(0x824810) in scope

Perl's signal handlers, including those set with sigtrap are program level, and not object level. So when perl calls the handler, it does not have any object to pass you.

If you want to clean up a bunch of objects when you receive a signal, you will need to code your module to keep track of the objects it has created. Then when you receive a signal, you can go through those objects and perform any destroy methods.

Something like this should get you started:

{package Test;
    use Scalar::Util 'weaken';
    use sigtrap handler => \&cleanup, 'normal-signals';

    my %objects;

    sub new {
        my ($class, $msg) = @_;
        my $self = [$msg];
        bless $self, $class;
        weaken($objects{$self} = $self);  # prevent memory leak
        $self
    }

    sub cleanup {
        my ($sig) = @_;
        say "cleanup on $sig";
        defined and $_->DESTROY for values %objects;
        exit;
    }

    sub DESTROY {
        my ($self) = @_;
        if (@$self) {
            say "DESTROY $self @$self";
            @$self = ();
            delete $objects{$self}
        }
    }

}

{my $obj1 = Test->new('out of scope')}

my $obj2 = Test->new('in scope');

1 while 1;

And when run:

$ perl so.pl
DESTROY Test=ARRAY(0x899150) out of scope
^Ccleanup on INT
DESTROY Test=ARRAY(0x824810) in scope
情绪 2024-12-15 02:53:45

感谢您的见解,但我最终通过使用 global 来跟踪它而作弊。
为了简洁起见,删除了所有导出和常见内容

Package Blah;
our $SIG_CAUGHT = '';
BEGIN {
    use sigtrap qw(handler shutdown normal-signals);
    use sigtrap qw(die untrapped normal-signals stack-trace any error-signals);
}
sub shutdown {
    $SIG_CAUGHT = shift;
    exit;
}

sub DESTROY {
    my $self = shift;
    my $message = 'Daemon shutting down';
    $message .= '.  Caught signal: SIG' . $SIG_CAUGHT if ( $SIG_CAUGHT ne '' );
    $message .= ' with error: ' . $! if $!; 
    $self->logger({severity => 5, message => $message});
    $self->{_dbh} = undef;
}
1;

。经过测试。正确处理 INT、KILL、DIE,在致命错误时传播错误。

一个很好的副作用是触发 INT 现在只需击键一次。
过去遇到过这样的问题,我必须反复使用 Control-C 我的程序才能让它们停止运行。

Thank you for your insights, but I ended up cheating by using global to track it.
All the exports and common stuff removed for brevity

Package Blah;
our $SIG_CAUGHT = '';
BEGIN {
    use sigtrap qw(handler shutdown normal-signals);
    use sigtrap qw(die untrapped normal-signals stack-trace any error-signals);
}
sub shutdown {
    $SIG_CAUGHT = shift;
    exit;
}

sub DESTROY {
    my $self = shift;
    my $message = 'Daemon shutting down';
    $message .= '.  Caught signal: SIG' . $SIG_CAUGHT if ( $SIG_CAUGHT ne '' );
    $message .= ' with error: ' . $! if $!; 
    $self->logger({severity => 5, message => $message});
    $self->{_dbh} = undef;
}
1;

Tested.. correctly handles INT,KILL,DIE, propagating errors when fatal.

One nice side effect is triggering INT is now one keystroke.
Had the issue in the past where I repeatedly had to Control-C my programs to get them to go down.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文