Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.03.22;
Скачать: CL | DM;

Вниз

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;
Скачать: CL | DM;

Наверх




Память: 0.48 MB
Время: 0.055 c
3-1284716344
Михаил
2010-09-17 13:39
2013.03.22
Проблема поключения к базе интербасе после сбоя в сервере


15-1330287987
Дмитрий С
2012-02-27 00:26
2013.03.22
Меня иногда удивляет, как можно придумывать вообще такое?


15-1344432770
ProgRAMmer Dimonych
2012-08-08 17:32
2013.03.22
Доступ к INI-файлу из нескольких процессов


15-1335541656
brother
2012-04-27 19:47
2013.03.22
Win 98


15-1349295678
ProgRAMmer Dimonych
2012-10-04 00:21
2013.03.22
Подсчёт ссылок на строку таблицы в MySQL