在Solaris 9(Sparc)的chroot环境中运行Perl时,我遇到了一些奇怪的错误。我们 使用自定义Perl,但它几乎完全是Perl 5.8.7,并且这个版本已经在包括Solaris 8-10在内的各种平台上运行多年。
以下代码非常简单:
#!/usr/bin/perl
use strict;
use warnings;
print "About to sleep(1)\n";
sleep 1;
print "Just woke up!\n";
然而,如果我跑了,“刚刚醒来!”从不打印 - 相反,程序结束,“闹钟”响应屏幕。只有在睡眠时才会发生这种情况 - 如果我编写的程序执行大量数学操作并需要10秒钟才能运行,那么一切正常。它也只发生在chroot环境中。
我转储了%SIG,其条目为'ALRM => undef',这是预期的 - 非chrooted环境具有相同的行为。但是,如果我将脚本更改为包括:
$SIG{ALRM} = sub {};
......一切正常。那么,这笔交易是什么?我没有很多使用Solaris的经验,但必须有一种方法可以使默认的信号处理程序正常运行。
答案 0 :(得分:9)
我建议只使用sleep 1
替换select(undef, undef, undef, 1)
来电并避免整个问题。
根据你给出的症状,我打赌你的chroot perl脚本正在sleep
实现SIGALRM
(由POSIX允许),并且由于某种原因perl是没有抓住那个应该发出的信号,也许是因为它不期待这种实施。它是你自定义构建的perl吗?这是chroot'd libc
中的特质吗? chroot下的perl -e "sleep 1"
是否显示同样的问题?等等。很难说无法访问环境和像 truss 这样的工具。
同样,可以避免整个问题:select
不会与SIGALRM
混淆。
答案 1 :(得分:3)
我要尝试的第一件事是在truss下运行你的示例程序:
truss testprogram.pl
这将显示用于实现睡眠的实际系统调用。在我有权访问的Solaris 8系统上,输出的相关部分是:
write(1, " A b o u t t o s l e".., 18) = 18
time() = 1247258429
alarm(0) = 0
sigaction(SIGALRM, 0xFFBEF6E0, 0xFFBEF790) = 0
sigfillset(0xFF0C28D0) = 0
sigprocmask(SIG_BLOCK, 0xFFBEF780, 0xFFBEF770) = 0
alarm(1) = 0
Received signal #14, SIGALRM, in sigsuspend() [caught]
sigsuspend(0xFFBEF760) Err#4 EINTR
setcontext(0xFFBEF448)
alarm(0) = 0
sigprocmask(SIG_UNBLOCK, 0xFFBEF780, 0x00000000) = 0
sigaction(SIGALRM, 0xFFBEF6E0, 0x00000000) = 0
time() = 1247258430
Just woke up!
write(1, " J u s t w o k e u p".., 14) = 14
在Solaris 10主机上,它输出:
write(1, " A b o u t t o s l e".., 18) = 18
time() = 1247258270
nanosleep(0xFFBFF770, 0xFFBFF768) = 0
time() = 1247258271
Just woke up!
write(1, " J u s t w o k e u p".., 14) = 14
我想你会更接近Solaris 8输出,并且它可能会因某种原因显示sigaction()调用失败。
除此之外,我还要检查chroot / usr / lib中的共享库实际上是主机和操作系统版本的正确版本。 truss输出还将显示perl正在加载哪些共享库。
答案 2 :(得分:1)
您是否还拥有Solaris附带的Perl版本?如果是这样,那么尝试你的代码。如果您没有该版本,那么我建议下载Perl 5.8.7,编译股票版本,然后在其上测试您的脚本。
如果您的脚本在这两个版本中的任何一个上正确运行,那么您就知道该问题与您的Perl版本中的更改有关。如果脚本有相同的错误,那么我建议下载Perl 5.8.9,编译它,然后检查bug是否消失。如果没有,那么,恭喜,您在Perl中发现了一个错误。您可能希望运行perlbug进行举报。