WSASYSCALLFAILURE с перекрывающимся вводом-выводом в Windows XP

Я столкнулся с ошибкой в ​​своем коде, которая использует результат WSARecv и WSAGetOverlapped для перекрывающегося сокета. При большой нагрузке WSAGetOverlapped возвращает сообщение WSASYSCALLFAILURE («Ошибка системного вызова, который никогда не должен завершаться ошибкой»), после чего мой TCP-поток не синхронизируется, вызывая хаос на верхних уровнях моей программы.

До сих пор мне не удавалось изолировать его от определенного набора оборудования или драйверов. Кто-нибудь столкнулся с этой проблемой и нашел решение или обходной путь?


person eile    schedule 16.07.2010    source источник


Ответы (2)


Сколько подключений, сколько ожидающих получения, сколько исходящих отправок? Что perfmon или диспетчер задач говорят об объеме используемого невыгружаемого пула? Сколько памяти в коробке? Она исчезнет, ​​если запустить программу на Vista или выше? У вас установлены какие-либо LSP?

Вы можете исчерпать невыгружаемый пул и вызвать неправильное поведение плохо написанного драйвера, когда ему не удается выделить память. Вероятность того, что эта проблема возникнет в Vista или более поздних версиях, меньше, так как объем доступного невыгружаемого пула резко увеличился (см. on-non-paged-pool.html" rel="nofollow noreferrer">http://www.lenholgate.com/blog/2009/03/excellent-article-on-non-paged-pool.html для подробностей). В качестве альтернативы вы можете достичь предела «заблокированных страниц» (вы можете заблокировать только фиксированное количество страниц в памяти ОС, и каждая ожидающая операция ввода-вывода блокирует одну или несколько страниц в зависимости от размера буфера и выравнивания распределения).

person Len Holgate    schedule 16.07.2010
comment
Около 10 соединений с одним ожидающим получением на соединение. Отправки реализованы с блокировкой, так что остается максимум одна ожидающая отправка. Остальные проверю позже. Тестирование на Vista займет некоторое время, так как у нас пока нет тестового кластера. Спасибо за все указатели - я опубликую снова, как только я отследил это. - person eile; 16.07.2010
comment
Тогда вряд ли это будут ограничения ресурсов. Может просто плохой водитель? Можете ли вы попробовать на машине с другой сетевой картой и драйверами? - person Len Holgate; 16.07.2010
comment
У нас проблема постоянно на разных машинах и драйверах. Я начинаю думать, что есть ошибка с перекрывающимися операциями ввода-вывода в XP. Наше приложение несколько отличается тем, что группа ведомых устройств рендеринга отправляет данные пикселей на одну машину, в отличие от серверных приложений, которые отправляют данные группе клиентов. - person eile; 17.07.2010
comment
Ошибка с перекрывающимися операциями ввода-вывода в XP. Если это так, то я никогда ее не видел, и я делаю МНОГО работы с перекрывающимися операциями ввода-вывода сокетов и делаю это в течение 10 лет или около того. Скорее всего, у вас есть ошибка в коде, извините ;) Можете ли вы опубликовать какой-нибудь код, показывающий область, в которой произошел сбой? - person Len Holgate; 17.07.2010
comment
Конечно, подключение здесь: equalizergraphics.com/cgi-bin/viewvc.cgi/trunk/src/lib/net/ Демультиплексируется с помощью объекта WaitForMultipleObjects здесь: equalizergraphics.com/cgi-bin/viewvc.cgi/trunk/src/ lib/net/ И используется из Node::runReceiverThread/handleData здесь: equalizergraphics.com/cgi-bin/viewvc.cgi/trunk/src/lib/net/ - person eile; 19.07.2010
comment
Лично я бы не стал устанавливать событие в вашем перекрытии, когда чтение возвращает 0, что указывает на то, что чтение завершено сразу; он устанавливается вызовом чтения, может быть состояние гонки между вами, обращающимся к нему после возврата WSARecv(), и тем, что вы с ним делаете (уничтожаете его в конечном итоге?) после того, как ваше ожидание вернется в другой поток... - person Len Holgate; 19.07.2010
comment
В этом вопросе говорится, что в этом случае событие не установлено WSARecv: stackoverflow.com/questions/2511690/ В любом случае я никогда не выполнял это условие, плюс чтение и WaitForMultipleObjects находятся в одном потоке. - person eile; 19.07.2010
comment
Это меня удивляет в случае с событием, но я не склонен использовать событие, я просто использую IOCP для работы с завершениями. Достаточно справедливо относительно резьбы. - person Len Holgate; 19.07.2010
comment
Вы так и не ответили на мой вопрос о том, установлены ли у вас какие-либо многоуровневые поставщики услуг на рассматриваемых машинах; антивирусные программы и брандмауэры иногда их устанавливают. Я прочитал от парня из MS, что WSASYSCALLFAILURE является результатом, если функция lastError не установлена ​​правильно, и что LSP, как правило, являются основным виновником... - person Len Holgate; 19.07.2010
comment
Наконец-то я смог это проверить. Никаких дополнительных LSP не установлено. - person eile; 20.07.2010
comment
Жаль... У меня нет идей. - person Len Holgate; 20.07.2010
comment
Спасибо, в любом случае. Я пытаюсь реализовать обходной путь и сразу же столкнулся со следующей странностью Winsock. Вздох. stackoverflow.com/questions/3296920/ - person eile; 21.07.2010

