четверг, 20 мая 2010 г.

И как отловить такой баг?

Пару рабочих дней убил на отлов элементарной ошибки.

Выглядело все следующим образом:
 * имелся некий TCP сервер с уже кучей кода и модулей, но в принципе рабочий;
 * еще один тот же TCP сервер, но на другой машине (плате);
 * первый TCP сервер подключался к другому, как клиент с целью обмена данными.


Ошибка была в том, что соединение по какой-то причине отрабатывалось неверно и повисало в состоянии CLOSE_WAIT. Первый сервер распознавал это как неактивный сервер и дисконнектил его по таймауту, второй - не видел соединения вообще.

Соответственно, ключевым словом для гугления стало состояние CLOSE_WAIT, на которое вываливается куча нетривиальной инфы, которую замучились перепроверять. Но вроде как оказалось, что все критерии выполнены и ошибок быть не должно.

Далее, начали проверять отработку процесса подключения ко второму серверу. Подключение детектировалось по наличию данных в сокете путем проверки select()-ом. Сервер был однопоточный и проверки запускались периодически + выполнялась служебная работа. Select() измучили как только можно, перепроверяя отдаваемые ему параметры по десять раз и все равно CLOSE_WAIT оставлись. Что сразу смущало - они были _не всегда_.

Когда уже наступила фаза отчаяния, случайно добавленная отладка в планировщик вызовов select() выявила, что планировщик тупо переставал запускаться. Оказывается дело было в том, что планировщик запускался по таймауту, который вычислялся последовательными вызовами gettimeofday(). А на той плате была особенность - она корректировала свое системное время. На несколько месяцев. А проверки на такие таймауты не было. Занавес.

Как можно силой мысли доползти от диагностики в виде CLOSE_WAIT на сокете до неверной отработки таймаутов планировщика я не знаю. :(

Комментариев нет: