名字:

Sys::SigAction  Perl 拓展用于一致的信号处理

 #do something non-interrupt able
       use Sys::SigAction qw( set_sig_handler );
       {
          my $h = set_sig_handler( 'INT' ,'mysubname' ,{ flags => SA_RESTART } );
          ... do stuff non-interrupt able
       } #signal handler is reset when $h goes out of scope

摘要:

这个模块实现了"set_sig_handler()", 它设置了一个信号处理器 返回一个导致信号处理器

被重置先先前值的对象

"timeout_call() 是实现通过一个超时参数,一个code引用和可选的参数,

执行代码引用封装使用一个alarm 超时  

描述:

在5.8版本之前, perl实现了不安全的信号处理。

这哥之所以认为不安全,是因为有一个风险 一个信号会到达和辈出当perl时改变内部数据结构。

Perl 5.8.0 和后面的版本实现了安全的信号处理在支持POSIX sigaction() function.

来自PERL 5.8.2 手册页:


因此  'deferred signal'  方法导致一些系统调用被重试在信号之前被调用

这个打破了 DBD-ORACLE的超时逻辑 

对于早期的PERL版本,这个可以是特别恼火的,

对于实例,当主机是不可达的:

 "DBI->connect()" hangs 几分钟在返回错误前
 
 (甚至不能用control-C中断)
 
这是因为信号出现被延迟 结果是不能实现超时 

[oracle@yyjk sbin]$ cat testdbi2.pl 
use DBI;
no warnings;

use DBI;
use HTTP::Date qw(time2iso str2time time2iso time2isoz);
use Net::SMTP;
use Encode;
use JSON;
my $dbip='10.2.120.192';
my $dbname='uacdb';
my $dbuser='uac';
my $dbpass='uac_123';
$dbh1 = DBI->connect( "dbi:Oracle://$dbip:1521/$dbname", $dbuser, $dbpass );
[oracle@yyjk sbin]$ time perl testdbi2.pl 
DBI connect('//10.2.120.192:1521/uacdb','uac',...) failed: ORA-12170: TNS: 连接超时 (DBD ERROR: OCIServerAttach) at testdbi2.pl line 13.

real    1m0.186s
user    0m0.101s
sys    0m0.015s

  Or as the author of bug #50628 pointed out, might probably better be
    written as:

       eval {
          local $SIG{ALRM} = sub { die "timeout" };
          eval {
             alarm 2;
             $sth = DBI->connect(...);
             alarm 0;
          };
          alarm 0;
          die if $@;
       };


[oracle@yyjk sbin]$ cat testdbi1.pl 
use DBI;
no warnings;

use DBI;
use HTTP::Date qw(time2iso str2time time2iso time2isoz);
use Net::SMTP;
use Encode;
use JSON;
use Sys::SigAction qw( set_sig_handler );
my $dbip='10.2.120.192';
my $dbname='uacdb';
my $dbuser='uac';
my $dbpass='uac';
eval {
     my $h = set_sig_handler( 'ALRM' ,sub { die; } ); #数据库连接超时后的返回结果
       alarm(5); #设置为5秒超时
      $dbh1 = DBI->connect( "dbi:Oracle://$dbip:1521/$dbname", $dbuser, $dbpass );
      alarm(0);
     };a
if ($@){
   print '11111111111111'."\n";
}
else{
  print '222222222222222'."\n";
};
You have mail in /var/spool/mail/oracle
[oracle@yyjk sbin]$ 
[oracle@yyjk sbin]$ time perl testdbi1.pl 
11111111111111

real    0m5.104s
user    0m0.100s
sys    0m0.019s