Кажется, я решил эту проблему, засыпая на 1 мс и повторяя результат WSAGetOverlapped, когда он сообщает о WSASYSCALLFAILURE.

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

@Len: еще раз спасибо за помощь.

РЕДАКТИРОВАТЬ: Ночной тест прошел успешно. Моя ошибка была вызвана двумя взаимозависимыми проблемами:

Проблема 1: WaitForMultipleObjects в ConnectionSet::select время от времени сигнализирует данные о пустом сокете, что приводит к взаимоблокировке SocketConnection::readSync. Исправление: неблокирующее чтение первого байта каждого пакета. Сбросить ConnectionSet, если сокет был пуст

Проблема 2: WSAGetOverlappedResult время от времени возвращает WSASYSCALLFAILURE, вызывая рассинхронизацию потока TCP. Исправление: повторите попытку WSAGetOverlappedResult после небольшого периода сна.

http://equalizer.svn.sourceforge.net/viewvc/equalizer?view=revision&revision=4649

person eile    schedule 22.07.2010
comment
Хм... Я обычно очень настороженно отношусь к "исправлениям", которые требуют сна... Я ожидаю, что более вероятно, что в вашем коде есть состояние гонки, и что ваше "исправление" вернется, чтобы укусить вас через пару лет. время, когда вы переходите на оборудование, о котором вы еще не можете мечтать ;) - person Len Holgate; 03.08.2010
comment
В целом я согласен с вашими комментариями и обычно не делаю таких «исправлений». Однако в данном случае я до смерти отлаживал код и совершенно убежден, что это не гонка в моем коде. Код ошибки — WSASYSCALLFAILURE, что означает не-ошибку. Кроме того, это происходит только с необычными моделями связи (много узлов отправляют одному узлу много данных), что может быть причиной того, что он все еще находится в WinSocks. У нас уже были другие проблемы с Winsocks, например, вот эта: mombu.com/microsoft/alt-winsock-programming/ - person eile; 03.08.2010
comment
Опять же, это похоже на состояние гонки ИМХО... Как вы узнаете, когда ваш ввод/вывод завершен, я не вижу никакого подсчета ссылок, и, ИМХО, вам нужен подсчет ссылок для каждого сокета и для каждого данные ввода-вывода, чтобы обеспечить уборку в нужное время, а не раньше... - person Len Holgate; 05.08.2010
comment
Получение данных осуществляется одним потоком. Данные принимаются в eq::net::Command, на который ссылаются, когда он вставляется в net::CommandQueue для отправки в поток обработки, и разыменовываются, когда он был обработан. Net::CommandCache позаботится о том, чтобы повторно использовать эти пакеты для ReceiverThread. Я подробно рассмотрел и протестировал этот код с помощью valgrind в Linux. - person eile; 06.08.2010