информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Атака на InternetПортрет посетителяГде водятся OGRы
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Очередное исследование 19 миллиардов... 
 Оптимизация ввода-вывода как инструмент... 
 Зловреды выбирают Lisp и Delphi 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
если вы видите этот текст, отключите в настройках форума использование JavaScript
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
Остановить все потоки. установить свой статус в stopped... 24.05.04 00:18  Число просмотров: 1497
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
> Подскажите, пожалуйста, как грамотно остановить сервис,
> обеспечить корректное завершение рабочего потока?
Остановить все потоки. Установить свой статус в STOPPED. Завершить выполнение ServiceMain.
> void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv)
> {
> <skip>
> ss.dwCurrentState = SERVICE_RUNNING;
> SetServiceStatus( hSS, &ss);
>
> hThread = _beginthreadex( NULL, 0, &SniffThread,
> NULL, 0, &thID );
> if (! hThread)
> err(_T("Error creating sniffer thread."));
>
> }
мм.. а дальше* ServiceMain должен завершаться только при завершении сервиса, а так висеть и к примеру ждать какого нить Mutex'а.
<programming>
[Win32] Не могу корректно остановить сервис NT. 23.05.04 23:43  
Автор: void <Grebnev Valery> Статус: Elderman
Отредактировано 23.05.04 23:44  Количество правок: 1
<"чистая" ссылка>
Подскажите, пожалуйста, как грамотно остановить сервис, обеспечить корректное завершение рабочего потока?
Предполагается, что сервис останавливается из mmc SCM. При завершении работы необходимо, чтобы рабочий поток освободил все используемые ресурсы.

В call-back хендлере, собственно, сделана робкая попытка только установить некий глобальный флаг g_bStopSniff = TRUE. Предполагалось (по наивности ), что рабочий поток сможет проанализировать g_bStopSniff ==TRUE ;)))Самое смешное, что некоторые гуру так и делают, блин ;))
Т.е хендлер:
DWORD WINAPI ServiceCtrlHandler( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext ) { DWORD rc = NO_ERROR; switch (dwControl) { case SERVICE_CONTROL_STOP: g_bStopSniff = TRUE; ss.dwWin32ExitCode = 0; ss.dwCurrentState = SERVICE_STOPPED; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; break; case SERVICE_CONTROL_PAUSE: <skip> default: rc = ERROR_CALL_NOT_IMPLEMENTED; break; } SetServiceStatus( hSS, &ss); return rc; }

Рабочим потоком может быть как, как собственно void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv), так и вторичный поток с функцией потока SniffThread:
void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv) { <skip> ss.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( hSS, &ss); hThread = _beginthreadex( NULL, 0, &SniffThread, NULL, 0, &thID ); if (! hThread) err(_T("Error creating sniffer thread.")); }

а код рабочего потока примитивен:

BOOL sniff( BOOL bDebug ) { WSAData wsaData; if (WSAStartup(0x0202,(WSADATA *) &wsaData )) { err( _T("Error WSAStartup"),WSAGetLastError()); return FALSE; } <skip … > SOCKET snfSock = socket( AF_INET, SOCK_RAW, IPPROTO_IP ); if( bind(snfSock, (SOCKADDR *)&sa, sizeof(SOCKADDR)) ) { err(_T("Error bind"),WSAGetLastError()); return FALSE; } <skip … > FILE* fl = _tfopen( szPathname, _T("w")); while( ! g_bStopSniff ) { <skip … > } closesocket( snfSock ); WSACleanup(); fclose( fl ); return TRUE; }

Понятно, что я хочу в этом примере. Если bStopSniff == TRUE, то я хочу остановить цикл while, прибить сокет snfSock и закрыть файл fl. Если там были выделены ещё какие-нить ресурсы, то хочу их освободить корректно.

В общем, что видится… Когда SCM вызывает хендлер ServiceCtrlHandler (SERVICE_CONTROL_STOP), то такое ощущение, что и ServiceMainProc и его вторичные потоки (если таковые были) – всё уже прибито SCM-ом ;( Поздно пить боржоми, чтобы чего-то там освободить ;((

Как быть, научите, плиз, недопрограммера ;)))
Остановить все потоки. установить свой статус в stopped... 24.05.04 00:18  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
> Подскажите, пожалуйста, как грамотно остановить сервис,
> обеспечить корректное завершение рабочего потока?
Остановить все потоки. Установить свой статус в STOPPED. Завершить выполнение ServiceMain.
> void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv)
> {
> <skip>
> ss.dwCurrentState = SERVICE_RUNNING;
> SetServiceStatus( hSS, &ss);
>
> hThread = _beginthreadex( NULL, 0, &SniffThread,
> NULL, 0, &thID );
> if (! hThread)
> err(_T("Error creating sniffer thread."));
>
> }
мм.. а дальше* ServiceMain должен завершаться только при завершении сервиса, а так висеть и к примеру ждать какого нить Mutex'а.
Сорри, Вы наверное про это и постили - то, что в конце я там... 24.05.04 02:07  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
Сорри, Вы наверное про это и постили - то, что в конце я там со Sleep пропостил.
1) Ты не понял. Рабочие потоки я могу создать, к примеру, в... 24.05.04 01:19  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> Остановить все потоки. Установить свой статус в STOPPED.

