...

Processi - Microsoft

by user

on
Category: Documents
15

views

Report

Comments

Transcript

Processi - Microsoft
Windows internals
http://www.microsoft.com/italy/msdn/studenti
[email protected]
Benvenuti

Un giorno di full immersion nel kernel di
Windows
Architettura del kernel
 Come funziona
 Come sfruttarlo al meglio
 Come analizzare i problemi

Agenda









Architettura kernel di Windows
Gestione della memoria
Processi
Thread
Thread pool
Jobs
Interprocess communication
Overlapped I/O
Domande & Risposte
Architettura kernel
di Windows
MS Windows NT: obiettivi del
progetto

Compatibilità


Portabilità







applicazioni Win32, Win16, MS-DOS, OS/2, POSIX
Ieri: piattaforma Intel, RISC
Oggi: IA-32 (Pentium), IA-64 (Itanium)
A breve: AMD-64 (Opteron)
Robustezza
Estendibilità
Performance
Compatibilità

binaria, sorgente, file system
Portabilità
Symmetric
Multiprocessors
Server
Laptop
Computer
Personal
Computer
Architettura di MS Windows NT
Applications and Subsystems
Software
(User-Mode Instruction Set)
Process Security Local Object
Virtual
Manager Monitor IPC Manager Memory
Manager
Kernel
I/O
Manager
GDI
USER
Device
Drivers
HAL
Hardware
I/O
Devices
DMA/Bus
Controller
Timers
Caches,
Interrupts
CPU
Privileged
Architecture
Robustezza:
Spazi di indirizzamento
separati
System
Memory
(2 GB)
Non-paged
Paged
Per-Process
Memory
(2 GB)
Physical
Addressing Range
Paged
Robustezza: User Mode e
Privileged-Processor Mode


User Mode

applicazioni in esecuzione

Accesso esclusivamente allo spazio di indirizzamento dei processi

Divieto di accesso diretto all’hardware
Privileged-Processor Mode

Contiene il codice di sistema: executive, drivers, kernel e HAL

“Trusted”

Può eseguire qualsiasi istruzione

Accesso all’intero spazio di indirizzamento
Robustezza: Security

Per-User Permissions



Access Control List (ACL)
Auditing Access
Quotas (sempre presente, non implementato
fino a Windows 2000)
Robustezza: i sottosistemi
User Mode
Win32-Based
Application
POSIX
OS/2
Subsystem
Local Procedure Call
Executive
Send
Reply
Privileged-Processor Mode
Win32
Subsystem
Estendibilità
Applications and Subsystems
Software
(User-Mode Instruction Set)
Process Security Local Object
Virtual
Manager Monitor IPC Manager Memory
Manager
Jobs
Kernel
Device
Drivers
I/O
Manager
NTFS
GDI
USER
FAT
Timer
Queue
Encryption
HAL
Hardware
I/O
Devices
DMA/Bus
Controller
Timers
NTFS-5
Caches,
Interrupts
CPU
Privileged
Architecture
Gli oggetti di NT (kernel objects)
Process
Access Token
Mutex
Thread
Event
Semaphore
Section
File
Registry
Object model

L’object model consente di:
monitorare le risorse
 implementare la sicurezza
 condividere le risorse

Object: struttura interna
Object Attributes
Object
Header
Object Name
Object Directory
Security Descriptor
Quota Charges
Open Handle Counter
Open Handle Database
Permanent/Temporary
Kernel/User Mode
Type Object Pointer
Object Body
Type
Object
Object: interfaccia esterna

Funzioni






