Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
| | | | | | |
ну блин 05.05.06 14:04 Число просмотров: 3444
Автор: z0 <z0> Статус: Member
|
> Не производит. И lsass.exe и rpc-серверы (в svchost.exe с > соответствующими dll-ками) запускаются как сервисы. А любой > сервис в своей ServiceMain должен проинициализировать > таблицу SERVICE_TABLE_ENTRY-ей и вызвать > StartServiceCtrlDispatcher (эта функция кстати не > возвращается пока не завершатся все сервисы, > контроллируемые данным процессом). > Это тоже так, мысли вслух
это тебя великий и могучий МСДН так учит что и как надо делать в ServiceMain
а сами вот как пишут - цитата из lsass.exe (windows 2003 std gold)
.text:01001418 _main proc near ; CODE XREF: mainNoCRTStartup()+33p
.text:01001418
.text:01001418 var_1C = dword ptr -1Ch
.text:01001418 var_4 = dword ptr -4
.text:01001418
.text:01001418 push ebp
.text:01001419 mov ebp, esp
.text:0100141B push ecx
.text:0100141C push esi
.text:0100141D push 1 ; uMode
.text:0100141F call ds:__imp__SetErrorMode@4 ; SetErrorMode(x)
.text:01001425 push offset _LsaTopLevelExceptionHandler@4 ; lpTopLevelExceptionFilter
.text:0100142A call ds:__imp__SetUnhandledExceptionFilter@4 ; SetUnhandledExceptionFilter(x)
.text:01001430 push 1
.text:01001432 push 0
.text:01001434 push 1
.text:01001436 call ds:__imp__RtlSetProcessIsCritical
.text:0100143C add esp, 0Ch
.text:0100143F push 4
.text:01001441 lea eax, [ebp+var_4]
.text:01001444 push eax
.text:01001445 push 5
.text:01001447 push 0FFFFFFFFh
.text:01001449 mov [ebp+var_4], 9
.text:01001450 call ds:__imp__NtSetInformationProcess@16 ; NtSetInformationProcess(x,x,x,x)
.text:01001456 mov esi, eax
.text:01001458 test esi, esi
.text:0100145A jl short loc_10014B7
.text:0100145C call _LsapCheckBootMode@0 ; LsapCheckBootMode()
.text:01001461 mov esi, eax
.text:01001463 test esi, esi
.text:01001465 jl short loc_10014B7
.text:01001467 call _ServiceInit@0 ; ServiceInit()
.text:0100146C mov esi, eax
.text:0100146E test esi, esi
.text:01001470 jl short loc_10014B7
.text:01001472 call _LsapInitLsa@0 ; LsapInitLsa()
.text:01001477 mov esi, eax
.text:01001479 test esi, esi
.text:0100147B jl short loc_10014B7
.text:0100147D call _SamIInitialize@0 ; SamIInitialize()
.text:01001482 mov esi, eax
.text:01001484 test esi, esi
.text:01001486 jl short loc_10014B7
.text:01001488 call _LsapDsInitializePromoteInterface@0 ; LsapDsInitializePromoteInterface()
.text:0100148D mov esi, eax
.text:0100148F test esi, esi
.text:01001491 jl short loc_10014B7
.text:01001493 push 1
.text:01001495 call _LsapAuOpenSam@4 ; LsapAuOpenSam(x)
.text:0100149A mov esi, eax
.text:0100149C test esi, esi
.text:0100149E jl short loc_10014B7
.text:010014A0 call _SampUsingDsData@0 ; SampUsingDsData()
.text:010014A5 xor ecx, ecx
.text:010014A7 test al, al
.text:010014A9 setnz cl
.text:010014AC inc ecx
.text:010014AD mov eax, ecx
.text:010014AF push eax
.text:010014B0 call _LsapDsInitializeDsStateInfo@4 ; LsapDsInitializeDsStateInfo(x)
.text:010014B5 mov esi, eax
.text:010014B7
.text:010014B7 loc_10014B7: ; CODE XREF: _main+42j
.text:010014B7 ; _main+4Dj ...
.text:010014B7 push esi
.text:010014B8 call _LsapNotifyInitializationFinish@4 ; LsapNotifyInitializationFinish(x)
.text:010014BD push esi ; dwExitCode
.text:010014BE call ds:__imp__ExitThread@4 ; ExitThread(x)
.text:010014C4 int 3 ; Trap to Debugger
.text:010014C5
StartServiceCtrlDispatcher вызывается из отдельного треда, созданного внутри samsrv!ServiceInit()
чтобы не ждать пока она действительно не возвращается
он там спокойно не спеша полазит по реестру, инициализирует все свои RPC-шки
а основной поток lsass сразу на старте как хорошо видно выходит по ExitThread
спорим на поллитра?
|
<programming>
|
[Win32] Не создается поток 30.04.06 14:58 [Killer{R}]
Автор: makeworld Статус: Member
|
есть такой код. CreateThread() отрабатывает нормально, но признаков работы потока нет. использую VC++ 2005. не могу понять, в чем дело..
#include <windows.h>
#include <stdio.h>
void func();
DWORD WINAPI ThreadProc(LPVOID lParam);
int main() {
func();
return 0;
}
void func() {
unsigned int tid;
char test[30]={0};
memset(&test[0], 'A', 29);
printf("%s\n", test);
HANDLE hT1 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
HANDLE hT2 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
HANDLE hT3 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
if ((hT1 == INVALID_HANDLE_VALUE)| (hT2 == INVALID_HANDLE_VALUE)| (hT3 == INVALID_HANDLE_VALUE))
printf("failed\n");
int lastErr = GetLastError();
if (lastErr)
printf("last error = %d\n", lastErr);
}
DWORD WINAPI ThreadProc(LPVOID lParam) {
char *p = (char *)lParam;
// Sleep(100);
printf("i'm thread %d\n", GetCurrentThreadId());
printf("%s\n", p);
MessageBox(NULL, TEXT("test"), TEXT("test"), MB_OK);
return 0;
}
---
|
|
я бы использовал _beginthreadex. 03.05.06 05:09
Автор: void <Grebnev Valery> Статус: Elderman
|
я бы использовал _beginthreadex.
Со слипами я бы разобрался. Может не нады они? Регулировать переключение слипами не стал бы. Не угадаешь. Если уж надо чего-то ждать - используйте события.
|
| |
а чем _beginthreadex реально лучше? вроде же это обертка над... 03.05.06 16:34
Автор: makeworld Статус: Member
|
> я бы использовал _beginthreadex. > Со слипами я бы разобрался. Может не нады они? Регулировать > переключение слипами не стал бы. Не угадаешь. Если уж надо > чего-то ждать - используйте события.
а чем _beginthreadex реально лучше? вроде же это обертка над API функцией CreateThread
про синхронизацию это само собой
я просто не знал о том, что потоки завершаются автоматом при завершении главного потока
|
| | |
Это не ко мне. Это к Рихтеру. 04.05.06 05:24
Автор: void <Grebnev Valery> Статус: Elderman
|
|
| | |
В который раз замечаю, что меня не замечают (sic!) 03.05.06 17:24
Автор: amirul <Serge> Статус: The Elderman
|
- Доктор, меня игнорируют.
- Следующий
> я просто не знал о том, что потоки завершаются автоматом > при завершении главного потока
К винде это не имеет никакого отношения. Просто в C программа завершается при выходе из функции main. При его разработке никто не закладывался на многопоточность. Вот и приходится при выходе из main прибивать все "лишние" потоки. Если ты поставишь в настройках линкера точку входа, отличную от xxxCRTStartup (вместо xxx - всякие main, wmain, WinMain и wWinMain), то процесс у тебя не завершится (естественно большинством рантаймовых функций ты пользоваться не сможешь и аргументы argv/argc не получшь)
dl уже даже протестил:
http://bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=134498
|
| | | |
а вообще этим могла бы заниматься и система 03.05.06 19:46
Автор: dl <Dmitry Leonov>
|
Хэндл главного потока ей по крайней мере при создании процесса известен, могла бы и запомнить, после чего обработать так же, как рантайм.
|
| | | | |
Могла бы, но незачем 03.05.06 21:15
Автор: amirul <Serge> Статус: The Elderman
|
> Хэндл главного потока ей по крайней мере при создании > процесса известен, могла бы и запомнить, после чего > обработать так же, как рантайм.
Не вводи сущностей сверх необходимости и прочее.
А вообще красивый и управляемый код чаще всего имеет высокую степень обобщенности и симметрии. В том смысле, что если нет ОБЯЗАТЕЛЬНЫХ причин выделять какой либо один поток, то лучше не делать этого из эстетических соображений.
А рантайм занимается этим насколько я понимаю именно из за того, что стандарт C напрямую указывает завершать программу (независимо от того, в каком виде она представлена) при выходе из main. Насколько я помню в posix-е и потоков то нету. Один процесс - один поток исполнения (другое дело, что они могут разделять память, хендлы и пр.., но у каждого свой PID и такое прочее).
|
| | | | | |
эстетика дело такое 03.05.06 21:41
Автор: dl <Dmitry Leonov>
|
зато не нужно было бы таскать из программы в программу один и тот же код :)
|
| | | |
пост читал 03.05.06 17:31
Автор: makeworld Статус: Member
|
> К винде это не имеет никакого отношения. Просто в C > программа завершается при выходе из функции main. При его > разработке никто не закладывался на многопоточность. Вот и > приходится при выходе из main прибивать все "лишние" > потоки. Если ты поставишь в настройках линкера точку входа, > отличную от xxxCRTStartup (вместо xxx - всякие main, wmain, > WinMain и wWinMain), то процесс у тебя не завершится > (естественно большинством рантаймовых функций ты > пользоваться не сможешь и аргументы argv/argc не получшь) > > dl уже даже протестил: > http://bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m= > 134498
пост читал
теперь понятно, что дело в CRT, хотя в принципе, если создавать обычное приложение без изменения точки входа, откючения CRT и т.д., не важно на уровне CRT или на уровне ОС происходит принудительное завершение потоков, результат один и тот же.
|
| | | | |
[UPD]как сказать 03.05.06 17:36
Автор: Killer{R} <Dmitry> Статус: Elderman Отредактировано 03.05.06 17:46 Количество правок: 2
|
> пост читал > теперь понятно, что дело в CRT, хотя в принципе, если > создавать обычное приложение без изменения точки входа, > откючения CRT и т.д., не важно на уровне CRT или на уровне > ОС происходит принудительное завершение потоков, результат > один и тот же. как сказать
#include "windows.h"
DWORD CALLBACK trd(void *)
{
for(;;)Sleep(1000);
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
CreateThread(NULL,0,trd,NULL,0,NULL);
ExitThread(0);
return 0;
}
[UPD]
BTW у меня есть сильное подозрение что когда у процесса заканчиваюцца потоки умирает он тоже не по собственному желанию а по приказу csrss.exe
|
| | | | | |
Нет. Процесс убивается в ядре 03.05.06 17:59
Автор: amirul <Serge> Статус: The Elderman
|
> BTW у меня есть сильное подозрение что когда у процесса > заканчиваюцца потоки умирает он тоже не по собственному > желанию а по приказу csrss.exe
DECLSPEC_NORETURN
VOID
PspExitThread(
IN NTSTATUS ExitStatus
)
{
// [skipped]
Thread = PsGetCurrentThread();
Process = THREAD_TO_PROCESS(Thread);
// [skipped]
if ( (Process->ThreadListHead.Flink == Process->ThreadListHead.Blink)
&& (Process->ThreadListHead.Flink == &Thread->ThreadListEntry) ) {
LastThread = TRUE;
if ( ExitStatus == STATUS_THREAD_IS_TERMINATING ) {
if ( Process->ExitStatus == STATUS_PENDING ) {
Process->ExitStatus = Process->LastThreadExitStatus;
}
} else {
Process->ExitStatus = ExitStatus;
}
DbgkExitProcess(ExitStatus);
}
// [skipped]
if ( LastThread && Process->Win32Process ) {
(PspW32ProcessCallout)(Process,FALSE); // Вот тут он разрегистрируется в csrss-е
}
// [skipped]
//
// If this is the last thread in the process, then clean the address space
//
if ( LastThread ) {
if (!(ExChangeHandle(PspCidTable,Process->UniqueProcessId, PspMarkCidInvalid, PSP_INVALID_ID))) {
KeBugCheck(CID_HANDLE_DELETION);
}
KeQuerySystemTime(&Process->ExitTime);
PspExitProcess(TRUE,Process);
}
// [skipped]
}
---
Такие дела.
Да, все функции убивания потока заканчиваются в этой самой PspExitThread. Если TerminateThread вызван для текущего потока, то напрямую, а если для другого - через special APC
|
| | | | | |
ну я имел ввиду относительно моего примера 03.05.06 17:49
Автор: makeworld Статус: Member Отредактировано 03.05.06 17:53 Количество правок: 4
|
> #include "windows.h" > > DWORD CALLBACK trd(void *) > { > for(;;)Sleep(1000); > } > int WINAPI WinMain( > HINSTANCE hInstance, // handle to current instance > HINSTANCE hPrevInstance, // handle to previous instance > LPSTR lpCmdLine, // command line > int nCmdShow // show state > ) > { > CreateThread(NULL,0,trd,NULL,0,NULL); > ExitThread(0); > return 0; > }
ну я имел ввиду относительно моего примера. А так вообще конечно надежней было бы, если бы этим ОС занималась. Тут вообще конфликт получается. С одной стороны есть CRT, а с другой вполне легальная функция ExitThread(), которой до CRT и ее функций, вызываюшихся после выхода из main/WinMain и т.д., дела нет.
|
| | |
именно тем что это обертка над... 03.05.06 16:54
Автор: Killer{R} <Dmitry> Статус: Elderman
|
Она дает знать CRT о том что тред запускается/завершается. Если ты не юзаешь CRT'шные функции в треде (что маловероятно), то можно и CreateThread заюзать.
|
| | | |
т.е. CRT-шные функции, используемые в потоке, будут работать... 03.05.06 17:26
Автор: makeworld Статус: Member
|
> Она дает знать CRT о том что тред запускается/завершается.
т.е. CRT-шные функции, используемые в потоке, будут работать учитывая то, что выполняются внутри потока??
можно простой пример пользы от примения _beginthreadex
|
| | | | |
примерно так 03.05.06 19:43
Автор: dl <Dmitry Leonov>
|
Точнее, для глобальных данных, используемых этими функциями, будет сделана обертка, привязанная к конкретному потоку, так чтобы их совместное использование из разных потоков не привело к глюкам.
Хотя на самом деле все не так страшно и может даже проскочить:
"Ой, вместо _beginthreadex я по ошибке вызвал CreateThread
Вас, наверное, интересует, что случится, если создать поток не библиотечной функ цией _begintbreadex, а Windows-функцией CreateThread Когда этот поток вызовет какую-нибудь библиотечную функцию, которая манипулирует со структурой tiddata, произойдет следующее. (Большинство библиотечных функций реентерабсльно и не требует этой структуры ) Сначала эта функция попытается выяснить адрес блока дан ных потока (вызовом TleGetValue). Получив NULL вместо адреса tiddata, она узнает, что вызывающий поток не сопоставлен с таким блоком. Тогда библиотечная функция тут
же создаст и инициализирует блок tiddata для вызывающего потока. Далее этот блок будет сопоставлен с потоком (через TlsSetValue) и останется при нем до тех пор, пока выполнение потока нс прекратится, С этого моменга данная функция (как, впрочем, и любая другая из библиотеки С/С++) сможет пользоваться блоком tiddata потока.
Как это ни фантасгично, но Ваш поток будет работать почти без глюков. Хотя некоторые проблемы все же появятся. Во-первых, если этот поток воспользуется биб лиотечной функцией signal, весь процесс завершится, так как SEH-фрейм не подго товлен. Во-вторых, если поток завершится, не вызвав endtbreadex, его блокданных не высвободится и произойдет утечка памяти. (Да и кто, интересно, вызовет end threadex иэ потока, созданного с помощью CreateTbread?)".
|
| | | | | |
ясно, спасибо. 03.05.06 20:03
Автор: makeworld Статус: Member
|
ясно, спасибо.
хотя signal не самая часто используемая функция, повод для использования именно CRT-обертки создания потока существенный
|
| | | | | | |
есть такие понятия как documentation и implementation 03.05.06 20:33
Автор: Killer{R} <Dmitry> Статус: Elderman
|
так вот если в документации написано чтотоНАДОделать так, а на практике известно что в принципе работает и по другому писать надо все равно именноТАКкак написано. Тк имплементация данной функции может поменяться как угодно любым хотфиксом, функция будет работать так как написано в документации, но не так как работала в прошлой версии CRT. В результате - юзера ругают программистов, пишут в техсуппорт, техсуппорт отправляет это дело манагерам, манагеры - ковыряют кто написал код который только делает вид что работает и увольняют его. Вот это основная причина почему надо юзать _beginthreadex вместо CreateThread, а не особенность поведения signal в внештатной ситуации в конкретной имплементации CRT.
|
| | | | |
Есть такое слово 03.05.06 17:31
Автор: Killer{R} <Dmitry> Статус: Elderman Отредактировано 03.05.06 17:33 Количество правок: 1
|
надо
Что и как там работает - тебя вообще в данном случае не должно интересовать, и если в конкретной версии CRT и твоих исходников CreateThread работает нормально это не значит что всегда так будет.
http://www.flounder.com/badprogram.htm
|
| | | | | |
Кстати, в VC 2005 нет single-threaded libraries, есть только... 03.05.06 19:56
Автор: makeworld Статус: Member
|
> надо > Что и как там работает - тебя вообще в данном случае не > должно интересовать, и если в конкретной версии CRT и твоих > исходников CreateThread работает нормально это не значит > что всегда так будет.
Кстати, в VC 2005 нет single-threaded libraries, есть только multi-threaded, и по дефолту для Debug-сборки стоит Multi-threaded Debug DLL, а для Release - Multi-threaded DLL. Т.е. главные довод, приведенный в линке, отбрасывается.
Хотя в принципе, ради избежания гемора с CRT функциями в потоках в будущем, лучше наверное использовать _beginthreadex.
CreateThread in a C program
|
|
и будет тебе счастье :) 30.04.06 16:10
Автор: ggg <ggg> Статус: Elderman
|
и будет тебе счастье :)
> > int main() { > func(); !!!!!!!!! Sleep(5000);
> return 0; > } >
правда счастье будет длиться 5 секунд :)
|
|
|