mirror of
https://github.com/dlang/phobos.git
synced 2025-05-09 21:11:57 +03:00
189 lines
6.1 KiB
D
189 lines
6.1 KiB
D
// Written in the D programming language
|
|
|
|
/*
|
|
* Copyright (C) 2010 by Digital Mars, http://www.digitalmars.com
|
|
* Written by Rainer Schuetze
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* o The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* o Altered source versions must be plainly marked as such, and must not
|
|
* be misrepresented as being the original software.
|
|
* o This notice may not be removed or altered from any source
|
|
* distribution.
|
|
*/
|
|
|
|
/**
|
|
* This module provides OS specific helper function for threads support
|
|
*/
|
|
|
|
module std.thread_helper;
|
|
|
|
version( Windows )
|
|
{
|
|
import std.c.windows.windows;
|
|
import std.c.stdlib;
|
|
|
|
public import std.thread;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
const SystemProcessInformation = 5;
|
|
const STATUS_INFO_LENGTH_MISMATCH = 0xc0000004;
|
|
|
|
// abbreviated versions of these structs
|
|
struct _SYSTEM_PROCESS_INFORMATION
|
|
{
|
|
int NextEntryOffset; // When this entry is 0, there are no more processes to be read.
|
|
int NumberOfThreads;
|
|
int[15] fill1;
|
|
int ProcessId;
|
|
int[28] fill2;
|
|
|
|
// SYSTEM_THREAD_INFORMATION or SYSTEM_EXTENDED_THREAD_INFORMATION structures follow.
|
|
}
|
|
|
|
struct _SYSTEM_THREAD_INFORMATION
|
|
{
|
|
int[8] fill1;
|
|
int ProcessId;
|
|
int ThreadId;
|
|
int[6] fill2;
|
|
}
|
|
|
|
alias extern(Windows)
|
|
HRESULT fnNtQuerySystemInformation( uint SystemInformationClass, void* info, uint infoLength, uint* ReturnLength );
|
|
|
|
const ThreadBasicInformation = 0;
|
|
|
|
struct THREAD_BASIC_INFORMATION
|
|
{
|
|
int ExitStatus;
|
|
void** TebBaseAddress;
|
|
int ProcessId;
|
|
int ThreadId;
|
|
int AffinityMask;
|
|
int Priority;
|
|
int BasePriority;
|
|
}
|
|
|
|
alias extern(Windows)
|
|
int fnNtQueryInformationThread( HANDLE ThreadHandle, uint ThreadInformationClass, void* buf, uint size, uint* ReturnLength );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// support attaching to thread other than just executing
|
|
void** getTEB( HANDLE hnd )
|
|
{
|
|
HANDLE nthnd = GetModuleHandleA( "NTDLL" );
|
|
assert( nthnd, "cannot get module handle for ntdll" );
|
|
fnNtQueryInformationThread* fn = cast(fnNtQueryInformationThread*) GetProcAddress( nthnd, "NtQueryInformationThread" );
|
|
assert( fn, "cannot find NtQueryInformationThread in ntdll" );
|
|
|
|
THREAD_BASIC_INFORMATION tbi;
|
|
int Status = (*fn)(hnd, ThreadBasicInformation, &tbi, tbi.sizeof, null);
|
|
assert(Status == 0);
|
|
|
|
return tbi.TebBaseAddress;
|
|
}
|
|
|
|
extern(Windows)
|
|
HANDLE OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
|
|
|
|
const SYNCHRONIZE = 0x00100000;
|
|
const THREAD_GET_CONTEXT = 8;
|
|
const THREAD_QUERY_INFORMATION = 0x40;
|
|
const THREAD_SUSPEND_RESUME = 2;
|
|
|
|
void** getTEB( uint id )
|
|
{
|
|
HANDLE hnd = OpenThread( THREAD_QUERY_INFORMATION, FALSE, id );
|
|
assert( hnd, "OpenThread failed" );
|
|
|
|
void** teb = getTEB( hnd );
|
|
CloseHandle( hnd );
|
|
return teb;
|
|
}
|
|
|
|
void* getThreadStackBottom( HANDLE hnd )
|
|
{
|
|
void** teb = getTEB( hnd );
|
|
return teb[1];
|
|
}
|
|
|
|
void* getThreadStackBottom( uint id )
|
|
{
|
|
void** teb = getTEB( id );
|
|
return teb[1];
|
|
}
|
|
|
|
HANDLE OpenThreadHandle( uint id )
|
|
{
|
|
return OpenThread( SYNCHRONIZE|THREAD_GET_CONTEXT|THREAD_QUERY_INFORMATION|THREAD_SUSPEND_RESUME, FALSE, id );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
// support attaching to all running threads
|
|
// using function instead of delegate here to avoid allocating closure
|
|
bool enumProcessThreads( uint procid, bool function( uint id, void* context ) dg, void* context )
|
|
{
|
|
HANDLE hnd = GetModuleHandleA( "NTDLL" );
|
|
fnNtQuerySystemInformation* fn = cast(fnNtQuerySystemInformation*) GetProcAddress( hnd, "NtQuerySystemInformation" );
|
|
if( !fn )
|
|
return false;
|
|
|
|
uint sz = 16384;
|
|
uint retLength;
|
|
HRESULT rc;
|
|
char* buf;
|
|
for( ; ; )
|
|
{
|
|
buf = cast(char*) std.c.stdlib.malloc(sz);
|
|
if(!buf)
|
|
return false;
|
|
rc = (*fn)( SystemProcessInformation, buf, sz, &retLength );
|
|
if( rc != STATUS_INFO_LENGTH_MISMATCH )
|
|
break;
|
|
std.c.stdlib.free( buf );
|
|
sz *= 2;
|
|
}
|
|
scope(exit) std.c.stdlib.free( buf );
|
|
|
|
if(rc != 0)
|
|
return false;
|
|
|
|
auto pinfo = cast(_SYSTEM_PROCESS_INFORMATION*) buf;
|
|
auto pend = cast(_SYSTEM_PROCESS_INFORMATION*) (buf + retLength);
|
|
for( ; pinfo < pend; )
|
|
{
|
|
if( pinfo.ProcessId == procid )
|
|
{
|
|
auto tinfo = cast(_SYSTEM_THREAD_INFORMATION*)(pinfo + 1);
|
|
for( int i = 0; i < pinfo.NumberOfThreads; i++, tinfo++ )
|
|
if( tinfo.ProcessId == procid )
|
|
if( !dg( tinfo.ThreadId, context ) )
|
|
return false;
|
|
}
|
|
if( pinfo.NextEntryOffset == 0 )
|
|
break;
|
|
pinfo = cast(_SYSTEM_PROCESS_INFORMATION*) (cast(char*) pinfo + pinfo.NextEntryOffset);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool enumProcessThreads( bool function( uint id, void* context ) dg, void* context )
|
|
{
|
|
return enumProcessThreads( GetCurrentProcessId(), dg, context );
|
|
}
|
|
|
|
|
|
}
|
|
|