Sistemas Operativos
Processos e threads no Windows
João Pedro Patriarca (jpatri@cc.isel.ipl.pt)
Centro de Cálculo
Visão conceptual (simplista) de Processo e Thread
• Processo:
1. Objecto kernel usado pelo sistema operativo para gerir o processo
2. Espaço de endereçamento que contém o módulo executável, DLL’s,
stacks e heaps
• Thread:
1. Objecto kernel usado pelo sistema operativo para gerir a thread
2. Stack da thread onde são mantidos os parâmetros e variáveis locais das funções em execução no contexto da thread
Função CreateProcess
BOOL CreateProcess(
PCTSTR pszApplicationName,
PTSTR pszCommandLine,
PSECURITY_ATTRIBUTES psaProcess,
PSECURITY_ATTRIBUTES psaThread,
BOOL bInheritHandles,
DWORD fdwCreate,
PVOID pvEnvironment,
PCTSTR pszCurDir,
PSTARTUPINFO psiStartInfo,
PPROCESS_INFORMATION ppiProcInfo);
Pode ter o valor NULL (o primeiro token do próximo parâmetro deverá indicar o nome da aplicação)
Pode ser NULL; Consultar bib:
http://msdn.microsoft.com/
en-us/library/ms682425(v=vs.85)
Indicam se os handles retornados
são herdáveis por futuros processos filhos. A NULL, os handles não são herdáveis
Indica se o processo filho herdará os
handles herdáveis do processo pai Flags que controlam a classe de prioridade
e a criação do processo
Pode ter o valor NULL, herdando as variáveis de ambiente do pai
A NULL, a directoria é a mesma do processo pai; caso contrário, deverá incluir a drive e directoria
Inicialização mínima (consultar bib):
STARTUPINFO si = { sizeof(si) }; CreateProcess( ..., &si, ...);
typedef struct _PROCESS_INFORMATION { HANDLE hProcess;
HANDLE hThread; DWORD dwProcessId;
Parâmetro fdwCreateFlags
• O valor 0 coloca a thread principal do novo processo na fila de
threads Ready
• Controlo da criação do processo
– CREATE_DEBUG, CREATE_SUSPENDED, CREATE_NEW_CONSOLE, CREATE_NO_WINDOW, DETACHED_PROCESS
• Classes de prioridade:
– REALTIME_PRIORITY_CLASS, HIGH_PRIORITY_CLASS,
ABOVE_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS,
BELOW_NORMAL_PRIORITY_CLASS, IDLE_NORMAL_PRIORITY_CLASS – Normalmente não é especificado: processos criados com a prioridade
Criação de processo – passos
Convert and validate parameters and flags
Perform Windows-subsystem specific process initialization
Open EXE and create section object Create Windows process
object
Create Windows thread object
Start execution of the initial thread
Return to caller
Set up for new process and thread Final process/image initialization Start execution at entry point Stage 1 Stage 2 Stage 3 Stage 4 Stage 5 Stage 6 Stage 7 Creating process Windows subsystem New process
Terminação de um processo
• Cenários em que um processo pode terminar
– A função de entrada da thread primária retorna (forma adequada de terminar uma thread)
– Uma thread do processo chama a função ExitProcess (evitar este
método)
– Uma thread noutro processo chama a função TerminateProcess (evitar
este método)
– Todas as threads do processo terminam por si mesmas (raramente acontece)
Terminação de um processo
A função de entrada da thread primária retorna
• O retorno desta forma garante:
– Qualquer objecto C++ criado pela thread será destruído usando o seu destrutor
– Libertação da memória associada ao stack da thread
– O sistema afecta o código de saída (mantido no objecto kernel do processo) como valor de retorno da função de entrada
– O sistema decrementa o contador de referências do objecto kernel processo
Terminação de um processo
Função ExitProcess
VOID ExitProcess(UINT fuExitCode);
• Termina o processo e afecta como código de saída o valor do
parâmetro
fuExitCode
• Esta função não retorna
• No runtime C/C++, quando a thread primária retorna da função de
entrada (main), retorna para o código de startup
– Chama as funções registadas (atexit(pfunc)) para serem executadas
na conclusão do programa
– Chama os destrutores dos objectos alocados estaticamente – Aguarda que as threads deste processo terminem
– Chama a função ExitProcess
• Se a thread primária terminar com a função ExitThread, o processo
só termina se não existirem mais threads no processo
Terminação de um processo
Função TerminateProcess
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);
• Distingue-se da função ExitProcess por poder ser chamada por
qualquer thread dentro ou fora do processo
• Usar apenas na condição de não se conseguir terminar o processo
por qualquer outro método
• O sistema garante que os recursos associados ao processo são
completamente eliminados
• Acção de terminação assíncrona o que justifica a chamada da função
WaitForSingleObject para determinar a conclusão do processo
Terminação de um processo
Todas as threads do processo terminam por si mesmas
• Todas as thread retornam da função de entrada ou chamam a função
ExitThread ou a função TerminateThread
• Numa situação destas, o sistema termina o processo marcando o
código de saída do processo com o valor do código de saída da
última thread que terminou
Terminação de um processo
Acções realizadas
• Termina as threads ainda existentes no processo
• Todos os objectos User e GDI alocados ao processo são libertados
• Todos os objectos kernel são fechados e eliminados se os
contadores de referências dos objectos atingiram o valor 0
• O código de saída do processo altera de
STILL_ACTIVE (0x103) para
o valor passado na função ExitProcess ou TerminateProcess
• O objecto kernel processo é sinalizado (para efeitos de
sincronização)
• O contador de referências do objecto kernel processo é
decrementado
BOOL GetExitCodeProcess(
HANDLE hProcess,
Processo filho
PROCESS_INFORMATION pi; DWORD dwExitCode;
// Spawn the child process.
BOOL fsuccess = CreateProcess(..., &pi);
if (fsuccess) {
// Close the thread handle as soon as it is no longer needed!
CloseHandle(pi.hThread);
// Suspend our execution until the child has terminated.
WaitForSingleObject(pi.hProcess, INFINITE);
// The child process terminated; get its exit code.
GetExitCodeProcess(pi.hProcess, &dwExitCode);
// Close the process ahndle as soon as it is no longer needed.
CloseHandle(pi.hProcess);
// Detached child process.
PROCESS_INFORMATION pi; BOOL fsuccess = CreateProcess(..., &pi); if (fsuccess) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); }
demo11
Terminate process and free resources
• As experiências, de 1 a 5, ilustram o comportamento na libertação dos recursos alocados nas diferentes formas de terminar um processo
Visão conceptual (simplista) de Processo e Thread
• Processo:
1. Objecto kernel usado pelo sistema operativo para gerir o processo 2. Espaço de endereçamento que contém o módulo executável, DLL’s,
stacks e heaps
• Thread:
1. Objecto kernel usado pelo sistema operativo para gerir a thread
2. Stack da thread onde são mantidos os parâmetros e variáveis locais das
funções em execução no contexto da thread
Função CreateThread
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD cbStackSize,
PTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreateFlags,
PDWORD pdwThreadID);
• Na escrita de programas em C/C++ dever-se-á usar a função
_beginthreadex em vez de CreateThread
Pode ter o valor NULL (atributos de segurança por omissão). Pode ser usado para determinar se um objecto processo filho tem acesso ao objecto kernel thread criado por esta função
Memória que ficará committed
inicialmente. O valor 0 usa os valores presentes na imagem do executável.
DWORD WINAPI <threadFuncName>( PVOID param);
O retorno corresponde ao valor de saída (idêntico ao valor de retorno da função main)
Pode ter o valor NULL Valor 0: a thread pode ser colocada de imediato em execução Valor CREATE_SUSPENDED: a thread sai do estado Suspended quando for
CreateThread steps
1. Transforma parâmetros Windows API em flags nativas e constrói
estrutura nativa que descreve os parâmetros objecto
2. Constrói lista de atributos com duas entradas: client ID e endereço TEB
3. NtCreateThread é chamada para criar o contexto do User. Depois
chama PspCreateThread para criar um objecto Executive thread suspensa
4. CreateThread realiza acções associadas com o stack
5. CreateThread notifica o subsistema Windows acerca da nova thread
para que realize algumas inicializações
6. O handle da nova thread e o seu ID são retornados para o chamador
7. A menos que a thread tenha sido criada com a flag CREATE_SUSPENDED
activa, a thread é colocada na fila de threads ready para ser colocada em execução pelo scheduler. Nessa altura executa o passo 7 descrito na iniciação de um processo já no contexto do User
Terminação de uma thread
• Cenários em que uma thread pode terminar
– A função correspondente ao ponto de entrada da thread retorna (método adequado)
– A thread mata-se a si própria chamando a função ExitThread (evitar
este método)
– Uma qualquer thread deste processo chama a função TerminateThread
(evitar este método)
Terminação de uma thread
A função correspondente ao ponto de entrada retorna
• O retorno desta forma garante:
– Todos os objectos C++ criados no âmbito da thread são destruídos apropriadamente com a chamada dos destrutores respectivos
– O sistema liberta a memória associada ao stack da thread
– O sistema afecta o código de saída (mantido no objecto kernel da thread) como valor de retorno da função de entrada
– O sistema decrementa o contador de referências do objecto kernel
thread
Terminação de uma thread
Função ExitThread
VOID ExitThread(DWORD dwExitCode);
• Termina a thread e o sistema operativo elimina todos os recursos
alocados à thread
• Recursos correspondentes a objectos C/C++ não são devidamente
destruídos
• Esta função não retorna
• Na escrita de programas em C/C++ dever-se-á usar a função
_endthreadex em vez de ExitThread
Terminação de uma thread
Função TerminateThread
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);
• Distingue-se da função ExitThread por poder ser chamada por
qualquer thread dentro do processo
• Usar apenas na condição de não se conseguir terminar a thread por
qualquer outro método
• Acção de terminação assíncrona o que justifica a chamada da função
WaitForSingleObject para determinar a conclusão da thread
• Ao contrário da função ExitThread, o stack da thread não é
eliminado com a chamada de
TerminateThread
– Qualquer outra thread que mantenha uma referência para uma variável no stack da thread terminada não recebe excepção quando aceder a essa posição de memória
Terminação de uma thread
Terminação de um processo
• As funções ExitProcess e TerminateProcess terminam todas as
threads contidas no processo
– Todos os recursos do processo serão eliminados incluindo os stacks das
threads
– Contudo não destrói adequadamente todos os recursos
• Não executa os destrutores dos objectos C++ • Não despeja os buffers em memória no disco • ...
• No runtime C/C++ quando a função
main da thread primária retorna
é chamada a função ExitProcess
Terminação de uma thread
Acções realizadas
• Liberta todos os handles de objectos User mantidos pela thread
• O código de saída da thread altera de STILL_ACTIVE (0x103) para o
valor passado na função
ExitThread ou TerminateThread
• O objecto kernel thread é sinalizado (para efeitos de sincronização)
• Se a thread for a última thread activa do processo, o sistema
considera o processo terminado também
• O contador de referências do objecto kernel thread é decrementado
BOOL GetExitCodeThread(
HANDLE hThread,
demo12
Terminate thread and free resources
• As experiências, de 1 a 5, ilustram o comportamento na libertação dos recursos alocados nas diferentes formas de terminar uma thread
Aspectos internos da thread quando iniciada
VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam) { __try {
ExitThread((pfnStartAddr)(pvParam)); }
__except(UnhandledExceptionFilter(GetExceptionInformation())) {
Other CPU registers CONTEXT
Thread Kernel object
Usage count = 2
Exit code = STILL_ACTIVE Suspend count = 1 Signaled = FALSE Other properties and statistics EIP SP pvParam pfnStartAddr . . . . Low address High address VOID RtlUserThreadStart(...) { ... } Thread stack NTDLL.dll
bib: Windows via C/C++, Richter, Nasarre, 5ª edição, fig. 6-1
Thread scheduling
• Dispatch
– Conjunto de código associado ao despacho de threads, preemptivo e baseado em prioridades
– Execução no âmbito do kernel
– Uma thread tem um tempo limite de posse do CPU (Quantum)
• Uma thread pode usar menos tempo que o seu Quantum
– Quando acontece necessidade de scheduling (context switch)?
• Uma nova thread ficou ready para executar
• A thread corrente em execução deixou o estado ready ou atingiu o seu Quantum • A prioridade de uma thread alterou
• A afinidade de uma thread a um processador alterou
– O sistema Windows é preemptivo
Dispatcher database
31 0 CPU 0 ready queues Ready summary Deferred Thread 1 Thread 2 Process Thread 3 Thread 4 Process 31 0 CPU 1 ready queues Ready summary Deferred 0 31 31 0 Campo KPRCB TipoReadySummary Bitmask (32 bits)
DeferredReadyListHead Lista simplesmente ligada
DispatcherReadyListHead Array de 32 entradas
Cenários de Scheduling
• Mudança voluntária
• Preempção
• Fim do quantum
Priority Running Ready 18 ... 16 14 ... To wait state
Priority Running Ready 18
... 16
14 ...
From Wait state
Priority Running Ready 15
14 13
Níveis de prioridade
• Nativo versus subsistema Windows
• Mapeamento
• Noção de prioridade base e prioridade corrente (no caso de threads)
• Alteração da prioridade base
– software
– comando de linha start (experimentar a aplicação Notepad e observar com o Task Manager)
Prioridades de processos e threads
Mapeamento entre sistema nativo e subsistema Windows
Real-time Levels 16-31 31 0 15 1 16 Real-time time critical
Real-time idle Dynamic time critical
Dynamic Levels 1-15
Dynamic idle
Level 0: Used for zero page thread; not available to Win32 applications
• Processo: classe de prioridade
• Thread:
– Prioridade base = Fx(classe de prioridade, prioridade relativa) – Prioridade corrente = prioridade base + boost priority
• Alteração da classe de prioridade
– Parâmetro fdwCreate da função CreateProcess – Linha de comando, com o comando Start:
> start /low notepad
– Após criação, com a função SetPriorityClass Prioridades nativas
Relative
Thread Priority
Process Priority Class Idle Below Normal Normal Above Normal High Real-Time Time-critical 15 15 15 15 15 31 Highest 6 8 10 12 15 26 Above normal 5 7 9 11 14 25 Normal 4 6 8 10 13 24 Below normal 3 5 7 9 12 23 Lowest 2 4 6 8 11 22
Programação de prioridades
Funções relevantes
Estados da thread
• Ready (1)
– Thread à espera para ser executada;
– O dispatcher olha para este pool de threads quando procura por uma thread para colocar em execução
• Deferred ready (7): threads que foram seleccionadas para execução num determinado
CPU mas que ainda não foram scheduled
• Standby (3): thread seleccionada para ser a próxima a correr num determinado CPU;
apenas uma thread neste estado por CPU no sistema
• Running (2)
– Uma thread entra no estado Running quando o dispatcher executa o Context Switch – A execução continua até terminar o seu quantum, ser preemptida por outra thread
com maior prioridade, terminar, ou entrar no estado Wait voluntariamente
• Waiting (5)
– Entra neste estado: por vontade própria (objectos de sincronização); o sistema operativo entrou no estado Wait no contexto da thread; entre outros
– Quando sai deste estado poderá ser colocada de novo em execução ou na lista de
threads Ready
• Gate Waiting (8): entra neste estado quando espera por um objecto gate dispatcher (cap. 3)
• Transition (6): entra neste estado quando a thread está preparada para execução mas ainda lhe faltam recursos em memória (kernel stack)
• Terminated (4): entra no estado quando a thread termina a execução
Transição entre estados numa thread
Ready Waiting or Gate waiting Deferred ready Transition Init Terminate Standby Running preempt preemption, quantum end voluntary switchQuantum
• Quantidade de tempo que uma thread possui o CPU
– A partir do Window Vista = 2 intervalos de clock – Windows Server 2008 = 12 intervalos de clock – 1 intervalo de clock (aproximadamente)
• x86, uniprocessador = 10 ms
• 64bits ou multiprocessador = 15 ms
• Quantum boosting
– Quando um processo é colocado em foreground as threads têm o seu quantum triplicado
Afinidade a CPUs
CPU0 CPU1 CPU2 CPU3 Memory Board 1 CPU4 CPU5 CPU6 CPU7 Memory Board 2 CPU8 CPU9 CPU10 CPU11 Memory Board 3 NUMA MachineLinhas de cache num contexto multiprocessador
• Cenário:
– CPU1 lê 1 byte. O byte solicitado e adjacentes são carregados na cache do CPU1
– CPU2 lê o mesmo byte. Os mesmos bytes são carregados na cache do CPU2
– CPU1 altera o byte lido
• O respectivo byte na cache do CPU2 fica inválido; a arquitectura garante a marcação como inválida da linha de cache do CPU2
• Boas práticas:
– Um CPU deverá ter as suas variáveis em memória agrupadas numa linha de cache: as variáveis de um programa que sejam acedidas num intervalo de tempo curto deverão ser declaradas próximas
– Evitar que dois ou mais CPU’s partilhem variáveis em memória: threads que partilhem recursos deverão ter afinidade ao mesmo CPU
– Separar dados de leitura apenas dos dados que serão lidos e escritos
• Usar a directiva para o compilador C/C++ __declspec(align(#)) int __declspec(align(CACHE_ALIGN)) var;
Como garante o sistema justiça na distribuição do CPU
Priority boost
• Cenários onde pode acontecer um priority boost
(as unidades incrementadas dependem do cenário em causa)1. Na conclusão de uma operação I/O completion
2. Depois de concluir uma acção de espera por eventos ou semáforos
3. Depois das threads de um processo foreground completarem uma
operação de Wait
4. Quando threads GUI acordam
5. Quando uma thread está Ready há demasiado tempo sem ser colocada
em execução (CPU starvation)
• Por cada quantum gasto em execução é decrementada a sua
prioridade até atingir o valor da prioridade base
– Uma thread nestas condições pode ser preemptida por outra de maior prioridade; a thread não perde o seu quanto de execução com a
Priority boost
Funções relevantes
BOOL SetProcessPriorityBoost( HANDLE hProcess,
BOOL bDisablePriorityBoost); // true: disable all
// process thread’s boost BOOL GetProcessPriorityBoost(
HANDLE hProcess,
PBOOL pbDisablePriorityBoost); BOOL SetThreadPriorityBoost(
HANDLE hThread,
BOOL bDisablePriorityBoost); // true: disable thread // boost
BOOL GetThreadPriorityBoost( HANDLE hThread,
Idle thread
• Idle thread é a thread com menor prioridade (incluindo a Zero Page
thread com nível de prioridade 0)
• A Idle thread, na realidade, não tem prioridade
• Apenas é colocada em execução quando não existir nenhuma outra
thread no estado Ready
Threads Schuduling
•Funções utilizadas na demo:
– SetProcessAffinityMask; – SetThreadAffinityMask; – SetThreadPriority;
– SetProcessPriorityBoost – SuspendThread;
Considerações sobre a biblioteca runtime C/C++
• Preocupações com a biblioteca standard do C num cenário de
programação concorrente
– A biblioteca na sua génese não previa execução concorrente – Variáveis com alocação estática: errno, strtok, strerror, ...
• Solução:
– Cada thread tem as variáveis globais da biblioteca reunidas num bloco – O bloco fica alojado num espaço de endereçamento pertencente à
thread (TLS – Thread Local Storage)
• Problema: Como associar o bloco a uma thread?
• Solução: Chamando a função
_beginthreadex em vez da função
CreateThread
Função _beginthreadex (pseudocódigo)
• O chamador deverá mapear os tipos dos argumentos da função CreateThread para a função _beginthreadex
uintptr_t __cdecl _beginthreadex( void* psa, unsigned cbStackSize,
unsigned (__stdcall * pfnStartAddr) (void*), void* pvParam,
unsigned dwCreateFlags, unsigned * pdwThreadID) { _ptiddata ptd; // Pointer to thread’s data block
uintptr_t thdl; // Thread handles // Allocate data block for the new thread
if ((ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) ==NULL) goto error_return;
initptd(ptd); // Initialize data block
// Save desired thread function and parameter
ptd->_initaddr = (void*)pfnStartAddr; ptd->_initarg = pvParam;
ptd->handle = (uintptr_t)(-1); // Create the new thread
thdl = (uintptr_t)CreateThread((LPSECURITY_ATTRIBUTES)psa, cbStackSize, _threadstartex, (PVOID)ptd, dwCreateFlags, pdwThreadID);
if (thdl == 0) goto error_return; return (thdl); error_return: _free_crt(ptd); return ((uintptr_t)0L); }
Considerações sobre a biblioteca runtime C/C++
As funções _beginthreadex, _threadstartex, _callthreadstartex e _endthreadex estão definidas no módulo <Visual Studio pathname>\vc\crt\src\threadex.c
Função _threadstartex (pseudocódigo)
static unsigned long WINAPI _threadstartex( void* ptd) {
// Associate the tiddata block with this thread so _getptd() // will be able to find it in _callthreadstartex
TlsSetValue(__tlsindex, ptd);
((_ptiddata)ptd)->_tid = GetCurrentThreadId(); // save this thread ID // ... initializations not relevant
_callthreadstartex(); // call helper function
// The execution code should never reach here //(the thread dies in _callthreadstartex)
return (0L); }
Função _callthreadstartex (pseudocódigo)
static void _callthreadstartex( void* ptd) {
_ptiddata ptd; // Pointer to thread’s data block
// Get the pointer to thread data from TLS
ptd = _getptd();
// Wrap desired thread function in SEH frame to handle run-time // errors and signal support
__try {
// Call desired thread function, passing it he desired parameter // Pass thread’s exit code value to _endthreadex
_endthreadex(
((unsigned (WINAPI*)(void*))(((_ptiddata)ptd)->_initaddr))
(((_ptiddata)ptd)->_initarg) );
}
__except(_XcptFilter(GetExceptionCode(), GetExceptionInformation())) {
// The execution code should never reach here
_exit(GetExceptionCode()); }
}
Função _endthreadex (pseudocódigo)
void __cdecl _endthreadex( unsigned retcode ) {
_ptiddata ptd; // Pointer to thread’s data block
// Not relevant cleanup
// Get the address of this thread’s tiddata block
ptd = _getptd_noexit(); // Free the tiddata block
if (ptd != NULL) _freeptd(ptd);
// Terminate the thread
ExitThread(retcode); }
Definição de errno
_CRTIMP extern int * __cdecl _errno (void);
#define errno (*_errno())
int * __cdecl _errno(void) {
_ptiddata ptd = _getptd_noexit(); if (!ptd) return &ErronoNoMem; else return (&ptd->_terrno); }
Considerações sobre a biblioteca runtime C/C++
int * p = &errno; if (*p == ENOMEM) { ...
Considerações sobre a biblioteca runtime C/C++
Bibliotecas runtime C/C++
• Bibliotecas usadas com o Microsoft Visual Studio
– LibCMt.lib, para ligação estática
– LibCMtD.lib, para ligação estática com debug
– MSVCRt.lib, para ligação dinâmica com a DLL MSVCR80.dll (biblioteca usada por omissão na criação de um novo projecto)
– MSVCRtD.lib, para ligação dinâmica com a DLL MSVCR80.dll com debug – MSVCMRt.lib, usada no âmbito de código managed e código nativo – MSVCURt.lib, biblioteca compilada com código 100% MSIL
• Caminho da configuração da biblioteca a usar no Visual Studio
– Project Properties → Configuration Properties → C/C++ → Code Generation – Escolher uma das bibliotecas associadas ao campo Runtime Library
• Funções da biblioteca que nunca deverão ser usadas
– unsigned long _beginthread(
void (__cdecl *start_address)(void *) unsigned stack_size,
void * arglist); – void _endthread(void);
Tempos associados à execução de uma thread
ULONGLONG GetTickCount64();
// Não considera a preempçãoBOOL GetThreadTimes(HANDLE hThread,
PFILETIME pftCreationTime,
// valor absoluto desde 1 de Janeiro de 1601PFILETIME pftExitTime,
// valor absoluto desde 1 de Janeiro de 1601PFILETIME pftKernelTime,
// valor relativo gasto em kernel modePFILETIME pftUserTime);
// valor relativo gasto em user mode• PFILETIME expresso no número de intervalos de 100 nano-segundos
• Funções adequadas para medir intervalos de tempo longos (fraca
precisão)
– O tempo de CPU de uma thread é contabilizado com base num temporizador que gera ciclos entre os 10 e 15 ms
BOOL GetProcessTimes(<same as GetThreadTimes>);
// Tempo
gasto por todas as threads do processo
Time Stamp Counter (contador de alta resolução)
• Time Stamp Counter: contador de 64 bits do processador que conta
o número de ciclos desde que a máquina iniciou
BOOL QueryThreadCycleTime(HANDLE ThreadHandle,
PULONG64 CycleTime);
BOOL QueryProcessCycleTime(HANDLE ProcessHandle,
PULONG64 CycleTime);
• Número de ciclos atribuídos a uma thread ou a todas as threads de
um processo (considera a preempção)
#define ReadTimeStampCounter()
• Macro definida no WinNT.h que retorna o valor do contador TSC (usa
a função intrínseca
__rdtsc providenciada pelo compilador C++)
• Funções medidoras de tempo de alta resolução
BOOL QueryPerformanceFrequency(LARGE_INTEGER* pliFrequency); BOOL QueryPerformanceCounter(LARGE_INTEGER* pliCount);
Bibliografia
• “Windows internals”, Russinovich e Solomon, cap. 5, 5ª edição
• “Windows via C/C++”, Richter e Nasarre, cap. 4, 6 e 7, 5ª edição
• MSDN - windows development
Bloco EPROCESS (Executive Process Block)
Estrutura de dados que representa um processo
Kernel process block (or PCB)
Process ID Parent process ID
Exit status Create and exit times
Active process link Quota block
Memory management information Exception port
Debugger port
Device map
Process environment block
Image filename Image base address Process priority class
Windows process block Job object
Primary access token Handle table
EPROCESS PsActiveProcessHead
Bloco KPROCESS (Kernel Process Block or PCB)
Estrutura de dados
Dispatcher header Kernel time
User time
Inswap/Outswap list entry Process spinlock
Process affinity
Resident kernel stack count Process base priority Default thread quantum
Process state Thread seed Disable boost flag
Process page directory
bib: Windows internals, Russinovich, Solomon, fig. 5-3
Bloco PEB (Process Environment Block)
Estrutura de dados
Image base address Module list
Thread-local storage data Code page data Critical section timeout
Number of heaps Heap size information GDI shared handle table
Operating system version number information Image version information
Image process affinity mask
Process heap
Variáveis kernel, contadores de performance e funções
relacionados com processos
• Fica apenas a referência dado o volume de informação
– “Windows Internals”, Russinovich e Solomon, Cap. 5 – Variáveis kernel: tabela 5-2
– Contadores de performance: tabela 5-3 – Funções relevantes: tabela 5-4
Bloco ETHREAD (Executive thread block)
Estrutura de dados que representa uma thread
KTHREAD Create and exit times
Process ID Thread start address Impersonation information
ALPC message information Timer information
EPROCESS Access token
Pending I/O requests TEB
Bloco KTHREAD (Kernel thread block)
Estrutura de dados
Dispatcher header Total user time Total kernel time
Thread-scheduling information Trap frame
Synchronization information List of pending APCs
Kernel stack information System service table
Thread-local storage array
TEB Timer block and wait block
List of objects thread is waiting on
Bloco TEB (Thread environment block)
Estrutura de dados
Exception list Stack base Stack limit Thread ID Active RPC handle LastError valueCount of owned critical sections
Subsystem thread information block (TIB) Fiber information
PEB
Current locale User32 client information
GDI32 information OpenGL information
TLS array
Winstock data
Variáveis kernel, contadores de performance e funções
relacionados com threads
• Fica apenas a referência dado o volume de informação
– “Windows Internals”, Russinovich e Solomon, Cap. 5 – Variáveis kernel: tabela 5-11
– Contadores de performance: tabela 5-12 – Funções relevantes: tabela 5-13
Funções da Windows API que promovem scheduling
Prioridades de processos e threads
Mapeamento entre sistema nativo e subsistema Windows
• Alteração da classe de prioridade
– Na criação com a função CreateProcess
Real-time Levels 16-31 31 0 15 1 16 24 Real-time time critical
Real-time idle Dynamic time critical
Dynamic Levels 1-15
Dynamic idle
Used for zero page thread; not available to Win32 applications Real-time High Above Normal Normal Below Normal Idle 13 10 8 6 4
• Processo: classe de prioridade
• Thread:
– Prioridade base =
Fx(classe de prioridade, prioridade relativa) – Prioridade corrente
bib: Windows internals, Russinovich, Solomon, fig. 5-13
Prioridades lógicas Prioridades nativas
Prioridades de processos e threads
Mapeamento entre sistema nativo e subsistema Windows
Relative Thread Priority
Process Priority Class
Idle Below Normal Normal Above Normal High Real-Time Time-critical 15 15 15 15 15 31 Highest 6 8 10 12 15 26 Above normal 5 7 9 11 14 25 Normal 4 6 8 10 13 24 Below normal 3 5 7 9 12 23 Lowest 2 4 6 8 11 22 Idle 1 1 1 1 1 16