Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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.47 MB
Время: 0.058 c
15-1333205037
MysqlWhata
2012-03-31 18:43
2013.03.22
Восстановление mysql базы из dump


1-1297354172
Unknown_user
2011-02-10 19:09
2013.03.22
Не отрисовываются все ячейки в DBGrid


2-1332225008
ixen
2012-03-20 10:30
2013.03.22
Обращение из потока


15-1333015766
Сергей М.
2012-03-29 14:09
2013.03.22
SMS и IMEI


6-1266221364
Pavel
2010-02-15 11:09
2013.03.22
Время обработки запроса





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский