3

在 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' 的条目,这是预期的 - 非 chroot 环境具有相同的行为。但是,如果我将脚本更改为包括:

$SIG{ALRM} = sub {};

...一切正常。那么,有什么关系呢?我对 Solaris 没有太多经验,但是必须有一种方法可以使默认信号处理程序正常运行。

4

3 回答 3

9

我建议简单地替换sleep 1调用select(undef, undef, undef, 1)并避免整个问题。

从你给出的症状来看,我敢打赌你的 chroot'd perl 脚本是sleep按照SIGALRM(POSIX 允许的)实现的,并且由于某种原因 perl 没有捕捉到它应该捕捉到的信号,也许是因为它不是t 期望实现。是您自定义的 perl 版本吗?这是 chroot'd 中的一个特质libc吗?perl -e "sleep 1"在 chroot 下是否显示同样的问题?等等等等。很难说没有进入环境和像truss这样的工具。

同样,整个问题都可以避免: select不会弄脏SIGALRM.

于 2009-07-06T04:00:08.913 回答
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 正在加载哪些共享库。

于 2009-07-10T20:47:35.350 回答
1

你还有 Solaris 附带的 Perl 版本吗?如果是这样,请尝试使用您的代码。如果你没有那个版本,那么我建议下载Perl 5.8.7,编译一个股票版本,然后在上面测试你的脚本。

如果您的脚本在这两个版本中的任何一个上正确运行,那么您就知道问题与您的 Perl 版本的更改有关。如果脚本有同样的错误,那么我建议下载Perl 5.8.9,编译它,然后检查错误是否消失。如果没有,那么恭喜您,您在 Perl 中发现了一个错误。您可能需要运行perlbug来报告它。

于 2009-07-06T12:46:01.717 回答