1) Ты не понял. Рабочие потоки я могу создать, к примеру, в ServiceMain. Дескрипторы этих потоков и всего, что в них создаётся ( сокетов, файлов и т.д.) я могу сделать, конечно глобальными. Но! Особождать ресурсы из другого потока (например, из которого вызывается хендлер SCM) и оттуда прибивать рабочие потоки при помощи BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode );
- ИМХО bad desing.
Потоки сами должны каким-то образом получить оповещение о том, что юзверь кликнул в остнастке SCM "stop". Они сами должны освободить ресурсы, которые ранее запрашивали, а затем функция потока должна завершиться, вернув 0.

2) Когда я пытаюсь что-то установить в хендлере сервиса (например, свой флаг STOP) , то подозреваю, что поток ServiceMain уже прибит силой SCM. Другими словами, когда в ServiceCtrlHandler я получаю dwControl = SERVICE_CONTROL_STOP, то все потоки рождённые от ServiceMain выглядят совершенно мёртвыми. В этих потоках невозможно по описанному сценарию проанализировать некую глобальную переменную STOP, и затем корректно самостоятельно завершить работу.

> Завершить выполнение ServiceMain.
> > void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR
> *lpszArgv)
> > {
> > <skip>
> > ss.dwCurrentState = SERVICE_RUNNING;
> > SetServiceStatus( hSS, &ss);
> >
> > hThread = _beginthreadex( NULL, 0, &SniffThread,
> > NULL, 0, &thID );
> > if (! hThread)
> > err(_T("Error creating sniffer thread."));
> >
> > }
> мм.. а дальше* ServiceMain должен завершаться только при
> завершении сервиса, а так висеть и к примеру ждать какого
> нить Mutex'а.

Ошибаешься ;)))) В той части, что ServiceMain умеет, что-то ждать (хоть там критической секции, хоть Mutex-ов;))), если в ServiceCtrlHandler ты получил dwControl = SERVICE_CONTROL_STOP и в ответ установил статус сервиса ss.dwCurrentState = SERVICE_STOPPED, то ServiceMain и все дочерние её потоки (если таковые были), будутнещадно_прибиты SCM. ;))
Ниже, совершенно рабочий код с_while(1)_в конце. ServiceMain ни в жисть не подвиснет там. ;)) Этот поток просто будет убиенным SCM-омо при остановке сервиса.

void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv) { <skip> ss.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( hSS, &ss); while(1); // здесь поток не подвиснет. С ним расправится SCM ;))) }
OOO !!! Вот я идиот. Но всё равно, подскажите 24.05.04 02:04  
Автор: void <Grebnev Valery> Статус: Elderman
Отредактировано 24.05.04 02:05  Количество правок: 1
<"чистая" ссылка>
Что называется, бывает хуже, но реже, блин....Добавил Sleep(1000). Естественно заработало ;)))
Т.е. та функция хендлера добавлена одной строчкой с :
DWORD WINAPI ServiceCtrlHandler( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext ) { DWORD rc = NO_ERROR; switch (dwControl) { case SERVICE_CONTROL_STOP: g_bStopSniff = TRUE; ss.dwWin32ExitCode = 0; ss.dwCurrentState = SERVICE_STOPPED; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; // HERE ;))) OOOOOOO !!!! Sleep(1000); break; case SERVICE_CONTROL_PAUSE: <skip> default: rc = ERROR_CALL_NOT_IMPLEMENTED; break; } SetServiceStatus( hSS, &ss); return rc; }

Это работает. Но всё же. Как делают программисты более грамотно. Может перед установкой ss.dwCurrentState = SERVICE_STOPPED делать так:
case SERVICE_CONTROL_STOP: bStopSniff = TRUE; ss.dwCurrentState = SERVICE_STOP_PENDING; ss.dwWaitHint = 1000; SetServiceStatus( hSS, &ss); Sleep(1000); ss.dwWin32ExitCode = 0; ss.dwCurrentState = SERVICE_STOPPED; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; break;

Как думают программисты?
тут уже был целый постинг с примерным сервисом на делфи правда 24.05.04 02:48  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
Вот тут - http://www.bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=104683
Да, внимательно не посмотрел вначале. Думал, что и так всё... 24.05.04 03:35  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> Вот тут -
> http://www.bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=1046
> 83
Да, внимательно не посмотрел вначале. Думал, что и так всё знаю. ;))) Чего смотреть ;))))
Конечно можно и так, при получении хендлером dwControl == SERVICE_CONTROL_STOP ответить только SetState(SERVICE_STOP_PENDING).
Далее дождаться эвента в рабочем потоке ServiceMain и там уже завершиться с установкой SetState(SERVICE_STOPPED).

Кстати, да. Так чисто получается ;)))
Ща мы тот код слямзим и отрехтуем в C ;)))
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2025 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach