2009-06-01 4 views
4

Я пытаюсь создать оболочку в Linux, которая контролирует, сколько одновременных исполнений чего-то разрешено сразу. Для этого я использую системный счетный семафор. Я создаю семафор, делаю sem_wait(), запускаю дочерний процесс, а затем делаю sem_post(), когда ребенок завершается. Это нормально.Безопасное использование сигнала sem_wait()/sem_post()

Проблема заключается в том, как безопасно обрабатывать сигналы, отправленные в эту оболочку. Если он не поймает сигналы, команда может завершиться без выполнения sem_post(), в результате чего количество семафоров будет постоянно уменьшаться на единицу. Итак, я создал обработчик сигнала, который делает sem_post(). Но все-таки есть проблема.

Если обработчик присоединен перед sem_wait() выполняется, сигнал может прибыть до sem_wait() завершается, в результате чего sem_post() происходить без sem_wait(). Реверс возможен, если я делаю sem_wait() перед настройкой обработчика сигнала.

Очевидным следующим шагом было блокирование сигналов во время настройки обработчика и sem_wait(). Это псевдокод того, что у меня сейчас:

void handler(int sig) 
{ 
    sem_post(sem); 
    exit(1); 
} 

... 
sigprocmask(...); /* Block signals */ 
sigaction(...);  /* Set signal handler */ 
sem_wait(sem); 
sigprocmask(...); /* Unblock signals */ 
RunChild(); 
sem_post(sem); 
exit(0); 

Сейчас проблема заключается в том, что sem_wait() может блокировать и в течение этого времени, сигналы блокируются. Пользователь, пытающийся убить процесс, может в конечном итоге прибегнуть к «kill -9», поведение которого я не хочу поощрять, поскольку я не могу справиться с этим делом независимо от того, что. Я мог бы использовать sem_trywait() в течение небольшого времени и теста sigpending(), но это влияет на справедливость, потому что больше нет гарантии, что процесс, ожидающий семафора, самый длинный, будет запущен дальше.

Есть ли действительно безопасное решение, которое позволяет мне обрабатывать сигналы во время получения семафора? Я рассматриваю возможность использования глобального «глобального слияния» и удаления блокировки сигнала, но это не на 100% безопаснее, поскольку получение семафора и установка глобального не являются атомарными, но могут быть лучше, чем блокировать сигналы во время ожидания.

ответ

6

Вы уверены, что sem_wait() вызывает блокировку сигналов? Я не думаю, что это так. man page for sem_wait() говорит, что код ошибки EINTR возвращается с sem_wait(), если он прерывается сигналом.

Вы должны иметь возможность обработать этот код ошибки, а затем ваши сигналы будут получены. Вы столкнулись с ситуацией, когда сигналы не были получены?

Я бы позаботился, чтобы вы обработали коды ошибок, которые могут быть возвращены sem_wait(). Хотя это может быть редко, если вы хотите быть на 100% уверенным, что хотите покрыть 100% своих баз.

+0

Извините, если я не понимаю.sem_wait() не вызывает блокировку сигналов, как вы говорите, но я использую sigprocmask(), чтобы заблокировать их. Но, я думаю, у вас есть правильное решение, которое должно смотреть на код ошибки EINTR, что означает, что обработчик не должен выйти, но установить некоторый флаг, чтобы сказать «время для выхода». Я проверю это. Благодарю. – Jeremy

+0

Это сработало. Я удалил блокировку сигналов и изменил обработчик сигнала, чтобы просто установить глобальный смысл, когда пришло время уйти. Если sem_wait() возвращает ошибку, то я прекращаю то, что отлично, и сохраняет счет семафора. Если я жду ребенка, я также тестирую timeToQuit global. Если пришло время уйти, я убиваю его и делаю sem_post(), который сохраняет счет семафора. Благодарю. Это должно быть безопасным сигналом, игнорируя kill -9. – Jeremy

0

Вы уверены, что используете эту проблему правильно? Если вы хотите дождаться завершения работы с ребенком, вы можете использовать системный вызов waitpid(). Как вы заметили, не стоит надеяться, что ребенок сделает sem_post(), если он может получать сигналы.

+0

На самом деле, ребенок не знает о семафоре, а родитель делает waitpid() в функции RunChild() в псевдокоде, который я не показывал. Эта часть была в порядке, и она обрабатывала завершение ребенка и сигналы, отправленные родителям после завершения sem_take(). Я был обеспокоен критическим разделом между установкой обработчика сигнала и sem_wait(), но проверка кода ошибки sem_wait() была простым решением, которое я не мог видеть. – Jeremy

0

Я знаю, что это старый, но в интересах тех, кто до сих пор читают эту любезность Google ...

Самый простой (и только?) Надежное решение этой проблемы заключается в использовании System V семафор, который позволяет клиенту приобретать ресурс семафора таким образом, который автоматически возвращается ядром. НЕТ МАТЕРИИ, КАК ПРОЦЕСС ВЫХОДИТ.

Смежные вопросы