3

Solaris 9 (Sparc) の chroot 環境で Perl を実行しているときに、ちょっと変わったエラーが発生します。カスタム Perl を使用していますが、ほぼ正確に P​​erl 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 環境でのみ発生します。

「ALRM => undef」のエントリを持つ %SIG をダンプしましたが、これは予期されることです。chroot されていない環境でも同じ動作をします。ただし、スクリプトを変更して次を含めると:

$SIG{ALRM} = sub {};

...すべて正常に動作します。それで、取引は何ですか?私は Solaris の経験があまりありませんが、デフォルトのシグナルハンドラを適切に動作させる方法が必要です。

4

3 に答える 3

9

sleep 1呼び出しを単純に置き換えて、select(undef, undef, undef, 1)問題全体を回避することをお勧めします。

あなたが与える症状から、あなたのchrootされたperlスクリプトが(POSIXで許可されているように)実装さsleepSIGALRMていること、そして何らかの理由でperlがそのシグナルを本来あるべきようにキャッチしていないことを賭けます.その実装を期待していません。perl のカスタム ビルドですか?それはchrootされた特異性libcですか?perl -e "sleep 1"chroot の下で同じ問題が発生しますか? 環境へのアクセスとtrussのようなツールがなければ、言うのは難しいです。

繰り返しますが、問題全体を回避でき selectますSIGALRM

于 2009-07-06T04:00:08.913 に答える
3

私が最初に試みることは、トラスの下でサンプル プログラムを実行することです。

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 内の共有ライブラリが実際にホストと OS のバージョンに対して正しいバージョンであることを確認します。truss の出力には、perl によってロードされている共有ライブラリも正確に表示されます。

于 2009-07-10T20:47:35.350 に答える
1

Solaris に付属しているバージョンの Perl をまだ持っていますか? もしそうなら、それであなたのコードを試してみてください。そのバージョンを持っていない場合は、Perl 5.8.7をダウンロードし、ストック バージョンをコンパイルしてから、スクリプトをテストすることをお勧めします。

これら 2 つのバージョンのいずれかでスクリプトが正しく実行される場合、問題は Perl のバージョンの変更に関連していることがわかります。スクリプトに同じエラーがある場合は、Perl 5.8.9をダウンロードしてコンパイルし、バグがなくなるかどうかを確認することをお勧めします。そうでない場合は、おめでとうございます。Perl にバグが見つかりました。それを報告するためにおそらくperlbugを実行したいと思うでしょう。

于 2009-07-06T12:46:01.717 に答える