Parametri comuni
Createxxx Security attributes, inheritance, name
Openxxx Security attributes, inheritance, name
BOOL CloseHandle(hObject)
BOOL DuplicateHandle(hSourceProcess, hSource,
hTargetProcess, lphTarget, fdwAccess,
fInherit, fdwOptions)
Lo scope di un Object Handle è relativo a ogni
singolo processo
Durata di un oggetto
Struttura
SECURITY_ATTRIBUTES
typedef struct
_SECURITY_ATTRIBUTES
{
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;
Access Token
Security Detail
Security ID: LEES
Group IDs: TEAM1
TEAM2
LOCAL
INTERACTIVE
WORLD
Privileges: None
.
.
.
Event Object
.
.
Security
Descriptor
.
.
Access Control List
Allow
LEES
Synchronize
Modify State
Allow
TEAM1
Synchronize
Allow
TEAM2
Synchronize
Modify State
Architettura Windows NT/2000




Radici nel passato (VMS)
Disegno modulare ed estendibile
Pochi cambiamenti e molte ottimizzazioni dal
kernel di Windows NT 3.1 a quello di Windows
2000
Modello ad oggetti, ma non object-oriented
Gestione della memoria
(Memory Manager)
Gestione della memoria






I processori iAPX86
Indirizzamenti real-mode e protected-mode
Funzioni API
Condivisione della memoria
VLM – Very Large Memory
AWE – Address Windowing Extension
I Processori Intel iAPX86

Tutti eseguono il boot in Real Mode
Su 8088/8086 è l’unica possibilità
 Su 286 e successivi è necessario per compatibilità
 Dopo il boot 286 e successivi possono passare al
protected mode


Tutti hanno un’architettura segmentata
Indirizzamento in real-mode
15
0
15
segment
0
offset
:
(shift left
by 4 bits)
19
43
0
19
segment’s base address 0 0 0 0
16 15
0000
0
effective address
1 MB
+
RAM
19
0
linear address
220 = 1MB
0
Real-mode


Nessun meccanismo di protezione della memoria
Diverse combinazioni segment:offset indirizzano la
stessa locazione di memoria fisica

Nessun supporto hardware nativo per una efficacie
implementazione del multitasking

Microsoft ha inventato una implementazione
software del multitasking per Windows 1.x
15
Protected-mode (32 bit)
selector
2 1 0
T
RPL
I
31
:
offset
15
BASE
ACCESS
0
?
63
15
1
TI = Table Index
RPL = Requestor Privilege Level
GDT = Global Descriptors Table (64KB)
LDT = Local Descriptors Table (64KB)
BASE = BA = Base Address (32 bit)
LIMIT = Limit (20 bit) = 1 MB
ACC. = ACCESS = Access Byte (12 bit)
SS = Segment Size
0
BASE
ACCESS
GDT
0
ACC. LIMIT
BASE
BASE
LIMIT
x 8192
48
LDT
SEGMENT
0
ACC. LIMIT
BASE
BASE
LIMIT
63
48
GD 0
16GB/
64TB
A
V
L
P DPL S
x 8192
TYPE
RAM
BA+SS
BA
0
Struttura Interna Access Byte
G = 0  SS = Limit x 1 Byte = 1 MB
G = 1  SS = Limit x 1 Page = Limit x 4KB = 4GB
(G = Granularity Bit)
Protected-mode (32 bit)



Se la granularità è una pagina (4KB), ciascun
segmento è da 4GB e lo spazio di
indirizzamento virtuale è di 64TB!
Il descriptor è comunque compatibile con 16 bit
PM
L’architettura è comunque segmentata e limita la
portabilità

Tipicamente le piattaforme RISC non hanno
architettura segmentata…
Eliminare la Segmentazione

In Win95 e WinNT, il sistema operativo utilizza un solo
segmento da 4GB





In pratica, l’indirizzamento in Win32 è basato esclusivamente
sull’offset (32 bit)
L’indirizzamento appare lineare (o flat)
Questo assicura la portabilità ad architetture non segmentate
(es. RISC)
Win32 indirizza fino a 4GB RAM fisica
Tuttavia la strategia di implementazione è basata sulle
Pagine

La quantità minima di memoria allocabile è la pagina = 4KB
Perchè Paginare la Memoria

Se l’offset fosse usato come un riferimento diretto alla locazione
di memoria, lo spazio di indirizzamento virtuale coinciderebbe
con la RAM fisica installata


Per indirizzare 4GB virtuali, sarebbe necessario disporre di 4GB di RAM
fisica in ogni sistema!
La paginazione consente di simulare uno spazio di
indirizzamento fisico da 4GB anche se la RAM fisica installata è
<4GB



Remapping della memoria fisica sulla memoria virtuale
Paginazione su disco
Exceptions generate dal processore e gestite dal sistema operativo
32 bit Offset in Win32
31
22 21
PDE (10 bit)
20 bits
12 11
PTE (10 bit)
12 bits
1023
20 bits
OFFSET (12 bit)
12 bits
0
Page Directory
CR#3
i386
0
4GB
1023
0
PAGE 4KB
Page Table
Win32
Process
Context
RAM
PDE = Page Directory Entry
PTE = Page Table Entry
CR#3 = Control Register #3
0
Spazio di indirizzamento
System
Memory
(2 GB)
Non-paged
Paged
Per-Process
Memory
(2 GB)
Physical
Addressing Range
Paged
Memoria virtuale
Process
Address Space
Physical Memory
2 GB
Page Tables
R
e
s
e
r
v
e
d
0
Committed
Pages
Invalid
Committed
Pages
Invalid
2 GB
Page Directory, Page Table,
Page Frame
Virtual
Physical
Address
Space
Directory
Table
1024 Entries
1024 Entries
Memory
4K
12 MB
Invalid
Frame
Invalid
8 MB
4 MB
0
4K
4K
Valid
Paged
Paging File
10 Bits
Directory Index
10 Bits
Table Index
12 Bits
Byte Within
Page
Paging File



Contiene Pagine scambiate dalla Memoria RAM
al Disco
Dimensione pagina: 4K o 8K
Paging Policy
Page Commitment
Process
Address Space
2 GB
R
e
s
e
r
v
e
d
Committed
Pages
Committed
Pages
Copy-on-Write e Guard Pages
Process 1
Virtual
Memory
Page 1
Committed
Memory
Page 2
Page 1
Page 2
Section
Page 1
Process 2 Page 2 Copy
Virtual
Memory
Page 2 Copy
(Read-Write)
Funzioni API: VirtualAlloc








Manipolazione pagine virtuali o spazi di indirizzamento
Lettura stato pagine virtuali o spazi di indirizzamento
LPVOID VirtualAlloc(lpvAddress, cbSize,
fdwAllocationType, fdwProtect)
BOOL VirtualFree(lpAddress, cbSize, fdwFreeType)
BOOL VirtualProtect(lpvAddress, cbSize, fdwNewProtect,
pfdwOldProtect)
DWORD VirtualQuery(lpAddress, pmbiBuffer,cbLength)
BOOL VirtualLock(lpvAddress, cbSize)
BOOL VirtualUnlock(lpvAddress, cbSize)
Esempio: Uso di Funzioni
VirtualXXX
...
lpBase = VirtualAlloc (NULL, my_size,
MEM_RESERVE,
PAGE_NOACCESS);
...
__try{
// an EXCEPTION_ACCESS_VIOLATION here
// will be fixed by MyFilter if possible
}
__except (MyFilter (GetExceptionInformation()))
{
}
...
VirtualFree (lpBase, 0, MEM_RELEASE);
...
Gestione Heap





Lo Heap è ottimizzato per allocare blocchi di
memoria più piccoli senza l’overhead di pagina
(4k o 8k)
Ogni processo ha uno Heap di default
E’ possibile allocare Heap privati
La memoria allocata in uno heap può portare a
fenomeni di frammentazione
Sono Thread-Safe per default
Funzioni API: HeapAlloc








Allocazione di un Heap privato
HANDLE HeapCreate(flOptions, dwInitialSize,
dwMaximumSize)
BOOL HeapDestroy(hHeap)
LPVOID HeapAlloc(hHeap, dwFlags, dwBytes)
BOOL HeapFree(hHeap, dwFlags, lpMem)
DWORD HeapSize(hHeap, dwFlags, lpMem)
LPVOID HeapReAlloc(hHeap, dwFlags, lpMem,
dwBytes)
Sono Thread-Safe per default
Funzioni API:
LocalAlloc/GlobalAlloc






Tutti i puntatori sono valori a 32 bit
LocalAlloc e GlobalAlloc allocano memoria
dallo stesso Heap
GlobalAlloc garantisce allocazioni con
allineamento a 16 bit
HGLOBAL GlobalAlloc(fuFlags, cbBytes)
HLOCAL LocalAlloc(fuFlags, cbBytes)
Presenti solo per ragioni di compatibilità:
richiamano HeapAlloc
Funzioni API: C Run-Time
Library


Le funzioni delle Standard C Run-Time Libraries
possono essere usate (malloc, calloc, free,
realloc, ...)
Bilanciare chiamate malloc() con free(), senza
mischiare con GlobalFree(), HeapFree() o altro
Memory-Mapped File


I Memory-Mapped Files consentono di
condividere la memoria tra processi diversi
Sono l’equivalente Win32 dell’oggetto kernel
Section
Viste di Memory-Mapped File
Physical Memory
PG.SYS
Sections
Views
File
FileMapping: le cose ovvie




Il file è mappato in memoria come se fosse
effettivamente caricato
Gli indirizzi di memoria necessari ad effettuare il
mapping devono essere riservati
Solo le pagine effettivamente utilizzate (a cui si accede
in lettura o in scrittura attraverso puntatori di memoria)
vengono effettivamente lette/scritte su disco
Il Paging File usato come Memory Mapped File non
rende persistenti le operazioni effettuate in memoria
File Mapping: le cose meno ovvie




Tutte le operazioni di I/O su file avvengono come
operazioni di file-mapping
La cache dell’I/O Manager è integrata con il Memory
Manager
Tutte le volte che si apre un eseguibile (.EXE, .DLL,
.OCX), il codice e le risorse non vengono caricate in
memoria fino a che non sono realmente utilizzate
(anche queste sono operazioni di file-mapping)
Caricando più volte la stesso file EXE/DLL da
processi diversi, la memoria fisica impegnata è sempre
la stessa
CreateFileMapping e
OpenFileMapping

Crea un oggetto Section


Apre un oggetto Section


HANDLE CreateFileMapping(hFile, lpsa,
fdwProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
lpszMapName)
HANDLE OpenFileMapping(dwDesiredAccess,
bInheritHandle, lpszMapName)
Assegnando a hFile il valore –1 si usa il
PagingFile
MapViewOfFile e
UnmapViewOfFile
LPVOID MapViewOfFile(hMapObject, fdwAccess,
dwOffsetHigh, dwOffsetLow, cbMap)
 BOOL UnmapViewOfFile(lpBaseAddress)
 BOOL FlushViewOfFile(lpvBase, cbFlush)
 UnmapViewOfFile scrive tutti i cambiamenti su disco
 Lazy Writes su disco delle scritture in memoria
 E’ garantita la coerenza di viste differenti di un singolo
oggetto Section

Usare Memory-Mapped File
come Shared Memory
Process 1
Virtual
Memory
View
Committed
Memory
Section
Process 2
Virtual
Memory
View
Gestione della memoria



Superare il muro dei 4Gb con Win32
Solo per i dati, non per il codice
VLM – Very Large Memory



Solo su Windows 2000 Advanced Server
Solo per processori a 64 bit, ad oggi solo Alpha, che non
supporta più Windows 2000
AWE – Address Windowing Extension



Su tutte le versioni di Windows 2000
Per tutti i processori a 32 e 64 bit (Win64)
Meno comodo da usare...
AWE – Address Windowing
Extension






Per tutti i processori e per tutte le versioni di Windows
2000
Memoria mappata nello spazio virtuale disponibile al
processo (2Gb/3Gb)
Non funziona con funzioni grafiche/video
Granularità 4K/8K
Il processo deve essere abilitato (diritto Lock Pages in
Memory)
Una zona allocata con AWE non può essere condivisa
con altri processi
AWE – Funzioni




AllocateUserPhysicalPages
VirtualAlloc
MapUserPhysicalPages
FreeUserPhysicalPages
Gestione della memoria





Introduzione architetturale
Funzioni API
Memory mapped file
Condivisione della memoria
VLM & AWE
Processi
Cosa è un Processo?


Un istanza di un programma in esecuzione
Un processo possiede degli Oggetti


Cosa distingue un processo da un altro?




Gli oggetti sono rappresentati dagli Handle
Handle table
Memoria privata
Windows
Il processo è un insieme di thread, ed esiste fino a che
contiene almeno un thread
Win32-Based Process Model
Access
Token
Virtual Address Space Description
...
Process
Object Table
Available Objects
Handle 1
Thread x
Handle 2
File y
Handle 3
Section z
Object Handle

Ogni Object Handle




E’ valido solo nel contesto del proprio processo
Può essere ereditato
Mantiene un oggetto in vita nel sistema fino a che tutti gli handle allo
stesso oggetto non sono chiusi
Tipi di Object Handle

Private:
CreateMutex, OpenSemaphore, ...


Duplicated: BOOL DuplicateHandle(...)
Inherited:
fInheritHandles a TRUE in CreateProcess

Pseudo:
GetCurrentProcess(), GetCurrentThread(), ...
Ciclo di vita di un Processo




Un processo viene creato associando sempre un file
eseguibile (.EXE), che è mappato in memoria ed
eseguito
Creando un processo viene creato un thread
Il primo thread di un processo può essere chiamato
thread principale, anche se la sua chiusura non
determina necessariamente la fine del processo
La run-time library del C termina il processo corrente
se si esce dalla funzione main() con return,
indipendentemente dalla presenza di altri thread
Creazione di un Processo

BOOL CreateProcess(lpszImageName,
lpszCommandLine, lpsaProcess,
lpsaThread,
fInheritHandles, fdwCreate,
lpvEnvironment,
lpszCurDir, lpsiStartInfo, lppiProcInfo)

HANDLE OpenProcess(fdwAccess, fInherit,
IDProcess)
Informazioni ritornate dalla
creazione di un Processo
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
Gli handle hProcess e hThread vanno sempre chiusi con
CloseHandle(hObject) quando non sono più utilizzati
E’ un errore frequente dimenticare questa operazione su
entrambi gli handle restituiti!
Chiudere un Processo

Chiusura normale


Chiudere l’handle ad un processo


BOOL CloseHandle(hObject)
Chiusura immediata (e anomala) di un processo


VOID ExitProcess(uExitCode)
BOOL TerminateProcess(hProcess, uExitCode)
La chiusura dell’ultimo thread di un processo implica
una chiamata ad ExitProcess()
Funzioni API








LPTSTR GetCommandLine(VOID)
HANDLE GetCurrentProcess(VOID)
DWORD GetCurrentProcessId(VOID)
VOID GetStartupInfo(lpsi)
HANDLE OpenProcess(fdwAccess, fInherit, IDProcess)
DWORD GetEnvironmentVariable(lpszName, lpszValue,
cchValue)
BOOL SetEnvironmentVariable(lpszName, lpszValue)
LPVOID GetEnvironmentStrings(VOID)
Interprocess Communication
(IPC)


IPC viene realizzata quando due o più processi
condividono un oggetto
Gli oggetti usati per IPC includono:
Shared memory (section object)
Files
Semaphores
Pipes / Mailslot
Windows sockets

I metodi di accesso condiviso sono gli stessi
per molti oggetti di tipo diverso
Condivisione di oggetti

Può avvenire in tre modi:
BOOL DuplicateHandle(hSourceProcess,
hSource,
hTargetProcess, lphTarget, fdwAccess, fInherit,
fdwOptions)
 Creando o aprendo un “Named Object”
 Ereditarietà

Condivisione di oggetti

Gli oggetti condivisi sono handle diversi che
puntano allo stesso oggetto kernel
Process A
Process B
Kernel Objects
Object Table
Thread x
Object Table
Handle 1
Thread y
Handle 1
Handle 2
File k
Handle 2
Handle 3
Section z
File w
Handle 3
Ereditarietà
Access
Token
Granted Access
Process A
Inheritance
Available Objects
Handle 1
Thread x
Handle 2
File y
Handle 3
Section z
Object Table

Ereditarietà
Gli oggetti condivisi attraverso ereditarietà
assumono lo stesso valore di Handle
CreateProcess(…)
Process A
Process B
Kernel Objects
Object Table
Thread x
Object Table
Handle 1
Thread y
Handle 1
Handle 2
File k
Handle 2
Handle 3
Section z
Handle 3
Controllare l’ereditarietà
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;
BOOL bInheritHandle;
Processi

Achitettura

Object Handle

Ciclo di vita di un processo

Condivisione di oggetti

Ereditarietà
Thread
Cosa è un Thread?




Un thread è un percorso di esecuzione all’interno
di un processo
Un thread accede a tutte le risorse del processo in
cui è contenuto
Il ThreadID contraddistingue un thread nel sistema
operativo, indipendentemente dal processo
ospitante
Un thread esiste fino a che:
il percorso di esecuzione termina
 viene chiuso con ExitThread
 viene chiuso/distrutto il processo ospitante

Preemptive vs. Cooperative
Preemptive (Windows NT)
Thread 1
Processor
Done
Thread 2
Time
Cooperative (Windows 3.1)
Task 1
Processor
Task 2
I/O or Idle
Executing
Involuntary
Voluntary
Win32 Preemptive Multitasking
Process A
Thread 1
System
Scheduler
Thread 2
Process B
Process C
Thread 1
Thread 1
i386
Process D
Thread 1
Thread 2
Process E
Thread 3
Thread 1
Perché usare thread multipli?





I thread sono più economici dei processi
Per dividere task paralleli
Per supportare la concorrenza
Perché i thread comunicano più velocemente
Per sfruttare Symmetric Multiprocessing
Thread Overhead




Ogni thread Win32 ha un “gemello” nel
sottosistema Host
Ci sono due stack per ogni thread
C’è un Hardware Context per thread
C’è un insieme di variabili statiche delle C RunTime Library per thread
Schedulazione dei Thread

Lo Scheduler Win32 :
Schedula soltanto thread
 E’ preemptive
 E’ basato sulle priorità

Scheduler


Lo scheduler conosce solo i Thread
Ogni Thread ha due livelli di priorità
Priorità di base
 Priorità corrente


La priorità corrente è analizzata per decidere
quale thread eseguire
Scheduler

La priorità di base è funzione di due valori:
Classe di priorità del processo
 Valore di priorità del thread


La priorità corrente è dinamica (viene variata
dallo scheduler), ma non scende mai al di sotto
della priorità di base
Priorità di processi e thread
Processi
Thread
IDLE
IDLE
BELOW_NORMA
L
NORMAL
LOWEST
ABOVE_NORMA
L
HIGH
REALTIME
BELOW_NORMA
L
NORMAL
ABOVE_NORMA
L
HIGHEST
TIME_CRITICAL
Calcolo priorità di base dei thread
Realtime Time Critical
31
Realtime
Realtime
Livelli 16-31
Realtime Idle
Dynamic Time Critical
24
High
16
15
Above Normal
13
Normal
Dynamic
10
Livelli 1-15
Below Normal
8
Idle
6
4
Dynamic Idle
System Idle
0
Scheduler

Logica di funzionamento dello scheduler




Trova il thread attivo con priorità corrente più alta e lo esegue
per un quantum
Solo il thread non sospeso con la priorità più alta viene
eseguito
Se ci sono più thread con lo stesso livello, effettua un roundrobin tra questi
L’unico modo per eseguire thread a priorità più bassa è che i
thread a priorità più alta vadano in stato di Wait (ad es. per
operazioni di I/O)
Scheduler

Impatto dello scheduler sui tempi di risposta
Appena un thread a priorità più alta non è più
sospeso, lo scheduler interrompe il thread in
esecuzione e passa il controllo al thread con la
priorità più alta
 La priorità di un thread non agisce quindi
direttamente sulla percentuale di tempo di CPU
assegnata

Priorità di processi e thread
Variable
Real-Time
Real-Time Class
High Class
Normal Class
Idle Class
1
5
10
15 16
20
25
31
Scheduler


Come fa Windows a funzionare?
Il trucco è che la priorità corrente del thread è
modificata continuamente dallo scheduler:
I thread in attesa vengono premiati
 I thread che usano più CPU sono penalizzati
 L’applicazione in primo piano riceve un quantum più
lungo

Scheduler

Andamento del livello di priorità corrente nel tempo
Priorità
Priority
Boost
Quantum
Decay
Base
Run
Wait
Run
Preempt
Tempo
Round-Robin
at Base
Run
Scheduler




Non voglio che lo scheduler cambi il livello di priorità
corrente di un thread. Come faccio?
Il livello di priorità corrente non scende mai al di sotto
della priorità base.
Un thread con priorità TIME_CRITICAL ha sempre il
valore di priorità corrente 15
Tutti i valori superiori a 15 non sono mai modificati
dinamicamente (processi in classe di priorità
REALTIME)
Scheduler
Priorità dinamiche
Priorità statiche
High Class
Real-Time Class
Above Normal
Normal Class
Non sono
solo driver
Below Normal
Idle Class
1
5
10
15 16
20
25
31
Controllare le priorità

Un’applicazione può controllare la priorità dei
suoi thread:
CreateProcess parametro fdwCreate
 BOOL SetPriorityClass(hProcess, fdwPriority)
 BOOL SetThreadPriority(hThread, nPriority)

Creazione di un Thread


La funzione Win32 per creare un thread è
CreateThread
Ogni libreria o ambiente di sviluppo ha delle
funzioni specifiche per creare un thread:



C/C++ RTL
MFC
_beginthread(...)
AfxBeginThread(...)
Se si usano le C-Run Time Libraries,
specificare la versione multi-thread delle
librerie nelle opzioni del progetto
C Run-Time Library
Funzioni di creazione dei Thread

Win32 API
HANDLE CreateThread(
lpsa,
cbStack,
lpStartAddr,
lpvThreadParm,
fdwCreate,
lpIDThread)

C Run-Time API
unsigned long _beginthread(
void (*start_address) (void *),
unsigned stack_size,
void *arglist)
Esempio CreateThread
DWORD WINAPI CalculationThreadProc (LPVOID lpv)
{
printf(“CalculationThreadProc: Param=%d\n”, *((lpint)lpv);
return 0;
}
DWORD main (void)
{
DWORD dwThreadId, dwThrdParam = 1;
HANDLE hThread;
hThread = CreateThread (NULL,
0,
CalculationThreadProc,
&dwThrdParam,
0,
&dwThreadId);
if (hThread == INVALID_HANDLE_VALUE)
return 1;
...
}
//no security attributes
//default stack size
//thread function
//thread function argument
//default creation flags
//returns thread ID
Esempio CalculationThreadProc
typedef struct _threadargs
{
...
} THREADARGS, * LPTHREADARGS;
DWORD WINAPI CalculationThreadProc (
LPVOID lpv)
{
LPTHREADARGS lpta = lpv;
BOOL bRet;
/*Do Calculation*/
return bRet;
}
Thread IDs e Handles




DWORD GetCurrentThreadId(VOID)
DWORD GetCurrentProcessId(VOID)
HANDLE CreateThread(lpsa, cbStack,
lpStartAddr, lpvThreadParm,
fdwCreate, lpIDThread)
HANDLE CreateRemoteThread(hProcess,
lpsa, cbStack, lpStartAddr,
lpvThreadParm, fdwCreate, lpIDThread)
HANDLE GetCurrentThread(VOID)
HANDLE GetCurrentProcess(VOID)
Uscita da un Thread

Funzioni API Win32
VOID ExitThread(dwExitCode)
BOOL TerminateThread(hThread, dwExitCode)

Funzioni API C Run-Time Libraries
void _endthread(void)
Valori di uscita da un thread

BOOL GetExitCodeProcess (hProcess,
lpdwExitCode)

BOOL GetExitCodeThread (hThread,
lpdwExitCode)

DWORD WaitForSingleObject(hObject, dwTimeout)

DWORD WaitForMultipleObjects(cObjects,
lphObjects,
fWaitAll, dwTimeout)
Sincronizzazione

Per scrivere codice efficiente è indispensabile...
evitare
tecniche di
polling
Sincronizzazione


Un thread che non deve aspettare un evento esterno
deve andare in stato di Wait
Se un thread deve aspettare che un altro thread abbia
compiuto una certa operazione, si sfruttano gli oggetti
kernel per la Sincronizzazione:




Mutex
Semaphore
Event
Critical Section
Attesa su Oggetti kernel

Per sospendere un thread fino a che uno o più oggetti
kernel non diventano “segnalati”, usare le funzioni di
Wait:



DWORD WaitForSingleObject(
hObject, dwTimeout)
DWORD WaitForMultipleObjects(
cObjects, lphObjects,
fWaitAll, dwTimeout)
DWORD MsgWaitForMultipleObjects(
lphObjects, fWaitAll,
dwTimeout, fdwWakeMask )
cObjects,
Scenario di sincronizzazione 1

Gestire in maniera efficiente l’input da una porta seriale




Attende il prossimo carattere o il riempimento del buffer di
input
Legge e processa i caratteri
Attende il prossimo carattere o il buffer
Si usa l’oggetto Event, che è funzionalmente simile ad
una variabile booleana
Event Objects






Interprocess or Intraprocess
Named or Unnamed
HANDLE CreateEvent(lpsa, fManualReset,
fInitialState,
lpszEventName)
HANDLE OpenEvent(fdwAccess, fInherit,
lpszEventName)
BOOL SetEvent(hEvent)
BOOL ResetEvent(hEvent)
Uso di Event
HANDLE hEvent = CreateEvent (
NULL, // no security
TRUE, // event must be reset
// manually
FALSE, // initially nonsignaled
NULL); // anonymous event
StartTaskThatSignalsEventWhenDone (hEvent);
// Do other processing.
// Wait for event to be signaled; then reset it.
WaitForSingleObject (hEvent, INFINITE);
ResetEvent(hEvent);
...
CloseHandle (hEvent);
Scenario di sincronizzazione 2

Proteggere strutture dati condivise, come code e liste in
memoria condivisa, dal danneggiamento dovuto ad
accessi concorrenti

Si usa l’oggetto Mutex, che è un flag che coordina
l’esecuzione di operazioni mutualmente esclusive
Solo un thread può detenere un Mutex, gli altri thread
vengono sospesi sulla Wait fino a che il Mutex non
viene rilasciato

Mutex Objects






Interprocess or Intraprocess
Named or Unnamed
Noncounting Mutual Exclusion
HANDLE CreateMutex(
lpsa, fInitialOwner, lpszMutexName)
HANDLE OpenMutex(
fdwAccess, fInherit, lpszMutexName)
BOOL ReleaseMutex(hMutex)
Uso di Mutex
if (!hMutex) // if we have not yet created the mutex...
{
// create mutex with creator having initial ownership
hMutex = CreateMutex (NULL, TRUE, "Bob");
if (GetLastError() == ERROR_ALREADY_EXISTS)
WaitForSingleObject (hMutex, INFINITE);
}
else
WaitForSingleObject (hMutex, INFINITE);
__try{ // use the resource protected by the mutex
}
__finally
{ ReleaseMutex (hMutex); }
...
CloseHandle (hMutex);
Scenario di sincronizzazione 3

Porta per n-way Mutex



Acquisisce una delle n risorse identiche da un pool di risorse
disponibili
Si usa l’oggetto Semaphore, che è simile ad un Mutex
con un contatore
Un Mutex è come un Semaphore che assume solo i
valori 0 e 1; quando il Semaphore diventa 0, le chiamate
a WaitFor... diventano sospensive, fino a che qualche
thread non incrementa il valore del Semaphore
Semaphore Objects






Interprocess or Intraprocess
Named or Unnamed
Counting
HANDLE CreateSemaphore(
lpsa, cSemInitial, cSemMax, lpszSemName)
HANDLE OpenSemaphore(
fdwAccess, fInherit, lpszSemName)
BOOL ReleaseSemaphore(
hSemaphore, cReleaseCount,
lplPreviousCount)
Uso di Semaphore
HANDLE hSem = CreateSemaphore (
NULL, // security
4,
// initial count
4,
// maximum count
"Sally"); // global object name
...
// Wait for any 1 of 4 resources to be available.
WaitForSingleObject (hSem, INFINITE);
__try{ // Use the semaphore.
}
__finally
{
ReleaseSemaphore (hSem, 1, &lPrevCount) };
...
CloseHandle (hSem);
Scenario di sincronizzazione 4

Sincronizzazione di diversi thread nello stesso
processo con un oggetto Mutex il più
velocemente possibile, con il minimo overhead
(es. inserimento di un oggetto in una coda)

Si usa l’oggetto Critical Section, che è un Mutex
utilizzabile solo da thread di uno stesso processo
Critical Section







Meccanismo veloce di condizione mutualmente
esclusiva
Memoria allocata dall’utente
VOID InitializeCriticalSection(lpcsCriticalSection)
VOID DeleteCriticalSection(lpcsCriticalSection)
VOID EnterCriticalSection(lpcsCriticalSection)
VOID LeaveCriticalSection(lpcsCriticalSection)
Protegge l’accesso a dati condivisi da thread dello stesso
processo
Uso di Critical Section
CRITICAL_SECTION cs;
InitializeCriticalSection (&cs);
.
.
EnterCriticalSection (&cs);
__try
{
// initialize the thread arguments.
ta.hWnd = hWnd;
ta.lpDIB = lpDIB;
ta.rc = *lprc;
ta.bFlags = bFlags;
ta.pMP = pMP;
}
__finally
{
LeaveCriticalSection (&cs);
}
DeleteCriticalSection (&cs);
Thread e code mesaggi:
Modello Win32
Mouse
Device Driver
Raw Input
Thread
Keyboard
Device Driver
RIT
Event
Queues
Thread
Thread
Application
Thread
Application
Funzioni API per messaggi e
thread

BOOL PostMessage(hWnd, uMsg, wParam, lParam)

BOOL GetMessage(lpmsg, hWnd, uMsgFilterMin, uMsgFilterMax)

BOOL PostThreadMessage(
dwThreadId, uMsg, wParam,lParam)

BOOL PeekMessage(lpmsg, hWnd, uMsgFilterMin,
uMsgFilterMax, fuRemoveMsg)

LRESULT SendMessage(hWnd, uMsg, wParam, lParam)

BOOL SendNotifyMessage(hWnd, uMsg, wParam, lParam)

BOOL AttachThreadInput(idAttach, idAttachTo, fAttach)

DWORD MsgWaitForMultipleObjects(cObjects, lphObjects,
fWaitAll, dwTimeout, fdwWakeMask )
Thread









Definizione di thread
Cooperative e preemptive multitasking
Perchè usare thread multipli?
Thread overhead
Scheduler
Creazione di un thread
C Run-Time Library
Oggetti per la sincronizzazione
Thread e code di messaggi
Thread Pool
Thread Pool



Insieme di Thread gestiti dal sistema
Disponibili solo da Windows 2000 in poi
Scenari affrontati:
1.
2.
3.
4.
Accodare l’esecuzione asincrona di diverse funzioni
Chiamare diverse funzioni periodicamente (senza
WM_TIMER)
Chiamare funzioni quando un oggetto kernel va in stato
“segnalato”
Chiamare una funzione quando una richiesta di I/O
asincrono viene completata
Thread Pool – Scenario 1



Scenario: accodare l’esecuzione asincrona di diverse
funzioni (ad es. una scrittura “posticipata”)
Senza Thread Pool
Creazione di un Thread, esecuzione della funzione,
distruzione del Thread
Con Thread Pool
Una chiamata a QueueUserWorkItem
Thread Pool – Scenario 1
BOOL QueueUserWorkItem(
LPTHREAD_START_ROUTINE pfnCallback,
PVOID pvContext,
ULONG Flags );
Valori di Flags:
WT_EXECUTEDEFAULT
WT_EXECUTEINIOTHREAD
WT_EXECUTEINPERSISTENTIOTHREAD
WT_EXECUTELONGFUNCTION
Thread Pool – Scenario 2

Scenario: chiamare diverse funzioni periodicamente

Senza Thread Pool
Un thread per ogni funzione, Sleep(x) tra una chiamata
e l’altra
WM_TIMER per ogni funzione

Con Thread Pool
Una chiamata a CreateTimerQueueTimer

Thread Pool – Scenario 2





CreateTimerQueue
CreateTimerQueueTimer
ChangeTimerQueueTimer
DeleteTimerQueueTimer
DeleteTimerQueueEx
Thread Pool – Scenario 2
BOOL CreateTimerQueueTimer(
PHANDLE phNewTimer,
HANDLE TimerQueue,
WAITORTIMERCALLBACK Callback,
PVOID Parameter, WORD DueTime,
WORD Period, LONG Flags );
Valori di Flags:
WT_EXECUTEINTIMERTHREAD
WT_EXECUTEINIOTHREAD
WT_EXECUTEINPERSISTENTIOTHREAD
WT_EXECUTELONGFUNCTION
Thread Pool – Scenario 3




Scenario: eseguire una funzione quando un oggetto
kernel diventa segnalato
Senza Thread Pool
Un thread per ogni funzione/oggetto,
WaitForSingleObject prima della chiamata
Un thread controlla più oggetti kernel con
WaitForMultipleObjects...
Con Thread Pool
Chiamare RegisterWaitForSingleObject
Thread Pool – Scenario 3


RegisterWaitForSingleObject
UnregisterWaitEx
Thread Pool – Scenario 3
BOOL RegisterWaitForSingleObject(
PHANDLE phNewObject,
HANDLE hObject,
WAITORTIMERCALLBACK Callback,
PVOID pvContext,
ULONG dwMillisecs, ULONG dwFlags );
Valori di Flags:
WT_EXECUTEDEFAULT
WT_EXECUTEINWAITTHREAD
WT_EXECUTEINIOTHREAD
WT_EXECUTEINPERSISTENTIOTHREAD
WT_EXECUTELONGFUNCTION
WT_EXECUTEONLYONCE
Thread Pool – Scenario 4



Scenario: chiamare una funzione quando termina
un’operazione di I/O asincrono
Senza Thread Pool
Creazione di un I/O completion port e gestione
manuale di un thread pool
Con Thread Pool
Una chiamata a BindIoCompletionCallback
Thread Pool – Scenario 4
BOOL BindIoCompletionCallback(
HANDLE FileHandle,
LPOVERLAPPED_COMPLETION_ROUTINE Function,
ULONG Flags );

Flags è riservato, deve valere sempre 0
Prototipo LPOVERLAPPED_COMPLETION_ROUTINE:
VOID WINAPI OverlappedCompletionRoutine(
DWORD dwErrorCode,
DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped );

Thread Pool




Esecuzione di funzioni asincrone
Esecuzione periodica di funzioni
Operazioni da eseguire quando un oggetto
kernel diventa “segnalato”
Operazioni da eseguire al termine di operazioni
di I/O
Jobs
Job





Gruppo di processi
E’ un oggetto kernel
Disponibile solo da Windows 2000 in poi
Crea delle regole per i processi che contiene
Può definire dei limiti su:




Risorse del sistema
Interfaccia utente
Sicurezza
Può monitorare l’attività dei processi
Job – Ciclo di vita







Il Job viene creato “vuoto”
Impostare proprietà del Job
Un processo viene assegnato ad un Job
La relazione Processo-Job è irreversibile
Un processo figlio può nascere fuori dal Job del
processo padre
Se un Job viene terminato, tutti i suoi processi vengono
terminati
Il Job comunica con l’esterno con le I/O completion
port (non segnala su Handle)
Job – Ciclo di vita


Il nome associato al Job è accessibile fino a che
ci sono handle aperti al Job
Se tutti gli handle al Job vengono chiusi, il Job
resta in vita ma non è più accessibile (verrà
distrutto quando tutti i processi all’interno si
saranno chiusi)
Job - Limiti

Limiti sulle risorse di sistema:
Process Priority
 Consumo CPU
 Working Set Size
 Consumo memoria
 Processor Affinity

Job - Limiti

Limiti su interfaccia utente
Accesso USER Handle (HWND, HMENU, ...)
 Creazione/Switch Desktop
 Modifica impostazioni video
 Modifica parametri di sistema
 Clipboard
 ExitWindows

Job - Limiti

Limiti sulla security – Token utilizzabili:
No Administrator
 Tutti i processi con un token uguale
 Solo token ristretti rispetto a quello del processo
 Filtro sui token (disabilitazione di alcuni diritti
indipendentemente dall’utente impersonato)

Job - Monitoraggio





Tempo CPU (kernel/user)
Page Fault
Numero processi (attivi/terminati)
Attività di I/O (operazioni/byte)
Elenco processi
Job - Funzioni







CreateJobObject
OpenJobObject
AssignProcessToJobObject
TerminateJobObject
QueryInformationJobObject
SetInformationJobObject
UserHandleGrantAccess
Jobs

Definizione di Job

Ciclo di vita

Limiti definibili

Monitoraggio
Comunicazione tra
processi
(IPC – Interprocess
Communication)
Comunicazione tra processi

Per comunicare tra loro, due processi devono
richiedere dei servizi al sistema operativo:

Memory Mapped File (Shared Memory)

Object Handles

File su disco

Socket, Named Pipe e Mailslot

RPC (Remote Procedure Call)
Memory Mapped File




Consente di condividere memoria tra processi diversi
E’ una scelta adeguata quando più processi devono
accedere contemporaneamente ad informazioni
contenute in strutture dati di vaste dimensioni
L’accesso simultaneo (almeno in scrittura) va protetto
tramite meccanismi di sincronizzazione tra thread
Non vi è una notifica istantanea della variazione di un
dato da parte di un processo
Object Handle


Più processi possono accedere ad uno stesso
oggetto kernel
E’ una tecnica indispensabile per condividere
oggetti di sincronizzazione tra processi diversi
File su disco


E’ un meccanismo che consente la condivisione
di informazioni tra programmi in esecuzione
anche su macchine diverse e con sistemi
operativi diversi
Le prestazioni e la scalabilità sono le più basse
rispetto alle tecniche esaminate
Socket, Named Pipe, Mailslot




Sono dei “canali” di comunicazione tra processi
Si possono usare anche tra processi residenti su
elaboratori diversi
La trasmissione delle informazioni è sequenziale
I dati inviati generano delle notifiche ai processi in
ascolto: questo consente di evitare tecniche di polling
anche su comunicazioni in rete
Socket





Windows Sockets 2 è l’implementazione Microsoft
dell’interfaccia di programmazione definita in
“Berkely Sockets”
Conosciuta come interfaccia di programmazione
per TCP/IP, è utilizzabile anche per altri protocolli
E’ il sistema ideale per implementare meccanismi
di comunicazione su rete tra sistemi operativi
diversi
Supporta una comunicazione bidirezionale
E’ un meccanismo client/server
Socket

Il client può risiedere sulla stessa macchina del server, o
su una macchina diversa
Processo S1
socket
Port 80
Processo C2
Port 1198
Port 80
socket
Computer A
Port 1219
Computer B
Processo C1
S1: Processo server
C1, C2: Processi client
Named Pipe








Meccanismo di comunicazione client-server
Simile ad un socket, ma indipendente dal protocollo fisico
Pipe Server: processo che crea una named pipe
Pipe Client: processo che si connette ad una istanza di named
pipe
La named pipe ha un nome univoco per la macchina in cui è
definita, ma possono esistere più istanze della stessa named-pipe
Integra la “security”
Modalità di funzionamento “message-mode”
Server solo su NT/2000, Client su Win9x/NT/2000
Named Pipe

Il client può risiedere sulla stessa macchina del
server, o su una macchina diversa
named pipe
Processo S1
Processo C2
\\S1\pipe\Test
\\S1\pipe\Test
named pipe
Computer A
Computer B
Processo C1
S1: Processo server
C1, C2: Processi client
Pipe Server

Sequenza di funzioni API da chiamare:
CreateNamedPipe
 ConnectNamedPipe
 ReadFile / WriteFile
 DisconnectNamedPipe
 CloseHandle

Pipe Client

Sequenza di funzioni API da chiamare:
CreateFile
 WriteNamedPipe
 SetNamedPipeHandleState
 ReadFile / WriteFile
 CloseHandle

Named Pipe: API speciali

BOOL TransactNamedPipe(…)



Esegue sequenzialmente WriteFile seguita da ReadFile
Si usa sul client per semplificare il codice di esecuzione di
transazioni sincrone
BOOL CallNamedPipe(…)


Esegue sequenzialmente WaitNamedPipe, CreateFile,
TransactNamedPipe e CloseHandle
Si usa sul client per semplificare il codice nel caso in cui per
ogni transazione si vuole aprire e chiudere una connessione
Mailslot







Meccanismo di comunicazione broadcast senza
connessione
Mailslot Server: processo che crea una mailslot e legge i
dati ad essa inviati
Mailslot Client: processo che scrive un messaggio su
una mailslot
Il nome di una mailslot è univoco per una macchina
Nessuna gestione di “security”
Modalità di funzionamento “message-mode”
Server e Client su Win9x / NT / 2000
Mailslot

Una macchina può ospitare solo una mailslot
con lo stesso nome
Processo C1
mailslot
Processo S2
\\.\mailslot\Test
mailslot
Computer A
\\.\mailslot\Test
Computer B
Processo S1
S1, S2: Processi server
C1: Processo client
Nomi delle Mailslot

Creazione mailslot (server):


\\.\mailslot\mailslotname
Apertura mailslot per scrittura (client):




\\.\mailslot\mailslotname
\\ComputerName\mailslot\mailslotname
\\DomainName\mailslot\mailslotname
\\*\mailslot\mailslotname
Mailslot locali





Il Mailslot server deve esistere quando il Mailslot client
viene creato
Un messaggio può essere lungo fino a 64K
I messaggi inviati al server vengono ricevuti una volta
I messaggi inviati vengono sicuramente ricevuti, ma
non si sa se e quando vengono letti
Possono esistere più client che scrivono sullo stesso
server, se i client usano gli attributi
FILE_SHARE_WRITE | FILE_SHARE_READ nella
CreateFile()
Mailslot remote






Deve esserci almeno un protocollo di rete attivo
Il Mailslot client può essere creato in qualsiasi momento
(anche se non esiste un Mailslot server)
La scrittura da parte del Mailslot client non genera mai errori
Un messaggio inviato ad un dominio può essere letto da
più server
Compatibilità garantita per messaggi fino a 425 byte
Viene inviata una copia del messaggio per ogni protocollo
di rete installato (il Mailslot server può ricevere più copie
dello stesso messaggio)
Mailslot Server

Sequenza di funzioni API da chiamare:
CreateMailslot
 ReadFile
 CloseHandle

Mailslot Client

Sequenza di funzioni API da chiamare:
CreateFile
 WriteFile
 CloseHandle

Remote Procedure Call




Consente di eseguire chiamate a funzioni
presenti in processi diversi, anche su elaboratori
diversi
E’ basato sugli standard definiti da
OSF (Open Software Foundation)
DCE (Distributed Computing Environment)
E’ indipendente dal protocollo di rete
E’ la base di DCOM

Remote
Procedure
Call
Per ogni chiamata, avviene una transazione coordinata dal sistema
operativo, per trasferire al “server” i parametri della funzione, e
ricevere da esso i risultati
Client
Server
Application
1
14
Client Stub
2
13
Client Run-Time Library
3
12
Application
8
7
Client Stub
9
6
Client Run-Time Library
10
5
Transport
Transport
11
4
Comunicazione tra processi





Shared Memory
Sockets
Named Pipe
Mailslot
Remote Procedure Call
Operazioni di I/O
(I/O Manager)
Windows NT I/O System Architecture
Applications and Subsystems
Software
(User-Mode Instruction Set)
Process Security Local Object
Virtual
Manager Monitor IPC Manager Memory
Manager
Kernel
I/O
Manager
GDI
USER
Device
Drivers
HAL
Hardware
I/O
Devices
DMA/Bus
Controller
Timers
Caches,
Interrupts
CPU
Privileged
Architecture
Name Space unico per tutti i
Device
Environment
Subsystem
or DLL
I/O System Services
File System
and Network Drivers
I/O Manager
Device Drivers
User Mode
Video Monitor
and Keyboard
Mouse
Kernel Mode
Printer
Network Device
Disk
Drive
CD-ROM
Drive
Tape
Link simbolici




Usati per mappare nomi di Device MS-DOS al Name
Space di Windows NT
DWORD QueryDosDevice(
lpDeviceName, lpTargetPath, ucchMax)
BOOL DefineDosDevice(
dwFlags, lpDeviceName, lpTargetPath)
Esempio
D: -> \DEVICE\HARDDISC0\PARTITION2
Cache Manager






Cache di tutto l’I/O per default
Incrementa le performance dei programmi che
effettuano molte operazioni di I/O
La dimensione della Cache è dinamica
E’ un insieme di oggetti Section
Ha il proprio spazio di indirizzamento (di
sistema)
Usa il Virtual Memory Manager per effettuare la
paginazione
API per File I/O

Si possono usare le seguenti API per accedere ai
file:
C Run-Time Library
 Windows 3.1 API (solo per compatibilità)
 Win32 API

Win95-Based Synchronous I/O
Processing
Application
WriteFile(file_handle
data, ...)
Returns
WriteFile(file_handle
data, ...)
Win32
Subsystem
Call Windows NT
Write File Service
Return Data
User Mode
Kernel Mode
Check Parameters
Create IRP
Call Device Driver
I/O Manager
Complete IRP
Return
Queue I/O
to Device
Device Driver
Device
Time
Perform I/O Transfer
Wait for Completion
Application
Windows NT–Based
. . . Processing
Synchronous
Win32
Subsystem
WriteFile(file_handle
data, ...,
overlapped)
<Wait ends>
Return I/O Status
Call Windows NT
Write File Service
User Mode
Kernel Mode
I/O Manager
Check Parameters
Create IRP
Call Device Driver
Queue I/O
to Device
Device Driver
Device
...
Time
Wait(...)
Set File Handle
to Signaled State
Return
Handle Interrupt
Perform I/O Transfer
Interrupt for Service
Asynchronous (Overlapped) I/O
Processing . . .
Application
WriteFile(file_handle
data, ...,
overlapped)
Win32
Subsystem
Call Windows NT
Write File Service
<Perform other work>
Wait(file_handle)
<Wait ends>
Return I/O
Pending Status
User Mode
Kernel Mode
I/O Manager
Check Parameters
Create IRP
Call Device Driver
Queue I/O
to Device
Device Driver
Device
...
Time
Return
Set File Handle
to Signaled State
Return
Handle Interrupt
Perform I/O Transfer
Interrupt for Service
Effettuare Overlapped I/O con
Win32


Usare il flag FILE_FLAG_OVERLAPPED
quando si apre un file con CreateFile()
Effettuare un’operazione di I/O, e mettersi in
Wait su:
File handle, oppure
 Event object, oppure
 Una I/O completion callback

Esempio: Overlapped I/O
HANDLE usando
hFile;
Event Object
LPOVERLAPPED lpo;
// create and initialize an OVERLAPPED structure
lpo = calloc (sizeof(OVERLAPPED), 1);
lpo->Offset = 0;
lpo->hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
hFile = CreateFile ("filename", GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED, NULL);
// begin async io
WriteFile(hFile, pBuffer, cbBuffer, &nBytesWritten, lpo);
// wait for io to complete and get result
GetOverlappedResult (hFile, lpo, &nBytesWritten, TRUE);
// cleanup
CloseHandle (lpo->hEvent);
free (lpo);
I/O Completion Routine

User-Mode Asynchronous Callback


Non è veramente asincrona, perché può essere
eseguita solo in corrispondenza di punti di controllo
definiti (Control Points)
Control Points

ReadFileEx, WriteFileEx,
WaitForSingleObjectEx,
WaitForMultipleObjectsEx, SleepEx
Esempio: I/O Completion
Routine
VOID WINAPI lpfnIOCompletion (
DWORD
dwError,
DWORD
cbWritten,
LPOVERLAPPED lpo)
{
if (!dwError)
lpo->Offset += cbWritten;
}
...
hFile = CreateFile ("filename", GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
// create and initialize an OVERLAPPED structure
lpo = calloc (sizeof(OVERLAPPED), 1);
lpo->Offset = GetFileSize (hFile, NULL);
// begin async io with callback
WriteFileEx (hFile, pBuffer, cbBuffer, lpo, lpfnIOCompletion);
...
// wait for callback to be called on i/o completion
SleepEx (INFINITE, TRUE);
...
I/O Completion Port



Basato su una coda (I/O Completion Port) di messaggi
relativi alle operazioni di I/O asincrone completate
(I/O Completion Packet)
Uno o più thread (generalmente worker thread)
possono prelevare messaggi dalla coda ed eseguire
operazioni appropriate
Si può controllare il numero massimo di thread attivi
che possono processare I/O Completion Packet
(eventuali altre richieste concorrenti sospendono il
thread richiedente fino a che uno dei thread in
esecuzione non completa l’elaborazione del Completion
Packet prelevato)
Scatter-Gather I/O






Meccanismo ad alte prestazioni per lettura/scrittura dati
su file
Disponibile su NT4.0 SP2 e successivi
Usato da SQL Server
Legge/scrive dati presenti in zone non contigue di
memoria su zone di file contigue, sfruttando il DMA
Granularità di pagina (4K / 8K)
Funzioni API:


ReadFileScatter(…)
WriteFileGather(…)
Change Notification

Oggetto kernel utilizzabile in funzioni di Wait
per monitorare il cambiamento del contenuto di
una directory
FindFirstChangeNotification(…)
 FindNextChangeNotification(…)
 FindCloseChangeNotification(…)


Nota bene: non si usa CloseHandle(…) per la
chiusura dell’handle ottenuto con
FindFirstChangeNotification(…)
I/O Manager






Architettura I/O Manager
Elaborazione sincrona dell’I/O
Elaborazione asincrona dell’I/O
I/O Completion Routine
I/O Completion Port
Change Notification
Riferimenti

http://msdn.microsoft.com

http://www.sysinternals.com
Altre Informazioni

Dove posso ottenere maggiori informazioni
www.sysinternals.com
 www.microsoft.com/msdn/italy/studenti
 www.ugidotnet.org


Developer resources

Microsoft Developer Network
Windows internals
I vostri feedback sono
importanti
 Compilate
il modulo di
valutazione
Grazie della partecipazione
– [email protected]
Fly UP