стоит сабжевая задача. Для ее решения я пошел по пути описанному в perldoc -f alarm (на CPAN есть штук пяток модулей на эту тему например Sys::AlarmCall (он же рекомендован к употреблению в perlfaq), я про них знаю, но описанная здесь проблема в них во всех проявляется, потому стоит задача написания нового модуля, либо прийти к нереализуемости задачи), итак, в perldoc -f alarm пример:
eval {
local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
alarm $timeout;
$nread = sysread SOCKET, $buffer, $size;
alarm 0;
};
if ($@) {
die unless $@ eq "alarm\n"; # propagate unexpected errors
# timed out
}
else {
# didn't
}
пишем вместо sysread ту функцию, которую хотим ограничить по времени
работы и вуаля - работает. Если посмотреть CPAN'овские модули, то все
они работают на этой технологии, только дополнительно делают следующие
вещи:
- определяют контекст вызова wantarray
- запоминают/восстанавливают предыдущее значение alarm
- ловят исключения в самой функции
- прочий сервисный шняг
но это несущественно, собственно вернемся к проблеме.
допустим мы заменили sysread на foo()
и как оказывается работа сей конструкции зависит от того чтоже там
внутри foo()
допустим foo у нас содержит такой код:
sub foo
{
for ($i = 0; $i < 100; $i++) {
sleep 1;
}
}
с такой функцией будет все ок.
но вот если например внутри функции хотя бы в одном месте будет eval
sub foo
{
for ($i = 0; $i < 100; $i++) {
eval "sleep 1";
}
}
то именно этот eval и получит die "alarm\n".
Теперь все зависит от функции, распространит она die выше или не
распространит. можно было бы сказать что функция которая не
распространяет die - "неправильная", да только таких функций в
cpan-модулях чуть меньше чем дохрена, да и "правильные есть"
sub divide($$)
{
my ($a, $b) = @_;
die "на ноль делить нельзя" unless $b;
return $a / $b;
}
тот кто использует divide знает что исключение может быть выброшено
строго в одном случае и может его просто поймать и не распространить
дальше, а скажем изменить алгоритм основной работы итп.
Получается хоть функция приведенная в perldoc -f alarm SIGALRM и
словила, но тормознуть выполнение "подопытной" функции не может, если
тот содержит eval.
Искал искал решение, но пока ничего приемлемого не нашел.
Может кто боролся с подобной проблемой? есть какие-либо предложения?
в обработчике SIGALRM мы в принципе видим стек вызовов, можно ли
как-то из него изъять несколько уровней? perl'овыми средствами
--
... mpd is off
. ''`. Dmitry E. Oboukhov
: :’ : email: [email protected] jabber://[email protected]
`. `~’ GPGKey: 1024D / F8E26537 2006-11-21
`- 1B23 D4F8 8EC0 D902 0555 E438 AB8C 00CF F8E2 6537
signature.asc
Description: Digital signature
-- Moscow.pm mailing list [email protected] | http://moscow.pm.org
