windowsnetwork-programmingthread-safetythreadpoolnetapi32

NetServerEnum create Worker Threads who won't close


While trying to solve a previously asked SO question of mine, I've find that even without my threads, the problem occurs.

what I have now , is a really simple single-threaded code , that calls - NetServerEnum() . when returned, it calls NetApiBufferFree() and return from main, which supposed to end the process. at that point, my thread truly ends, but the process won't exit , as there are 4 threads opened (not by me):

1 * ntdll.dll!TplsTimerSet+0x7c0 (stack is at ntdll.dll!WaitForMultipleObjects)

(This one opened upon the call to NetServerEnum())

3 * ndll.dll!RtValidateHeap+0x170 (stack is at ntdll.dll!ZwWaitWorkViaWorkerFactory+0xa)

(These are open when my code returns)

UPDATE: If I kill the thread running ntdll.dll!TplsTimerSet+0x7c0 externally (using process explorer) , before return of main(), the program exit gracefully. I thought it might be useful to know.

UPDATE2: (some more tech info) I'm using: MS Visual Studio 2010 Ultimate x64 (SP1Rel) on Win7 Enterprise SP1 Code is C (but compile as c++ switch is on) Subsystem: WINDOWS Compiler: cl.exe (using IDE) all other parameters are default.

I'm Using a self modified entry point (/ENTRY:"entry") , and it is the only function In my program):

int entry(void)
{
SERVER_INFO_101* si;
DWORD a,b;
NET_API_STATUS c;
c = NetServerEnum ( NULL , 101 , (LPBYTE*) &si , MAX_PREFERRED_LENGTH , &b ,  &a  , SV_TYPE_WORKSTATION, NULL , 0 );

c = NetApiBufferFree (si);

Sleep(1000);

return 0;

}

all the tested mentioned before where preformed inside a windows domain network of about 100 units.

UPDATE 3: This problem does not occur when tested on a (non-virtual) WinXP 32bit. (same binary, though for the Win7 x64 two binary were tested - 32bit over WOW , and native x64)


Solution

  • When you use a custom entry point, you're bypassing the runtime library, which means you're responsible for exiting the process. The process will exit implicitly if there are no more threads running, but as you've discovered, the operating system may create threads on your behalf that you don't have control over.

    In your case, all you need to do is to call ExitProcess explicitly at the end of the entry() function.

    int entry(void)
    {
       SERVER_INFO_101* si;
       DWORD a,b;
       NET_API_STATUS c;
    
       c = NetServerEnum ( NULL , 101 , (LPBYTE*) &si , MAX_PREFERRED_LENGTH , &b ,  &a  , SV_TYPE_WORKSTATION, NULL , 0 );
    
       c = NetApiBufferFree (si);
    
       Sleep(1000);
    
       ExitProcess(0);
    }
    

    In the absence of a call to ExitProcess and with a custom entry point, the behaviour you're seeing is as expected.