Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
ВнизSpurious wakeup в WinSock? Найти похожие ветки
← →
ProgRAMmer Dimonych © (2012-08-01 14:31) [0]Столкнулся со следующей ситуацией.
Есть приложение, которое активно работает с сетью. Один из его потоков работает так:
1. socket(...)
2. WSACreateEvent() + WSAEventSelect(FD_CONNECT | FD_READ | FD_CLOSE)
3. connect()
4. WSAWaitForMultipleEvents(1, hEvent)
5. WSAEnumNetworkEvents()
Достаточно часто стала наблюдаться ситуация, когда Wait возвращает WSA_WAIT_OBJECT_0, а EnumNetworkEvents возвращает обнулённое поле lNetworkEvents, т.е. типа "событий не было". Трейсы и API Monitor подтверждают.
Гугл выдаёт ссылки на несколько форумов, но ничего конкретного там найти не удалось. На тестовом приложении (однопоточном) проблема не повторяется, в исходном проекте проблемный код полностью изолирован от других потоков (переменные локальные, вся указанная логика - в отдельном потоке).
Собственно, вопрос: сталкивался ли кто-нибудь с таким. Любые рассуждения по теме приветствуются.
P.S. Сам пока активно ищу ошибки в программе, но уже пошли в ход самые безумные предположения.
← →
Вариант (2012-08-01 15:30) [1]Где код этого хозяйства?
> ProgRAMmer Dimonych © (01.08.12 14:31)
> 1. socket(...)
> 2. WSACreateEvent() + WSAEventSelect(FD_CONNECT | FD_READ
> | FD_CLOSE)
> 3. connect()
> 4. WSAWaitForMultipleEvents(1, hEvent)
> 5. WSAEnumNetworkEvents()
← →
Сергей М. © (2012-08-01 15:58) [2]
> Любые рассуждения по теме приветствуются
WSACreateEvent принципиально ничем не отличается от CreateEvent, т.е. возвращает хендл event-объекта, который м.б. использован в любых wait-вызовах общего назначение, не только в WSAWait.
По этой причине WSAWaitForMultipleEvents вполне может вернуть WAIT_OBJECT_0, если ей подсунули любой другой сигналящий event-объект, не имеющий ничего общего с тем который был создан при WSACreateEvent.
Это наводит на мысль что в период времени между п.2 и п.4 область данных, распределенных под хранение хендла, созданного тобой при WSACreateEvent, была неосознанно затерта и перезаписана значением хендла совсем другого существующего event-объекта, который на момент п.4 находился или перешел в сигнальное состояние, что и вызвало WAIT_OBJECT_0.
При этом если ф-ция в п.5 гарантированно вернула не SOCKET_ERROR, значит ей передан правильный, но не просигналивший на самом деле хендл.
← →
ProgRAMmer Dimonych © (2012-08-01 18:03) [3]> [1] Вариант (01.08.12 15:30)
> Где код этого хозяйства?
С кодом не всё просто: часть одного из модулей защиты, теоретически коммерческая тайна. Если убрать все подробности, то что-то типа такого получится:...
if (SOCKET_ERROR == WSAEventSelect(ConnectSock, hEvent, FD_CONNECT | FD_READ | FD_CLOSE))
break;
Result = ConnectWithTimeout(ConnectSock, hEvent, (LPSOCKADDR)AgentAddr, sizeof(SOCKADDR_STORAGE), dwTimeout);
if (ERR_GOODRET != Result)
break;
...
int CWSMonitor::ConnectWithTimeout(SOCKET s, WSAEVENT hConnectEvent, SOCKADDR *name, int namelen, DWORD Timeout)
{
int Result = 0;
while (TRUE)
{
ResetEvent(hConnectEvent);
if (SOCKET_ERROR == connect(s, name, namelen))
{
Result = WSAGetLastError();
if (WSAEWOULDBLOCK != Result)
break;
}
Result = WSAWaitForMultipleEvents(1, &hConnectEvent, TRUE, Timeout, FALSE);
if (WSA_WAIT_EVENT_0 != Result)
break;
WSANETWORKEVENTS Events;
ZeroMemory(&Events, sizeof(Events));
if (SOCKET_ERROR == WSAEnumNetworkEvents(s, hConnectEvent, &Events))
{
Result = WSAGetLastError();
break;
}
if (Events.lNetworkEvents == 0)
{
TRACE("===== Spurious wakeup! =====");
}
if (Events.lNetworkEvents & FD_CLOSE)
{
Result = WSAECONNREFUSED;
break;
}
Result = Events.iErrorCode[FD_CONNECT_BIT];
break;
}
return Result;
}
hEvent - локальная переменная в вызывающем методе (приведён частично). ConnectSock - копия значения поля класса, передаётся параметром метода.
← →
ProgRAMmer Dimonych © (2012-08-01 18:06) [4]> [2] Сергей М. © (01.08.12 15:58)
В эту сторону и копаю, но с каждым изменением проблемный код всё больше отделяется от остального, а потенциальные проблемы находить становится всё сложнее. Смущает упоминание на форумах подобных явлений (в т.ч. именно с этими функциями) под названием spurious wakeup:уж больно красивое название, чтобы обоначать ошибку прикладного программиста, а не фичу системы. Хотя доселе ни разу не слышал о таком вообще.
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Память: 0.46 MB
Время: 1.747 c