Wednesday, December 24th, 2003 12:05 am
Обнаружил баг в Apache/PHP.

Проявляется в том, что некоторые запросы переходят в keepalive state (т.е. ждут продолжения запроса после окончания предыдущего на том же сокете) и остаются там навечно. Таким образом, постепенно все процессы Apache попадают в это состояние, если keealive включен, а так как выйти из него у них не получается - сервер постепенно задыхается. Причём таймаут, который у апача есть для избежания таких ситуаций, не работает. Собственно, с этого всё и началось - сервер наш начал вдруг необьяснимо дохнуть, притом что ни нагрузки процессора, ни наплыва посетителей особого не наблюдалось.

По расследованию оказалось, что функция, которая должна работать по таймауту, не вызывается. А не вызывается она потому, что есть такой флаг alarms_blocked, который блокирует обработку сигналов. Когда обработка сигналов неуместна, вызывается ap_block_alarms(), которая делает ++alarms_blocked, а когда снова можно - ap_unblock_alarms(), в которой написано вот что:

--alarms_blocked;
if (alarms_blocked == 0) {
и далее обрабатываются случаи, видимо, когда в период, что сигналы были заблокированы, был сигнал и теперь пора его отработать.

Постфактум я думаю, что уже увидя этот код, я должен был заподозрить неладное. Но с первого раза я не понял, в чём дело. Запустил отладчик и посмотрел значение alarms_blocked в зависших процессах. И оно оказалось - -1, -2 и т.п. Тут до меня дошло - а что будет, если какой-то кривой код вызовет ap_unblock_alarms(), не вызывая перед этим block()? А то и будет, что с этого момента не судьба этому процессу больше принимать сигналы по таймауту - то есть судьба, но ровно тогда, когда кто-нибудь ему это _запретит_.
Завтра буду искать, кто же это такой умный этот флаг портит. То ли это в самом Apache, то ли в модуле PHP - он тоже с этими функциями играется.
Tuesday, December 23rd, 2003 02:39 pm (UTC)
А не легче сам ap_unblock_alarms() изменить, чтобы и такой случай правильно обрабатывал, чем надеяться на тех, кто его вызывает? Или его трогать нельзя?
Tuesday, December 23rd, 2003 02:39 pm (UTC)
Я бы, наверное, так сделал:

--alarms_blocked;
if (alarms_blocked < 0) {
alarms_blocked = 0;
<log a warning on incorrect signal blocking } if (alarms_blocked == 0) ..... И никакие модули более ничего не испортят... Все тот же парадигм - веди себя максимально корректно, принимай от других максимально широкии диапазон поведения (и некорректного тоже).
Tuesday, December 23rd, 2003 04:14 pm (UTC)
Конечно, ведь в unblock не только отрицательное значение но и нулевое возможно неверно
(0 когда должно быть 1).
Плюс неясно сколько раз этот модуль может вызвать
unlock без block
Wednesday, December 24th, 2003 12:22 am (UTC)
а это... thread synchronization отменили уже, или там все сингл?
Wednesday, December 24th, 2003 12:39 am (UTC)
Меня иногда умиляет то доверие, с которым некоторые разработчики относятся к самим себе и себе подобным.

По-моему лучше всего именно ту функцию, которая сокращает alarms_blocked, заставить проверять, не равняется-ли эта переменная нолю перед попыткой сократить.
Wednesday, December 24th, 2003 03:55 am (UTC)
Мне когда-то один из разработчиков ядра FreeBSD говорил, что ядро Linux работает медленнее из-за того, что разные части ядра друг другу не доверяют и перепроверяют переданные параметры.
Wednesday, December 24th, 2003 07:35 am (UTC)
Этого не достаточно
Wednesday, December 24th, 2003 02:27 pm (UTC)
Я вас успокою: конечно же API нарушен. И не один раз, и наверняка даже самим API. Это вполне нормально (увы). Другой разговор, что есть критический код, который пишется "на все случаи жизни[идиотизма]".

Вот я иногда так самому себе не доверяю, что в подобных функциях ставлю проверку, которую потом можно убрать если что, потому как она в ifdef обозначена. Так называемый test-run debugging. Очень полезный подход к вопросу. Ну и в сислог сливаю, что этот код, несмотря на его неактульность, был вызван. Так иногда выявляются весьма любопытные аномалии, без риска угробить систему и образовать downtime.

А вообще мне все эти приколы напоминают старый анекдот про х.й с винтом и ж..у с закоулками...:)
Wednesday, December 24th, 2003 02:29 pm (UTC)
Брехня это всё. Весь кернел компилируется с оптимизацией, а это значит, что лишний код вылетает за скобки. Советую попробывать дать gcc скомпелировать код в ассемблер с -O и без и сравнить результат. Вы будете очень приятно удивлены:)))
Wednesday, December 24th, 2003 02:29 pm (UTC)
Ну понятное дело - надо бы еще разработчикам Apache бошки оторвать:)))
Friday, January 2nd, 2004 03:29 pm (UTC)
А что изменилось, что это начало случаться?