Sei sulla pagina 1di 191

Facolt di Ingegneria Corso di Studi in Ingegneria Informatica

tesi di laurea

Il sistema operativo Mac OS X


Anno Accademico 2006/2007

relatore Ch.mo prof. Domenico Cotroneo candidato Massimiliano Di Cesare matr. 41/2764

Ad Anastasia Per aspera sic itur ad astra

Indice
Introduzione 6

Capitolo 1. Architettura del Mac OS X 1.1 Il sottosistema Darwin 1.2 Il kernel XNU 1.2.1 Mach 1.2.2 BSD 1.2.3 I/O Kit 1.2.4 Libreria libkern 1.2.5 Libreria libsa 1.2.6 Platform export 1.2.7 Kernel extensions 1.3 Il file system 1.4 La sicurezza 1.4.1 Kernel-space security 1.4.2 User-space security 1.4.3 Amministrazione del sistema 1.4.4 Sistema di verifica

23 25 26 27 28 30 31 32 33 34 34 36 37 39 41 43

Capitolo 2. Il Kernel XNU 2.1 XNU Source 2.2 Mach 2.2.1 Tasks e Threads 2.2.2 Ports 2.2.3 Messages 2.2.4 Virtual Memory e Memory Objects 2.2.5 Exception Handling 2.3 Allinterno del kernel 2.3.1 Tipi di Trasferimento del Controllo 2.3.1.1 External Hardware Interrupts 2.3.1.2 Processor Traps 2.3.1.3 Software Traps 2.3.1.4 System Calls

45 45 51 53 55 57 58 59 61 62 63 63 64 64

III

Capitolo 3. I Processi 3.1 Astrazioni, Strutture dati e APIs del Mach 3.1.1 Processor sets 3.1.2 Processors 3.1.3 Tasks 3.1.4 Threads 3.1.4.1 Kernel Threads 3.1.5 Astrazioni relative al thread 3.1.5.1 Chiamata a procedura remota 3.1.5.2 Attivazione e Shuttle 3.1.5.3 Migrazione del thread 3.1.5.4 Continuazioni 3.1.6 I threads del Mac OS X 3.2 Lo Scheduling 3.2.1 Scheduler Operation 3.2.2 Scheduling Policies

65 67 68 71 75 77 82 85 85 86 88 89 91 92 93 100

Capitolo 4. La memoria 4.1 La memoria virtuale 4.1.1 Task Address Spaces 4.1.2 VM Maps 4.1.3 VM Map Entries 4.1.4 VM Objects 4.1.5 Pagers 4.1.6 Copy-on-Write 4.1.7 The Physical Map (pmap) 4.2 La memoria residente 4.2.1 Page Faults 4.3 Universal Page Lists (UPLs) 4.4 Unified Buffer Cache (UBC) 4.5 Il programma Dynamic Pager 4.6 LUpdate Daemon 4.7 La memoria condivisa di sistema 4.8 Task Working Set 4.9 Memory-mapped files

105 108 110 110 111 112 114 120 123 125 129 130 131 135 136 136 137 140

Capitolo 5. Interprocess Communication 5.1 LIPC del Mach 5.1.1 Le porte Mach 5.1.2 I messaggi IPC del Mach 5.2 IPC Mach: implementazione nel Mac OS X 5.2.1 Gli spazi IPC 5.2.2 Anatomia di una porta Mach 5.2.3 Tasks e IPC

148 150 150 153 155 155 157 159

IV

5.2.4 Threads e IPC 5.2.5 Allocazione di una porta 5.2.6 Implementazione del messaging 5.3 Lo standard POSIX

161 162 164 166

Capitolo 6. Il file system HFS+ 6.1 Concetti fondamentali 6.1.1 B-Trees 6.2 La struttura di un volume HFS+ 6.2.1 Frammentazione 6.3 Particolarit dellHFS+ 6.3.1 Permessi 6.3.2 Journaling 6.3.3 Deframmentazione on-the-fly 6.3.4 Zona metadata 6.3.5 Hot File Clustering

169 169 172 179 180 182 182 183 186 186 187

Bibliografia

191

Il sistema operativo Mac OS X

Introduzione

Alla fine del 1975, Stephen Gary Steve Wozniak termin il suo prototipo di computer fatto in casa utilizzando componenti a basso costo. Il primo aprile del 1976 Steven Paul Steve Jobs, Steve Wozniak e Ronald Wayne fondarono la societ Apple1, ed il loro primo prodotto fu il computer di Wozniak: lApple I. Alla fine dellanno Wozniak cre lApple ][, basato sullo stesso processore, ma presentato come un computer integrato. Apple rilasci nel luglio del 1978 la sua prima versione di DOS: lApple DOS 3.12. Limpegno della Apple per rendere il personal computing appetibile economicamente per le masse riusc con lApple ][, ma restava la difficolt per tali masse di interagire con i computer. Questo fatto fu percepito anche da Apple come un forte impedimento alla crescita della diffusione dei personal computers. Nel 1979 nacque il progetto LISA (Local Integrated Software Architecture) con lintento di creare un microcomputer integrato, autonomo, monoutente e soprattutto facile da usare. LISA fu introdotto con un sistema operativo proprietario (Lisa OS, Lisa Office System) ed una suite dapplicazioni da ufficio. Molte caratteristiche di Lisa faranno parte dei sistemi Apple a venire; infatti, molti di questi concetti esistono anche in Mac OS X.

Ronald Wayne lasci lApple dopo meno di due settimane, poich ritenne troppo rischioso linvestimento. Il numero di versione fu 3.1 e non 1.0 perch Paul Laughton (uno degli implementatori) increment il contatore di revisioni ad ogni ricompilazione del codice sorgente. Il contatore part da 0.1 ed increment di .1 ad ogni ricompilazione. LApple DOS fu quindi testato in beta come versione 3.0 e rilasciato come versione 3.1.
2

Il sistema operativo Mac OS X

Il progetto Lisa fu fallimentare a causa dei costi elevati e fu abbandonato definitivamente nel 1985. Nel settembre del 1989 lApple arriv al punto di mandare in discarica circa 2700 computers, poich lo sgravio fiscale per la rottamazione di un PC Lisa aveva superato il suo valore commerciale. C da ricordare che, nonostante questinsuccesso commerciale, Lisa pu considerarsi un successo tecnologico dellApple. Nella primavera del 1979 il progetto Annie (nato per creare una versione economica di Lisa) fu affidato a Jef Raskin, il quale ritenne che luso di nomi come Lisa e Annie fosse una discriminante sessuale nei suoi confronti e quindi rinomin il progetto in Macintosh, un deliberato refuso di McIntosh3. Durante la battaglia legale con la McIntosh Labs (societ produttrice di stereo) per il trademark, lApple vagli anche degli acronimi come ad esempio MAC (Mouse Activated Computer4). Prima che Macintosh divenisse una realt, Raskin lasci il progetto ed in seguito anche la societ. A lui subentr Steve Jobs che, abbandonato il progetto (business-oriented) di Lisa, rivers le sue energie nel progetto (home-oriented) Annie/Macintosh. Il prodotto Macintosh fu presentato il 24 gennaio del 1984 a Cupertino, in occasione del meeting annuale degli azionisti Apple, con uneccellente operazione di marketing5. A differenza di Lisa, il Macintosh non fu pensato per far funzionare pi sistemi operativi. Le sue ROM contenevano sia codice di basso livello (inizializzazione hardware, diagnostica, drivers, etc) che codice di alto livello (Toolbox: una collezione di routines a disposizione delle applicazioni, pi o meno come una shared library). Dopo il rilascio, lApple spese gli anni successivi nel miglioramento del sistema operativo Macintosh dal System 2 al System 6. Nel marzo del 1988 un gruppo dingegneri e managers si riunirono e crearono 3 moduli: blue, pink e red. Blue era il modulo per migliorare il sistema operativo Macintosh esistente, e form la base del System 7.

La McIntosh una variet di mela. Qualcuno sostiene che allinterno di Apple alcuni commentarono che la sigla MAC stesse per Meaningless Acronym Computer (computer con acronimo senza significato). 5 Steve Jobs esord citando un brano di The times they are a-changin di Bob Dylan e dopo la presentazione delle potenzialit del sistema (di derivazione Lisa) mise in scena un dialogo con un programma vocale in esecuzione sul Macintosh.
4

Il sistema operativo Mac OS X

Pink era il modulo per creare un sistema operativo orientato agli oggetti. Avrebbe dovuto avere la completa protezione della memoria, il multitasking con threads leggeri, un gran numero di spazi degli indirizzi protetti e numerose altre caratteristiche moderne. Dopo un lungo periodo dinattivit, il progetto Pink venne trasferito alla Taligent, una societ congiunta tra Apple e IBM. Red era il modulo contenente le innovazioni del Pink ritenute troppo avanzate.

Figura I-1

Larchitettura di A/UX

Sul finire degli anni 80 il software di sistema era alla versione 6. LApple present due interessanti sistemi operativi in questo periodo: il GS/OS e lA/UX. Questultimo, rilasciato nellinverno del 1988, rappresentava la versione Apple conforme alle norme POSIX dellUnix. La prima versione dellA/UX si basava su 4.2BSD e AT&T Unix System V 8

Il sistema operativo Mac OS X

Release 2, ma le versioni successive si ispirarono da 4.3BSD e varie releases susseguenti del System V. Le versioni 3.x dellA/UX combinano un ambiente Unix System V con il Macintosh System 7 (presentato nel 1991). Lultima versione dellA/UX (la 3.1.1) fu rilasciata nel 1995. Lintroduzione del System 7 rappresent un enorme balzo in avanti rispetto alle precedenti versioni di Macintosh. In particolare introdusse il multitasking, ma non la protezione della memoria. Nello stesso periodo lApple form unalleanza6 con IBM e Motorola per far creare una piattaforma hardware comune (CHRP, Common Hardware Reference Platform). Grazie a tale alleanza i PowerPC approdarono nel mondo Macintosh.

Figura I-2

Transizione allarchitettura PowerPC

Larchitettura PowerPC nasce da un progetto dellIBM denominato POWER (Performance Optimized With Enhanced RISC7). Il primo PowerPC fu il 601 e fu introdotto nel settembre del 1993. Il 601 implementava il subset a 32bit dellarchitettura PowerPC, ma non il set completo: ci avrebbe permesso ai venditori di effettuare la transizione verso i PowerPC.
Tale sodalizio fu chiamato AIM dalle iniziali delle tre societ: Apple, IBM e Motorola. RISC lacronimo di Reduced Instruction Set Computer (computer a set di istruzioni ridotto), in contrapposizione al tradizionale CISC (Complex Istruction Set Computer).
7 6

Il sistema operativo Mac OS X

Il Macintosh System 7.1.2 fu il primo sistema operativo Apple a funzionare su un PowerPC, anche se molte parti del codice non fossero native. Il porting di tutte le componenti del sistema operativo verso la nuova architettura avrebbe richiesto un tempo proibito per Apple. Inoltre era importante garantire che le applicazioni scritte per il Motorola 68K continuassero a funzionare anche sui PowerPC. Larchitettura di sistema (a nanokernel) creata incluse uno strato dastrazione hardware (HAL, hardware abstraction layer) ed un emulatore 68K. Nel frattempo (dal 2001) la Microsoft di Bill Gates aveva lanciato con successo il suo sistema operativo Windows 3.x. Apple doveva rispondere allassalto di Microsoft prima del rilascio di Windows 95, che si proponeva come un sistema operativo end-user. I progetti Red e Pink risultarono inappropriati8 ed Apple decise di continuare a cercare una soluzione al problema SO in un modo o nellaltro. Star Trek fu un corposo progetto che Apple port avanti in collaborazione con Novell per effettuare il porting del Mac OS sulle piattaforme x869. Nonostante il team congiunto dingegneri fosse riuscito a creare un prototipo efficace in tempi brevissimi, il progetto fu cancellato per vari motivi: Apple aveva gi commissionato il PowerPC; molti allinterno ed allesterno della Apple ritennero che il progetto potesse corrompere lesistente modello economico; il feedback dei venditori non era affatto incoraggiante. Il progetto Star Trek fu vendicato nel 2005 con lannuncio della transizione di Mac OS X sulla piattaforma x86. La prima macchina Macintosh basata sullx86 venne presentata nel gennaio del 2006 a San Francisco. Allinizio del 1994 la Apple annunci lintenzione di convogliare oltre dieci anni desperienza nella nuova release del sistema operativo Macintosh, il Mac OS 8 (nome in codice Copland).

Il progetto Red fu rinominato Raptor, ma fu chiuso per mancanza di fondi e (soprattutto) per attriti interni al team di sviluppo. Il progetto Pink, che si proponeva come un sistema operativo orientato agli oggetti, fu affidato alla Taligent (controllata da Apple e IBM) nel 1992 e si trasform in un ambiente orientato agli oggetti chiamato CommonPoint. Taligent Object Services (TalOS) fu il nome di un set di tecnologie di basso livello, costruite intorno al Mach 3.0, con lintento di creare un sistema operativo orientato agli oggetti snello e flessibile. Nel 1995 la societ Taligent pass sotto il controllo esclusivo della IBM, rendendo di fatto il progetto Pink lennesima occasione mancata dalla Apple. 9 Qualche anno dopo Darwin (il core di Mac OS X) funzioner sia su PowerPC e x86.

10

Il sistema operativo Mac OS X

Purtroppo, nonostante le grandi attese, il progetto continuava a slittare e la sua uscita prevista, e fortemente sperata, per il 1996 non sembr fattibile. Il CEO dellApple, Gil Amelio, defin lo stato di Copland come solo una collezione di pezzi separati, ognuno sviluppato da un team diverso che in qualche modo dovrebbero magicamente unirsi

Figura I-3

Larchitettura di Copland

LApple decise di cancellare Copland nel maggio del 1996. Amelio annunci che le parti migliori di Copland sarebbero state utilizzate nelle future releases dei loro sistemi, sin dallimminente System 7.6, il cui nome fu formalmente cambiato in Mac OS 7.6. Per un breve periodo Apple vagli anche lidea di una partenership per creare un Apple OS basandosi su altri sistemi operativi: furono presi in considerazione Windows NT (Microsoft), Solaris (Sun Microsystems) e BeOS (Be). Nei fatti fu lacquisizione di Be da parte di Apple quella che and materializzandosi. La Be fu fondata nel 1990 da Jean-Louis Gasse, ex capo Product Development dellApple. Purtroppo, nonostante il team dingegneri della societ fosse riuscito a sviluppare un impressionante sistema operativo, BeOS non era ancora un prodotto completo ed inoltre cerano ancora pochissime applicazioni scritte per tale sistema.

11

Il sistema operativo Mac OS X

Gasse negozi a lungo con Apple per la vendita di Be, ma alla fine non trovarono un accordo sul prezzo e laffare non fu concluso.10

Figura I-4

Storia dei sistemi operativi NeXT

Be ebbe un duro avversario in NeXT, una compagnia fondata da un altro ex dirigente dellApple: Steve Jobs. Tutte le responsabilit operative di Steve Jobs allApple furono
10

Gasse chiedeva 275 milioni di dollari, mentre la Apple ne offr al massimo 200. La societ Be fall infine e le sue tecnologie furono acquisite da Palm, Inc. nel 2001.

12

Il sistema operativo Mac OS X

rimosse il 31 maggio del 1985. Nel successivo mese di settembre, Jobs reclut cinque impiegati Apple e cominci un nuovo progetto: creare il computer perfetto per la ricerca.11 La Apple lo cit, ma dopo pochi mesi lasci cadere le accuse a patto che Jobs rinunciasse a costruire computer competitivi e si impegnasse a non assumere impiegati dellApple per sei mesi. Nacque cos la NeXT Computer, Inc. che, partita con i soli finanziamenti personali di Jobs, trov ben presto investitori. Il 12 ottobre del 1988, a San Francisco, Steve Jobs present il suo NeXT cube corredato dal sistema operativo NEXTSTEP. Questo sistema operativo era basato sul porting del kernel CMU Mach 2.0 con un ambiente 4.3BSD ed un windows server basato su Display PostScript12. Il sistema NEXTSTEP usava come linguaggio di programmazione nativo lObjective-C13. Al momento del lancio di NeXT cube il sistema era alla versione 0.8 e ci volle un anno affinch venisse alla luce una matura versione 1.0 ed un altro anno per la 2.0. Al NeXTWORLD Expo del 1992 fu presentato NEXTSTEP 486, per piattaforma x86. Lultima versione di NEXTSTEP (la 3.3) fu presentata nel febbraio del 1995.14 NEXTSTEP ha funzionato sulle piattaforme 68K, x86, PA-RISC e SPARC. Fu possibile creare una singola versione di unapplicazione contenente i binari per tutte le architetture supportate. Tali binari multi-architettura sono noti come fat binaries15. Nonostante leleganza dellhardware e le virt del software, la compagnia NeXT non risult essere economicamente stabile negli anni: allinizio del 1993 annunci il piano di abbandonare lo sviluppo hardware per permettere al progetto NEXTSTEP di progredire per la piattaforma x86.

Steve Jobs aveva persino cercato di convincere il premio Nobel per la biochimica, Paul Berg, ad utilizzare uno dei suoi computers per le simulazioni. 12 Nel 1986, Sun Microsystems annunci il proprio Display Postscript Window System chiamato NeWS. 13 Objective-C un linguaggio di programmazione compilato orientato agli oggetti, inventato da Brad Cox e Tom Love nei primi anni 80. Si tratta di un superset orientato agli oggetti del C, con binding dinamico e sintassi di messaging ispirata a Smalltalk. Volendo essere pi semplice del C++ ne ha meno caratteristiche (come ereditariet multipla e overloading degli operatori). Cox e Love fondarono la StepStone Corporation da cui NeXT compr la licenza del linguaggio e cre il proprio compiler. Nel 1995, NeXT compr tutti i diritti intellettuali relativi allObjective-C. Il compilatore Objective-C della Apple utilizzato in Mac OS X una versione modificata del compiler GNU. 14 Nellinverno del 1990, Timothy John Tim Berners-Lee del CERN cre il primo web browser con WYSIWYG browsing ed authoring. Il browser fu sviluppato su una macchina NeXT. 15 Mac OS X supporta i fat binaries. In particolare, un fat binary pu essere utilizzato per contenere le versioni a 32bit e 64bit di un programma Mac OS X dalla versione 10.4 e successive. I cosiddetti Universal Binaries sulla versione x86 del Mac OS X altro non sono che semplici fat binaries.

11

13

Il sistema operativo Mac OS X

NeXT instaur una collaborazione con Sun Microsystems per rilasciare congiuntamente le specifiche di OpenStep, una piattaforma aperta comprendente molte API e strutture che permettono lo sviluppo di implementazioni proprie di un sistema operativo orientato agli oggetti. Le API OpenStep furono implementate su SunOS, HP-UX e Windows NT. Limplementazione propria della NeXT, essenzialmente una versione di NEXTSTEP conforme alle specifiche di OpenStep, fu rilasciata come OPENSTEP 4.0 nel luglio del 1996 (le versioni 4.1 e 4.2 seguirono a breve). Le API OpenStep ed il sistema operativo OPENSTEP, nonostante un oggettivo interesse, non cambiarono molto la situazione di NeXT. Questa cominci a spostare i propri interessi al progetto WebObjects, un ambiente multipiattaforma per la rapida realizzazione e rilascio di applicazioni web-based.16 Insieme al sistema operativo della NeXT arriv il suo kernel, che divent la base per i sistemi futuri dellApple, in particolare del Mac OS X. Un gruppo di ricercatori dellUniversit di Rochester, New York, cominci lo sviluppo di un sistema gateway intelligente (RIG, Rochesters Intelligent Gateway) nel 1975. Jerry Feldman, coniatore dellacronimo, fece gran parte del progetto iniziale. Il RIG fu pensato per garantire un accesso uniforme, tramite terminali, ad una moltitudine di risorse locali (dischi, nastri magnetici, stampanti, plotters etc) e remote (accessibili medianti network come ARPANET). Il sistema operativo del RIG, chiamato Aleph, funzionava su un minicomputer Data General Eclipse ed il suo kernel fu strutturato intorno ad un sistema di IPC (Interprocess Communication). I processi di RIG potevano mandarsi messaggi lun laltro, con un porta17 che ne specificava la destinazione. Ogni processo poteva avere pi porte definite, ognuna delle quali poteva essere usata per attendere larrivo di un messaggio. Un processo X poteva essere shadow o interpose rispetto ad un processo Y. Nel caso dello shadowing, il processo X riceveva una copia dogni messaggio inviato a Y. Nel caso invece di interposing, X intercetta tutti i messaggi da e per Y. Questo sistema IPC basato
16 17

Il sistema operativo Mac OS X si basa sulle tecnologie di NeXT ed Apple utilizza WebObjects per i propri siti. Una porta era una coda di messaggi intra-kernel globalmente unificata da una coppia di interi nel formato <.> indicanti il numero di processo ed il numero di porta.

14

Il sistema operativo Mac OS X

su messaggi e porte fu un mattone fondamentale del sistema operativo. Il progetto RIG fu terminato qualche anno dopo a causa di svariate imperfezioni nel progetto. Richard Rashid fu una delle persone che lavorarono al progetto RIG. Nel 1979 si spost alla Carnegie Mellon University, dove inizi a lavorare su Accent, il kernel per un sistema operativo di rete. Lo sviluppo attivo dellAccent inizi nellaprile del 1981. Cos come RIG, anche Accent era un sistema orientato alla comunicazione che usava lIPC come strumento base della sua struttura. Tuttavia Accent risolse molte delle imperfezioni di RIG. Si potrebbe pensare che Accent non sia altro che unevoluzione del RIG con memoria virtuale e messaggistica network-trasparent. Accent funzionava su macchine PERQ, delle workstations grafiche prodotte da Three Rivers Corporation dal 1980. QNIX fu un ambiente UNIX, sviluppato da Spider Systems, basato su AT&T System V UNIX che funzionava al di sotto di Accent sulle macchine PERQ. 18 Una macchina LISP (SPICE LISP) fu disponibile per Accent insieme ad altri linguaggi come Ada, PERQ Pascal, C e Fortran. Il progetto Matchmaker part nel 1981 come parte del progetto SPICE. Si trattava di un linguaggio per la specifica dellinterfaccia nato per lavorare con i linguaggi di programmazione esistenti. Attraverso Matchmaker, era possibile specificare interfacce per RPC (Remote Procedure Call) orientate agli oggetti. La specifica era poi convertita in codice interfaccia da un compilatore multitarget. Matchmaker comparabile al protocollo rpcgen ed al suo linguaggio. Il programma MIG (Mach Interface Generator) usato nel Mac OS X derivato da Matchmaker. Nel giro di pochi anni, il futuro dellAccent non risult promettente come sembrava. Aveva bisogno di una nuova base hardware, supporto per multiprocessori, portabilit su altre tipologie hardware ed inoltre aveva difficolt nel supporto di software UNIX. Il successore dellAccent fu chiamato Mach, un sistema concepito come ispirato ad Accent ma pienamente compatibile UNIX. Retrospettivamente si pu sostenere che RIG e
18

PERQ poteva interpretare i bytecode in hardware, in analogia con il successivo meccanismo di Java.

15

Il sistema operativo Mac OS X

Accent furono, rispettivamente, la versione 0.8 e 0.9 del Mach. Quando fu sviluppato il Mach, lUnix era ormai in giro da oltre 15 anni e la sua complessit era cresciuta al punto da non essere facilmente modificabile. Il progetto Mach inizi nel 1984 con lobiettivo di creare un microkernel che sarebbe potuto essere la base per la creazione daltri sistemi operativi. 19 Il Mach fu pensato soprattutto per implementare il processore e la gestione della memoria, ma non il file system, il networking o lI/O: il vero sistema operativo doveva agire come un task a livello utente del Mach. Limplementazione del Mach utilizzava come codice base il 4.3BSD, come riferimenti per la sezione di messaggistica aveva RIG e Accent, e per quanto riguardava il sottosistema di gestione della memoria virtuale sispir al sistema operativo TOPS-20 della DEC. Man mano che procedeva lo sviluppo di Mach, intere porzioni di codice del kernel BSD furono sostituite dalle equivalenti versioni Mach con laggiunta di nuove componenti. 20 Il kernel Mach fu presentato, nel 1986, come la nuova base per lo sviluppo di UNIX; nonostante non tutti lo vedessero in questo modo, si accinse a diventare un sistema abbastanza popolare.21 La decisione di non supportare nessun file system, networking o I/O fu presa allo scopo di mantenere la semplicit e promuovere la portabilit dei sistemi operativi sviluppati attraverso il Mach. Uno o pi sistemi operativi potrebbero funzionare su un Mach come tasks a livello utente. Tuttavia, le implementazioni reali deviarono da questo concetto. La release 2.0 del Mach, cos come la successiva e riuscitissima 2.5, ha implementazioni monolitiche in cui Mach e BSD risiedono nello stesso spazio degli indirizzi. Una delle pi importanti decisioni della CMU (Carnegie Mellon University) fu di fornire tutto il software Mach con licenza non restrittiva (esente da tasse o diritti dautore di distribuzione). La OSF (Open Software Foundation) utilizz il Mach 2.5 per realizzare
19 20

Essendo scritto in C, il kernel Mach risulta molto portabile. Larchitettura della memoria virtuale di FreeBSD basata sul Mach. 21 Avadis Tevanian, uno degli inventori del Mach e futuro Chief Software Technology Officer della Apple, racconta sullorigine del nome Mach. Durante un pranzo a Pittsburgh con Richard Rashid (futuro capo della Microsoft Reasearch) si discuteva dellacronimo del progetto e Tevanian propose MUCK (Multi-User Communication Kernel oppure Multiprocessor Universal Communication Kernel). Rashid pass tale sigla ad un collega italiano, tale Dario Giuse, che pronunci erroneamente mach a Rashid piacque.

16

Il sistema operativo Mac OS X

buona parte dei servizi nel sistema operativo OSF/1. Le versioni Mach 2.x furono utilizzate anche in Mt. Xinu, Multimax (Encore), Omron LUNA/88k, NEXTSTEP e OPENSTEP. Il progetto Mach 3.0, iniziato alla CMU e continuato dallOSF, fu la prima vera versione a microkernel: BSD funzionava come un task user-space, con le sole caratteristiche fondamentali fornite dal kernel Mach. I benefici intesi nella politica dei sistemi operativi microkernel-based, come appunto il Mach 3.0, furono presto spiazzati dai problemi prestazionali che una tale scelta comportava. Furono creati emulatori Mach per BSD, DOS, HP-UX, OS/2, OSF/1, SVR4, VMS e persino per sistemi operativi Macintosh. LApple e lOSF iniziarono un progetto per eseguire il porting del Linux in modo da farlo funzionare su varie architetture PowerPC, con Linux hostato su unimplementazione Mach dellOSF. Il progetto port ad un core system chiamato osmfk, mentre lintero sistema fu conosciuto come MkLinux. La prima versione, basata su Linux 1.3, fu rilasciata come MkLinux DR1 nei primi mesi del 1996. MkLinux usava un approccio a singolo server: il kernel monolitico di Linux funzionava come un singolo task sul Mach. Il Mac OS X usa una base kernel derivata da osmfk, e include molti dei miglioramenti del MkLinux. In ogni caso, tutte le componenti del kernel del Mac OS X, incluse le porzioni BSD, risiedono nello stesso spazio degli indirizzi.22

La prima release di un sistema operativo Apple, dopo lacquisto della NeXT, fu il Mac OS 7.623 nel tardo 1996. Il piano dellApple era di rilasciare unistallazione completa (standalone) ogni anno, intervallata da vari upgrades. Molti dei modelli Power Macintosh e PowerBook non supportati dal Mac OS 7.6 furono integrati nellupdate 7.6.1 successivo. In quel periodo cerano due fenomeni che stavano spazzando il mondo dei computer:

Oltre allA/UX e MkLinux ci fu un terzo incontro tra i sistemi Macintosh ed il mondo UNIX: il MachTen della Tenon System. Si trattava di unapplicazione che girava sul sistema operativo Apple, in contrasto con lA/UX che funzionava direttamente sullhardware. Il MacTen fu basato sul kernel Mach, calato in un ambiente BSD. Forniva il preempitive multitasking per le applicazioni Unix, mentre nellambiente MacOS lesecuzione rimaneva in cooperative multitasking. 23 Fu il primo sistema ad essere nominato Mac OS.

22

17

Il sistema operativo Mac OS X

Internet e Microsoft Windows 95. LApple enfatizz la sua compatibilit con Windows 95 e pose laccento sula capacit di integrazione con Internet del suo sistema. Il sistema che avrebbe dovuto essere il Mac OS 7.7 divent in realt il Mac OS 8. Come previsto molte delle caratteristiche sviluppate per Copland furono integrate nelle versioni 8 e 9 del Mac OS. La versione 8.5 fu realizzata solo per piattaforma PowerPC. Il nanokernel fu ispezionato nel Mac OS 8.6 per integrare il multitasking ed il multiprocessing, includendo un allocatore di memoria preemption-safe. Nel 1999 usc il Mac OS 9, e fu salutato dallApple come best Internet operating system ever. Fu il primo sistema operativo a poter essere aggiornato attraverso Internet. Un elemento importante del Mac OS 9 fu una matura istallazione delle API di Carbon (che allepoca rappresentavano circa il 70% delle API dellintero sistema). Carbon garantiva la compatibilit con le versioni 8.1 e successive. Lultima release del Mac OS 9, la 9.2.2, fu rilasciata alla fine del 2001. Con lavvento del Mac OS X, queste vecchie versioni di Mac OS furono riferite come Classic.

Il progetto, chiamato Rhapsody, dei sistemi operativi di nuova generazione basati su OPENSTEP fu presentato la prima volta al WWDC (World Wide Developers Conference) del 1997. Rhapsody consisteva nelle seguenti componenti primarie: Il kernel ed i relativi sottosistemi, basati su Mach e BSD; Un sottosistema compatibile con Mac OS, chiamato Blue Box; Unimplementazione estesa delle API OpenStep, detta Yellow Box; Una macchina virtuale Java (JVM, Java Virtual Machine); Un sistema a finestre basato su Display PostScript; Uninterfaccia utente simile a quella del Mac OS ma con caratteristiche prese dallOPENSTEP. LApple pianific di portare su Rhapsody molte delle strutture chiave del Mac OS. Ci furono due releases per sviluppatori del Rhapsody, la DR1 e la DR2, e furono entrambe rilasciate sia per PowerPC sia per le piattaforme x86. Il Rhapsody support inoltre una moltitudine di file systems tra cui AFP (Apple Filing Protocol), FAT, HFS, HFS Plus, ISO 18

Il sistema operativo Mac OS X

9660 e UFS. Poco dopo il rilascio del Rhapsody DR1, lApple estese la versione PowerPC con un ambiente compatibile con Mac OS, chiamato Blue Box. Implementato da unapplicazione Rhapsody (MacOS.app), il Blue Box era un ambiente virtuale che appariva come un nuovo modello hardware Macintosh. Inizialmente il Blue Box virtualizz24 il Mac OS 8.x in full screen; in seguito fu aggiunto il supporto alle nuove versioni del Mac OS e fu introdotta la possibilit desecuzione in finestra. Nel Mac OS X, lambiente Blue Box sar conosciuto come Classic environment (e sar fornito dallapplicazione Classic Startup.app). La piattaforma di sviluppo di Rhapsody fu chiamata Yellow Box. Oltre ad essere disponibile sul Rhapsody per Power Macintosh e per x86, esisteva anche una versione indipendente per Microsoft Windows. La Yellow Box comprendeva i tools di sviluppo di derivazione NeXT. Le implementazioni per Windows NT e le prime implementazioni delle API OpenStep (per piattaforme come Solaris) utilizzarono architetture simili. La Yellow Box evolse nelle API Cocoa del Mac OS X.

Dopo il rilascio di Rhapsody DR2, Apple cambi nuovamente la sua strategia per i sistemi operativi, ma stavolta riusc nellintento di avere un sistema veramente nuovo. Durante il WWDC del 1998, Adobes Photoshop fu fatto funzionare su quello che, 3 anni dopo, sarebbe stato il Mac OS X. Nel marzo del 1999, mentre si aspettava il rilascio di Rhapsody DR3, Apple annunci luscita del Mac OS X Server 1.0: essenzialmente una versione potenziata del Rhapsody con lincorporazione di strumenti per la gestione di reti. Contemporaneamente annunci anche una nuova iniziativa (una fork del progetto Rhapsody) chiamata Darwin: la base open-source dei futuri sistemi operativi Apple. Nel corso dei tre anni successivi (1998-2001) man mano che erano rilasciati nuovi updates per i prodotti server, progrediva lo sviluppo dei prodotti desktop, con la versione server che godeva di molti dei miglioramenti della versione desktop. Miglioramenti sostanziali
24

Lambiente Blue Box uno strato di virtualizzazione, non di emulazione. Le istruzioni innocue vengono eseguite in modo nativo sul processore, mentre quelle dannose (come quelle che riguardano lhardware) sono trappate e maneggiate in modo appropriato.

19

Il sistema operativo Mac OS X

furono introdotti nel corso delle quattro Developer Preview del Mac OS X. Nella prima (Mac OS X DP1, maggio 1999) ci fu limplementazione delle API di Carbon, per consentire agli sviluppatori il passaggio dal Mac OS 9 al Mac OS X. Unapplicazione Classic richiedeva che il Mac OS X funzionasse su unistallazione di Mac OS 9, mentre unapplicazione Carbon poteva essere compilata per funzionare in modo nativo su entrambi. Nella seconda (Mac OS X DP2, novembre 1999) la Yellow Box divent Cocoa. Fu introdotta una JDK (Java Development Kit) ed un compilatore JIT (just-in-time). Il Blue Box fu fornito attraverso Classic.app (una nuova versione di MacOS.app) funzionante come un processo chiamato TruBlueEnvironment. Lambiente UNIX si basava su 4.4BSD. Furono introdotte numerose API: BSD, Carbon, Classic, Cocoa e Java. Nella terza (Mac OS X DP3, gennaio 2000) furono introdotti Aqua (la nuova interfaccia utente grafica) e Dock. Nella quarta (Mac OS X DP4, maggio 2000) il Finder fu rinominato Desktop. Fece la sua prima comparsa lapplicazione System Preferences (Preferences.app), permettendo allutente di configurare una moltitudine di preferenze di sistema come: Classic, ColorSync, Date&Time, Energy Saver, Internet, keyboard, Login Items, Monitor, Mouse, Network, Password e cos via. Il Dock fu scorporato dal Finder e reso unapplicazione a se stante (Dock.app). Apple rilasci una versione beta di Mac OS X allApple Expo di Parigi il 13 settembre del 2000. In vendita a $29.95 e disponibile in Inglese, Francese e Tedesco si trattava essenzialmente di una preview pubblicamente ottenibile per la valutazione e lo sviluppo: la confezione conteneva un messaggio dellApple ai beta testers che recitava You are holding the future of the Macintosh in your hands. Anche se la Mac OS X Public Beta fosse priva dimportanti caratteristiche e apparentemente mancasse di stabilit e prestazioni, riusc a mostrare molte importanti tecnologie Apple allopera (in modo particolare a coloro che non avevano seguito levoluzione delle varie releases DP). Con Darwin, lApple cerc continuamente di fare leva su di un gran numero di software open-source per utilizzarli con (ed a volte integrarli in) Mac OS X. 20

Il sistema operativo Mac OS X

LApple e lInternet System Consortium, Inc. (ISC) fondarono congiuntamente il progetto OpenDarwin nellaprile del 2002 per promuovere lo sviluppo open-source di Darwin.25 Il kernel di Darwin si chiama XNU, ufficiosamente acronimo ricorsivo per Xnu is Not Unix26. Basato fondamentalmente su Mac e FreeBSD, include anche codice e concetti da varie fonti come ad esempio il progetto MkLinux (sostenuto direttamente dallApple), il lavoro svolto sul Mach dallUniversity of Utah, NetBSD e OpenBSD.

Figura I-5

Storia del sistema Mac OS X

25 26

GNU-Darwin un sistema operativo open-source basato su Darwin. Sembra essere anche un tributo al fatto che effettivamente lo XNU per il Mac OS X rappresenta il NuKernel (mai riuscito a realizzare) per i sistemi precedentemente realizzati da Apple.

21

Il sistema operativo Mac OS X

La prima versione del Mac OS X fu rilasciata il 24 marzo del 2001 con il nome di Mac OS X 10.0 Cheetah. Poco tempo dopo, lo schema delle versioni del prodotto server fu rivisto per sincronizzarsi con quello del prodotto desktop. Da allora la tendenza il rilascio di una nuova versione desktop, seguita a breve dallequivalente revisione server.27 Version 10.0 10.1 10.2 10.3 10.4 10.5 Codename Cheetah Puma Jaguar Panther Tiger Leopard Release Date March 24, 2001 September 29, 2001 August 23, 2002 October 24, 2003 April 29, 2005 August 7, 200628

27 28

I primi computer Macintosh con piattaforma x86 venduti, utilizzavano il Mac OS X 10.4.4 come sistema operativo. Il Mac OS X 10.5 Leopard in commercio dal 26 ottobre 2007.

22

Il sistema operativo Mac OS X

Capitolo 1
Architettura del Mac OS X

Il Mac OS X un miscuglio di differenti tecnologie che differiscono non solo in ci che fanno ma anche nella provenienza, nella filosofia che rappresentano e nel modo in cui sono implementate. Allutente finale, tuttavia, il Mac OS X si presenta con unimmagine coesa e consistente. Il fatto che i computers Apple abbiano una base hardware limitata e ben definita ne ha sicuramente aiutato il successo, a fronte di un certo ecletticismo del software che compone il sistema operativo. Da un punto di vista high-level, il Mac OS X pu essere considerato come composto da tre classi di tecnologie: quelle originate allinterno dellApple, quelle originate allinterno della NeXT e quelle originate in qualunque altro posto29. Da una parte una tale confluenza di fonti rende in qualche modo difficile visualizzare chiaramente la struttura del Mac OS X, e potrebbe creare un muro per i nuovi programmatori che volessero avvicinarsi al mondo della mela. Dallaltra parte i programmatori con un minimo desperienza hanno a loro disposizione un ambiente variopinto in cui dare sfogo ai propri fervori creativi. Lutente finale rimane in ogni caso il maggior beneficiario, potendo contare su una variet di software mai vista su una singola piattaforma. Il Mac OS X fornisce i benefici di un tipico sistema UNIX mantenendo la tradizionale facilit duso del Macintosh. Il suo ambiente UNIX sufficientemente conforme allo standard da garantire

29

Questa terza classe principalmente composta di software open-source sviluppato in altri ambiti. Notiamo comunque che anche nelle altre due classi presente software open-source.

23

Il sistema operativo Mac OS X

la portabilit della maggior parte dei software per UNIX30. Molti altri programmi nonUNIX (come Microsoft Office o Adobe Creative Suite) sono disponibili in modo nativo per Mac OS X, per non parlare poi della variet di programmi propri della Apple.

Figura 1.1

Architettura high-level del Mac OS X

Nella figura 1.1 possiamo vedere una rappresentazione stratificata dellarchitettura. Limmagine da considerarsi approssimata poich inutile cercare di dividere il sistema in strati assolutamente separati: spesso ci sono sovrapposizioni degli strati dovute a componenti complesse. Il firmware non tecnicamente parte del Mac OS X, ma gioca un ruolo importante nelle operazioni di un computer Apple. Laddove i computer Apple PowerPC-based utilizzano Open Firmware, i sistemi x86-based utilizzano Extensible Firmware Interface (EFI). Open Firmware un boot firmware non proprietario, non dipendente dalla piattaforma, che risiede nella boot ROM di un computer Apple-PowerPC. Il suo ruolo nellavvio del

30

Il Mac OS X considerato da molti come un sistema UNIX per le masse.

24

Il sistema operativo Mac OS X

sistema in qualche modo analogo a quello del PC BIOS di unarchitettura x86, con laggiunta di altre capacit come: booting personalizzato, diagnosi, debuggind ed anche programmazione. Nei fatti lOpen Firmware , a suo modo, un ambiente di runtime e di programmazione accessibile dallutente. LEFI concettualmente molto simile allOpen Firmware. Il bootloader della versione PowerPC del Mac OS X si chiama BootX, che risiede come un singolo file nel file system. LOpen Firmware carica il file da una periferica di boot31 e lo esegue nel suo ambiente runtime. Il codice del BootX esegue una serie di passi affinch il kernel del Mac OS X possa funzionare, ed eventualmente lancia il kernel stesso. La versione x86 del Mac OS X usa un bootloader chiamato boot.efi, che un eseguibile che gira in ambiente EFI. La nostra trattazione riguarder solo i livelli pi bassi dellarchitettura del Mac OS X.

1.1 Il sottosistema Darwin


Darwin nasce come una fork di una developer release di Rhapsody, il precursore del Mac OS X. Unimportante componente di Darwin lambiente kernel del Mac OS X che, unito allambiente user del Darwin stesso, rende questo un sistema operativo stand-alone. LApple annunci la transizione del Mac OS X su piattaforme x86 solo nel 2005, mentre Darwin fu sempre supportato sia su piattaforme PowerPC che x86. Darwin pu essere meglio compreso come una collezione di tecnologie open source che sono state integrate da Apple per formare una parte fondamentale di Mac OS X. LApple mette a disposizione Darwin come un set di packages, dove ogni pacchetto un archivio contenente il codice sorgente di una parte del Mac OS X. Il numero di pacchetti presenti varia da release a release, ad esempio nel Darwin 8.6 per PowerPC (relativo al Mac OS X 10.4.6) sono presenti circa 350 packages. Come nello stile Apple, anche Darwin contiene codice sorgente sia di Apple che di terze parti tra le quali Open Source e Free Software Foundation (FSF). Le componenti sviluppate allinterno della societ sono generalmente rilasciate con licenza APSL (Apple
31

Con dispositivo di boot, in questo caso, si intende un dispositivo di memorizzazione locale o la rete.

25

Il sistema operativo Mac OS X

Public Source License)32, che dalla versione 2.0 stata classificata dalla FSF come una free software license. Darwin quindi rappresenta una grande quantit di software che lApple ha riunito da una variet di fonti come NEXTSTEP e OPENSTEP, Mach, vari flavors di BSD (principalmente FreeBSD), la GNU software suite, il progetto XFree86 e cos via. La cosa pi importante, per, che tutti questi software esterni sono stati integrati nel Mac OS X molto efficacemente, grazie ad importanti modifiche e ottimizzazioni. Anche se possibile configurare e controllare la maggior parte di tale software cos come si farebbe normalmente su un tradizionale sistema UNIX, il Mac OS X mette a disposizione interfacce utente semplificate e pi consistenti che riescono a nascondere la sottostante complessit. Questa efficienza nelladottare tecnologie da diverse fonti, integrandole in modo sinergico, una delle grandi forze del Mac OS X. importante notare che Darwin solo un sottoinsieme del Mac OS X ( essenzialmente le fondamenta su cui si basa) e che, pur essendo privo delle tecnologie visive del Mac OS X, possibile far girare Darwin con lX Window System che ne fornisce linterfaccia utente grafica.

1.2 Il kernel XNU


Il kernel del Mac OS X si chiama XNU e, in maniera semplicistica, pu essere visto composto da un core basato su Mach 3, una personalit da sistema operativo basata sul FreeBSD 5 ed un ambiente runtime orientato agli oggetti per le estensioni del kernel (drivers compresi). Un kernel in esecuzione contiene numerosi drivers che non risiedono nel codice base del kernel, ma hanno i propri packages Darwin: in questo senso possiamo affermare che il kernel di Mac OS X qualcosa di pi di XNU, ma noi ci riferiremo con il termine XNU alla combinazione del codice di base (quello implementato nel package XNU di Darwin per intenderci) e di tutte le estensioni del kernel.

32

Il codice esterno fornito con le relative licenze, quali ad esempio la GNU General Public License (GPL), la BSD License, la Carnegie Mellon University License e cos via.

26

Il sistema operativo Mac OS X

Fatta questa premessa, possiamo dividere il kernel del Mac OS X nelle seguenti parti: Mach lo strato di servizio BSD il fornitore primario dellinterfaccia di programmazione di sistema LI/O Kit lambiente runtime per i drivers libkern una libreria interna al kernel libsa una libreria interna al kernel utilizzata solo allinizio del system startup il Platform Expert il modulo di astrazione hardware Kernel extension varie famiglie di I/O Kit, la maggior parte dei drivers di periferica caricabili e qualche estensione non appartenente allI/O Kit Il package XNU del Darwin contiene approssimativamente un milione di linee di codice, in cui una met sono riconducibili al BSD ed un terzo al Mach. Le varie estensioni del kernel, di cui non tutte sono necessarie (o caricate) in un dato sistema, formano nellinsieme un altro milione di linee di codice. Il numero di kernel extensions caricate in un certo momento in un dato sistema sono significativamente meno di quelle presenti nel sistema33.

1.2.1 Mach
Se il kernel XNU il cuore del Mac OS X, allora il Mach pu essere considerato il cuore di XNU. Il Mach fornisce servizi di basso livello critici che sono trasparenti alle applicazioni. Gli aspetti del sistema di cui responsabile il Mach includono: Astrazione hardware (in parte) Gestione del processore (incluso lo scheduling ed il multiprocessing simmetrico) Preempitive multitasking (incluso il supporto ai tasks ed ai threads) Gestione della memoria virtuale (incluso il paging di basso livello, la protezione della memoria, la condivisione e lereditariet) Meccanismi IPC di basso livello (che sono la base dello scambio di messaggi nel kernel) Supporto real-time (che permette alle applicazioni time-sensitive di avere accesso
33

Il comando kextstat pu essere utilizzato per ottenere una lista delle estensioni caricate.

27

Il sistema operativo Mac OS X

latency-bounded alle risorse del processore) Supporto al debugging del kernel34 Console I/O Il Mach spesso inequivocabilmente identificato come microkernel, anche se solo dalla versione 3 fu realmente tale. Le precedenti versioni, inclusa la 2.5 da cui nacque il sistema operativo OSF/1 dellOpen Software Foundation, avevano unimplementazione monolitica in cui BSD e Mach risiedevano nello stesso spazio degli indirizzi del kernel. Anche se Apple utilizza una implementazione del Mach che deriva dalla versione 3, lo XNU non utilizza il Mach come un microkernel tradizionale. Vari sottosistemi che sarebbero implementati come servers nello user-space di un vero sistema microkernel, sono parti proprie del kernel nel Mac OS X. In particolare la porzione BSD dello XNU, lI/O Kit ed il Mach risiedono nello stesso spazio degli indirizzi: tuttavia hanno responsabilit ben definite che li separano in termini di funzioni ed implementazione.

1.2.2 BSD
Il kernel XNU contiene una quantit sostanziale di codice di derivazione BSD, ed quello a cui collettivamente ci riferiamo quando ci riferiamo a BSD nel contesto del Mac OS X. Non un caso se un kernel BSD ben definito giri allinterno di XNU, sia come un singolo task del Mach che viceversa. Tuttavia se alcune porzioni di XNU di derivazione BSD sono molto simili alle loro forme originali, altre porzioni invece sono abbastanza differenti visto che sono state realizzate per coesistere con entit estranee al BSD (come ad esempio lI/O Kit ed il Mach). Di conseguenza possibile trovare parecchi casi di codice proveniente da diverse origini intessuti nel kernel XNU. Le funzioni di cui il codice BSD responsabile includono: Il modello dei processi nello stile BSD I Segnali Gli User IDs, i permessi e le politiche base della sicurezza

34

Il kernel debugger di basso livello integrato nello XNU si chiama KDB (o DDB). implementato nella porzione Mach del kernel, cos come KDP che il protocollo remoto di debugging del kernel usato dal debugger GNU (GDB).

28

Il sistema operativo Mac OS X

Le APIs del POSIX Le APIs di I/O asincrono (AIO, Asynchronous I/O) Le chiamate di sistema nello stile BSD Lo stack TCP/IP, i sockets BSD ed il firewalling Le Network Kernel Extensions (NKEs)35 Lo strato VFS (Virtual File System) e numerosi file systems, incluso un meccanismo di journaling a livello VFS indipendente dal file system I meccanismi IPC del System V e del POSIX Una struttura crittografica intra-kernel Un sistema di notifiche (basato sul meccanismo kqueue/kevent del FreeBSD), che un servizio a livello di sistema che abilita notifiche tra applicazioni e dal kernel alle applicazioni Il meccanismo di notifica del cambio di file system fsevents (utilizzato dalla tecnologia di ricerca Spotlight) Le liste di controllo degli accessi (ACLs, Access Control Lists) e la struttura dautorizzazioni kauth36 Varie primitive di sincronizzazione Alcune funzionalit del kernel hanno implementazioni a basso livello in una porzione del kernel con strati dastrazione dalto livello in unaltra porzione. Per esempio la tradizionale struttura dei processi (struct proc), che la struttura dati primaria del kernel rappresentante un processo UNIX, contenuta nella porzione BSD cos come la uarea37. Parlando in senso stretto, nel Mac OS X non eseguito nessun processo BSD: esso coincide con un task Mach che contiene uno o pi threads Mach, e sono questi threads ad

35

Si tratta di un tipo particolare di estensioni del kernel che rendono larchitettura networking di BSD pienamente compatibile con XNU. Prima del Mac OS X 10.4, un NKE era unestensione del kernel appositamente progettata. A partire dalla versione Tiger, le funzionalit di NKE sono accessibili ad una regolare estensione del kernel attraverso un set di KPIs (Kernel Programming Interfaces). 36 A partire dalla versione 10.4 del Mac OS X, il kauth utilizzato per la valutazione delle ACLs. Si tratta di una struttura estensibile dautorizzazioni a carattere generale. 37 Storicamente larea utente (user area o u-area) il nome di strutture contenenti dati per-process o per-thread che possibile scambiare.

29

Il sistema operativo Mac OS X

essere eseguiti. Consideriamo ad esempio la chiamata di sistema fork() che, a meno di varianti come vfork(), il solo modo per creare un nuovo processo in un sistema UNIX. Nel Mac OS X i task ed i threads Mach sono creati e manipolati attraverso delle Mach calls, che lutente non utilizza direttamente: limplementazione BSD-style della fork utilizza queste chiamate per creare un task (ed allocarne e inizializzarne la struttura processo associata) ed un thread. Dal punto di vista del chiamante la fork(), questa appare atomica e con le strutture dati Mach e BSD-style sincronizzate. Similmente la UBC (Unified Buffer Cache) del BSD si aggancia al sottosistema della memoria virtuale del Mach. La UBC permette al file system ed al sottosistema della memoria virtuale di condividere i buffers di memoria del kernel. Ogni memoria virtuale di un processo contiene in genere un mappa sia della memoria fisica che dei file su disco. Unificando la buffer cache si ottiene un singolo deposito per varie entit, riducendo il numero di accessi al disco e la quantit di memoria utilizzata.

1.2.3 I/O Kit


Lo XNU ha un framework orientato agli oggetti per i drivers di periferica chiamato I/O Kit, che utilizza un ristretto sottogruppo del C++38 come linguaggio di programmazione. Limplementazione dellI/O Kit consiste nelle librerie C++ residenti nel kernel (libkern e I/O Kit) ed un framework per lo spazio utente (IOKit.framework). Le librerie residenti nel kernel sono disponibili ai drivers caricabili. Notiamo che il framework del kernel (Kernel.framework) incapsulano le librerie residenti nel kernel in modo da esportare i loro header files il codice eseguibile per queste librerie contenuto nel kernel. L IOKit.framework un framework

convenzionale utilizzato per scrivere programmi user-space che comunicano con lI/O Kit. Larchitettura runtime dellI/O Kit modulare ed a strati. Fornisce uninfrastruttura per catturare, rappresentare e mantenere relazioni tra varie componenti hardware e software che sono coinvolte nelle connessioni di I/O. In questo modo lI/O Kit presenta delle
38

Le caratteristiche non supportate da questo sottogruppo dellEmbedded C++ comprendono: eccezioni, ereditariet multipla, templates, costruttori complicati, liste di inizializzazione e RTTI (runtime type identification). LI/O Kit comunque implementa una propria, minima, RTTI.

30

Il sistema operativo Mac OS X

astrazioni dellhardware sottostante al resto del sistema. Ad esempio lastrazione di una partizione disco comprende relazioni dinamiche tra numerose classi di I/O: il disco fisico, il controller del disco, il bus a cui attaccato il controller e cos via. Il modello di device driver fornito con lI/O Kit ha una moltitudine di utili caratteristiche, tra cui le seguenti: Interfacce di programmazione estese, incluse interfacce per applicazioni e drivers user-space per comunicare con lI/O Kit Numerose famiglie di periferiche come ATA/ATAPI, FireWire, Graphics, HID, Network, PCI e USB Astrazioni orientate agli oggetti delle periferiche Plug-and-play e hot-plugging (il dynamic device management) Power management Preempitive multitasking, threading, multiprocessing simmetrico, protezione della memoria e data management Identificazione e caricamento dinamico di drivers per bus di tipo multiplo Registro di I/O, un database per tracciare e mantenere dettagliate informazioni sugli oggetti stanziati Catalogo di I/O, un database di tutte le classi di I/O Kit a disposizione in un sistema Driver stacking Le periferiche standard, conformi alle ben definite e ben supportate specifiche, non richiedono tipicamente dei driver di I/O Kit specifici. Anche se una periferiche dovesse richiedere un driver custom, avrebbe bisogno solo di un driver user-space se utilizzasse una connessione FireWire o USB.

1.2.4 Libreria libkern


La libreria libkern implementa il sistema di runtime per il ristretto sottogruppo del C++ utilizzato dal modello di programmazione dellI/O Kit. Oltre a fornire i normali servizi necessari ai drivers, libkern contiene anche classi che sono generalmente utili allo sviluppo di software del kernel. In particolare definisce la classe OSOBject che, oltre ad essere la 31

Il sistema operativo Mac OS X

root base class per il kernel del Mac OS X, implementa il dynamic typing per il supporto ai moduli del kernel caricabili. I seguenti sono alcuni esempi delle funzionalit fornite da libkern: Allocazione, costruzione e distruzione dinamica di oggetti (con supporto per una variet di oggetti incorporati come arrays, booleans e dictionaries) Operazioni atomiche e funzioni varie come bcmp(), memcmp() e strlen() Funzione per il byte-swapping Disposizioni per tracciare il numero di istanze correnti per ogni classe Meccanismi per alleviare il C++ fragile base-class problem39

1.2.5 Libreria libsa


La libsa40 una libreria di supporto (essenzialmente un linker) in-kernel, utilizzata durante le prime fasi dellavvio del sistema per caricare le estensioni del kernel. Le estensioni del kernel del Mac OS X sono normalmente caricate, su richiesta, attraverso il daemon dello spazio utente kextd (/usr/libexec/kextd). Durante le prime fasi del bootstrapping il kextd non disponibile, quindi la libsa ne fornisce un subset al kernel. Esempi delle specifiche funzionalit implementate dalla libsa per caricare, lineare e registrare i file oggetto dellestensioni del kernel includono i seguenti: Allocazione di memoria semplice Ricerca binaria Ordinamento Funzioni varie di manipolazione delle stringhe Symbol remangling Un pacchetto del grafico di dipendenza utilizzato durante la determinazione delle
39

Il problema della fragile base-class si ha quando modifiche ad un classe non-foglia, provocano la rottura di una classe derivata. Una classe si dice non-foglia quando la base di almeno unaltra classe. La suddetta rottura avviene perch la classe derivata conta (implicitamente o esplicitamente) sulla conoscenza di alcune caratteristiche della classe nonfoglia. Esempi di queste caratteristiche sono la dimensione della tabella virtuale della classe base (vtable), offset nella vtable, offset dei dati protetti della classe e offset dei dati pubblici. La libekern fornisce metodi per creare un numero limitato, ovviamente, di spazi riservati allinserimento di futuri data members e funzioni virtuali. 40 Il finale sa nel suo nome un riferimento al suo essere una libreria che fornisce funzioni che sono usate da applicazioni stand-alone, il kernel in questo caso. Libreria stand-alone esistono in altri sistemi operativi, con il nome libstand, per fornire un ambiente runtime minimo.

32

Il sistema operativo Mac OS X

dipendenze tra le estensioni del kernel Decompressione di kernels compressi e verifica dei checksum Notiamo che libsa non una libreria del kernel generalmente disponibile: in un tipico scenario di bootstrap, il codice libsa rimosso dal kernel appena diventa disponibile kextd. Anche nel caso in cui fosse presente, le sue funzioni costituenti non sono disponibili al kernel in nessuninterfaccia di programmazione.41

1.2.6 Platform Expert


Il Platform Expert un oggetto (essenzialmente un driver specifico della motherboard) che conosce il tipo di piattaforma sui cui sta girando il sistema. LI/O Kit registra un nub42 per il Platform Expert durante linizializzazione del sistema. Una istanza della classe IOPlatformExpertDevice diventa la radice dellalbero della periferica, quindi il root nub carica il corretto driver della specifica piattaforma, che successivamente scopre i busses presenti nel sistema ed assegna un nub per ogni bus trovato. LI/O Kit carica un corrispondente driver per ogni bus nub, che in seguito scopre le periferiche collegate al bus e cos via. Lastrazione del Platform Experts fornisce laccesso ad una vasta variet di funzioni e informazioni specifiche della piattaforma, come quelle relative a: Costruire gli alberi di periferica Analizzare di alcuni argomenti di boot Identificare la macchina (che include la determinazione della velocit di clock del processore e del bus) Accedere alle informazioni di Power Management Recuperare e settare il tempo di sistema Recuperare e settare le informazioni di console

41

Il kernel accede alla funzionalit di caricamento delle estensioni di libsa attraverso un puntatore a funzione condiviso tra libsa ed il kernel. La funzione costruttore di libsa inizializza tale puntatore in modo da puntare alla relativa funzione di libsa. 42 Nel contesto dellI/O Kit, un nub un oggetto che definisce un punto di accesso ed un canale di comunicazione per una periferica fisica o un servizio logico. Un periferica fisica pu essere un bus, una partizione disco, una scheda grafica e cos via; esempi di servizi logici sono larbitraggio, il riconoscimento del driver ed il power management.

33

Il sistema operativo Mac OS X

Fermare e riavviare la macchina Accedere al controllore delle interruzioni Creare la stringa del numero di serie del sistema Salvare le informazioni di kernel panic Inizializzare uninterfaccia utente da utilizzare in caso di kernel panics Leggere e scrivere la memoria non volatile (NVRAM) Leggere e scrivere la memoria di parametro (PRAM)

1.2.7 Kernel extensions


Oltre al nucleo del kernel, lambiente kernel del Mac OS X include le estensioni del kernel che sono caricate dinamicamente quando necessarie. Molte delle estensioni standard sono indirizzate allI/O Kit, ma ci sono eccezioni come quelle collegate alla rete ed al filesystem (come ad esempio webdav_fs.kext e PPP.kext). In una tipica istallazione del Mac OS X ci possono essere circa mille estensioni del kernel caricate nello stesso momento, ma molte altre si trovano nella directory

/System/Library/Extensions/.

1.3 Il file system


Il file system, o meglio il suo contenuto ed il suo layout, fondamentale per il modo in cui gli utenti interagiscono con il sistema. Il layout del file system del Mac OS X principalmente una superimposizione di file systems di derivazione UNIX e NEXTSTEP, con molte influenze provenienti dal tradizionale Macintosh. Mac OS X divide concettualmente il file system in quattro domini: User, Local, Network e System. Il dominio User contiene risorse specifiche dellutente ed quello che nella terminologia UNIX sarebbe la users home directory. Per un utente di nome massimiliano, la locazione di default della home directory locale /Users/massimiliano/, e la locazione di default della network home directory /Network/Users/massimiliano/. Una users home directory contiene generalmente molte directory standard come ad esempio: 34

Il sistema operativo Mac OS X

.Trash, Applications, Desktop,

Documents,

Library,

Movies,

Music, Pictures, Public e Sites. Alcune directory per-user (come Public e Sites) sono pensate per essere pubblicamente accessibili ed a volte hanno permessi di lettura verso altri utenti. Il dominio Local contiene risorse disponibili a tutti gli utenti su un singolo sistema, include applicazioni e documenti condivisi ed , usualmente, localizzato nel boot volume (che in genere anche il root volume), la directory /Applications/ risiede nel dominio Local. In contrapposizione al dominio User, che pu essere manipolato arbitrariamente dal proprio utente, solo un utente con i privilegi di amministratore di sistema pu modificare il dominio Local. Il dominio Network contiene risorse disponibili a tutti gli utenti della LAN, come ad esempio applicazioni e documenti che sono condivise attraverso una rete, normalmente localizzato in un file server localmente montato su una macchina client sotto /Network/. Solo un utente con privilegi di amministratore di rete pu modificare tale dominio. Directories specifiche del dominio Network includono Applications, Library, Servers e Users. Il dominio System contiene le risorse appartenenti al Mac OS X (come il sistema operativo, le librerie, i programmi, gli scripts ed i files di configurazione) e risiede, come il dominio Local, in un volume boot/root. La sua locazione standard la directory /System/. Il sistema ricerca le risorse, come fonts e plug-ins, nei vari domini partendo dal pi specifico fino al pi generico, secondo lordine UserLocalNetworkSystem. Ogni dominio del file system contiene diverse directories standard, alcune delle quali esistono in pi domini o addirittura in tutti. Forse la pi interessante di queste la Library, che contiene una gerarchia di diverse subdirectories standard. In particolare, una parte sostanziale del sistema operativo risiede in /System/Library/.

35

Il sistema operativo Mac OS X

1.4 La sicurezza
Con security, nel nostro ambito, si intende lunione di software, hardware, politiche e pratiche che permettono ad un sistema ed ai suoi utenti di: Verificare le identit degli utenti e dei servizi di sistema Salvaguardare le informazioni sensibili43 durante limmagazzinamento, la trasmissione e lutilizzo Una risorsa di sistema (incluse quelle esterne, condivise) vulnerabile agli attacchi: dallesterno e a volte anche dallinterno. Possiamo pensare ad un vulnerabilit come ad un potenziale (come ad esempio un bug software, di un errore di progetto, di una errata configurazione e cos via) per un uso non previsto. In questi termini potremmo, in modo molto informale, definire con il termine security quella condizione in cui tutte le risorse del sistema sono, in ogni caso, utilizzate as intended. Quando sfruttate attraverso degli attacchi, le vulnerabilit possono portare a danni, tangibili o meno. I seguenti sono esempi di alcuni comuni tipi di danno potenziale: Fuoriuscita di dati sensibili Modifica di dati sensibili Distruzione di dati sensibili Uso non autorizzato di un servizio di sistema Rifiuto di un sistema in modo che i suoi utenti legittimi non possano utilizzarlo Distruzione o degradamento di unoperazione di sistema Una risorsa di sistema pu essere abusata senza rifiutare il servizio verso utenti legittimi o senza causare nessun danno apparente al sistema stesso. Per esempio, se una risorsa di sistema sta giacendo inattiva, pu essere abusata come punto dingresso per infiltrarsi in un altro sistema. Le caratteristiche della sicurezza del Mac OS X possono essere divise a livello kernel e a livello utente44.

43 44

Sono, ad esempio, informazioni sensibili i dati personali degli utenti, le chiavi crittografiche e le password. Esiste anche una password a livello di firmware che potrebbe essere usata in un computer Apple.

36

Il sistema operativo Mac OS X

1.4.1 Kernel-space security


Il modello della sicurezza al livello di kernel del Mac OS X comprende sia le caratteristiche specifiche del sistema operativo, sia quelle tipiche dei sistemi UNIX. Ad esempio caratteristiche relative alla sicurezza al livello del kernel sono: Identificatori di utenti e gruppi BSD (UIDs e GIDs) i tradizionali UIDs e GIDs sono la base, poco flessibile, dei sistemi di sicurezza. Esempi di politiche di sicurezza basate sugli ID includono la gestione della propriet ed i permessi (lettura, scrittura ed esecuzione) degli oggetti del file system oltre a operazioni ristrette a processi con UID effettivo pari a 0 (root euid policy) oppure operazioni su un oggetto ristretto ad un processo legato al proprietario delloggetto stesso o ad un processo con UID effettivo pari a 0 (owner or root euid policy). Diritti sulle porte Mach (Mach port rights) oltre ad essere canali IPC, una porta Mach pu rappresentare una variet di risorse, come ad esempio tasks, threads, blocchi di memoria, processori e altre periferiche. Inoltre Mach un sistema in cui i diritti sulle porte determinano quali operazioni un task pu compiere o no sulle porte in questione. Il kernel gestisce e protegge le porte, assicurando che solo i tasks con i diritti richiesti possano eseguire operazioni privilegiate. Sistema di verifica (auditing system) il Mac OS X implementa un sistema di verifica basato su BSM (Basic Security Module), che sia un format di verifica della sicurezza, sia una API utilizzata per tracciare gli eventi relativi alla sicurezza che avvengono nel sistema. Accounting di processo (process accounting) laccounting a livello del sistema per ogni processo in esecuzione pu essere abilitato o disabilitato mediante il comando accton. Quando laccounting di processo abilitato, il comando lastcomm fornisce informazioni sullultimo comando eseguito. Memoria virtuale criptata (encrypted virtual memory) il kernel pu, eventualmente, utilizzare lalgoritmo AES per criptare le pagine di memoria virtuale che sono scambiate con la memoria secondaria. ACLs le ACLs del file system sono supportate per un raffinato e flessibile 37

Il sistema operativo Mac OS X

controllo delle ammissioni quando si utilizzano informazioni residenti sul disco. Allinterno del file system le ACLs relative ad ogni singolo file sono implementate come attributi estesi. Kauth il Kauth un meccanismo in-kernel flessibile ed estensibile per la valutazione delle ACLs. Permette ai programmatori del kernel di istallare i propri callbacks (o listeners) per le richieste dautorizzazione nel kernel. Quando unentit vuole eseguire unoperazione su di un oggetto, tutti i listeners registrati sono invocati e vengono loro fornite informazioni contestuali riguardanti le credenziali del richiedente e loperazione richiesta: un listener pu permettere, negare o rinviare45 la richiesta.

Figura 1.4.1

Architettura della sicurezza nel Mac OS X

45

Il rinvio serve sostanzialmente a tirare fuori dalla decisione un listener, in modo che sia gli altri (o eventualmente il default listener) a decidere se soddisfare o meno la richiesta.

38

Il sistema operativo Mac OS X

1.4.2 User-space security


Al livello utente, il Mac OS X fornisce un modello molto flessibile di sicurezza largamente basato sul CDSA (Common Data Security Architecture), unarchitettura open source adottata come standard tecnico dallOpen Group46. Il CDSA consiste in un framework crittografico e vari livelli di servizi per la sicurezza. Limplementazione specifica della Apple rappresentata nella figura 1.4.1. Il CDSA permette limplementazioni di caratteristiche di sicurezza come encryption, autenticazione dellutente, gestione dei permessi di accesso e immagazzinamento sicuro dei dati. Lo strato pi basso del CDSA consiste in plug-ins utilizzati dallo strato superiore. Lo standard CDSA non impone una limitazione nel numero di plug-ins e permette che essi si invochino lun laltro. Il cuore del CDSA un set di moduli chiamati CSSM (Common Security Services Manager). Nella figura 1.4.1 possiamo vedere i Managers CSSM implementati nellApple CDSA, che nellinsieme formano lAPI del CSSM. Fintanto che i plug-ins rispettano le regole di interfaccia con i managers CSSM, essi possono implementare qualsiasi sottogruppo delle caratteristiche del CDSA, incluse le combinazioni di caratteristiche associate a due o pi managers. Le applicazioni del Mac OS X utilizzano normalmente delle APIs del middleware di sicurezza della Apple, costruite sulle APIs CSSM per accedere alle funzionalit CDSA. comunque possibile che unapplicazione utilizzi direttamente lAPI CSSM. Esempi di servizi forniti dalle APIs middleware includono: Keychan Services che forniscono limmagazzinamento sicuro per certificati, chiavi, passwords e altre informazioni arbitrarie Secure transport che forniscono comunicazioni di rete sicure attraverso limplementazione dei protocolli SSL (Secure Socket Layer) e TSL (Transport Layer Security)

46

Le specifiche del CDSA furono inizialmente sviluppate da Intel Architecture Labs, ma lattuale standard frutto della collaborazione di molte organizzazioni e compagnie tra le quali Apple e IBM.

39

Il sistema operativo Mac OS X

Certificate, Key e Trust Services che rispettivamente crea, accede e manipola i certificati; crea chiavi di crittazione e gestiscono le trust policies Authorization Services che utilizzata come API primaria dalle applicazioni per autorizzare laccesso ad azioni specifiche (ad esempio creare un file in una restricted directory) o dati. Come mostrato in figura 1.4.1, gli Authorization Services comunicano con il Security Server (che non fa parte del CDSA), ed questo che poi utilizza le APIs del CDSA. Oltre allautorizzazione, lAPI dei servizi di autorizzazione gestisce anche lautenticazione47. Il Security Server (/usr/sbin/securityd) si comporta come un arbitro di svariati tipi daccessi e operazioni relative alla sicurezza. LAPI dellAuthorization Services include funzioni per aggiungere, cancellare, modificare e leggere oggetti del database delle politiche di sicurezza (policy database). Quando unapplicazione richiede un diritto, ad esempio it.unina.Test.DoSomething48, fa una chiamata dautorizzazione instradata al securityd che consulta il policy database alla ricerca di una regola che collimi con il diritto richiesto. Nel caso in cui nessuna regola soddisfi la richiesta, il securityd utilizza le regole wildcards alla ricerca della prima regola con la maggiore compatibilit alla richiesta. Se anche in questo caso la ricerca non dovesse produrre risultati, si utilizza allora la regola generale, che utilizzata per i diritti che non hanno specifiche regole. Se lautenticazione dellutente avviene con successo, il securityd crea una credenziale valida per 5 minuti49. Lapplicazione Security Agent (SecurityAgent.app) il gestore dellinterfaccia utente del securityd, poich questo non interagisce direttamente con lutente ma lancia il Security Agent come un processo separato, che mostra la richiesta dello username e password. In questo modo il Security Agent assicura linterazione con la GUI (Graphic User Interface), che normalmente garantisce la presenza fisica. Altre caratteristiche di sicurezza direttamente utilizzabili, o comunque controllabili, dallutente finale sono:
47

Lautorizzazione consiste nel chiedere se una data entit abilitata a compiere una data operazione. Prima che la richiesta possa essere fatta, il richiedente deve essere autenticato, ovvero deve dimostrare in qualche modo di essere chi afferma di essere. Solo dopo lautenticazione del richiedente pu essere verificata lautorizzazione della richiesta. 48 Regole e diritti sono convenzionalmente nominati nel policy database utilizzando uno schema inverso del DNS. 49 Il tempo di validit della credenziale specificato nella chiave timeout del policy database.

40

Il sistema operativo Mac OS X

FileVault, unimmagine disco criptata con lalgoritmo AES che contiene i dati relativi ad una users home directory. Per esempio, se esiste un utente di nome Massimiliano, la sua direcotry home /Users/Massimiliano avr un file di tipo immagine disco chiamata Massimiliano.sparseimage che conterr un volume HFS Plus. Tale file sar visibile, da un account administrator, quando lutente Massimiliano non risulter loggato. Nel momento in cui Massimiliano dovesse effettuare il log-in, il volume con limmagine disco montato su /Users/Massimiliano, mentre il precedente contenuto di tale directory (in particolare il file immagine stesso) spostato in /Users/.Massimiliano. Eliminazione sicura dei file attraverso il Finders Secure Empty Trash ed il programma da linea di comando srm. Lapplicazione Disk Utility (Disk Utility.app) permette ai dischi ed ai volumi di essere cancellati in sicurezza utilizzando uno dei vari schemi messi a disposizione: scrittura di zeri su tutti i dati del disco (zero-out data), scrittura dei dati dellintero disco per sette volte (7-pass erase) o anche trentacinque (35-pass erase). Inoltre il recupero di files gi cancellati pu essere reso difficoltoso dalla cancellazione sicura dello spazio libero di un volume. Crittografia della memoria virtuale, che pu essere abilitata o disabilitata mediante il pannello Security dellapplicazione System Preferences. Al tempo di boot, il sistema operativo controlla la variabile di shell encryptswap per determinare se la memoria virtuale deve essere criptata o meno. Il valore della variabile posto a yes o no in /etc/hostconfig in relazione alla configurazione del System Preferences.

1.4.3 Amministrazione del sistema


Il sistema Mac OS X pu essere amministrato effettivamente sia tramite interfaccia grafica che mediante linea di comando. Andremo ora ad esaminare alcuni aspetti specifici dellamministrazione di sistema che utilizzano la linea di comando.

41

Il sistema operativo Mac OS X

Il comando security fornisce laccesso alle funzionalit del Security framework (Security.framework). in particolare, questo comando pu essere utilizzato per accedere e manipolare certificati, chiavi, keychains e password. La versione server del Mac OS X utilizza il software Open Directory, basato su LDAP (Lightweight Directory Access Protocol), per fornire i servizi di directory e autenticazione dei clients Mac OS X, Unix e Windows. Un servizio di directory semplicemente un deposito centrale in cui memorizzare informazioni riguardo gli utenti, i computers, le stampanti e altre risorse di rete allinterno di unorganizzazione. Le applicazioni ed i software di sistema possono accedere a queste informazioni per svariati utilizzi: autenticare i logins, localizzare le users home directories, far rispettare le quote delle risorse, controllare gli accessi al file system e cos via. Tradizionalmente i sistemi UNIX immagazzinano tali informazioni allinterno file di testo semplice come quelli della directory /etc ed, in effetti, tale direcoty pu essere considerata come un primitivo servizio di directory. Altri esempi di servizi di directory sono il NIS (Network Information Service) della Sun e lActive Directory della Microsoft50. Il servizio di directory ereditato dal Mac OS X Server si chiama NetInfo e, nonostante non sia pi utilizzato per le directory condivise, viene ancora utilizzato nel dominio locale. Il comando dscl pu essere utilizzato per operare sulle sorgenti dei dati, che possono essere nomi di nodo directory oppure hosts su cui stanno girando servizi di directory. In maniera simile il comando niutil pu essere utilizzato per operare sui domini NetInfo. Notiamo infine che Open Directory include un plug-in NetInfo chge permette di interoperare con NetInfo. Il comando scutil pu essere utilizzato per accedere e manipolare vari aspetti della configurazione del sistema locale. Il daemon System Configuration

(/usr/sbin/configd) memorizza i dati di configurazione in un deposito dinamico accessibile mediante scutil. Tale daemon utilizza svariati agenti di configurazione,
Il NIS conosciuto anche come Yellow Pages (yp). Le recenti versioni del Solaris hanno abbandonato il NIS ed il NIS+ (che ne il successore) in favore di un servizio di directory basato su LDAP. Anche lActive Directory si basa su LDAP.
50

42

Il sistema operativo Mac OS X

ognuno dei quali si occupa di una particolare area di gestione della configurazione, in modo da formare una visione di insieme della configurazione del sistema. Tali agenti sono contenuti in pacchetti allinterno di /System/Library/SystemCOnfiguration/.

1.4.4 Sistema di verifica


Il sistema di verifica del Mac OS X consiste nel supporto al kernel ed una suite di programmi dello user-space51. Il kernel memorizza gli eventi di verifica allinterno di un file registro (un audit trail file) basandosi su vari criteri. Un daemon dello spazio utente, chiamato auditd, ascolta i trigger events dal kernel ed i control events dai programmi utente: i primi avvisano il daemon se il file di log si riempito o se lo spazio libero del file system sceso sotto una determinata soglia, nel qual caso auditd cercher di rimediare alla situazione; i secondi sono utilizzati per far rileggere il file di configurazione, passare ad un nuovo file di log o terminare lauditing system.

File/Directory /usr/sbin/auditd

Description Audit log management daemon receives trigger messages form the kernel and control messages from the audit management utility

/usr/sbin/audit /usr/sbin/auditreduce

Audit management utility used to control the audit daemon by sending it control messages Utility that selects records from the audit trail files based on the specified criteria and prints matching records in raw form either to a file or to the standard output

/usr/sbin/praudit /var/audit /etc/security/rc.audit /etc/security/audit_control /etc/security/audit_class /etc/security/audit_event /etc/security/audit_user /etc/security/audit_warn

Utility that prints selected records in human-readable format Directory for storing audit trail files Script executed durino system startup by the /etc/rc master script to start the audit daemon Default audit policy file contains global audit parameters File containing descriptions of audit event classes File containing descriptions of audit events File specifying event classes tha are to be audited on a peruser basis Administrator-configurable script run when the audit daemon generates a warning

51

Nel Mac OS X 10.4 i programmi di verifica ed i file di configurazione dello user-space sono forniti dal pacchetto denominato Common Criteria Tools, che non istallato di default.

43

Il sistema operativo Mac OS X

La variabile audit contenuta nel file /etc/hostconfig pu assumere diversi valori: yes per abilitare il sistema di verifica, no per disabilitarlo, failstop o failhalt per abilitarlo con condizioni particolari. Nel primo caso auditd lanciato con largomento s, che specifica che ogni singolo processo deve essere fermato se laudit log si riempie (continuare lesecuzione comporterebbe la perdita dinformazioni di verifica). Nel secondo caso il daemon lanciato con largomento h, che specifica che il sistema debba andare in halt in caso di fallimento dellaudit. Il kernel registra su di un solo file audit trail alla volta. Questi files utilizzano un sistema dei nomi specifico: una stringa formata dal tempo di creazione del file, seguita da un punto, seguita dal tempo di terminazione. Il nome del file attivo, che lunico a non essere terminato, contiene la stringa not_terminated invece del tempo. Entrambe le sottostringhe di tempo utilizzano il formato %Y%m%d%H%M%S della funzione strftime().

44

Il sistema operativo Mac OS X

Capitolo 2
Il Kernel XNU

Come abbiamo gi visto, lambiente kernel del Mac OS X composto di derivazioni del Mach e del BSD, il driver framework dellI/O Kit, librerie in-kernel ed altre estensioni caricabili. Anche se il pacchetto XNU del Darwin contiene solo la met del codice che potenzialmente gira nellambiente del kernel, noi consideriamo XNU il kernel. In questo capitolo esamineremo varie astrazioni e meccanismi proprio dello XNU.

2.1 XNU Source


Per meglio capire com organizzato il codice sorgente ne faremo un panoramica. Ovviamente, essendo composto di quasi 3000 files, andremo ad esaminare solo le directories principali. Al livello pi alto, XNU contiene le directories indicate nella tabella 2-1. Oltre a queste esistono altri files e directories che per non rientrano nella nostra trattazione.

Table 2-1 Directory bsd/ config/ iokit/ libkern/ libsa/ osmfk/ pexpert/

Primary Components of the XNU Kernel Source Component The BSD Kernel Lists of per-subsystem exported functions, property list files for pseudo-extensions The I/O Kit kernel runtime The kernel library The stand-alone library The Mach kernel The Platform Export

45

Il sistema operativo Mac OS X

Nella tabella 2-2 riportiamo una parte del contenuto della directory bsd/.
Table 2-2 Directory bsm/ Primary Contents of the bsd/ Directory Description Basic Security Module (BSM) headers used by the kernels auditing mechanism. BSM is both a security audit format and an API used to track security-related events in the operating system. crypto/ dev/memdev.c dev/ppc/ Various cipher and hash implementations: AES (Rijndael), Blowfish, CAST-128, DES, MD5, RC4, SHA-1, and SHA-2. A RAM disk driver (for /dev/mdX devices) BSD drivers for entities such as /dev/console, /dev/mem, /dev/kmem, /dev/zero, and a BSD driver wrapper for the NVRAM. The latter calls Platform Export functions to perform the actual work. The BSD device switch tables for block and character devices are also initialized here. Also present are some machine-dependent functions used in the BSD subsystem, such as unix_syscall(), unix_syscall_return(), ppc_gettimeofday(), and signalhandling functions. dev/random/ dev/unix_startup.c dev/vn/ An implementation of the Yarrow* pseudorandom number generator (PRNG) and the /dev/random device. Functions that initialize various BSD-related data structures dureing system startup. The vnode disk driver, which provides block and character interfaces to a vnode, allowing file sto be treated as disks. The /usr/libexec/vndevice utility is used to control the driver. hfs/ isofs/ kern/ The HFS and HFS Plus file systems. The ISO 9660 file system for read-only optical discs. The core of XNUs BSD component. It contains implementations of asynchronous I/O calls, the Kauth mechanism, the audit mechanism, process-related system calls, sysctl calls, POSIX IPC, System V IPC, the unified buffer cache, sockets, mbufs, and various other system calls. libkern/ miscfs/ Utility routines such as bcd(), bcmp(), inet_ntoa(), rindex(), and strtol(). Miscellaneous file systems: the dead file system for vnodes whose underlying file system has been dissociated (deadfs), the device file system (devfs), the file descriptor file system (fdesc), the fifo file system (fifofs), the null mount file system (nullfs), the file system for devicespecial file (specfs), the in-memory synthfs used for synthesizing mount points, the union mount file system (union), and the volume ID file system (volfs).

46

Il sistema operativo Mac OS X

net/

Networking: the Berkeley racket filter (BPF), bridging, data link interface layer (DLIL), Ethernet, ARP, PPP, routing, IEEE 802.1q (VLAN), IEEE 802.3ad (Link Aggregation), etc.

netat/ netinet/ netinet6/ netkey/ nfs/ ufs/ uxkern/ vfs/ vm/

Apple Talk Networking. IPv4 Networking: BOOTP, DHCP, ICMP, TCP, UDP, IP, the dummynet bandwidth limiter, and divert sockets. IPv6 Networking. pf_key Key Management API (RFC 2367). NFS client and the kernel portion of the NFS server. An implementation of UFS based on the fast file system (ffs). A Mach exception handler that translates Mach exceptions into UNIX signals. The BSD virtual file system layer. Vnode pager (swap to/from vnodes, demand paging from files), shared memory server calls.

*. Yarrow gets its name from a flowering plant woth distintive flat flowers heads and lacy leaves. In China, its stalks have been used as a randomizer in divination since the second millenium B.C.

Nella tabella 2-3 riportiamo una parte del contenuto della directory iokit/.
Table 2-3 Primary Contents of the iokit/ Directory Description Implementations of I/O Kit array classes listed e.g., in the KernelConfigTables AppleCPU,

Directory Drivers/platform/

AppleNMI, and AppleNVRAM. The I/O Catalog is inizialized with the contents of this array. Families/IONVRAM/ Subclass of the NVRAM controller class simply calls the Platform Export to register the NVRAM controller, which publishes the IONVRAM resource in the I/O Kit. Families/IOSystemManagement/ IOKit/ Kernel/ KernelConfigTables.cpp bsddev/ Watchdog timer. I/O Kit header files. Implementations of core I/O Kit classes and utility functions. Declarations of the list of fake kernel extensions and the KernelConfigTables array. Support functions for BSD e.g., the di_root_image() netboot hook called by BSD to mount a disk image as the root device, and several other functions used by BSD while searching for a root device.

47

Il sistema operativo Mac OS X

Nella tabella 2-4 riportiamo una parte della directory libkern/.


Table 2-4 Directory c++/ gen/ kmod/ libkern/ mach-o/ ppc/ stdio/ uuid/ Primary Contents of the libkern/ Directory Description Implementations of various libkern classes High-level-language wrappers around assembly functions for atomic operations, miscellaneous debugging functions. Start and stop routines for the kernels C++ and C language runtime environments. libkern header files. A header describing the format of Mach-O files (loader.h), and another header containing definitions for accessing Mach-O headers (mach_header.h). Implementations of PowerPC-specific bcmp(), memcmp(), strlen(), and atomic increment/decrement functions. An implementation of scanf(). Routines for parsine and generatine universally unique identifiers (UUIDs) based on the first Ethernet devices hardware address and the current time.

La libreria libkern parte del framework del Kernel ed il suo header si trova in /System/Library/Frameworks/Kernel.framework/Headers/libkern/. Nella tabella 2-5 riportiamo le pi importanti classi contenute nella libreria.

Table 2-5

libkern Classes and Routines The abstract base class for the Mac OS X kernel. It derives from the true root class OSMetaClassBase. It implements basic functionality such as allocation primitives, reference counting, and type-safe object casting.

Base and Abstract Classes OSObject

OSMetaClass

A peer class to OSObject. It derives from the true root class OSMetaClassBase. An instance of this class represents one class that is know by the I/O Kits RTTI system.

OSCollection OSIterator Collection Classes OSArray OSDictionary OSOrderedSet OSSet

The abstract superclass for all collections. The abstract superclass for iterator classes. A class for maintaining lists of object references. A class for maintaining dictionaries of object references. A class for maintaining and sorting sets of OSMetaClassBasederived objects. A class for storing OSMetaClassBase-derived object.

48

Il sistema operativo Mac OS X

OSCollectionIterator

A class that provides a mechanism to iterate over OSCollectionderived collections.

Container Classes OSBoolean OSData OSNumber OSString OSSymbol OSSerialize OSUnserializeXML

A class for Booelan values. A class for managing byte arrays. A class for numeric values. A class for managing strings. A class for representing unique string values. A class used by the container classe sto serialize their instance data. A class that recreates a container object from its serialized instance data in an XML buffer.

Nella tabella 2-6 riportiamo una parte del contenuto della directory libsa/.
Table 2-6 Primary Contents of the libsa/ Directory Description Constructor and destructor functions for libsa. Functions for binary searching, directed graphs, and heap sort used for supportino kernel extension loading. Symbol remangler for code compiled with version 2.95 of the GNU C++ compiler invoked during symbol table parsing when Mach-O object file (typically a kernel extension) is mapped. catalogue.cpp I/O Catalog routines, such as those for accessing and manipulating kernel extension dictionaries, accessing mkext caches, and recording boot-time kernel extensions into dictionaries. kext.cpp, kld_patch.c, kmod.cpp, load.c malloc.c mkext.c strrchr.c, strstr.c vers_rsrc.c The core of libsas functionality: routines for resolving kernel extension dependancies, retrieving kernel extension version, loading kernel extensions, patching vtables, etc. Simple implementations of malloc() and realloc(). Routines for LZSS compression/decompression, and for computing 32bit Adler checksum. String functions. Routines for parsine and generatine version string.

File bootstrap.cpp bsearch.c, dgraph.c, sort.c c++rem3.c

Sappiamo che la libreria stand-alone libsa utilizzata solamente per caricare le estensioni del kernel durante lavvio del sistema. In un tipico scenario di booting, il daemon kextd manda un messaggio kIOCatalogRemoveKernelLinker allI/O Catalog nel kernel. Questo messaggio comunica allI/O Catalog che il kextd pronto a gestire le estensioni 49

Il sistema operativo Mac OS X

del kernel dallo spazio utente. Inoltre richiede allI/O Catalog linvocazione del distruttore per il segmento __KLD del kernel (che il segmento contente il codice di libsa) e la sua deallocazione (insieme al segmento __LINKEDIT). Nella tabella 2-7 riportiamo una parte del contenuto della directory osfmk/.
Table 2-7 Primary Contents of the osfmk/ Directory Description Kernel portion of the Kernel User Notification Center (KUNC) mechanism, which can be used by software running in the kernel to execute user-space programs and to display notices or alert messages. The /usr/libexec/kuncd daemon is the user-space agent that processes such requests from the kernel. console/i386/ console/iso_font.c console/panic_dialog.c console/panic_image.c console/panic_ui/ console/ppc/ console/rendered_numbers.c console/video_console.c ddb/ default_pager/ device/ ipc/ kdp/ kern/ VGA test console, x86 serial console. Data for the ISO Latin-1 font Panic user-interface routines, includine routines for drawing, amanging, and testing the panic dialog. Pixel data for the default panic image an 8-bit, 472x255 image. Panic image files and utilities to convert the minto a kernelusable format. Fast video scrollino, PowerPC serial console. Pixel data for hexadecimal digits 0 through F and the colon character. Hardware-independent portion of the video console. Built-in kernel debugger. Default pager, including the back-end for managing swap files. Mach support for the I/O Kit, including device representation through Mach ports. The I/O Kit master port is also set here. The core of Machs IPC facility implementation. A kernel debugging protocol called KDP that uses a TFTP-like UDP-based tranfer mechanism. The core of Mach kernel: implementations of abstractions such as processors, processor sets, tasks, threads, memory allocation, and timers. IPC interfaces are also implemented here. mach/ mach-o/ mach_debug/ machine/ Mach headers and MIG definition files. Functions for accessing Mach-O headers. Mach debugging headers and MIG definition files. Headers that are wrappers for machine-dependent headers.

Directory or File UserNOtification/

50

Il sistema operativo Mac OS X

ppc/

PowerPC-specific code: machine startup, exception vectors, trap handling, low-level context-switching code, low-level memory management, diagnostic calls, Classic support functions, machine-dependent debugger components, virtual machine monitor, kernel components for Apples CHUD Tools, etc.

profiling/

Kernel profiling support, which must be explicitly compiled in. The kgmon utility is used to control the profiling mechanism: it can stop or start the collection of kernel profiling data, dump the contents of the profile buffers, reset all the profile buffers, and retrieve specific named values from the kernel.

sys/ vm/

Miscellaneous headers. Mach virtual memory subsystem, including the in-kernel shared memory server.

Nella tabella 2-8 riportiamo una parte del contenuto della directory pexpert/.
Table 2-8 Primary Contents of the pexpert/ Directory Description Boot-argument parsing routines. Routines for accessing device tree entries and their properties. Miscellaneous functions, including an 8-bit color lookup table used during bootstrapping. i386/ Machine modification, debugging output support, keyboard driver, generic interrupt handler, polled-mode serial port driver, and other platformdependent routines such as for reading the timestamp counter, setting and clearing interruptus, generatine a fake device tree, etc. pexpert/ ppc/ Miscellaneous platform headers, including those containing image data for the rotatine gearwheel image shown at startup to indicate boot progress. Machine identification, debugging output support, clock speed determination by running timed loops, timebase value retrieval, and other platform functions.

Directory or File gen/bootargs.c gen/device_tree.c gen/pe_gen.c

2.2 Mach
Il Mach stato progettato come un kernel per sistemi operativi orientati alla comunicazione con pieno supporto al multiprocesso. Nellidea degli sviluppatori dovrebbe essere un microkernel in cui i tradizionali servizi del sistema operativo (come il file system, lI/O, i gestori della memoria, i networking stacks etc.) sono residenti nello spazio 51

Il sistema operativo Mac OS X

utente, con una chiara e logica separazione modulare tra loro ed il kernel. Nella pratica, le releases precendeti la 3 avevano unimplementazione monolitica. Il progetto iniziato alla CMU (Carnegie Mellon University) e continuato dalla OSF (Open Software Foundation) diede vita alla release 3 del Mach: la prima vera versione a microkernel del Mach, in cui BSD gira come un task utente. La porzione Mach dello XNU fu originalmente basata sul sistema Mach Mk 7.3 dellOpen Group, che a sua volta era basato sul Mach 3. Questa porzione contiene i miglioramenti sviluppati nellMkLinux ed usufruisce del lavoro svolto sul Mach dallUniversity of Utah. Va precisato che lo XNU non un microkernel. Tutte le componenti del kernel del Mac OS X risiedono in un singolo spazio di memoria kernel. Anche se modulare e flessibile resta un kernel monolitico, tuttavia va notato che il kernel lavora a stretto contatto con pochi daemons dello spazio utente come dynamic_pager, kextd e kuncd. Il Mach fornisce uninterfaccia di macchina virtuale agli alti strati creando unastrazione dellhardware di sistema, cosa molto comune in molti sistemi operativi. Pensato per essere semplice ed estensibile, il cuore del kernel Mach fornisce un meccanismo IPC che il fondamento per una moltitudine dei servizi offerti dal kernel. In particolare, lunione dellIPC e del sottosistema della memoria virtuale porta a varie ottimizzazioni e semplificazioni. Il Mach ha cinque astrazioni base dal punto di vista del programmatore: Task Thread Port Message Memory Object Oltre a fornire le astrazioni base, il Mach rappresenta varie risorse hardware e software come dei port objects, permettendo la manipolazione di tali risorse attraverso il meccanismo IPC.

52

Il sistema operativo Mac OS X

2.2.1 Tasks e Threads


Il Mach divide le astrazioni tradizionali dei processi UNIX in due parti: un task ed un thread. Nel Mac OS X, i termini thread e process hanno delle connotazioni specifiche a seconda del contesto ovvero dellambiente user-space. Allinterno del kernel, un processo BSD (che analogo ad un tradizionale processo UNIX), una struttura dati con una corrispondenza 1-a-1 verso un task del Mach. Un task del Mach ha le seguenti caratteristiche chiave: un ambiente desecuzione ed unentit statica. Un task non esegue, cio non compie computazione da solo, ma fornisce una struttura nella quale altre entit (i threads) eseguono. lunit base dellallocazione delle risorse e pu essere pensata come resource container. Un task contiene un collezione di risorse come accesso ai processori, spazio di indirizzi virtuali paginato (memoria virtuale), spazio IPC, gestori delle eccezioni, credenziali, descrittori di file, stato della protezione, stato della gestione dei segnali e statistiche. Notiamo che le risorse del task includono oggetti UNIX, che in Mac OS X sono contenuti in un task mediante la sua corrispondenza 1-a-1 con la struttura del processo BSD. Rappresenta il contorno di protezione di un programma. Un task non pu accedere alle risorse di un altro task senza aver ottenuto una esplicita autorizzazione mediante luso di una specifica interfaccia. Un thread lattuale entit di esecuzione nel Mach ed un punto di controllo di flusso allinterno di un task. Ha le seguenti caratteristiche: Esegue allinterno di un task, rappresentando un program counter indipendente (uno stream distruzioni) nel task. Un thread anche lentit schedabile fondamentale, con attributi e priorit di scheduling associate. Ogni thread schedato pre-empitivamente ed indipendentemente dagli altri threads, sia quelli dello stesso task che quelli di qualsiasi altro task. Il codice eseguito da un thread risiede nello spazio degli indirizzi del proprio task. Ogni task pu contenere nessuno o pi threads, ma ogni thread porta ad uno ed un 53

Il sistema operativo Mac OS X

solo task. Un task senza threads, anche se legittimo, non pu andare in esecuzione. Tutti i threads interni ad un task condividono le risorse del task. In particolare, poich tutti i threads condividono la stessa memoria, un thread pu sovrascrivere la memoria di un altro, senza la necessit di ottenere nessun privilegio aggiuntivo. Poich possono esserci molti threads in esecuzione concorrente allinterno di un task, i threads appartenenti ad un task devono cooperare. Un thread pu avere il proprio gestore delle eccezioni (exception handler). Ogni thread ha un proprio stato di computazione, che include i registri di processore, un program counter ed uno stack. Notiamo che nonostante lo stack di un thread sia indicato come privato, esso risiede nello stesso spazio degli indirizzi di tutti gli altri threads appartenenti allo stesso task. Di conseguenza, per quanto detto, ogni thread pu accedere agli stacks degli altri threads dello stesso task. Un thread utilizza uno stack del kernel, delle dimensioni di 16KB, per amministrare le chiamate di sistema. Ricapitolando: un task passivo, con risorse proprie e costituisce lunit base della protezione; un thread attivo, esegue istruzioni ed lunit base del controllo di flusso. Un processo tradizionale UNIX a singolo thread analogo ad un task del Mach con un singolo thread, mentre un processo UNIX multi-thread analogo ad un task Mach con molti threads. Un task considerevolmente pi costoso da creare o distruggere di un thread. Mentre ogni thread ha il suo task contenitore, un task Mach non in relazione con il suo task creatore (al contrario dei processi UNIX). Ad ogni modo il kernel mantiene le relazioni padre-figlio a livello di processo nelle strutture di processo BSD. Tuttavia possiamo considerare un task che ne crea un altro come task padre ed il neonato come task figlio. Durante la creazione il figlio eredita lacune aspetti del padre, come le porte registrate, le porte di eccezione e bootstrap, tokens di verifica e sicurezza, regioni di mapping condivise e set di processori. Notiamo che se il processor set del padre marcato come inattivo, il figlio assegnato al processor set di default. 54

Il sistema operativo Mac OS X

Una volta creato un task, chiunque con un valido identificatore di task (ed gli appropriati diritti ad una porta IPC Mach) pu compiere operazioni sul task. Un task pu spedire il proprio identificatore ad un altro task in un messaggio IPC, se lo desidera. Il kernel utilizza le astrazioni di task e thread per dividere le proprie funzionalit in vari flussi desecuzione. Il kernel utilizza un singolo task (il kernel task) con threads multipli che compiono le operazioni del kernel, come scheduling, thread reaping, callout management, paging e UNIX exception handling. Quindi XNU un kernel monolitico, contenente componenti marcatamente differenti (come Mach, BSD e lI/O Kit) che girano tutte come gruppi di threads allinterno di un singolo task nello stesso spazio degli indirizzi.

2.2.2 Ports
Una porta Mach unastrazione con varie sfaccettature, tradizionalmente implementata come una coda a lunghezza finita di messaggi. Oltre alle porte Mach, il Mac OS X fornisce molti altri meccanismi IPC, sia nello spazio kernel sia nello spazio utente. Esempi di tali meccanismi includono le IPC del POSIX e del System V, il descriptor passing, le notifiche multiple e gli Apple Events. Lastrazione port, insieme alle sue operazioni (tra le quali le principali sono la send e la receive) costituiscono la base per la comunicazione nel Mach. Ogni porta ha dei diritti (rights) associati, gestiti dal kernel, che un task che voglia manipolare tale porta deve avere. Ad esempio, i rights determinano quali tasks possono mandare dei messaggi ad una data porta p quale task pu ricevere i messaggi destinati ad essa. Notiamo che mentre possibile avere pi tasks con i send rights verso una particolare porta, solo un task pu avere i receive rights di tale porta. Nella accezione orientata agli oggetti, una porta un riferimento ad un oggetto. Svariate astrazioni del Mach, incluse le strutture dati ed i servizi, sono rappresentate da porte. In questo senso una porta funziona come un provider di accesso protetto ad una risorsa di sistema. Si accede agli oggetti come tasks, threads o memory object52 attraverso le
52

Con leccezione della memoria virtuale, tutte le risorse di sistema nel Mach sono accedute tramite porte.

55

Il sistema operativo Mac OS X

rispettive porte. Ad esempio ogni task ha una task port che lo rappresenta nelle chiamate al kernel. Similmente un punto di controllo di un thread accessibile ai programmi utente attraverso una thread port. Ognuno di questi accessi richiede una capacit (capability) della porta, vale a dire il diritto di mandare o ricevere messaggi verso tale porta, ovvero loggetto che tale porta rappresenta. In particolare, le operazioni su un oggetto sono eseguite mediante messaggi mandati su una delle sue porte53. Loggetto che detiene i diritti di ricezione della porta pu quindi ricevere il messaggio, processarlo e possibilmente effettuare unoperazione richiesta nel messaggio. Facciamo due esempi ti tale meccanismo: Un window manager pu rappresentare ogni finestra che gestisce mediante una porta. Il suo client task esegue le operazioni sulla finestra spedendo messaggi sulle appropriate window ports. Il task del window manager riceve e processa queste operazioni. Ogni task, ed ogni thread al suo interno, hanno un exception port. Un gestore degli errori pu registrare una delle sue porte come una exception port di thread. Quando avviene uneccezione, un messaggio spedito a tale porta ed il gestore pu riceverlo e processarlo. In modo simile, un debugger pu registrare una delle sue porte come la exception port del task. Da quel momento in poi, fino a quando un thread non registra esplicitamente la propria exception port, le eccezioni in tutti threads del task saranno comunicate al debugger. Poich una porta una risorsa relativa al task, tutti i threads in un task accedono automaticamente alle porte del task. Un task pu permettere laccesso ad una o pi delle sue porte ad altri tasks, mediante il passaggio dei diritti attraverso messaggi IPC. Inoltre un thread pu accedere ad una porta solo se tale porta nota al suo task contenitore, poich non esiste uno spazio dei nomi di porta globale di sistema. Molte porte possono essere raggruppate insieme in un port set. Tutte le porte in un set condividono la stessa coda. Pur continuando ad esserci un singolo ricevente, ogni
53

Gli oggetti possono avere molte porte rappresentanti differenti tipologie di funzionalit o livelli di accesso. Per esempio, un risorsa privilegiata pu avere un porta di controllo accessibile solo dal superuser ed un porta di informazioni disponibile a tutti gli utenti.

56

Il sistema operativo Mac OS X

messaggio contiene un identificatore per la specifica porta del set sulla quale deve essere ricevuto il messaggio54. Le porte del Mach sono progettate per essere trasparenti rispetto alla rete, permettendo ai tasks sulle macchine collegate di comunicare lun laltro senza preoccuparsi di dove si trovino. In questo scenario viene tipicamente utilizzato un server di rete per i messaggi (netmsgserver) come mediatore di fiducia. I tasks possono pubblicizzare i propri servizi registrandoli al netmsgserver con un nome unico. Gli altri tasks, compresi quelli su altre macchine, possono cercare i nomi dei servizi sul server utilizzando una sua porta disponibile a tutti. In questo modo il server pu propagare i diritti delle porte attraverso tutta la rete. Il Mac OS X non supporta questa caratteristica di IPC distribuito del Mach, e di conseguenza non ha nessun server dei messaggi di rete, ne interno ne esterno. LIPC distribuito comunque possibile anche sul Mac OS X, attraverso meccanismi di alto livello come lAPI Distributed Objects del Cocoa. Notiamo che una porta pu essere utilizzata per mandare messaggi in una sola direzione, quindi una porta non rappresenta lend point di un canale di comunicazione bidirezionale, al contrario del socket BSD. Se un messaggio di richiesta spedito su una certa porta ed il mittente ha bisogno di una risposta, deve essere disponibile unaltra porta su cui inviarla.

2.2.3 Messages
I messaggi IPC del Mach sono data objects che i threads si scambiano per comunicare. La comunicazione tra tasks, inclusa quella tra il kernel ed i tasks utente, avviene tramite messaggi. Un messaggio pu contenere dati inline attuali oppure puntatori a dati out-ofline (OOL). Il trasferimento di dati OOL una ottimizzazione per i grandi trasferimenti: il kernel alloca una regione di memoria per il messaggio nello spazio degli indirizzi del ricevente, senza creare una copia fisica del messaggio. Le pagine di memoria condivisa sono marcate copy-on-write (COW). Un messaggio pu contenere dati arbitrari di programma, copie di blocchi di memoria, eccezioni, notifiche, capacit di porta e cos via. In particolare, lunico modo per trasferire
54

Tale funzionalit simile alla chiamata di sistema UNIX select().

57

Il sistema operativo Mac OS X

le capacit di porta da un task ad un altro attraverso messaggi. I messaggi Mach sono trasferiti in modo asincrono. Anche se un solo task pu usufruire dei diritti di ricezione di una porta, molti threads in un task possono cercare di ricevere messaggi su una porta. In questo caso, solo uno dei threads avr successo nella ricezione di un dato messaggio.

2.2.4 Virtual Memory e Memory Objects


Il sistema della memoria virtuale (VM, Virtual Memory) del Mach pu essere nettamente suddiviso nella parte dipendente dalla macchina, come la mappa fisica (pmap), e quella indipendente, come le mappe degli indirizzi, gli oggetti della memoria, le mappe condivise e la memoria residente. Le caratteristiche VM Mach includono: Il Mach fornisce spazi degli indirizzi protetti per task, con layout a memoria sparsa. Una descrizione di spazio degli indirizzi di un task una lista lineare di regioni di memoria (vm_map_t), dove ogni regione punta ad un oggetto della memoria (vm_object_t). La mappatura degli indirizzi dipendente dalla macchina contenuta in un oggetto pmap (pmap_t). Un task pu allocare o deallocare le regioni di memoria virtuale sia nel proprio spazio degli indirizzi, sia negli spazi degli indirizzi di altri tasks. I tasks possono specificare le propriet di protezione ed ereditariet della memoria su una base per pagina. La pagine di memoria possono essere tolte dalla condivisione tra tasks o condivise utilizzando i modi copy-on-write o read-write. Ogni gruppo di pagine, ovvero regione di memoria (memory region), ha due valori di protezione: corrente (current) e massima (maximum). La protezione corrente corrisponde allattuale protezione hardware utilizzata per le pagine, mentre la protezione massima il pi alto valore che la protezione corrente possa raggiungere. La protezione massima un limite superiore assoluto che non pu mai essere innalzato (reso pi permissivo) ma soltanto abbassato (reso pi restrittivo). Perci la protezione massima rappresenta il massimo accesso che pu essere avuto 58

Il sistema operativo Mac OS X

da una regione di memoria. Un oggetto della memoria (memory object) un contenitore di dati, mappato nello spazio degli indirizzi di un task e serve da canale per fornire memoria ai tasks. Il Mach tradizionalmente permette che un memory object sia gestito da un gestore esterno della memoria, in cui i page faults e le page-out data request possano essere gestiti nello spazio utente. Un paginatore esterno pu anche essere utilizzato per implementare la memoria virtuale di rete. Questa external memory management (EMM) del Mach non utilizzata nel Mac OS X. Lo XNU fornisce servizi di paginazione base nel kernel attraverso tre pagers: Il default pager gestisce la memoria anonima, vale a dire quella che non ha un paginatore esplicitamente designato. Il vnode pager utilizzato per i files mappati in memoria55. Il device pager utilizzato per la memoria non general-purpose. implementato nello strato Mach, ma utilizzato dallI/O Kit.

2.2.5 Exception Handling


Uneccezione Mach uninterruzione sincrona dellesecuzione di un programma. Le cause deccezione possono essere condizioni errate come lesecuzione di unistruzione illegale, la divisione per zero o laccesso ad un indirizzo di memoria invalido. Le eccezioni possono anche essere deliberatamente causate, come ad esempio quando si raggiung un breakpoint durante il debugging. Limplementazione Mach dello XNU associa un array di porte deccezione ad ogni task, ed un altro per ogni thread nel task. Ognuno di questi array ha tante celle quanti sono i tipi deccezioni implementate (la cella zero non valida). Tutte le porte deccezione dogni thread sono inizializzate sulla porta nulla (IP_NULL) al momento della creazione, mentre le porte deccezione del task sono ereditate da quelle del task padre. Il kernel permette comunque al programmatore di leggere o scrivere individualmente le porte deccezione sia

55

Da quando il VFS del Mac OS X si trova nella porzione BSD del kernel, il paginatore vnode implementato nello strato BSD.

59

Il sistema operativo Mac OS X

per i tasks sia per i threads. Di conseguenza, un programma pu avere diversi exception handlers, anche se un gestore solo pu manipolare diversi tipi di eccezioni. La preparazione tipica per la gestione di uneccezione consiste nellallocazione di una o pi porte con cui il kernel possa scambiare messaggi di notifica delleccezione. La porta pu quindi essere registrata come unexception port per uno o pi tipi di eccezioni per un thread o un task. Il codice di un exception handler gira tipicamente in un thread dedicato, restando nellattesa di messaggi di notifica dal kernel. Lexception handling nel Mach pu essere vista come una meta-operazione consistente in diverse sotto-operazioni. Il thread che causa uneccezione chiamato victim, mentre quello che la gestisce detto handler. Quando una vittima causa uneccezione, il kernel sospende il victim thread e spedisce un messaggio allappropriata porta deccezione, che pu essere una thread exception port (pi specifica) oppure una task exception port (se il thread non ha messo unexception port). Allatto della ricezione del messaggio, lhandler thread processa leccezione operazione che pu consistere nel recuperare lo stato della vittima, prepararne la terminazione, registrare un errore e cos via. Lhandler a questo punto risponde al messaggio indicando se leccezione stata processata con successo (exception cleared). A questo punto il kernel effettua il resume del thread vittima oppure lo termina. Una porta deccezione di thread tipicamente rilevante per la gestione degli errori. Ogni thread pu avere i propri gestori delle eccezioni che processano le eccezioni corrispondenti agli errori che riguardano solo threads individuali. Una porta deccezione di task tipicamente rilevante per il debugging. Un debugger si pu collegare ad un task mediante la registrazione di una delle sue porte come la debugged tasks exception port. Dal momento che un task eredita le sue porte deccezione dal task creatore, il debugger che controlla il padre pu controllare anche i processi figlio. Inoltre, le notifiche deccezione relative a tutti i threads che non hanno registrato un porta deccezione, sono indirizzate alla task exception port.

60

Il sistema operativo Mac OS X

2.3 Allinterno del Kernel


In un tipico sistema operativo, i processi utente sono isolati logicamente dalla memoria del kernel mediante lutilizzo di differenti modi di esecuzione. Il kernel del Mac OS X eseguito nel modo privilegiato PowerPC OEA (Operating Environment Architecture) superiore a quelli, PowerPC UISA (User Instruction Set Architecture) e VEA (Virtual Environment Architecture), di qualsiasi programma utente. Ogni processo utente, ossia ogni task Mach, ha il proprio spazio di indirizzo virtuale. In modo simile, il kernel ha il proprio distinto spazio dindirizzo virtuale che non occupa una sottogamma del massimo spazio dindirizzi possibile per un processo utente. Nello specifico, il kernel del Mac OS X ha uno spazio dindirizzo virtuale privato a 32-bit (4GB), cos come ogni processo utente a 32-bit. Similmente, un processo utente a 64-bit ha anche uno spazio dindirizzo virtuale privato che non suddiviso in parte kernel e parte utente56. Ci riferiremo allo spazio dindirizzo virtuale del kernel semplicemente come allo spazio kernel. Inolte, anche se ogni processo utente ha il proprio spazio dindirizzo, spesso utilizzeremo la frase lo spazio utente quando lo specifico processo non rilevante. In questa accezione, possiamo pensare che tutti i processi utente risiedano nello spazio utente. Elenchiamo ora alcune importanti caratteristiche degli spazi kernel e utente: Lo spazio kernel inaccessibile ai tasks utente. Il kernel garantisce tale protezione utilizzando un hardware per la gestione della memoria, in modo da creare una separazione tra codice kernel-level e user-level. Lo spazio utente pienamente accessibile al kernel. Il kernel normalmente impedisce ad un task utente di modificare, o anche solo accedere, la memoria di un altro task. Tale protezione comunque soggetta alla propriet del task e del sistema. Per esempio, esiste un meccanismo del kernel attraverso il quale un task T1 pu accedere allo spazio dindirizzo di un altro task

56

Anche se, nel Mac OS X, gli spazi dindirizzo virtuale del kernel e dellutente non sono suddivisioni di un singolo spazio dindirizzo virtuale, le quantit di memoria virtuale utilizzabile con entrambi sono limitate in accordo con le mappature convenzionali. Per esempio, gli indirizzi kernel nello spazio dindirizzo virtuale a32-bit del kernel giacciono tra 0x1000 e 0xDFFFFFFF (3.5GB). In modo simile, la quantit di memoria virtuale utilizzabile da un processo utente a 32-bit significativamente inferiore ai 4GB, poich varie librerie di sistema sono mappate per default in ogni spazio dindirizzo utente.

61

Il sistema operativo Mac OS X

T2 se T1 in esecuzione con i privilegi di root, o se T1 e T2 sono dello stesso utente. I tasks possono anche condividere esplicitamente la memoria con altri tasks. Lo spazio utente non pu accedere direttamente allhardware. comunque possibile avere drivers user-space che accedano allhardware dopo la mediazione del kernel. Poich il kernel media laccesso alle risorse fisiche, un programma utente deve scambiare informazioni con il kernel per avvalersi dei servizi del kernel. Lesecuzione tipica nello spazio utente richiede lo scambio sia di dati sia dinformazioni di controllo. In un tale scambio tra il task Mach ed il kernel, un thread interno al task effettua la transizione allo spazio kernel dallo spazio utente trasferendo il controllo al kernel. Dopo aver gestito la richiesta del thread utente, il kernel ritorna il controllo al thread, permettendogli di continuare la normale esecuzione. In altre occasioni il kernel pu acquisire il controllo anche se il thread corrente non coinvolto nel trasferimento nei fatti il trasferimento raramente richiesto dal programmatore. Ci riferiremo allesecuzione nello spazio kernel e nello spazio utente come kernel mode e user mode rispettivamente. Tecnicamente anche il kernel mode del Mac OS X pu essere visto come composto di due sottomodi. Il primo si riferisce allambiente in cui girano i threads propri del kernel, ossia il task kernel e le sue risorse. Il task kernel un task Mach nel vero senso della parola ( il primo task Mach ad essere creato) che esegue diverse dozzine di threads in un tipico sistema. Il secondo modo si riferisce ai threads in esecuzione nel kernel dopo essere entrati nello spazio kernel attraverso una chiamata di sistema cio una threads trap dallo spazio utente nel kernel. I sottosistemi del kernel che devono essere informati dei due modi possono gestirli differentemente.

2.3.1 Tipi di trasferimento del controllo


Anche se i trasferimenti del controllo sono tradizionalmente divisi in categorie basate sugli eventi che li causano, al livello del processore PowerPC tutte le categorie sono gestite dallo stesso meccanismo deccezione. Esempi deventi che causano il cambio di modo desecuzione del processore, sono i seguenti: 62

Il sistema operativo Mac OS X

Segnali esterni, come quelli di un controllore dinterruzione hardware Condizioni anormali incontrate durante lesecuzione di unistruzione Eventi di sistema previsti, come il rescheduling ed i page faults Eccezioni della traccia causate dalla deliberata abilitazione del single-stepping (bit SE del MSR) o del branch-tracing (bit BE del MSR) Condizioni interne al processore, come il rilevamento di un errore di parit nella L1 D-cache Esecuzione dellistruzione di chiamata di sistema Tuttavia rimane utile dividere i trasferimenti del controllo in categorie basate sugli eventi che li generano. Andiamo ad esaminare alcune grandi categorie.

2.3.1.1 External Hardware Interrupts


Uninterruzione hardware esterna un trasferimento del controllo nel kernel tipicamente iniziata da una periferica hardware per indicare un evento. Tali interruzioni sono segnalate al processore dallasserzione del segnale dingresso di interruzione esterna del processore, che causa uneccezione dinterruzione esterna nel processore. Le interruzioni esterne sono asincrone e non sono generalmente correlate al thread correntemente in esecuzione. Notiamo che le interruzioni esterne possono essere mascherate. Un esempio di interruzione esterna un controller di periferica di storage che causa uninterrupt per segnalare il completamento di una richiesta di I/O. In certi processori uneccezione termica segnalata dallasserzione del segnale dingresso di interruzione termica: in questo caso, anche se la condizione anormale interna al processore, la sorgente dellinterruzione esterna.

2.3.1.2 Processor Traps


Una trappola di processore un trasferimento del controllo nel kernel iniziata dal processore stesso a causa di qualche evento che necessita attenzione. Tali trappole possono essere sincrone o asincrone. Anche se le condizioni che causano una traps possono essere tutte definite anormali, in quanto tutte eccezionali, utile sottoclassificarle come attese 63

Il sistema operativo Mac OS X

(expected) o inattese (unexpected). Alcuni esempi di cause di trappole sono lerrore di divisione per zero, completamento di unistruzione di tracciamento, accesso illegale alla memoria o anche lesecuzione di una istruzione illegale.

2.3.1.3 Software Traps


Il kernel del Mac OS X implementa un meccanismo chiamato asynchronous system traps (ASTs), dove uno o pi bits possono essere fissati dal software per un processore o un thread. Ognuno di tali bits rappresenta una particolare trappola software. Quando un processore sta per ritornare da un contesto di interruzione, incluso il ritorno da una chiamata di sistema, esso controlla questi bits e se ne trova uno attivo prende la trappola relativa. Questultima operazione consiste nelleseguire il corrispondente codice di

gestione dellinterruzione. Un thread controlla spesso tali trappole quando sta per cambiare il suo stato di esecuzione, come ad esempio quando passa dallo stato suspended a quello running. Anche il clock interrupt handler del kernel controlla periodicamente le ASTs. Noi categorizziamo le ASTs nel Mac OS X come delle software traps poich sono iniziate e gestite completamente dal software, anche se alcune implementazioni AST possono usare un supporto hardware.

2.3.1.4 System Calls


Listruzione di chiamata di sistema PowerPC utilizzata per generare uneccezione di chiamata di sistema, che causa la preparazione e lesecuzione, da parte del processore, del system call handler nel kernel. La system call exception sincrona. Un set di interfacce ben definito composto da centinaia di system calls, che fungono da punti di ingresso nel kernel per i programmi utente. Un set di system calls standard definito dal Portable Operating System Interface (POSIX), che definisce uninterfaccia e non la sua implementazione. Il Mac OS X fornisce un esteso subset dellAPI POSIX.

64

Il sistema operativo Mac OS X

Capitolo 3
I Processi

In un tipico sistema operativo, un processo rappresenta un programma in esecuzione con le risorse di sistema associate, che possono essere fisiche (come i cicli di processore e la memoria) o astratte57 (come il numero di files che il processo pu aprire). Il kernel fornisce unillusione desecuzione concorrente attraverso lo scheduling delle risorse tra i processi ready-to-run. Su un sistema multiprocessore, o multicore, possibile eseguire in modo realmente concorrente pi processi. Il kernel del Mac OS X divide la tradizionale astrazione di processo in pi astrazioni correlate. In questo capitolo andremo ad esaminare i dettagli del sottosistema di processo del Mac OS X, sia del livello kernel sia del livello utente. Nei primi sistemi UNIX, un processo poteva eseguire un programma utente o rappresentare uno o pi flussi di controllo nel kernel. Lunico modo di creare un nuovo processo in un tradizionale UNIX era attraverso la chiamata di sistema fork(), e lunico modo di far girare un nuovo programma in un processo era attraverso la chiamata di sistema exec(). Comparati ai moderni sistemi operativi, i primi UNIX avevano unastrazione di processo molto semplice. Solo dopo essere stato riscritto in C, il kernel UNIX ha potuto avere pi di un processo in memoria contemporaneamente. Oltre al testo del programma ed ai dati, ogni processo ha uno stack kernel-mode ed unarea dati (la struttura utente o u-area). Ricordiamo infine che pu esserci un solo processo corrente.
57

Le risorse astratte sono spesso limitate, direttamente o indirettamente, dalle risorse fisiche.

65

Il sistema operativo Mac OS X

Come gli altri sistemi operativi moderni, anche il Mac OS X ha dei limiti soft e hard nel numero di processi consentiti. Il limite hard maggiore o uguale al limite soft, fissato al tempo di compilazione e non pu essere cambiato. Il limite soft pu variare mediante linterfaccia sysctl fissando il valore della variabile kern.maxproc.

$ sysctl a | grep proc kern.maxproc = 532 kern.maxfilesperproc = 10240 kern.maxprocperuid = 100 kern.aioprocmax = 16 kern.proc_low_pri_io = 0

// bsd/conf/param.c #define NPROC (20+16*MAXUSERS) #define HNPROC (20+64*MAXUSERS) int maxproc = NPROC; /* hardcoded limit */ __private_extern__ int hard_maxproc = HNPROC;

Il valore di MAXUSERS definito in un file di configurazione nella porzione BSD del kernel, dalla tabella 3-1 possiamo ricavarne i valori. Un kernel Mac OS X standard compilato in una configurazione medium, con MAXUSERS pari a 32. I corrispondenti valori di NPROC e HNPROC sono 532 e 2068 rispettivamente.
Tabella 3-1 Configurazione xlarge large medium small xsmall bsmall Configurazione della dimensione del sistema Descrizione Scala extra-large Scala large Scala medium Scala small Scala extra-small Scala extra-small speciale (come per i floppies di boot) MAXUSERS 64 50 32 16 8 2

La differenza nel numero massimo di processi permessi tra i primi sistemi UNIX (tipicamente 50) ed il Mac OS X (dieci volte superiore) insignificante rispetto alle differenze nelle rispettive composizioni dei loro sottosistemi di processo. Nella figura 3-1 possiamo vedere la composizione del sottosistema di processo del Mac OS X. Nonostante la presenza di numerose entit process-like, una ed una sola astrazione ad essere eseguita in un processore: il thread Mach. Tutte le altre entit sono eventualmente stratificate sui threads Mach.

66

Il sistema operativo Mac OS X

Figura 3-1

Il sottosistema di processo del Mac OS X

3.1 Astrazioni, Strutture dati e APIs del Mach


Esaminiamo alcune delle strutture dati del kernel, che giocano un ruolo importante nel sottosistema di processo del Mac OS X: struct processor_set [osfmk/kern/processor.h] la struttura

dellinsieme di processori. struct processore. struct task [osfmk/kern/task.h] la struttura del task Mach. struct thread [osfmk/kern/thread.h] la struttura del thread Mach indipendente dalla macchina. struct machine_thread [osfmk/ppc/thread.h] la struttura di stato del thread dipendente dalla macchina. 67 processor [osfmk/kern/processor.h] la struttura del

Il sistema operativo Mac OS X

struct proc [bsd/sys/proc.h] la struttura del processo BSD. struct uthread [bsd/sys/user.h] la struttura dellutente per-thread BSD. struct run_queue [osfmk/kern/sched.h] la struttura della coda di esecuzione utilizzata dallo scheduler. Il Mach raggruppa i processors in uno o pi processor sets, ognuno dei quali con una propria run queue di threads eseguibili, e ogni processore ha la sua coda di esecuzione locale. Oltre alla coda, un insieme di processori mantiene anche una lista di tutti i threads nel set, insieme al task assegnato al set. Un task contiene una lista dei suoi threads ed un riferimento al relativo processor set. Uno stato del thread machine-dependent, incluso il process control block (PCB), catturato in una struttura machine_thread. Un processo BSD ha inoltre una struttura proc che si riferisce al task associato. Un processo multithread implementato come un task Mach contenente threads Mach multipli. Ogni thead in un processo BSD contiene un puntatore alla struttura uthread. La struttura proc, inoltre, contiene una lista di puntatori alle strutture uthreads, una per ogni thread del processo.

3.1.1 Processor sets


Durante la fase davviamento del kernel, prima che lo scheduler possa partire, viene inizializzato il default processor set con tutti i processori del sistema58. Il primo task creato dal kernel assegnato al set di default. La motivazione originale dietro gli insiemi di processori fu di raggruppare i processori per allocarli ad attivit di sistema specifiche. Nelle prime versioni del Mac OS X i processor sets hanno avuto associate politiche di scheduling ed attributi, che fornivano un controllo uniforme delle funzioni di scheduling dei threads nel set. Politiche specifiche possono essere abilitate o disabilitate al livello dellinsieme di processori. Come risulta dalla figura 3-2, un oggetto processor set ha due porte Mach che lo
58

Ne consegue che esiste sempre almeno un processor set (quello di default). Un processor set pu anche essere vuoto, tranne quello di default che ne contiene almeno uno. Inoltre un processore appartiene al massimo ad un processor set alla volta.

68

Il sistema operativo Mac OS X

rappresentano: la porta name e la porte control. La porta nome un identificatore, che pu essere utilizzata solo per recuperare informazioni circa linsieme di processori. La porta controllo rappresenta loggetto sottostante, che pu essere utilizzato per eseguire operazioni di controllo (come ad esempio assegnare processori, tasks e threads al processor set). Questo scenario rappresentativo dellarchitettura Mach, dove le operazioni di controllo sui vari oggetti Mach sono effettuate spedendo gli appropriati messaggi alle porte di controllo dei rispettivi oggetti.
Figura 3-2 La struttura del processor set nel kernel XNU

// osfmk/kern/processor.h struct processor_set { queue_head_t idle_queue; int idle_count; queue_head_t active_queue; queue_head_t processors; int processor_count; decl_simple_lock_data(,sched_lock) struct run_queue runq; queue_head_t tasks; int task_count; queue_head_t threads; int thread_count; int ref_count; int active; ... struct ipc_port *pset_self; struct ipc_port *pset_name_self; uint32_t run_count; uint32_t share_count; integer_t mach_factor; integer_t load_average; uint32_t pri_shift; };

// // // // // // // // // // // // // // // // // // // //

queue of idle processors how many idle processors? queue of active processors queue of all processors how many processors? scheduling lock run queue for this set tasks assigned to this set how many tasks assigned? threads in this set how many threads assigned? structure reference count is this set in use? control port (for operations) name port (for information) threads running timeshare threads running the Mach factor load average scheduler load average

extern struct processor_set default_pset;

LAPI del processor set del Mach fornisce delle routines che possono essere chiamate dallo spazio utente per richiedere e manipolare59 gli insiemi di processori. Riportiamo di seguito alcuni esempi di tali routines: host_processor_sets() ritorna una lista di send rights rappresentante le porte nome di tutti gli insiemi di processori presenti nellhost. host_processor_set_priv() traduce una porta nome in una porta controllo dellinsieme di processori. processor_set_default() ritorna la porta nome per il default processor set.
59

La manipolazione dei processor sets unoperazione privilegiata.

69

Il sistema operativo Mac OS X

processor_set_create() crea un nuovo processor set e ne ritorna le porte nome e controllo. processor_set_destroy() distrugge linsieme di processori specificato e rilascia i suoi processori, task e threads al default processor set. processor_set_info() recupera varie informazioni riguardo linsieme di processori specificato in base al parametro (flavour) passato, ad esempio PROCESSOR_SET_BASIC_INFO fornisce il numero di processori assegnati e la politica di timeshare utilizzata per default (POLICY_TIMESHARE), restituiti attraverso una struttura processor_set_basic_info PROCESSOR_SET_TIMESHARE_DEFAULT fornisce gli attributi base per la politica di scheduling timeshare, restituiti attraverso una struttura

policy_timeshare_base PROCESSOR_SET_TIMESHARE_LIMITS fornisce i limiti sugli attributi permessi di politica timeshare, restituiti attraverso una struttura

policy_timeshare_limit. processor_set_statistics() recupera le statistiche di scheduling per linsieme di processori specificato in base al parametro passato, ad esempio PROCESSOR_SET_LOAD_INFO fornisce le statistiche di caricamento, restituite attraverso una struttura processor_set_load_info. processor_set_tasks() ritorna una lista di send rights alle porte del kernel contenente tutti i tasks assegnati correntemente allinsieme di processori specificato. processor_set_threads() ritorna una lista di send rights alle porte del kernel contenente tutti i threads assegnati correntemente allinsieme di processori specificato. processor_set_stack_usage() recupera informazioni sullutilizzo dello stack del thread in un dato insieme di processori60. Notiamo che utilizzando la lista dei processor sets, tutti i task ed i threads nel sistema
60

Si tratta di una routine di debug che abilitata solo se il kernel stato compilato con lopzione MACH_DEBUG.

70

Il sistema operativo Mac OS X

possono essere individuati. Se il kernel supporta solo un insieme di processori, ovviamente le chiamate alle routines di creazione e distruzione falliranno. Nel Mac OS X linterfaccia del processor set disapprovata e probabilmente verr cambiata o addirittura fatta sparire. Il kernel XNU, infatti, supporta solo un singolo insieme di processori: le routines dinterfaccia operano sul default processor set.

3.1.2 Processors
La struttura processor una descrizione indipendente dalla macchina di un processore fisico. Alcuni campi della struttura processor sono simili a quelli della struttura processor_set, ma con una portata locale al processore. Ad esempio il campo runq in questo caso si riferisce ai soli threads collegati al processore in questione.
Figura 3-3 La struttura del processor nel kernel XNU

// osfmk/kern/processor.h struct processor { queue_chain_t processor_queue; int state; struct thread *active_thread; struct thread *next_thread; struct thread *idle_thread; processor_set_t processor_set; int current_pri; timer_call_data_t quantum_timer; uint64_t quantum_end; uint64_t last_dispatch; int timeslice; int deadline; struct run_queue runq; queue_chain_t processors; ... struct ipc_port *processor_self; processor_t processor_list; processor_data_t processor_data; }; ... extern processor_t master_processor;

// // // // // // // // // // // // // //

idle, active, or action queue link processor state thread running on processor next thread to run if dispatched this processor's idle thread the processor set that we belong to current thread's priority timer for quantum expiration time when current quantum ends time of last dispatch quantum before timeslice ends current deadline local run queue for this processor all processors in our processor set

// processor's control port // all existing processors // per-processor data

La figura 3-3 mostra un estratto della dichiarazione della struttura processor. I possibili stati in cui si pu trovare un processore sono: PROCESSOR_OFF_LINE (non disponibile), PROCESSOR_RUNNING (in normale esecuzione), PROCESSOR_IDLE (in attesa), PROCESSOR_DISPATCHING (in transizione dallattesa allesecuzione),

PROCESSOR_SHUTDOWN (in disattivazione), PROCESSOR_START (attivato).

71

Il sistema operativo Mac OS X

Figura 3-4

Un processor set contenente due processori

La figura 3-4 mostra come sono interconnesse le strutture processor processor in un sistema con un insieme di processori e due processori.

set e

Il campo processors in ogni processore, insieme con quello dellinsieme di processori, sono collegati insieme mediante una lista circolare. Tale campo un elemento coda contenente solo due puntatori: prev (precedente) e next (successivo). In particolare, il puntatore next del campo processors relativo alla struttura processor_set punta 72

Il sistema operativo Mac OS X

al primo processore (o master processor). In pratica possibile attraversare la lista di tutti i processori in un processor set sia dallinsieme sia da un qualsiasi processore. In modo analogo si pu attraversare la lista di tutti i processori attivi in un insieme, utilizzando il campo active_queue della struttura processor_set ed i campi

processor_queue di ogni struttura processor dellinsieme. La figura 3-5 mostra le relazioni tra le strutture quando entrambi i processori (della figura 3-4) sono nella coda attiva dellinsieme di processori di default.

Figura 3-5

Un processor set con due processori nella sua coda attiva

73

Il sistema operativo Mac OS X

Riportiamo ora alcuni esempi di routines Mach relative ai processori: host_processors() ritorna un array di send rights rappresentante tutti i processori nel sistema61. processor_control() esegue operazioni di controllo dipendenti dalla macchina, o commands, sul processore specificato. processor_info() recupera informazioni relative al processore specificato in base al parametro (flavour) passato, ad esempio PROCESSOR_BASIC_INFO fornisce il tipo, il sottotipo ed il numero di slot del processore, se in esecuzione e se si tratta del master processor PROCESSOR_CPU_LOAD_INFO fornisce il numero di tasks e threads assegnati al processore, il suo carico medio ed il suo fattore Mach. in un sistema multiprocessore, processor_start() fa partire il processore indicato se questi era offline (assegnandolo poi al default processor set), mentre processor_exit() lo ferma (rimuovendolo dal processor set assegnato). processor_get_assignement() ritorna la porta nome per linsieme di processori a cui attualmente assegnato il processore indicato. processor_assign() assegna un processore ad un insieme di processori. Poich il kernel XNU supporta solo un insieme di processori, lultima routine fallisce sempre, mentre la processor_get_assignement() ritorna sempre il default processor set. Molte routines Mach relative ai processori hanno un comportamento dipendente dalla macchina e, in particolare, le routines che riguardano il comportamento globale di un processore sono privilegiate. Esistono inoltre delle chiamate per fissare (set) oppure ottenere (get) la corrispondenza tra linsieme di processori ed i tasks e threads. Ad esempio task_assing() assegna un task, ed eventualmente tutti i suoi threads, ad un dato insieme di processori. A meno che tutti i threads siano inclusi, solo i nuovi threads

61

Notiamo che il chiamante nello spazio utente riceve larray come out-of-line data in un messaggio IPC Mach. La memoria appare implicitamente allocata nello spazio di memoria virtuale del chiamante. In questo caso, il chiamante dovr esplicitamente deallocare la memoria al termine dellutilizzo mediante una delle routines Mach a disposizione, vm_deallocate() oppure mach_vm_deallocate().

74

Il sistema operativo Mac OS X

creati saranno assegnati al nuovo processor set. Cos come le altre chiamate collegate a processor sets multipli, task_asign() ritorner sempre un fallimento nel Mac OS X.

3.1.3 Tasks
Un task Mach unastrazione, indipendente dalla macchina, dellambiente desecuzione dei threads. Come sappiamo un task un contenitore di risorse, che incapsula accesso protetto ad uno spazio degli indirizzi virtuali sparso, uno spazio (di porte) IPC, risorse di processore, controllo di scheduling e, ovviamente, i threads che utilizzano tali risorse. La figura 3-6 mostra un estratto della dichiarazione della struttura task del Mac OS X.
Figura 3-6 La struttura del task nel kernel XNU

// osfmk/kern/task.h struct task { ... vm_map_t queue_chain_t ... queue_head_t int ... integer_t integer_t ...

map; pset_tasks;

// address space description // list of tasks in our processor set

threads; // list of threads in this task thread_count; // number of threads in this task priority; // base priority for threads max_priority; // maximum priority for threads

// IPC structures ... struct ipc_port *itk_sself; // a send right struct exception_action exc_actions[EXC_TYPES_COUNT]; // exception ports struct ipc_port *itk_host; // host port struct ipc_port *itk_bootstrap; // bootstrap port // "registered" ports -- these are inherited across task_create() struct ipc_port *itk_registered[TASK_PORT_REGISTER_MAX]; struct ipc_space *itk_space; // the IPC space ... // locks and queue_head_t queue_head_t int int ... semaphores semaphore_list; lock_set_list; semaphores_owned; lock_sets_owned; // // // // list of owned semaphores list of owned lock sets number of owned semaphores number of owned locks

#ifdef MACH_BSD void *bsd_info; #endif

// pointer to BSD process structure

struct shared_region_mapping *system_shared_region; struct tws_hash *dynamic_working_set; ... };

Riportiamo di seguito alcuni esempi delle routines relative al task Mach accessibili attraverso la libreria di sistema: 75

Il sistema operativo Mac OS X

mach_task_self() la trappola didentit del task e ritorna un diritto di spedizione alla porta kernel del task chiamante. pid_for_task() recupera lID del processo BSD per il task specificato attraverso la porta data62. task_for_pid() recupera la porta per il task corrispondente allo specificato ID di processo BSD. task_info() recupera informazioni sul dato task a seconda del parametro (flavour) passato, ad esempio TASK_BASIC_INFO fornisce la dimensione della memoria virtuale, la dimensione della memoria residente, il suspend count e cos via TASK_THREAD_TIMES_INFO fornisce il tempo totale dei threads vivi TASK_EVENT_INFO fornisce i page faults, le system calls, i context switch etc. task_threads() ritorna un array di send rights alle porte kernel di tutti i threads del task specificato. task_create() crea un nuovo task Mach che pu ereditare lo spazio degli indirizzi del task chiamante o essere creato con uno spazio degli indirizzi vuoto; il task chiamante ha pieno accesso alla porta kernel del task creato, che non contiene threads; notiamo che questa chiamata non crea un processo BSD e quindi non usufruibile dallo spazio utente. task_suspend() incrementa il suspend count del task e ne ferma tutti i threads; i nuovi threads creati nel task non potranno essere eseguiti finch il suspend count relativo positivo. task_resume() decrementa il suspend count del task e se ha raggiunto il valore zero, allora riprende lesecuzione dei suoi threads63. task_terminate() elimina il task specificato e tutti i suoi threads, deallocandone tutte le risorse. task_get_exception_ports() recupera i send rights verso uno specifico
62

Notiamo che, mentre tutti i processi BSD hanno un corrispondente task Mach, tecnicamente possibile avere un task Mach che non sia associato con un processo BSD. 63 Il suspend count di un task non pu mai essere negativo, pu essere nullo (runnable task) o positivo (suspended task).

76

Il sistema operativo Mac OS X

gruppo di exception ports per il task specificato64. task_set_exception_ports() definisce le porte deccezione del task. task_swap_exception_ports() esegue le funzioni combinate delle due routines precedenti. task_get_special_port() recupera un send right per una specificata porta speciale in un task, ad esempio alcune porte speciali sono TASK_KERNEL_PORT65 utilizzata per controllare il task TASK_BOOTSTRAP_PORT utilizzata nelle richieste per recuperare le porte che rappresentano i servizi di sistema TASK_HOST_NAME_PORT66 utilizzata per recuperare informazioni sullhost. task_set_special_port() fissa una delle porte speciali del task al send right specificato. task_policy_get() recupera i parametri della politica di scheduling per il task specificato; pu anche essere utilizzata per recuperare i valori dei parametri della default task policy. task_policy_set() utilizzata per definire le informazioni della politica di scheduling per un task.

3.1.4 Threads
Un thread Mach un singolo flusso di controllo in un task Mach. In funzione della natura e dellarchitettura di unapplicazione, lutilizzo di threads multipli pu portare a miglioramenti nelle prestazioni dellapplicazione stessa, come nei seguenti esempi: quando la computazione e lI/O possono essere separati e sono mutuamente indipendenti, dei threads dedicati possono essere utilizzati per eseguire queste due tipologie di attivit simultaneamente.

Ricordiamo che una exception port una porta a cui il kernel manda messaggi quando si hanno uno o pi tipi di eccezioni. Notiamo inoltre che i threads hanno le proprie exception ports, che sono prioritarie rispetto a quella del task. Solo se una porta deccezione di thread impostata sulla porta nulla (IP_NULL), o ritorna con un fallimento, allora la porta deccezione del task entra in gioco. 65 La stessa porta ritornata dalla routine mach_task_self(). 66 La stessa porta ritornata dalla routine mach_host self().

64

77

Il sistema operativo Mac OS X

quando i contesti di esecuzione (threads o processi) devono essere creati e distrutti frequentemente, utilizzando i threads si ottengono prestazioni migliori poich un thread sostanzialmente meno oneroso da creare di un intero processo67. in un sistema multiprocessore, i vari threads allinterno dello stesso task possono realmente essere eseguiti in modo concorrente, il che aumenta le prestazioni (se il thread trae benefici dalla computazione concorrente).
Figura 3-7 La struttura del threads nel kernel XNU

// osfmk/kern/thread.h struct thread { queue_chain_t links; run_queue_t runq; wait_queue_t wait_queue; event64_t wait_event; ... thread_continue_t continuation; void *parameter; ... vm_offset_t kernel_stack; vm_offset_t reserved_stack; int state;

// // // //

run/wait queue links run queue thread is on wait queue we are currently on wait queue event

// continue here next dispatch // continuation parameter // current kernel stack // reserved kernel stack // state that thread is in

// scheduling information ... // various bits of stashed machine-independent state ... // IPC data structures ... // AST/halt data structures ... // processor set information ... queue_chain_t task_threads; struct machine_thread machine; struct task *task; vm_map_t map; ... // // // // threads in our task machine-dependent state containing task containing task's address map

// mutex, suspend count, stop count, pending thread ASTs ... // other ... struct ipc_port *ith_sself; // a send right struct exception_action exc_actions[EXC_TYPES_COUNT]; // exception ports ... #ifdef MACH_BSD void *uthread; #endif }; // per-thread user structure

Un thread contiene varie informazioni, tra cui: la priorit e la politica di scheduling, insieme agli attributi relativi.
67

Il miglioramento delle prestazioni percepibile solo se lapplicazione crea cos tanti processi (o li crea in maniera tale) che loverhead diventa un fattore limitante della performance dellapplicazione.

78

Il sistema operativo Mac OS X

le statistiche sullutilizzo del processore. un numero ristretto di port rights specifici, inclusi la threads kernel port ed i thread-level exception ports (corrispondenti ai thread-level exception handlers). lo stato di macchina (attraverso una struttura thread-state dipendente dalla macchina), che cambia nel corso dellesecuzione del thread. Nella figura 3-7 possiamo vedere le costituenti principali della struttura thread, cos com definita nel Mac OS X. Un programma utente controlla un thread Mach utilizzando la porta kernel del thread. Tale controllo avviene normalmente in modo indiretto, attraverso la libreria Pthreads che fa parte delle librerie di sistema (libSystem.dylib) del Mac OS X. Esaminiamo alcune routines accessibili attraverso la libreria di sistema che compongono, nel loro insieme, lAPI del thread: mach_thread_self() ritorna i send rights alla porta kernel del thread chiamante. thread_info() recupera informazioni riguardanti il thread specificato in base al parametro (flavour) passato, in particolare THREAD_BASIC_INFO che fornisce i run times dutente e di sistema, la politica di scheduling in uso, il suspend count e cos via68. thread_get_state() recupera lo stato desecuzione user-mode specifico della macchina per il relativo thread, che non deve essere il thread chiamante. A seconda del flavour passato, la routine restituisce uno stato contenente differenti set di valori di registro specifici della macchina. Alcuni esempi di tali flavours sono PPC_THREAD_STATE, PPC_THREAD_STATE64, PPC_EXCEPTION_STATE, PPC_EXCEPTION_STATE64, PPC_VECTOR_STATE e PPC_FLOAT_STATE. thread_set_state() esegue loperazione inversa della precedente,

ricordando che il thread chiamante non pu modificare il proprio stato attraverso questa routine.
68

Esistono altri flavours, ormai obsoleti, come THREAD_SCHED_FIFO_INFO, THREAD_SCHED_RR_INFO e THREAD_SCHED_TIMESHARE_INFO che forniscono informazioni riguardo la politica di scheduling.

79

Il sistema operativo Mac OS X

thread_create() crea un thread, allinterno del task indicato, con suspend count pari a 1 e senza uno stato di macchina69. thread_create_running() thread_create(), combina leffetto e delle routines

thread_set_state()

thread_resume()

creando cos un thread running (con lo stato di macchina fornito) allinterno del task specificato. thread_suspend() incrementa il suspend count del thread; fin quando il suspend count rester positivo, il thread non potr eseguire nessuna istruzione a livello utente70. thread_resume() decrementa il suspend count del thread; se il valore diventa zero, il thread ripreso (ma non obbligatoriamente rimesso in esecuzione)71. thread_terminate() distrugge il thread specificato e, se si tratta dellultimo thread da terminare in un task che corrisponde ad un processo BSD, il codice di terminazione del thread esegue anche unuscita del processo BSD. thread_switch() istruisce lo scheduler di cambiare contesto direttamente verso un altro thread. Il chiamante pu anche specificare un particolare thread come suggerimento. In questo caso lo scheduler tenter di effettuare lo switch verso il thread specificato. Molte condizioni devono sussistere affinch lo switch suggerito avvenga con successo72. Nel caso non sia suggerito nessun thread, la routine forza una rischedulazione ed un nuovo thread da eseguire scelto. Lesistente stack kernel del chiamante scartato e, quando questo eventualmente ripreso, esegue la funzione di continuazione thread_switch_continue() (contenuta in osfmk/kern/syscall_subr.c) in un nuovo stack kernel.

69

Lo stato di macchina del nuovo thread dovr essere specificato esplicitamente mediante la chiamata alla routine thread_set_state() prima di poter essere ripreso mediante chiamata alla routine thread_resume(). 70 Nel caso il thread fosse in esecuzione nel kernel a causa di una trap (come una chiamata di sistema o un page fault), allora pu bloccarsi in loco o proseguire fino quasi al termine della trap, a seconda della tipologia di trap. Tuttavia la trap ritorner solo con la ripresa del thread. 71 Dobbiamo precisare che se il suspend count del task maggiore di zero, un suo thread non pu andare in esecuzione anche se il proprio suspend count pari a zero. Analogamente a quello del task, il suspend count del thread non pu essere negativo. 72 Si tratta di un esempio di handoff scheduling, infatti, il quantum del chiamante passato (handed off) al nuovo thread.

80

Il sistema operativo Mac OS X

La routine thread_switch() pu essere istruita a bloccare il thread chiamante per un tempo specificato, unattesa che pu essere cancellata solo attraverso la chiamata a thread_abort(). Pu anche abbassarne temporaneamente la priorit, modificando gli attributi di scheduling in modo che lo scheduler gli fornisca il servizio pi basso possibile per il tempo specificato. Al termine di questo tempo, o quando il thread corrente sar eseguito in seguito, la scheduling depression abortita. Pu esserci anche una terminazione esplicita mediante chiamata a thread_abort() oppure thread_depress_abort(). thread_wire() marca il thread come privilegiato in modo tale che possa consumare la memoria fisica dal pool riservato del kernel quando la memoria libera scarseggia73. Inoltre, se un simile thread deve essere inserito in una coda dattesa di threads, sar inserito in testa a tale coda. thread_abort() pu essere usato da un thread per fermarne un altro. Tale routine termina una variet di operazioni in corso nel thread designato, come ad esempio clock sleeps, scheduling depressions, page faults e altre chiamate di primitive Mach (come le system calls). Se il thread designato si trovava in kernel mode, una chiamata riuscita della routine comporta un ritorno dal kernel del thread. Nel caso di una chiamata di sistema, ad esempio, lesecuzione del thread riprende nel codice di ritorno della system call (con un codice di ritorno di chiamata di sistema interrotta). Notiamo che thread_abort() dovrebbe essere usata solo su un thread sospeso, in questo caso verr interrotto quando riprender. Questo perch se un thread sta eseguendo una operazione non atomica nel momento in cui la routine chiamata su di lui, loperazione sarebbe terminata in un punto arbitrario e non si potrebbe farla ripartire. La thread_abort() stata pensata per fermare il target in modo pulito. Nel caso di chiamata alla thread_suspend(), se il target in esecuzione nel kernel e lo stato del thread modificato (attraverso

Questa routine pensata per i threads direttamente coinvolti nel meccanismo di page-out, non dovrebbe mai essere invocata da un programma utente.

73

81

Il sistema operativo Mac OS X

thread_set_state()), allora lo stato pu essere alterato in maniera imprevedibile come effetto collaterale della chiamata di sistema al momento della ripresa del thread. thread_abort_safely() simile alla precedente, ma nel caso sia invocata durante una operazione non atomica ritorna un errore. In questo caso il thread dovr essere ripreso ed una nuova chiamata della routine dovr essere tentata. thread_get_exception_ports() recupera i send rights di una o pi porte deccezione per un dato thread. I tipi deccezione per i quali recuperare le porte sono specificati attraverso una flag word. thread_set_exception_ports()definisce la porta data come porta deccezione per il tipo deccezione specificato. thread_get_speacial_port() restituisce un send right da una specifica porta speciale per un dato thread. thread_set_special_port() definisce una specifica porta speciale per un dato thread modificandola con il send right fornito dal chiamante. Il precedente send right rilasciato dal kernel. thread_policy_get() recupera i parametri della politica di scheduling per il dato thread. thread_policy_set() definisce le informazioni della politica di scheduling per il dato thread. Un thread pu mandare un port right ad un altro thread (anche se appartenente ad un altro task) attraverso lIPC Mach. In particolare, se un thread spedisce la porta kernel del suo task ad un thread in un altro task, un thread nel task ricevente pu controllare tutti i threads nel task mittente, poich laccesso alla porta kernel di un task comporta laccesso alle porte kernel dei suoi threads.

3.1.4.1 Kernel Threads


Un thread Mach che la rappresentazione nel kernel di un thread dello spazio utente, pu essere chiamato un kernel thread. Unaltra connotazione del termine kernel thread si 82

Il sistema operativo Mac OS X

applica a quelli interni che il kernel esegue per le proprie funzionalit. Riportiamo una serie desempi di funzioni che il kernel esegue come threads dedicati per implementare le funzionalit del kernel come bootstrapping, scheduling, exception handling, networking e file system I/O. processor_start_thread() [osfmk/kern/startup.c] il primo thread da eseguire su un processore. kernel_bootstrap_thread() [osfmk/kern/startup.c] avvia vari serivizi kernel durante lavvio del sistema ed eventualmente diventa il daemon di page-out, eseguendo vm_page() [osfmk/vm/vm_pageout.c]. Questultima crea altri kernel threads per eseguire I/O e garbage collection. idle_thread() [osfmk/kern/sched_prim.c] il thread di processore inattivo, che gira cercando altri threads da eseguire. sched_tick_thread() [osfmk/kern/sched_prim.c] esegue funzioni periodiche di contabilit relativa allo scheduler. thread_terminate_daemon() pulizia finale per i threads terminali. thread_stack_daemon() [osfmk/kern/thread.c] alloca gli stacks per i threads messi in coda per la stack allocation. serial_keyboard_poll() [osfmk/ppc/serial_io.c] sonda la porta seriale in cerca di input. Il meccanismo di callout del kernel gestisce le proprie funzioni come kernel threads. Le classi dellI/O Kit IOWorkLoop e IOService usano IOCreateThread() [iokit/Kernel/IOLib.c] per creare kernel threads. Il meccanismo dellI/O asincrono del kernel (AIO) crea dei threads specifici per gestire le richieste di I/O. audit_worker() [bsd/kern/kern_audit.c] processa la coda delle annotazioni di verifica scrivendole nel logfile di verifica o altrimenti rimuovendole dalla coda. 83 [osfmk/kern/thread.c] esegue la

Il sistema operativo Mac OS X

mbuf_expand_thread() [bsd/kern/uipc_mbuf.c] aggiunge un cluster di mbufs per aggiungerne di nuovi liberi. ux_handler() [bsd/uxkern/ux_exception.c] il gestore UNIX delle eccezioni che converte le eccezioni Mach in valori di segnali e di codice UNIX.

Figura 3-8

Funzioni per creare kernel threads

nfs_bind_resv_thread()

[bsd/nfs/nfs_socket.c]

gestisce

le

richieste di legame sulle porte riservate da parte di processi non privilegiati. dlil_input_thread() [bsd/net/dlil.c] assiste le code di ingresso 84

Il sistema operativo Mac OS X

dellmbuf delle interfacce di rete, compresa quella dellinterfaccia di loopback, ingerendo i pacchetti di rete mediante dlil_input_packet()

[bsd/net/dlil.c]. Inoltre chiama proto_input_run() per eseguire liniezione del pacchetto di livello protocollo. dlil_call_delayed_detach_thread() [bsd/net/dlil.c] esegue una separazione ritardata (sicura) di protocolli, filtri e filtri dellinterfaccia. bcleanbuf_thread() [bsd/vfs/vfs_bio.c] esegue un servizi di lavanderia di buffer del file system. Ripulisce i buffers presenti in una coda speciale (to-be-cleaned queue) scrivendoli sul disco. bufqscan_thread() [bsd/vfs/vfs_bio.c] bilancia una porzione delle code dei buffers, pubblicizzando la pulizia dei buffers e rilasciando quelli puliti alla coda dei buffers vuoti. La figura 3-8 mostra le funzioni kernel di alto livello coinvolti nella creazione di kernel threads. Tra questi, kernel_thread() e IOCreateThread() devono essere utilizzate dal Mach e dallI/O Kit rispettivamente.

3.1.5 Astrazioni relative al thread


Andiamo ora ad esaminare un ristretto numero dastrazioni rilevanti nel contesto dei threads Mach cos come implementati nel kernel del Mac OS X. Discuteremo di remote procedure call (RPC), thread activation e shutlle, thread migration e continuations.

3.1.5.1 Chiamata a procedura remota


Il Mach un kernel orientato alla comunicazione, lastrazione della chiamata a procedura remota quindi fondamentale al funzionamento del Mach. Noi definiamo la RPC come lastrazione di chiamata a procedura quando il chiamante ed il chiamato sono in tasks differenti; in questo caso, infatti, la procedura remota dal punto di vista del chiamante. Anche se il Mac OS X utilizza solo RPC kernel-level tra tasks locali, quando i partecipanti allRPC sono su macchine differenti il concetto simile. In un tipico scenario RPC, lesecuzione (ossia il controllo di flusso) spostata temporaneamente in unaltra locazione 85

Il sistema operativo Mac OS X

(che corrisponde alla procedura remota) e, in seguito, riportata alla locazione originale cos come nelle chiamate di sistema. Il chiamante (client) raduna tutti i parametri insieme in un messaggio che spedisce al fornitore di servizio (server). Questultimo scompone il messaggio nei suoi pezzi originali e li processa come operazioni locali.

3.1.5.2 Attivazione e Shuttle


Prima del Mac OS X 10.4, un kernel thread era diviso in due parti logiche: lactivation e lo shuttle. Il motivo di questa divisione era la necessit di avere una parte che fornisse un controllo esplicito sul thread (lactivation) ed unaltra parte che venisse utilizzata dallo scheduler (lo shuttle). La thread activation rappresenta il contesto di esecuzione del thread, rimane collegata al suo task (e quindi ha sempre un fissato puntatore a task valido) e, fino a quando non terminata, rimane nello stack di attivazione del task74. Il thread shuttle lentit schedulata corrispondente al thread, pu operare (per un certo tempo75) allinterno di unactivation e pu migrare durante una RPC a causa di una contesa di risorse. Uno shuttle contiene scheduling, accounting, informazioni di timing e supporto al messaging.

Figura 3-9

Le strutture dati shuttle e activation nel Mac OS X 10.0

74 75

Un thread, in quanto flusso logico di controllo, rappresentato da uno stack dattivazioni allinterno di un task. Fino a che uno shuttle utilizza unactivation, mantiene un riferimento su questa.

86

Il sistema operativo Mac OS X

Notiamo che lactivation vicina alla nozione popolare di thread, essendo la parte esternamente visibile di manipolazione del thread. In contrasto lo shuttle ne rappresenta la parte pi interna. Allinterno del kernel, current_act() ritorna un puntatore alla corrente attivazione, laddove current_thread() restituisce un puntatore allo shuttle. Lastrazione duale shuttle/activation ha subito modifiche di implementazione nelle varie versioni di Mac OS X. Come possiamo vedere dalla figura 3-9, nella versione 10.0 limplementazione di un thread consisteva di due strutture dati primarie: la thread_shuttle e la thread_activation, con il tipo di dato thread (thread_t) che punta alla struttura thread_shutlle. Lactivation pu essere acceduta dallo shuttle, e quindi un thread_t rappresenta un thread nella sua interezza.

Figura 3-10

La struttura thread nel Mac OS X 10.3

Nelle versioni successive del Mac OS X, la struttura dati del thread ha inglobato, da un punto di vista sintattico, lo shuttle e lactivation in una singola struttura (vedi figura 3-10). La figura 3-11 mostra limplementazione di current_thread() e current_act() nel Mac OS X 10.3 e 10.476.

76

A partire dalla versione 10.4 la distinzione tra shuttle e activation non pi presente.

87

Il sistema operativo Mac OS X

Figura 3-11

Recupero del thread corrente (shuttle) e dellactivation corrente nelle versioni Mac OS X 10.3 e 10.4

// osfmk/ppc/cpu_data.h (Mac OS X 10.3) extern __inline__ thread_act_t current_act(void) { thread_act_t act; __asm__ volatile("mfsprg %0,1" : "=r" (act)); return act; }; ... #define current_thread() current_act()->thread // osfmk/ppc/cpu_data.h (Mac OS X 10.4) extern __inline__ thread_t current_thread(void) { thread_t result; __asm__ volatile("mfsprg %0,1" : "=r" (result)); return (result); } // osfmk/ppc/machine_routines_asm.s (Mac OS X 10.4) /* thread_t current_thread(void) * thread_t current_act(void) * Return the current thread for outside components. */ align 5 .globl EXT(current_thread) .globl EXT(current_act) LEXT(current_thread) LEXT(current_act) mfsprg r3,1 blr

Il modello originale dellRPC nel Mach basato su servizi per lo scambio di messaggi, dove threads distinti leggono messaggi e scrivono risposte. Abbiamo visto che anche i diritti daccesso sono comunicati nel Mach attraverso messaggistica. I sistemi operativi hanno supportato lIPC procedurale in diverse forme: gates nel Multics, lightweight RPC (LRPC) nel TaOS, doors nel Solaris ed event pairs nel Windows NT sono esempi di meccanismi di chiamata a procedura cross-domain. Il modello di thread nello Spring System della Sun ha il concetto di shuttle, la vera entit schedulabile dal kernel che supporta una catena di threads visibili dalle applicazioni (analoghi alle attivazioni).

3.1.5.3 Migrazione del thread


Nella discussione sulla dualit shuttle/attivazione abbiamo accennato alla migrazione di un thread77. Il termine migration si riferisce al modo in cui trasferito il controllo tra il client ed il server durante una RPC. La sequenza deventi successivi allinizio della chiamata a procedura remota da parte del client, comportano molti cambi di contesto. Con il modello
77

Il modello dei migrating threads fu sviluppato allUniversity of Utah.

88

Il sistema operativo Mac OS X

a thread diviso, piuttosto che bloccare il thread client sulla sua RPC kernel, il kernel pu farlo migrare in modo da riprendere lesecuzione nel codice del server. Anche se richiesto ancora qualche context switch (in particolare quello delladdress space, lo stack pointer e forse qualche subset del register state), non sono pi due interi threads ad essere coinvolti. Dal punto di vista dello scheduler, tra laltro, non c nessun cambio di contesto. Infine, il client utilizza il proprio tempo di processore durante la sua esecuzione allinterno del codice del server; in questo senso, la migrazione del thread un meccanismo di ereditariet prioritaria.78

3.1.5.4 Continuazioni
Il kernel del Mac OS X utilizza un kernel stack di 16KB per ogni thread (KERNEL_STACK_SIZE [osfmk/mach/ppc/vm_param.h]). Allaumentare del numero di threads in un sistema, la memoria consumata dai soli kernel stacks pu diventare irragionevole, secondo le risorse disponibili. Alcuni sistemi operativi convogliano diversi threads utente in un unico kernel thread, anche se al costo della concorrenza (poich questi user threads non possono essere schedulati

indipendentemente). Ricordando che un Mach thread (o una attivazione) legato al suo task per tutta la vita del thread e che ogni task (che abbia un significato) ha almeno un thread, possiamo affermare che in un sistema il numero di threads almeno pari al numero dei tasks. I sistemi operativi utilizzano uno dei due modelli storici per lesecuzione kernel: il process model o linterrupt model. Nel modello di processo, il kernel mantiene uno stack per ogni thread. Quando un thread eseguito nel kernel (a causa di una chiamata di sistema o uneccezione) il suo kernel stack dedicato, utilizzato per tracciare il suo stato desecuzione. Se il thread si blocca nel kernel, non richiesto un salvataggio esplicito dello stato, poich lo stato catturato nel kernel stack del thread. La semplificazione introdotta da questo approccio

78

Il concetto di migrazione pu essere comparato al modello UNIX della chiamata di sistema. Dove un thread utente (o processo) migra allinterno del kernel durante una system call, senza un cambio di contesto completo.

89

Il sistema operativo Mac OS X

controbilanciata da una richiesta maggiore di risorse, e dal fatto che lo stato macchina pi difficile da valutare se uno dovesse analizzarlo per ottimizzare il trasferimento del controllo tra threads. Nel modello di interruzione, il kernel tratta le chiamate di sistema e le eccezioni come se fossero interruzioni. Si utilizza un kernel stack per ogni processore durante tutta lesecuzione kernel dei threads. Ci richiede che i threads bloccati nel kernel devono salvare esplicitamente il loro stato desecuzione da qualche parte, in modo che il kernel possa utilizzare lo stato salvato al momento del resume del thread bloccato. Il tipico kernel UNIX ha usato il modello a processi, cos come le prime versioni del Mach. Il concetto di continuations fu utilizzato nel Mach 3 come un approccio intermedio che permettesse ad un thread bloccante lopzione di utilizzare il process model oppure linterrupt model. Il Mac OS X continua ad utilizzare tale astrazione e di conseguenza un thread bloccante nel Mac OS X ha la possibilit di decidere come bloccarsi. La funzione thread_block() [osfmk/kern/sched_prim.c] accetta un singolo argomento, che pu essere una funzione di continuazione oppure il valore THREAD_CONTINUE_NULL definito nellheader file osfmk/kern/kern_types.h. Tale funzione chiama thread_block_reason() [osfmk/kern/sched_prim.c] che a sua volta chiama thread_invoke() [osfmk/kern/sche_prim.c] per effettuare un cambio di contesto iniziare lesecuzione di un nuovo thread selezionato per il processore corrente. Questa funzione controlla se stata specificata una continuazione valida e, in caso positivo, cerca79 di passare il kernel stack del vecchio thread al nuovo. Quindi, quando il vecchio thread si blocca il suo contesto viene scartato e quando riprende gli viene fornito un nuovo kernel stack, su cui verr eseguita la funzione di continuazione. La variante thread_block_parameter() [osfmk/kern/sched_prim.c]

accetta un singolo parametro che thread_block_reason() memorizza in una struttura thread, dalla quale recuperato e passato alla funzione di continuazione. Una funzione specificata come continuazione non pu ritornare normalmente, ma solo
79

Un thread con una politica di scheduling real-time non rilascia il proprio stack.

90

Il sistema operativo Mac OS X

chiamare una funzione o unaltra continuazione. Un thread che usa una continuazione deve salvare ogni stato che potrebbe essere necessario dopo la ripresa. Tale salvataggio deve avvenire in uno spazio dedicato che la struttura thread (o una struttura associata) deve avere, altrimenti il thread bloccante dovr allocare memoria aggiuntiva per questo scopo. La funzione di continuazione dovr conoscere in quale modo il thread bloccante provvede alla memorizzazione dello stato. Le continuazioni sono molto utili nei casi di thread bloccanti in cui non ci sia uno stato da salvare (o comunque sia piccolo). Esempi di uso delle continuazioni nel Mac OS X includono i threads di inattivit del processore, il thread di tick dello scheduler, il thread di swap-in ed il daemon di page-out.

3.1.6 I threads del Mac OS X


Il Mac OS X non il frutto di un team di progettisti, ma il risultato di un vasto conglomerato di tecnologie differenti provenienti da svariate sorgenti. In quanto sistema operativo commerciale, che si rivolge sia ad utenti esperti (che necessitano di strumenti potenti) sia a neofiti (che hanno bisogno di supporto), il Mac OS X include uninusuale quantit di meccanismi ed interfacce. Il sottosistema di processo visibile allutente una buon esempio di tale fenomeno: il Mac OS X ha diversi flavours di processi e threads user-level, a seconda dellambiente dellapplicazione in uso. Alcuni esempi di tali flavours sono i seguenti: un thread Mach creato in un kernel task, per luso del kernel stesso un processo BSD a singolo thread creato mediante la chiamata di sistema fork() un processo BSD multi-threaded creato originariamente dalla chiamata di sistema fork(), seguita dalla creazione di uno o pi threads aggiuntivi creati utilizzando lAPI del Pthreads unapplicazione Java con vari threads Java creati utilizzando lAPI di java.lang.Thread un sottoprocesso creato usando lAPI di Cocoa NSTask un thread creato usando lAPI di Cocoa NSThread 91

Il sistema operativo Mac OS X

un processo CPM (Cocoa Process Manager) creato chiamando lAPI di Carbon LaunchApplication() tasks schedulati in modo preempitivo, creati in unapplicazione utilizzando Carbon Multiprocessing Service threads schedulati in modo cooperativo, creati in unapplicazione utilizzando Carbon Thread Manager un thread in esecuzione in un ambiente Carbon A questo punto, i seguenti punti generali possono essere riferiti ai threads del Mac OS X: Il kernel conosce un solo tipo di thread: il thread Mach. Quindi ogni entit in esecuzione visibile allutente, gira come thread Mach, anche se una libreria utente che gestisce tali entit pu stratificare queste su di un thread Mach, facendo girare una di queste alla volta. Unentit simile ad un processo di prima classe visibile allutente ha, tipicamente, un corrispondente processo BSD e, di conseguenza, un corrispondente task Mach. Unentit simile ad un thread di prima classe visibile allutente ha, tipicamente, un corrispondente pthread e, di conseguenza, un corrispondente thread Mach. Abbiamo detto tipicamente e non sempre, poich tecnicamente possibile creare un task Mach senza un processo BSD ed un thread Mach senza un pthread. Potrebbero esserci anche altre eccezioni, ad esempio lintero ambiente Classic, insieme a tutti i suoi processi di Process Management, corrisponde ad un solo processo BSD.

3.2 Lo Scheduling
Un sistema timesharing fornisce lillusione che molti processi girino in modo concorrente interponendo la loro esecuzione, cambiando contesto da uno allaltro in base a varie condizioni. Linsieme di regole in base alle quali si determina lordine di esecuzione dei threads chiamato scheduling policy. Una componente del sistema, chiamata scheduler, implementa la politica mediante strutture dati e algoritmi; limplementazione permette allo scheduler di applicare la politica durante la selezione dei threads da eseguire tra quelli pronti. 92

Il sistema operativo Mac OS X

Anche se lesecuzione concorrente ed il parallelismo sono obiettivi importanti per gli schedulers, specialmente con laffermarsi dei sistemi multiprocessore, abbastanza comune per un sistema operativo moderno supportare differenti politiche di scheduling, permettendo ai differenti carichi di lavoro di essere trattati in modo appropriato. In unoperazione tipica, lo scheduler del Mac OS X concede il processore ad ogni thread per un breve periodo di tempo, detto (timeslicing) quantum, dopo il quale prende in considerazione di passare ad un altro thread in attesa di esecuzione, con priorit maggiore o uguale. Notiamo che nel caso si presenti un thread con priorit maggiore, quello in esecuzione pu essere interrotto prima dello scadere del proprio quantum per lasciare il processore al thread prioritario (preemptive scheduling).

3.2.1 Scheduler Operation


Il Mac OS X , fondamentalmente, un sistema a suddivisione di tempo e quindi i threads sono soggetti ad una politica di scheduling generalmente di tipo timeshare. In questo tipo di policy, il sistema tende a dare, senza garanzie, un equo tempo di processore ad ogni thread in competizione, dove per equit si intende fornire approssimativamente uguali quantit di risorse del processore in e per un tempo ragionevole. La figura 3-12 mostra un grafico (non esaustivo) delle chiamate, costituito da varie funzioni chiave che sono coinvolte nellesecuzione e nello scheduling dei threads. I seguenti punti caratterizzano lo scheduling nel Mac OS X: Lo scheduler si occupa dei soli threads Mach. Di conseguenza non schedula nessuna altra entit di livello superiore. Lo scheduler non usa la conoscenza che due o pi threads portino allo stesso task per selezionare tra loro. In teoria tale conoscenza potrebbe essere utilizzata per ottimizzare il cambio di contesto intra-task. Il Mach utilizza lo stesso scheduler sia per monoprocessore sia per multiprocessori. Nei fatti il Mach utilizza lo stesso kernel, in versione multiprocessore, senza tener conto del numero di processori presenti sulla macchina. Questo, ovviamente, crea delloverhead su sistemi monoprocessore. 93

Il sistema operativo Mac OS X

Figura 3-12

Grafico delle chiamate di funzioni per lesecuzione e lo scheduling di un thread

Il kernel del Mac OS X supporta lhandoff scheduling, nel quale un thread pu cedere direttamente il processore ad un altro thread senza coinvolgere completamente lo scheduler. Il meccanismo di scambio dei messaggi del kernel pu utilizzare lhandoff scheduling durante il passaggio di un messaggio. Se un thread in attesa di ricevere un messaggio, il thread mittente pu cambiare 94

Il sistema operativo Mac OS X

direttamente sul thread ricevente. Il destinatario eredita effettivamente gli attributi di scheduling del mittente, incluso il residuo del quantum corrente del mittente. Una volta espirato il quantum, tuttavia, gli effetti di tale eredit scompaiono. Lo scheduler del Mac OS X supporta varie politiche di scheduling, inclusa una politica real-time soft, ma non fornisce una interfaccia per caricare policies personalizzate. Ogni processore ha il proprio, dedicato, idle thread che ricerca altri threads da eseguire.
Tabella 3-2 Livelli 0-10 Priorit nello scheduler del Mac OS X Descrizione Priorit pi basse (aged, idle) e priorit abbassate (aged). La priorit minore (0) ha numerosi sinonimi, come MINPRI_USER, MINPRI, IDLEPRI (idle priority) e DEPRESSPRI (depress priority). 11-30 31 32-51 Priorit abbassate. Priorit base di default (BASEPRI_DEFAULT) per i threads utente. La routine host_info() ritorna questo valore come user priority. Priorit elevate, come quelle ottenibili attraverso task_policy_set(). Per esempio BASEPRI_BACKGROUND (46), BASEPRI_FOREGROUND (47) e BASEPRI_CONTROL (48) corrispondono alle priorit base dei tasks che sono stati designati come background, foreground e control rispettivamente. 52-63 64-79 Priorit elevate. Quando un nuovo task creato la sua massima priorit fissata da MAXPRI (63). Priorit alte normalmente riservate al sistema. Gli estremi di tale range sono chiamati MINPRI_RESERVED (64) e MAXPRI_RESERVED (79). MINPRI_RESERVED ritornato dalla routine host_info() come la server priority. 80-95 Priorit kernel-only. Le priorit 80, 81, 93 e 95 sono chiamate MINPRI_KERNEL, BASEPRI_KERNEL, BASEPRI_PREEMPT e MAXPRI_KERNEL rispettivamente. La routine host_info() ritorna MINPRI_KERNEL sia come kernel priority sia come system priority. 96-127 Priorit real-time ottenibili attraverso thread_policy_set(). Le priorit 96, 97 e 127 sono chiamate BASEPRI_REALTIME, BASEPRI_RTQUEUES e MAXPRI rispettivamente.

Lo scheduler del Mac OS X basato sulla priorit, quindi la selezione dei threads da mettere in esecuzione tiene in conto della loro priorit. La tabella 3-2 mostra i vari ranges di priorit nel sottosistema di scheduling, dove tanto pi alto il valore numerico tanto 95

Il sistema operativo Mac OS X

maggiore la priorit. Il flavor HOST_PRIORITY_INFO della routine Mach host_info() pu essere utilizzato per recuperare i valori di varie priorit specifiche. Una struttura dati fondamentale mantenuta dallo scheduler la run queue. Ognuna delle strutture run_queue (figura 3-13) rappresenta una coda di priorit dei runnable threads e contiene un array di NRQS liste a doppio collegamento, una per ogni corrispondente livello di priorit. Il membro highq un hint che indica la probabile locazione del thread a priorit pi alta. Ricordiamo inoltre che ogni processor set ha la propria run queue, ed ogni processore ha la propria local run queue.
Figura 3-13 La struttura run_queue
// // // // // // 128 levels per run queue number of words per bitmap maximum priorit possible lowest legal priorit schedulable idle thread priority depress priority

// osfmk/kern/sched.h #define NRQS 128 #define NRQBM (NRQS/32) #define MAXPRI (NRQS-1) #define MINPRI IDLEPRI #define IDLEPRI 0 #define DEPRESSPRI MINPRI ... struct run_queue { int highq; int bitmap[NRQBM]; int count; int urgency; queue_head_t queues[NRQS]; };

// // // // //

highest runnable queue run queue bitmap array number of threads total level of preemption urgency one for each priority

Per bilanciare lutilizzo del processore fra i vari threads, lo scheduler modifica le priorit dei threads tenendo conto del loro uso. Esistono svariate limitazioni e misure relative alle priorit associate ad ogni task e thread. Per comprenderle andiamo a riesaminare le strutture task e thread ponendo lattenzione alle parti riguardanti lo scheduling. Come mostrato nella figura 3-14, ogni thread ha una priorit base, tuttavia la scheduled priority quella che lo scheduler esamina quando seleziona i threads da mandare in esecuzione80. La scheduled priority calcolata sulla base priority con un offset derivato dal recente utilizzo del processore da parte del thread. La priorit base di default per i threads utente timesharing 31, mentre la priorit minima del kernel 80: di conseguenza i kernel threads sono sostanzialmente favoriti rispetto ai threads utente standard.

80

Questo quanto accade ai threads in timesharing; quelli real-time sono trattati in maniera specifica dallo scheduler.

96

Il sistema operativo Mac OS X

Figura 3-14

Parti relative allo scheduling delle strutture task e thread

// osfmk/kern/task.h struct task { ... // task's role in the system // set to TASK_UNSPECIFIED during user task creation task_role_t role; // default base priority for threads created within this task // set to BASEPRI_DEFAULT during user task creation integer_t priority; // no thread in this task can have priority greater than this // set to MAXPRI_USER during user task creation integer_t max_priority; ... }; // osfmk/kern/thread.h struct thread { ... // scheduling mode bits include TH_MODE_REALTIME (time-constrained thread), // TH_MODE_TIMESHARE (uses standard timesharing scheduling), // TH_MODE_PREEMPT (can preempt kernel contexts), ... // // TH_MODE_TIMESHARE is set during user thread creation integer_t sched_mode; integer_t sched_pri; // scheduled (current) priority // base priority // set to parent_task->priority during user thread creation integer_t priority; // maximum base priority // set to parent_task->max_priority during user thread creation integer_t max_priority; // copy of parent task's base priority // set to parent_task->priority during user thread creation integer_t task_priority; // copy of task's base priority ... // task-relative importance // set to (self->priority - self->task_priority) during user thread creation integer_t importance; // parameters for time-constrained scheduling policy struct { ... } realtime; uint32_t current_quantum; // duration of current quantum ... // last scheduler tick // set to the global variable sched_tick during user thread creation natural_t sched_stamp; // timesharing processor usage // initialized to zero in the "template" thread natural_t sched_usage; // factor for converting usage to priority // set to the processor set's pri_shift value during user thread creation natural_t pri_shift; };

Man mano che un thread utilizza il processore, la sua priorit diminuisce e, poich lo scheduler favorisce le priorit pi alte, questo pu condurre ad una situazione in cui un thread ha utilizzato talmente tanto tempo di processore che lo scheduler non pi disposto a concedergliene altro a causa della grande diminuzione di priorit. Lo schedulatore Mach si occupa di questo problema invecchiando (aging) luso del processore: in pratica

97

Il sistema operativo Mac OS X

dimentica esponenzialmente il passato utilizzo del processore da parte del thread andandone ad aumentare gradualmente la priorit. Tuttavia questo crea un altro problema: se il sistema ha un tale carico di lavoro che la maggior parte (o tutti) i threads ricevono un piccolo tempo di processore, allora la priorit di tutti questi threads aumenter e la conseguente contesa deteriorer la risposta del sistema. Per ovviare questaltro problema, lo scheduler moltiplica lutilizzo del processore da parte del thread per un fattore di conversione relativo al carico del sistema.
Figura 3-15 Calcolo della priorit timesharing di un thread

// osfmk/kern/priority.c #define do_priority_computation(thread, pri) \ do { \ (pri) = (thread->priority) /* start with base priority */ \ - ((thread)->sched_usage >> (thread)->pri_shift); \ if ((pri) < MINPRI_USER) \ (pri) = MINPRI_USER; \ else if ((pri) > MAXPRI_KERNEL) \ (pri) = MAXPRI_KERNEL; \ } while (FALSE);

In figura 3-15 vediamo com effettuato tale calcolo. Osserviamo che lutilizzo di processore del thread (threadsched_usage), dopo essere stato ridotto da un fattore di conversione (threadpri_shift), sottratto alla sua priorit base

(threadpriority) per restituire la scheduled priority. Andiamo ora ad esaminare com calcolato tale fattore di conversione81 e in che modo decade nel tempo lutilizzo del processore. Il fattore di conversione consiste di due parti: una fissa basata sullunit di tempo assoluto dipendente dalla macchina, e una dinamica basata sul carico del sistema. La variabile globale sched_pri_shift contiene la parte fissa (computata nella fase di inizializzazione dello scheduler), mentre la parte dinamica una entry di un array costante in cui lindice indica il carico di sistema. In figura 3-16 vediamo un estratto di codice per il calcolo della parte dinamica del fattore di conversione.

La routine update_priority() [osfmk/kern/priority], invocata frequentemente nello scheduling, in determinate condizioni aggiorna il valore del fattore di conversione del thread ponendolo uguale a quello del processor set che contiene il thread.

81

98

Il sistema operativo Mac OS X

Figura 3-16

Calcolo del fattore di conversione utilizzo-priorit per priorit timeshare

// osfmk/kern/sched_prim.c int8_t sched_load_shifts[NRQS]; ... // called during scheduler initialization // initializes the array of load shift constants static void load_shift_init(void) { int8_t k, *p = sched_load_shifts; uint32_t i, j; *p++ = INT8_MIN; *p++ = 0; for (i = j = 2, k = 1; i < NRQS; ++k) { for (j <<= 1; i < j; ++i) *p++ = k; } } // osfmk/kern/sched_average.c void compute_averages(void) { ... register int nthreads, nshared; register uint32_t load_now = 0; ... if ((ncpus = pset->processor_count) > 0) { nthreads = pset->run_count - 1; // ignore current thread nshared = pset->share_count; // so many timeshared threads ... if (nshared > nthreads) nshared = nthreads; // current was timeshared! if (nshared > ncpus) { if (ncpus > 1) load_now = nshared / ncpus; else load_now = nshared; if (load_now > NRQS - 1) load_now = NRQS - 1; } pset->pri_shift = sched_pri_shift - sched_load_shifts[load_now]; } else { ... pset->pri_shift = INT8_MAX; // hardcoded to 127 ... } // compute other averages ... }

Lo scheduler invecchia luso del processore dei threads in maniera distribuita mediante svariate chiamate alla routine update_priority() [osfmk/kern/priority.c]. Tale routine comincia calcolando la differenza (ticks) tra lo scheduler tick corrente (sched_tick), che incrementato periodicamente, e lo scheduler tick registrato del thread (thread->sched_stamp). Questultimo tenuto aggiornato aggiungendoci il valore ticks. In base a tale valore si possono verificare due situazioni: se ticks maggiore o uguale rispetto a sched_decay_ticks (32), allora lutilizzo del processore del thread azzerato; se minore, allora lutilizzo moltiplicato per ()ticks. Ci sono fondamentalmente due ragioni per la scelta di come fattore di decadimento esponenziale: fornisce un comportamento dello scheduling simile a quello di altri sistemi

99

Il sistema operativo Mac OS X

timesharing; la moltiplicazione con tale fattore pu essere approssimata con operazioni binarie semplici. Consideriamo la moltiplicazione di un numero per , che pu essere scritto come +. La moltiplicazione di un numero per si effettua con un shift a destra di 1, quella per con uno shift a destra di 3 e sommando i risultati si ottiene il risultato cercato. Per facilitare il computo, il kernel ha un array statico con

sched_decay_ticks coppie di interi, dove la coppia di indice i contiene i valori shift per approssimare ()i. Se il valore di ticks nellintervallo [0, 31], la coppia di indice ticks usata in accordo alla seguente formula:
if (/* the pairs second value is positive */) usage = (usage >> (first value)) + (usage >> abs(second value))); else usage = (usage >> (first value)) - (usage >> abs(second value)));

Notiamo che non sufficiente rendere un thread responsabile del decadimento delluso del processore. I threads con priorit basse potrebbero continuare a rimanere nella run queue senza avere possibilit di entrare in esecuzione a causa dei threads a priorit maggiore. In particolare, questi threads a bassa priorit sarebbero incapaci di aumentare la loro priorit abbattendo il loro processor usage. Di conseguenza lo scheduler utilizza un kernel thread dedicato, il thread_update_scan(), per questo scopo. La routine consiste di due passi logici. Nel primo itera sulle run queues, comparando il valore sched_stamp dei threads timesharing con sched_tick. In questo passo sono raccolti in un array fino a THREAD_UPDATE_SIZE (128) threads candidati. Il secondo passo itera sugli elementi di tale array, chiamando update_priority() sui threads timesharing che soddisfano i seguenti criteri: Il thread non sospeso e non ne stato richiesto lo stop, cio il bit TH_SUSP del suo stato non settato. Il thread non in coda di attesa, cio il bit TH_WAIT del suo stato non settato. Il valore sched_stamp del thread non ancora aggiornato con sched_tick.

3.2.2 Scheduling Policies


Il Mac OS X supporta politiche di scheduling multiple denominate (timesharing),

THREAD_STANDARD_POLICY

THREAD_EXTENDED_POLICY, 100

Il sistema operativo Mac OS X

THREAD_PRECEDENCE_POLICY

THREAD_TIME_CONSTRAINT_POLICY

(realtime). Le routines Mach policy_get() e policy_set() possono essere utilizzate per recuperare e modificare, rispettivamente, la politica di scheduling di un thread. Le equivalenti routines della Pthreads API sono pthread_getschedparam() e pthread_setschedparam(). Le informazioni sulla politica di scheduling posso anche essere specificate allatto della creazione come attributi del pthread. Notiamo che la Pthreads API utilizza diverse politiche denominate SCHED_FIFO (first in first out), SCHED_RR (round robin) e SCHED_OTHER (system-specific policy)82. La THREAD_STANDARD_POLICY la politica di scheduling standard ed il default per i threads timesharing. Secondo tale politica, ai threads che eseguono delle computazioni long-running sono equamente assegnate le risorse di processore. Un conto dei threads timesharing mantenuto per ogni processor set. La THREAD_EXTENDED_POLICY una versione estesa della politica standard. In questa politica, un hint booleano designa un thread come long-running (timesharing) o non-longrunning (non-timesharing). Nel primo caso, la politica adottata identica alla THREAD_STANDARD_POLICY. Nel secondo caso il thread girer ad una priorit fissata purch il suo utilizzo di processore non superi una soglia di sicurezza, nel qual caso lo scheduler lo retroceder temporaneamente come thread timesharing attraverso un meccanismo a prova di errore. La THREAD_PRECEDENCE_POLICY prevede un importance value (un signed integer) da associare ad un thread, permettendo cos ai threads di un task di essere designati come pi o meno importanti luno rispetto allaltro. A parit di tutti gli altri aspetti, il thread pi importante del task favorito rispetto a quelli meno importanti. Notiamo che questa politica pu essere utilizzata in congiunzione con le altre. La THREAD_TIME_CONSTRAINT_POLICY la politica di scheduling real-time intesa per quei threads con costrizioni sulla propria esecuzione. Un thread specifica allo scheduler di avere bisogno di una certa frazione del tempo di processore, forse

82

Nel caso del Mac OS X la politica SCHED_OTHER il timesharing. Notiamo inoltre che la Pthreads API non supporta specificamente una politica di scheduling realtime.

101

Il sistema operativo Mac OS X

periodicamente. Lo scheduler preferir un thread real-time rispetto a tutti gli altri threads, a meno forse daltri real-time. Tale policy pu essere applicata ad un thread utilizzando la routine thread_policy_set() con i seguenti parametri: tre interi espressi in unit di tempo assoluto (period, computation e constraint) e un booleano (preemptible). Un valore non nullo di period indica la periodicit nominale nella computazione, vale a dire il tempo tra due arrivi delaborazione consecutivi. Il valore di computation indica il tempo nominale necessario ad un periodo delaborazione. Il valore di constraint specifica il massimo quantitativo di tempo reale che pu passare tra linizio di un periodo delaborazione alla fine della computazione. Notiamo che la differenza tra il valore di constraint e computation, che sempre un valore non negativo, indica la latenza real-time. Infine, il parametro preemptible dichiara se la computazione pu essere interrotta o no. Notiamo che la politica real-time non necessita privilegi speciali per essere usata, quindi necessaria una certa prudenza poich porta la priorit di un thread sopra quella di diversi kernel threads. Lo scheduler include un meccanismo fail-safe per i threads non-timesharing per i quali lutilizzo del processore eccede una soglia pericolosa. Quando si esaurisce il quantum di un tale thread, esso viene retrocesso a thread timesharing e la sua priorit impostata a DEPRESSPRI. Tuttavia, nel caso di policy real-time, lo scheduler ricorda le precedenti necessit real-time del thread e, dopo un periodo di sicurezza per il rilascio, lo promuove di nuovo a thread real-time e ne imposta la priorit a BASEPRI_RTQUEUES.83 Quando si utilizza la routine thread_policy_set() per cambiare la politica di scheduling, o per modificare i parametri della politica in uso, il kernel ricalcola la priorit del thread e i valori dimportanza, in conformit ai limiti di priorit minimi e massimi del thread (vedi figura seguente).

La massima unsafe computation definita come il prodotto tra il quantum standard e la costante max_unsafe_quanta. Il valore di default di tale costante MAX_UNSAFE_QUANTA, definito in osfmk/kern/sched_prim.c pari a 800. Un valore alternativo pu essere ricavato attraverso largomento di boottime unsafe.

83

102

Il sistema operativo Mac OS X

Figura 3-17

Ricalcolo della priorit di un thread in seguito al cambio di politica di scheduling


thread)

// osfmk/kern/thread_policy.c static void thread_recompute_priority(thread_t { integer_t priority; if (thread->sched_mode & TH_MODE_REALTIME) priority = BASEPRI_RTQUEUES; else { if (thread->importance > MAXPRI) priority = MAXPRI; else if (thread->importance < -MAXPRI) priority = -MAXPRI; else priority = thread->importance; priority += thread->task_priority; if (priority > thread->max_priority) priority = thread->max_priority; else if (priority < MINPRI) priority = MINPRI; } // set the base priority of the thread and set_priority(thread, priority); }

// real-time // very important thread // very unimportant thread

// add base priority // clip to maximum allowed // clip to minimum possible

reset its scheduled priority

Sappiamo che la routine task_policy_set() pu essere utilizzata per definire la politica di scheduling associata ad un task. Un esempio di flavor di una task policy TASK_CATEGORY_POLICY, che informa il kernel del ruolo che il task ha allinterno del sistema operativo. Con tale flavor, la routine di cui sopra pu essere utilizzata per designare il ruolo di un task. Esempi di ruoli di task nel Mac OS X sono i seguenti: TASK_UNSPECIFIED il ruolo di default. TASK_FOREGROUND_APPLICATION progettato per una normale applicazione UI-based pensata per girare in foreground dal punto di vista dellUI. Lassegnazione di questo ruolo ad un task fissa la sua priorit a

BASEPRI_FOREGROUND (vedi tabella 3-2). La priorit massima del task rimane invariata. TASK_BACKGROUND_APPLICATION progettato per una normale applicazione UI-based pensata per girare in background dal punto di vista dellUI. Lassegnazione di questo ruolo ad un task fissa la sua priorit a

BASEPRI_BACKGROUND (vedi tabella 3-2). La priorit massima del task rimane invariata. TASK_CONTROL_APPLICATION un ruolo che pu essere assegnato al pi ad un task alla volta, su una base first-come first-serve. Esso designa il task come la 103

Il sistema operativo Mac OS X

applicazione di controllo UI-based. Il programma logwindow normalmente usa questa designazione. Lassegnazione di questo ruolo unazione privilegiata che porta la priorit del task a BASEPRI_CONTROL senza modificare la massima priorit. TASK_GRAPHIC_SERVER pu essere assegnato al programma WindowServer. Cos come per TASK_CONTROL_APPLICATION pu essere assegnato (con accesso privilegiato) ad un solo task per volta su base first-come first-serve. La priorit del task fissata a (MAXPRI_RESERVED-3) mentre la priorit massima a MAXPRI_RESERVED. Luso di tale ruolo opzionale per il sistema. Notiamo che i ruoli non sono ereditati attraverso i tasks, quindi ogni task nasce con il ruolo TASK_UNSPECIFIED.

104

Il sistema operativo Mac OS X

Capitolo 4
La memoria

La memoria, specificamente quella fisica, una preziosa risorsa in un computer. Una caratteristica integrale dei moderni sistemi operativi la memoria virtuale (VM, virtual memory). La tipica implementazione della VM fornisce lillusione di un esteso e contiguo spazio dindirizzi virtuali ad ogni programma, senza che il programmatore debba conoscerne i dettagli, come ad esempio quali parti del programma sono residenti nella memoria fisica (e dove) in ogni momento. La memoria virtuale comunemente implementata attraverso il paging: uno spazio degli indirizzi suddiviso in pagine (pages) di dimensione fissata. Quando residente, ogni pagina virtuale caricata in una particolare porzione, detta page frame, di memoria fisica. Oltre al nucleo del sottosistema VM del Mach, la gestione della memoria nel Mac OS X comprende diversi altri meccanismi, alcuni dei quali non strettamente facenti parte del sottosistema della memoria virtuale ma in ogni caso strettamente correlati a questo. Nella figura 4-1 possiamo vedere tali componenti e le loro interazioni. Andiamo ad esaminarli brevemente, lasciando il loro approfondimento ai paragrafi successivi. Il sottosistema Mach VM composto dal modulo pmap (physical map) dipendente dalla macchina, e da altri moduli indipendenti dalla macchina per la gestione delle strutture dati corrispondenti alle astrazioni come VM maps, VM objects, named entries e resident pages. Il kernel esporta diverse routine nello spazio utente come parte dellAPI Mach VM. 105

Il sistema operativo Mac OS X

Il kernel utilizza la struttura dati UPL (universal page list) per descrivere un ristretto gruppo di pagine fisiche. Le UPL contengono vari attributi delle pagine che descrivono. I sottosistemi del kernel (particolarmente il file system) utilizzano le UPLs durante la comunicazione con il sottosistema della memoria virtuale.

Figura 4-1

Il sottosistema della memoria del Mac OS X

La UBC (unified buffer cache) un insieme di pagine per il caching del contenuto di files e le porzioni anonime degli spazi di indirizzo dei task. Lesempio pi comune di memoria anonima quello della memoria allocata dinamicamente. 106

Il sistema operativo Mac OS X

Il kernel include tre paginatori interni chiamati default (anonymous) pager, device pager e vnode84 pager. Questi si occupano delle operazioni di page-in e page-out nelle regioni di memoria. I pagers comunicano con il sottosistema Mach VM mediante le interfacce UPL e le interfacce derivate dal Mach pager. Il device pager, che gestisce la memoria delle periferiche, implementato nella porzione I/O Kit del kernel. Nellhardware a 64-bit, il device pager utilizza una parte del controllore della memoria, il DART (Device Address Resolution Table). Il DART, abilitato di default su hardware a 64-bit, mappa gli indirizzi dalla memoria a 64-bit allo spazio degli indirizzi (a 32-bit) delle periferiche PCI. Il page-out daemon un gruppo di kernel threads che scrive porzioni dello spazio dindirizzi del task nel disco come parte delloperazione di paging nella memoria virtuale. Esso esamina luso delle pagine residenti ed impiega uno schema LRU85like per rimuovere le pagine che non sono state utilizzate per un certo tempo. Il programma utente dynamic_pager crea e distrugge i files di scambio per luso del kernel. Notiamo che questo programma non compie nessuna operazione di paging, come potrebbe invece far supporre il nome. Il daemon utente update invoca periodicamente la chiamata di sistema sync() per scaricare nel disco le caches del file system. Il sottosistema di rilevamento del TWS (task working set) mantiene i profili di comportamento di page-fault dei tasks in base allapplicazione. Quando unapplicazione causa un page-fault, il kernel (o meglio il meccanismo di gestione del page-fault) consulta tale sottosistema per determinare per quali ulteriori pagine, se ce ne sono, deve essere fatto il page-in. Il kernel fornisce diversi meccanismi si allocazione di memoria, alcuni dei quali sono le sovrastrutture specifiche del sottosistema di altri. Tutti questi meccanismi infine utilizzano lallocatore di pagine a livello kernel. Gli schemi di allocazione di

84

Un vnode (nodo virtuale) unastrazione di un oggetto filesystem indipendente dal file system. analogo ad una classe base astratta da cui sono derivate le istanze specifiche dei vari file systems. Ogni directory o file attivo (dove attivo assumen connotazioni diverse a seconda del contesto) ha un vnode allinterno della memoria. 85 LRU sta per least recently used ossia usato meno di recente.

107

Il sistema operativo Mac OS X

memoria dello spazio utente sono costruite sullAPI del Mach VM. Il sottosistema Shared Memory Server un servizio kernel che fornisce due regioni globali di memoria condivisa da 256MB: una read-only per il testo che parte dallindirizzo di memoria virtuale utente 0x9000_0000 ed completamente condivisa tra i tasks; laltra per i dati che parte dallindirizzo di memoria virtuale 0xA000_0000 ed condivisa copy-on-write. Il dynamic link editor (dyld) utilizza questo meccanismo per caricare le librerie condivise allinterno degli spazi dindirizzo del task.

4.1 La memoria virtuale


Andremo ora ad esaminare larchitettura della memoria virtuale del Mach, cos com implementata nel kernel del Mac OS X. Il progetto della Mach VM comprende i seguenti aspetti notevoli: Una netta separazione tra la parte dipendente dalla macchina e quella indipendente. Solo questultima ha informazioni relative alla memoria virtuale complete. Spazi dindirizzo virtuale grandi e sparsi, uno per ogni task e completamente condiviso tra i threads del task. Integrazione tra gestione della memoria e comunicazione interprocesso. Il Mach fornisce delle interfacce basate su IPC per lavorare con gli spazi dindirizzo del task. Queste interfacce sono specialmente flessibili nel permettere ad un task di manipolare lo spazio dindirizzo di un altro task. Operazioni di copia virtuale, ottimizzate attraverso gli algoritmi di copy-on-write (simmetrico o asimmetrico). Memoria flessibile che si ripartisce tra tasks collegati o indipendenti, con supporto al COW, che utile durante una fork() o durante i grandi trasferimenti IPC. Files memory-mapped. Vari tipi di backing store utilizzabili attraverso pagers multipli. Ogni spazio dindirizzo di un task rappresentato nel kernel mediante una mappa di indirizzi (VM map), che contiene una lista doubly linked di regioni di memoria ed una 108

Il sistema operativo Mac OS X

struttura mappa fisica (pmap) machine-dependant. Questultima gestisce le traduzioni degli indirizzi da virtuali a fisici. Ogni regione di memoria (VM map entry) rappresenta una serie contigua dindirizzi di memoria, ognuno dei quali attualmente mappato (valido) nel task. In ogni caso, ogni serie ha i propri attributi di protezione ed ereditariet, quindi anche se un indirizzo valido, il task potrebbe non essere capace di accederci per uno o pi tipi di operazione. Le VM map entries, ordinate per indirizzo nella lista, hanno un VM object associato che contiene informazioni circa laccesso alla memoria dalla sua sorgente.

Figura 4-2a

Implementazione nel Mac OS X dellarchitettura della Mach VM

109

Il sistema operativo Mac OS X

Un oggetto VM contiene una lista di pagine residenti (VM pages), ognuna delle quali identificata nediante il suo offset allinterno delloggetto. La memoria dei VM objects non necessariamente residente nella memoria fisica. Un VM object generalmente sostenuto (backed) da un memory object, che semplicemente una porta Mach a cui il kernel pu inviare messaggi al fine di recuperare i dati cercati. Il possessore di un oggetto di memoria un memory manager (gestore di memoria) o pager (paginatore). La figura 4-2a mostra limplementazione del Mac OS X dellarchitettura Mach VM.

4.1.1 Task Address Spaces


Ogni task ha uno spazio dindirizzo virtuale che definisce un set di indirizzi virtuali a cui ogni thread interno al task pu riferirsi. Un task a 32-bit ha uno spazio dindirizzo virtuale di 4GB. Le ultime versioni del Mac OS X supportano task utente a 64-bit con spazio dindirizzo virtuale da 51-bit, che corrisponde 2 PiB (Pebibyte) di memoria virtuale. Per un tipico task il suo virtual address space grande nel senso che usa solo una parte della memoria virtuale disponibile: in ogni istante diversi subranges del spazio dindirizzo del task pu essere inutilizzato, portando alla tipica memoria virtuale sparsamente popolata. comunque possibile che programmi con scopi specifici abbiano richieste di memoria virtuale eccedenti quella che uno spazio a 32-bit possa fornire.

4.1.2 VM Maps
Ogni virtual address space di task descritto da una struttura dati VM map (struct vm_map [osfmk/vm/vm_map.h]). Il campo map della struttura task punta ad una struttura vm_map. La struttura task contiene anche informazioni utilizzate dai sottosistemi task working set detection e global shared memory, che analizzeremo in seguito. Una VM map una collezione di regioni di memoria dette VM entries; ognuna di queste un set di pagine virtualmente contigue (un range virtuale) caratterizzato dalle stesse propriet. La VM map punta ad una lista doubly linked ordinata di VM map entries. Ogni entry ha un indirizzo di inizio (start address) ed uno di fine (end address).

110

Il sistema operativo Mac OS X

Figura 4-2b

Dettagli implementativi nel Mac OS X dellarchitettura della Mach VM

4.1.3 VM Map Entries


Una VM map entry rappresentata da una struttura dati struct vm_map_entry [osfmk/vm/vm_map.h]. Poich ogni entry rappresenta un range di memoria virtuale attualmente mappata nel task, il kernel consulta la entry list svariate volte, particolarmente durante lallocazione di memoria. La funzione vm_map_lookup_entry()

[osfmk/vm/vm_map.c] utilizzata per cercare la VM map entry, se esistente, che

111

Il sistema operativo Mac OS X

contiene lindirizzo specificato in una data una VM map86. Il kernel ha la possibilit, se necessario, di dividere (split) o riunire (merge) le pagine delle VM entries.

4.1.4 VM Objects
La memoria di un task pu avere diverse sorgenti. Per esempio, una libreria condivisa mappata lo spazio dindirizzo del task rappresenta quella memoria la cui sorgente il file della libreria condivisa. Abbiamo detto in precedenza che tutte le pagine di una singola VM map entry ha la stessa sorgente: un VM object (struct vm_object

[osfmk/vm/vm_object.h]) rappresenta tale sorgente, con la entry che rappresenta il ponte tra un object e una map. Un VM object concettualmente un deposito contiguo di dati, alcuni dei quali possono essere tenuti (cached) nella memoria residente mentre il resto dei dati possono essere recuperati dalla corrispondente memoria secondaria (backing store). Lentit incaricata del trasferimento delle pagine tra memoria fisica e memoria secondaria chiamata pager, o in maniera pi appropriata memory manager87. Un VM object contiene una lista delle sue pagine residenti, insieme alle informazioni per recuperare le pagine non residenti. Notiamo che le pagine residenti non sono condivise tra i vari oggetti, una data pagina esiste in esattamente un VM object. La lista in questione risulta particolarmente utile allatto del rilascio di tutte le pagine associate ad un oggetto quando questo viene distrutto. Una struttura dati vm_object contiene inoltre propriet come le seguenti: La dimensione delloggetto Il numero di riferimenti alloggetto Loggetto di memoria associato (pager) e loffset nel pager La porta di controllo delloggetto di memoria Gli eventuali puntatori agli oggetti shadow e copy
86

Lalgoritmo di ricerca lineare e pu iniziare o dalla testa della lista o da un punto specificato da un hint memorizzato durante un lookup precedente completato con successo. Questo hint conservato allinterno della VM map, insieme ad un altro hint usato per determinare un indirizzo di spazio libero velocemente. Se lindirizzo cercato non dovesse essere trovato, la funzione restituisce lentry immediatamente precedente. 87 Anche se tendiamo ad usare i termini pager e memory manager come sinonimi, va ricordato che il secondo (oltre al paging) si occupa anche di mantenere la consistenza tra il contenuto della memoria secondaria e quello delle pagine residenti che corrispondono ad un oggetto di memoria virtuale.

112

Il sistema operativo Mac OS X

La strategia di copia che il kernel dovrebbe utilizzare durante la copia dei dati del VM object Un flag indicante se loggetto interno (e cos creato dal kernel e gestito dal pager di default) Un flag indicante se loggetto temporaneo (e cos non modificabile esternamente da un memory manager; le modifiche in memoria di un tale oggetto non sono riflesse indietro al memory manager) Un flag indicante se loggetto pu persistere (in altre parole, se il kernel pu mantenere in cache i dati delloggetto, insieme ai diritti alloggetto di memoria associato) dopo che tutte le referenze di mappa dindirizzo alloggetto sono deallocato Come si pu vedere nella figura 4-2b, un oggetto di memoria implementato come una porta Mach della quale un pager detiene i diritti di ricezione. Quando il kernel ha bisogno che una pagina di un VM object sia passata dalla memoria secondaria a quella fisica, esso comunica con il pager associato attraverso la porta delloggetto di memoria. La porta di controllo delloggetto di memoria, di cui il kernel detiene i receive rights, utilizzata per ricevere i dati dal pager. Con questa conoscenza, possiamo ridescrivere la figura completa come segue: una VM map mappa ogni regione valida di uno spazio dindirizzo virtuale di un task in un offset allinterno di qualche oggetto di memoria. Per ogni oggetto di memoria usato in una VM map, il sottosistema della memoria virtuale mantiene un VM object. Un backing store un luogo dove sono conservati i dati, quando non sono residenti. Pu anche esserne la sorgente, ma non necessariamente. Nel caso di un file mappato in memoria, il backing store il file stesso. Quando il kernel deve rimuovere dalla memoria fisica una pagina sostenuta da un file, pu semplicemente scartare la pagina a meno che questa sia stata modificata mentre era residente: in questo caso la modifica pu essere impegnata nel backing store. La memoria allocata dinamicamente anonima in quanto non ha una named source con cui iniziare. Quando una pagina anonima utilizzata per la prima volta, il Mach fornisce 113

Il sistema operativo Mac OS X

una pagina fisica riempita di zeri (da questo viene il nome alternativo di zero-filled memory). In particolare, non c backing store associato inizialmente alla memoria anonima. Quando il kernel deve rimuovere una tale pagina, utilizza lo spazio di scambio come backing store. La memoria anonima non persiste attraverso i riavvii di sistema. I corrispondenti VM objects, creati dal kernel, sono anche chiamati oggetti interni. Quando alloca memoria anonima, il kernel controlla se unesistente VM entry pu essere estesa in modo da non dover creare una nuova entry ed un nuovo oggetto.

4.1.5 Pagers
Un pager gestisce, oltre alle pagine, anche i memory objects; di questi possiede la porta che usata dai clients del pager come interfaccia. Un oggetto di memoria pu essere visto come un incapsulamento object-oriented di memoria che implementa i metodi come lettura e scrittura. Un memory object rappresenta lo stato non-residente del sottostante backing storage, dove lo stato non-residente essenzialmente la memoria secondaria che il kernel mette in cache nella memoria primaria (fisica). Come abbiamo visto nella figura 4-1, il Mac OS X prevede tre paginatori in-kernel: Il default pager, che trasferisce i dati tra la memoria fisica e lo spazio di swap Il vnode pager, che trasferisce i dati tra la memoria fisica ed i files Il device pager, che usato per il mapping della memoria special-purpose Un paginatore pu occuparsi di qualsiasi numero di memory objects, ognuno dei quali rappresenta un range di pagine che il pager gestisce. Laddress space di un task pu avere qualsiasi numero qualsiasi numero di pagers che gestiscono sue parti separate. Un paginatore non direttamente coinvolto nelle policies di paginazione, non pu modificare lalgoritmo di sostituzione delle pagine kernel (al di l della modifica degli attributi del memory object). Il termine external memory manager (o external pager) pu essere interpretato in due modi. Nel primo caso, si riferisce a qualsiasi pager che non sia quello di default, nello specifico uno che gestisce la memoria la cui sorgente esterna al kernel. La memoria anonima corrisponde a oggetti interni, mentre files memory-mapped corrispondono ad 114

Il sistema operativo Mac OS X

oggetti esterni. In questo senso, il vnode pager pu essere definito un paginatore esterno. Questa laccezione a cui noi faremo riferimento. Laltra interpretazione si riferisce a dove sono implementati i pager. Se definiamo un pager in-kernel come un paginatore interno, allora un paginatore esterno sar implementato come un task utente specializzato. Considerato che un memory object rappresenta una sorgente di dati, il pager del memory object il provider ed il manager di questi dati. Quando una porzione di memoria rappresentata da un oggetto di memoria utilizzata da un task cliente, ci sono tre parti primarie coinvolte: il pager, il kernel ed il task cliente. Un task utilizza vm_map(), direttamente o indirettamente, per mappare una parte (o tutta) la memoria dei memory objects nelladdress space. Per fare questo, il chiamante deve avere i send rights sulla porta Mach che rappresente loggetto di memoria. Il pager possiede tale porta e pu quindi fornire i diritti ad altri. Un paginatore pu pubblicizzare una porta di servizio alla quale i clients possono mandare messaggi per ottenere oggetti di memoria. I tre paginatori del Mac OS X hanno porte definite direttamente nel codice (hardcoded). Quando necessario comunicare con un pager, si determina quale chiamare in base al valore del memory object passato, dato che il valore deve corrispondere ad uno dei pagers conosciuti. Loperazione di un pager nel kernel del Mac OS X utilizza una combinazione di: un subset dellinterfaccia del pager Mach originale, le UPLs (universal page lists) e lUBC (unified buffer cache). Notiamo che il kernel fornisce implicitamente loggetto di memoria per un pager interno, il task chiamante non deve acquisire i send rights direttamente. Il paging nel Mach pu essere sommariamente descritto come segue: un task cliente ottiene la porta di un oggetto di memoria direttamente o indirettamente da un gestore di memoria. Richiede il kernel chiamando vm_map() per mappare il memory object nel suo virtual address space. In seguito, quando il task cerca di accedere (in lettura o scrittura) per la prima volta ad una pagina nella memoria appena mappata, si verifica un errore di pagenot-resident. Nella gestione del page fault, il kernel comunica con il gestore di memoria attraverso un messaggio di richiesta dei dati mancanti e questultimo li va a prendere dal backing store che sta gestendo. Gli altri tipi di page faults sono gestiti appropriatamente 115

Il sistema operativo Mac OS X

con il kernel che chiama il memory manager e questo che gli risponde in modo asincrono. Questo il modo in cui il kernel usa la memoria fisica come una cache per i contenuti dei vari oggetti di memoria. Quando il kernel deve rimuovere delle pagine residenti, pu (secondo la natura del mapping) spedire le pagine sporche (ossia quelle modificate mentre residenti) al memory manager. Quando un task cliente fatto utilizzando un range di memoria mappato, esso pu chiamare vm_deallocate() per rimuovere il range. Quando tutte le mappature di un oggetto di memoria sono andate, loggetto terminato.

Figura 4-3

Linterfaccia del pager Mach nel Mac OS X

116

Il sistema operativo Mac OS X

La figura 4-3 mostra diversi messaggi88 che fanno parte del dialogo tra un gestore della memoria ed il kernel. Quando un oggetto di memoria mappato per la prima volta, il kernel deve notificare al pager che sta utilizzando loggetto. Questa notifica avviene mediante la chiamata a
kern_return_t memory_object_init(memory_object_t memory_object, memory_object_control_t memory_control, memory_object_cluster_size_t memory_object_page_size);

Largomento memory_object la porta che rappresenta loggetto in questione. Largomento memory_control la porta, di cui il kernel detiene i send rights, che il pager usa per mandare messaggi al kernel (per questo detta anche pager reply port). Consideriamo lesempio specifico del paginatore vnode del Mac OS X. Quando la routine memory_object_init() determina (usando la porta hardcoded del vnode pager) che loggetto di memoria passatogli corrisponde al vnode pager, richiama la funzione vnode_pager_init() [osfmk/vm/bsd_vm.c]. Questa non impianta il vnode pager, che gi attivo dal momento della creazione del vnode, ma chiama a sua volta la
kern_return_t memory_object_change_atributes(memory_object_control_t memory_object_flavor_t memory_object_info_t mach_msg_type_number_t control, flavor, attributes, count);

Il kernel conserva gli attributi degli oggetti mappati, in particolare cacheability e copy strategy. Lattributo cacheability specifica se il kernel pu mettere in cache loggetto (a patto che ci sia abbastanza memoria) anche dopo che tutti gli utenti delloggetto sono andati. Se un oggetto marcato come non cacheable, non sar conservato quando non in uso: il kernel ritorner le pagine sporche al pager, richieder le pagine pulite e informer il pager che loggetto non pi in uso. Lattributo copy strategy specifica in che modo le pagine delloggetto di memoria sono copiate. Alcuni strategie di copia valide sono: MEMORY_OBJECT_COPY_NONE Le pagine del pager possono essere copiate immediatamente, senza ottimimizzazione COW dal kernel. MEMORY_OBJECT_COPY_CALL Se il kernel deve copiare una qualsiasi pagina del pager, deve chiamare il pager. MEMORY_OBJECT_COPY_DELAY Il pager promette di non modificare
88

Nel Mac OS X, i messaggi sono semplicemente delle chiamate di funzione, non dei messaggi IPC.

117

Il sistema operativo Mac OS X

esternamente alcun dato cached dal kernel, in modo che questo sia libero di utilizzare una strategia copy-on-write ottimizzata (asymmetric COW). MEMORY_OBJECT_COPY_TEMPORARY Questa strategia funziona come la precedente, con laggiunta che il pager non interessato a vedere alcun cambiamento dal kernel. MEMORY_OBJECT_COPY_SIMMETRIC Questa strategia funziona come la precedente, con laggiunta che il memory object non multi-mappato (symmetric COW). Gli attributi possono essere recuperati attraverso la routine
kern_return_t memory_object_get_attributes(memory_object_control_t control, memory_object_flavor_t flavor, memory_object_info_t attributes, mach_msg_type_number_t *count);

Quando un task cliente accede ad una pagina di un memory object che non residente, si verifica un errore di pagina. Il kernel localizza il VM object appropriato e richiama la funzione memory_object_data_request(). Il pager fornisce tipicamente i dati prelevandoli dal backing store.
kern_return_t memory_object_data_request(memory_object_t memory_object_offset_t memory_object_cluster_size_t vm_prot_t memory_object, offset, length, desired_access);

Nel Mach, il pager risponde alla richiesta dati mandando un risposta asincrona al kernel89. Nel Mac OS X, la routine memory_object_data_request() chiama

esplicitamente uno dei tre paginatori. Nel caso del vnode pager, il kernel chiama vnode_pager_data_request() [osfmk/vm/bsd_vm.c], che invoca a sua volta vnode_page_cluster_read() [osfmk/vm/bsd_vm.c]. Questultima causa la paginazione dei dati attraverso la chiamata alla routine vnode_pagein() [bsd/vm/vnode_pager.c], che infine chiama loperazione di page-in specifica del
89

Il pager spedisce il messaggio memory_object_data_supply o memory_object_data_provided (a seconda della versione del Mach) alla porta di controllo del memory object. Il pager pu anche rispondere con un messaggio memory_object_data_unavaible o memory_object_data_error. Il primo indica che, nonostante il range allinterno del memory object sia valido, non ci sono ancora dati. Questo messaggio notifica al kernel di ritornare pagine zero-filled per il range. Anche se il pager stesso potrebbe creare tali pagine (mediante memory_object_data_supply), il codice del kernel probabilmente ottimizzato. Se un errore di paging (ad esempio un settore disco difettoso) causa un mancato recupero dei dati da parte del pager, questo risponde con un messaggio memory_object_data_error.

118

Il sistema operativo Mac OS X

file system. Quando il kernel ha bisogno di reclamare memoria e ci sono pagine sporche per un oggetto di memoria, il kernel pu mandare tali pagine al pager attraverso memory_object_data_return. Nel Mac OS X questo compito svolto dal daemon di page-out del kernel.
kern_return_t memory_object_data_return(memory_object_t memory_object_offset_t vm_size_t memory_object_offset_t int boolean_t boolean_t int memory_object, offset, size, *resid_offset, *io_error, dirty, kernel_copy, upl_flags);

Non c una risposta esplicita a questo messaggio, il pager semplicemente dealloca le pagine dal suo address space in modo che il kernel possa utilizzare la memoria fisica per altri scopi. Nel Mac OS X, per il vnode pager, la memory_object_data_return chiama vnode_pager_data_return() [osfmk/vm/bsd_vm.c], che a sua volta chiama vnode_page_cluster_write() [osfmk/vm/bsd_vm.c]. Questultima causa il page-out dei dati attraverso la chiamata a vnode_pageout()

[bsd/vm/vnode_pager.c], che infine chiama loperazione di page-out specifica del file system. Il paginatore usa memory_object_lock_request() per controllare luso dei dati (residenti) associati con loggetto di memoria. I dati sono specificati come il numero di bytes (argomento size) allindirizzo relativo (argomento offset) allinterno del memory object. Tale funzione, dopo aver verificato la coerenza dei suoi parametri, chiama vm_object_update() [osfmk/vm/memory_object.c] sul VM object associato.
kern_return_t memory_object_lock_request(memory_object_control_t control, memory_object_offset_t offset, memory_object_size_t size, memory_object_offset_t *resid_offset, int *io_errno, memory_object_return_t should_return, int flags, vm_prot_t prot);

Largomento should_return utilizzato per specificare i dati da ritornare, alloccorrenza, al gestore di memoria e pu assumere i seguenti valori: MEMORY_OBJECT_RETURN_NONE non ritorna nessuna pagina 119

Il sistema operativo Mac OS X

MEMORY_OBJECT_RETURN_DIRTY ritorna solo le pagine sporche MEMORY_OBJECT_RETURN_ALL ritorna sia le pagine sporche sia quelle preziose MEMORY_OBJECT_RETURN_EVERYTHING ritorna tutte le pagine residenti Largomento flags specifica leventuale operazione da eseguire sui dati. Le operazioni valide sono MEMORY_OBJECT_DATA_SYNC, o anche MEMORY_OBJECT_COPY_SYNC,

MEMORY_OBJECT_IO_SYNC

MEMORY_OBJECT_DATA_NO_CHANGE,

MEMORY_OBJECT_DATA_FLUSH e MEMORY_OBJECT_DATA_PURGE. Notiamo che la combinazione di should_return e flags determina il destino dei dati: per esempio se should_return MEMORY_OBJECT_RETURN_NONE e flags

MEMORY_OBJECT_DATA_FLUSH, allora le pagine residenti saranno scartate. Largomento prot utilizzato per restringere laccesso alla memoria specificata. Il suo valore specifica laccesso che deve essere disabilitato; il valore speciale

VM_PROT_NO_CHANGE indica che non si desidera nessuna modifica della protezione. Il kernel utilizza memory_object_terminate() per notificare al pager che loggetto non pi in uso. Il pager utilizza memory_object_destroy() per notificare al kernel di chiudere un oggetto di memoria anche se ci sono ancora riferimenti al VM object associato. Questo comporta la chiamata a vm_object_destroy()

[osfmk/vm/vm_object.c]. nel Mac OS X, tale funzione chiamata a causa di vclean() [bsd/vfs/vfs_subr.c] che ripulisce un vnode quando richiesto.
kern_return_t memory_object_terminate(memory_object_t memory_object); kern_return_t memory_object_destroy(memory_object_control_t control, kern_return_t reason);

4.1.6 Copy-on-Write
La copy-on-write (COW) una tecnica dottimizzazione della copia di pagine fisiche. Consiste nel mettere in condivisione le pagine fisiche tra le due parti coinvolte nella copia fino al momento in cui una di queste non cerca di scrivere su una di tali pagine. A questo punto viene creata una copia delle sole pagine modificate che viene assegnata al

120

Il sistema operativo Mac OS X

richiedente la scrittura. Riesamindo le figure 4-2, possiamo notare che ci sono due VM entries che puntano allo stesso VM object. Nella figura 4-4, invece, possiamo vedere lo schema di come il Mach implementa il symmetric COW90.

Figura 4-4

Copy-on-Write simmetrico con luso degli oggetti shadow

In unoperazione di COW simmetrico sia la sorgente sia la destinazione hanno il bit needs_copy settato ed entrambe le entries puntano allo stesso oggetto VM che incrementa il proprio ref_count. In questo modo entrami i task accedono alle stesse

90

Lo schema simmetrico, poich il suo comportamento non dipende da quale task, sorgente o destinazione, modifica una pagina condivisa.

121

Il sistema operativo Mac OS X

pagine fisiche durante le operazioni di lettura. Visto che tutte le pagine del VM object sono protette dalla scrittura, quando uno dei task prova a scrivere su una di queste avviene un errore di protezione. Il kernel non modifica il VM object originale, ma ne crea uno nuovo (uno shadow object contenente una copia delle faulting pages) dandolo al task che ha modificato le pagine. Le altre pagine, comprese le versioni originali delle pagine modificate, rimangono nel VM object originale, in cui il bit needs_copy rimane settato. Nella figura 4-4, quando il task destinazione accede ad una pagina (precendetemente condivisa mediante COW) che stata gi modificata, il kernel trover tale pagina nelloggetto shadow. Per trovare le altre pagine il kernel dovr seguire il link alloggetto originale dove sono memorizzate. Lutilizzo ripetuto delle operazioni COW possono portare alla copia shadow di un oggetto shadow, creando cos una shadow chain. importante notare che quando si crea uno shadow object durante una COW simmetrica, nessun gestore di memoria coinvolto. Il kernel utilizza lo spazio di swap come backing store, ed il paginatore di default come memory manager, quando ha bisogno di effettuare il page-out di memoria anonima. Rimane comunque un problema quando un gestore di memoria esterno, come ad esempio il vnode pager nel caso di un file memory-mapped, restituisce il VM object originale. Il kernel non pu modificare il VM object, poich questo disconnetterebbe il file mapping. Siccome la modifica in una COW simmetrica visibile solo dagli oggetti shadow, loggetto originale (che collegato al memory manager) non vedr mai tali modifiche. Il Mach risolve tale problema mediante luso dellalgoritmo asymmetric copy-on-write, in cui la sorgente mantiene il VM object originale ed il kernel crea un nuovo oggetto per la destinazione. Lalgoritmo asimmetrico (vedi figura 4-5) funziona nel seguente modo: Quando si esegue unoperazione di copia, crea un nuovo oggetto (copy object) per la destinazione. Fa puntare il campo shadow del copy object alloggetto originale. Fa puntare il campo copy delloggetto originale al copy object. 122

Il sistema operativo Mac OS X

Marca il copy object come copy-on-write (loggetto originale non lo ). Ogni volta che una pagina sta per essere modificata nel source mapping, la copia prima in una nuova pagina e poi la inserisce nel copy object.

Figura 4-5

Copy-on-Write asimmetrico con luso degli oggetti copy

4.1.7 The Physical Map (Pmap)


Una VM map punta anche ad una struttura dati pmap (struct pmap [osfmk/ppc/pmap.h]), che descrive la traduzione degli indirizzi da virtuali a fisici definita per lhardware. Lo strato pmap del Mach incapsula il codice VM dipendente dalla macchina (in particolare quello per la gestione dellMMU e delle caches) ed esporta le funzioni generiche per lutilizzo dello strato indipendente dalla macchina. Il kernel del Mac OS X contiene altro codice (osfmk/ppc/mappings.c) oltre al modulo pmap per il mappings virtual-to-physical nel PowerPC. Tale codice funge da ponte tra lo strato pmap e lhardware sottostante, che contrario allincapsulazione tradizionale del Mach. Per comprendere quale ruolo gioca lo strato pmap nel sistema, analizziamo qualche esempio di funzioni dellinterfaccia pmap. La funzione pmap_map(), richiamata durante la fase di bootstrapping, mappa il virtual address range che parte da va nel physical address range spa attraverso epa, con il valore di protezione prot indipendente dalla 123

Il sistema operativo Mac OS X

macchina.
vm_offset_t pmap_map(vm_offset_t va, vm_offset_t spa, vm_offset_t epa, vm_prot_t prot);

La funzione pmap_create() crea e restituisce una mappa fisica, recuperandola dalla lista delle pmaps libere o allocandola da zero. Tale funzione chiamata durante la fase di creazione del task, indipendentemente dal fatto che il figlio stia ereditando la memoria del padre o meno. Se non c eredit di memoria, viene creato un nuovo spazio dindirizzo per il task figlio; altrimenti ogni singola VM entry nel task padre esaminata per vedere se deve essere condivisa, copiata o non ereditata affatto. Oltre alla lista delle pmap libere (free_pmap_list), il kernel mantiene anche le seguenti strutture dati: Una lista delle pmaps in uso (ancorata da kernel_pmap). Una lista degli indirizzi fisici delle pmaps in uso (ancorata da

kernel_pmap_phys). Un puntatore ad un cursore pmap (cursor_pmap), che il kernel usa come punto di partenza durante la ricerca di pmaps libere.
pmap_t pmap_create(vm_map_size_t size);

La funzione pmap_destroy(), chiamata quando viene distrutta una VM map, rimuove un riferimento alla pmap indicata. Quando il conteggio dei riferimenti arriva a zero, la pmap aggiunta alla lista delle pmaps libere. La funzione pmap_reference(), invece, incrementa di uno il conteggio dei riferimenti della pmap indicata.
void pmap_destroy(pmap_t pmap); void pmap_reference(pmap_t pmap);

La funzione pmap_enter() crea una traslazione per lindirizzo virtuale va alla pagina fisica numero pa nella pmap specificata con la protezione prot. Largomento flags pu essere usato per specificare attributi particolari per il mapping.
void pmap_enter(pmap_t vm_map_offset_t ppnum_t vm_prot_t unsigned int __unused boolean_t pmap, va, pa, prot, flags, wired);

La funzione pmap_remove() demappa tutti gli indirizzi virtuali nel virtual address range determinato dalla pmap specificata e lintervallo [sva, eva).
void pmap_remove(pmap_t pmap, addr64_t sva, addr64_t eva);

124

Il sistema operativo Mac OS X

La funzione pmap_page_protect() riduce i permessi di tutte le mappature per una data pagina. In particolare, se prot VM_PROT_NONE, questa funzione rimuove tutte le mappature alla pagina.
void pmap_page_protect(ppnum_t pa, vm_prot_t prot);

La funzione pmap_protect() cambia la protezione su tutti gli indirizzi virtuali del virtual address range determinato dalla pmap specificata e lintervallo [sva, eva). Se prot VM_PROT_NONE, la funzione pmap_remove() chiamata sul virtual address range.
void pmap_protect(pmap_t vm_map_offset_t vm_map_offset_t vm_prot_t pmap, sva, eva, prot);

La funzione pmap_switch() commuta ad una nuova pmap, ossia cambia ad un nuovo spazio dindirizzo. chiamata durante il cambio di contesto di thread, a meno che i due threads non appartengano allo stesso task e quindi condividano lo stesso spazio dindirizzo.
void pmap_switch(pmap_t pmap);

La funzione pmap_clear_modify() azzera il dirty bit per una pagina indipendente dalla macchina che parte dallindirizzo fisico indicato. La funzione

pmap_is_modified() controlla se la pagina fisica specificata stata modificata dallultima chiamata a pmap_clear_modify(). Le funzioni

pmap_clear_reference() e pmap_is referenced() funzionano in modo simile sul referenced bit.


void boolean_t void boolean_t pmap_clear_modifiy(ppnum_t pa); pmap_is_modified(register ppnum_t pa); pmap_clear_reference(ppnum_t pa); pmap_is_referenced(ppnum_t pa);

4.2 La memoria residente


Il Mach divide uno spazio dindirizzi in pagine, con la dimensione della pagina generalmente pari alla dimensione della pagina hardware nativa91. Il progetto del Mach

91

possibile che lhardware nativo supporti diverse dimensioni di pagina: ad esempio, il PowerPC 970FX supporta pagine da 4KB e 16MB. La variabile kernel vm_page_shift contiene il numero di bits da shiftare a destra per convertire un byte address in un numero di pagina. La variabile di librearia vm_page_size contiene la dimensione di pagina usata dal Mach.

125

Il sistema operativo Mac OS X

permette comunque lutilizzo di una pagina virtuale di dimensioni maggiori, utilizzando pi pagine hardware fisicamente contigue. Visto che la memoria visibile al programmatore indirizzabile per byte, le primitive Mach per la memoria virtuale operano solo su pagine. In effetti il Mach allinea internamente gli offset di memoria nelle pagine ed arrotonda la dimensione dei memory range al pi vicino limite di pagina. Inoltre lapplicazione da parte del kernl della protezione della memoria a livello di pagina. Le porzioni valide di un address space corrispondono a pagine virtuali valide. In funzione dello schema dutilizzo della memoria utilizzato nel programma (insieme con altri fattori), la memoria virtuale pu essere cached nella memoria fisica attraverso le pagine residenti92.

Figura 4-6

La struttura di una pagina residente

Una struttura di pagina residente (struct vm_page [osfmk/vm/vm_page.h]) corrisponde ad una pagina di memoria fisica, e viceversa. La struttura contiene un puntatore al VM object associato /e loffset in esso) insieme alle informazioni indicanti se la pagina riferita, se stata modificata, se criptata e cos via. La figura 4-6 mostra una visione dinsieme di come la struttura vm_page connessa alle altre strutture dati. Notiamo che la struttura risiede in svariate liste contemporaneamente. Il kernel mantiene una tabella hash delle pagine residenti, detta VP table (virtual-to92

Il trasferimento della memoria virtuale pu essere completo, parziale o nullo.

126

Il sistema operativo Mac OS X

physical), utilizzata per la ricerca di una pagina residente data la coppia {VM object, offset}. Riportiamo di seguito qualcuna delle funzioni usate per manipolare la VP table.
vm_page_t vm_page_lookup(vm_object_t object, vm_object_offset_t offset); void vm_page_insert(vm_page_t mem, vm_object_t object, vm_object_offset_t offset); void vm_page_remove(vm_page_t mem);

Notiamo che la funzione di ricerca utilizza un hint93 memorizzato nel campo memq_hint del VM object. Prima di esaminare la tabella di hash per la data coppia oggetto/offset, la funzione vm_page_lookup() [osfmk/vm/vm_resident.c] esamina la pagina residente specificata dallhint e, se necessario, anche la precedente e la successiva. Il kernel mantiene un contatore che incrementato per ogni ricerca (basata sullhint) che abbia esito positivo. Una pagina residente paginabile risiede in una delle seguenti tre code di paging mediante il campo pageq della struttura vm_page. La free queue (vm_page_queue_free) contiene le pagine libere

immediatamente disponibili allallocazione. Una pagina di tale coda non ha mappature e non contiene dati utili. Quando il kernel ha bisogno di pagine vuote, ad esempio durante un page fault o lallocazione di memoria del kernel, le prende da questa coda. La inactive queue (vm_page_queue_inactive) contiene le pagine che non sono riferite in nessuna pmap ma hanno ancora una mappatura di pagina oggetto/offset. Una pagina di tale coda pu essere sporca. Quando il kernel deve liberare della memoria, rimuove delle pagine dal questa lista. Esiste una coda della memoria inattiva separata per la memoria anonima (vm_page_queue_zf), che permette al daemon di page-out di assegnare una maggiore affinit alle pagine di memoria anonima. Si tratta di una lista FIFO (first-in first-out). La active queue (vm_page_queue_active) contiene le pagine che sono riferite in almeno una pmap. Anche questa una lista FIFO ed ha un ordinamento simile allLRU. Poich la memoria fisica una risorsa limitata, il kernel deve continuamente decidere
93

Esiste anche una versione della funzione lookup che non utilizza lhint del VM object: tale versione utilizzata dal sottosistema task-working-set-detection.

127

Il sistema operativo Mac OS X

quali pagine devono rimanere residenti e quali devono essere rimosse. La politica di rimpiazzo utilizzata chiamata FIFO with Second Chance, che approssima il comportamento dellLRU. Un obiettivo specifico del page replacement di mantenere lequilibrio tra le liste active e inactive. La lista active dovrebbe idealmente contenere solo i working set di tutti i programmi. Il kernel gestisce le tre code fondamentali summenzionate con una serie di parametri di page-out che specificano i confini di paging ed altri vincoli. La gestione della coda di pagine include le seguenti operazioni specifiche: Spostare le pagine dallinizio dellactive queue allinactive queue. Pulire le pagine sporche dellinactive queue. Spostare le pagine pulite dallinactive queue alla free queue. Poich lactive queue gestita in modalit FIFO, la pagina pi vecchia la prima ad essere rimossa. Se una pagina inattiva riferita viene riportata nella coda attiva, perci le pagine nella coda inattiva sono idonee ad una seconda opportunit di essere riferite94. La pulitura delle pagine sporche effettuata dal deamon di page-out, che consiste dei seguenti kernel threads: vm_pageout_iothread_internal() [osfmk/vm/vm_pageout.c] vm_pageout_iothread_external() [osfmk/vm/vm_pageout.c] vm_pageout_garbage_collect() [osfmk/vm/vm_pageout.c] Entrambi i threads internal ed external richiamano la stessa continuazione (vm_pageout_iothread_continue() [osfmk/vm/vm_pageout.c]), ma

usano differenti code (laundry) di page-out: vm_pageout_queue_internal e vm_pageout_queue_external rispettivamente. La funzione di continuazione compie il lavaggio della laundry queue specificata, richiamando se necessario la routine memory_object_data_return() per mandare i dati allappropriato pager. Il thread vm_pageout_garbage_collect() libera i kernel stacks in eccesso e possibilmente attiva la garbage collection nel Mach. Il daemon di page-out controlla inoltre il rateo al

94

Se una pagina riferita abbastanza frequentemente, gli sar impedito lo spostamento nella coda libera in modo da non doverla reclamare.

128

Il sistema operativo Mac OS X

quale

le

pagine

sono

spedite

ai

paginatori;

in

particolare,

la

costante

VM_PAGE_LAUNDRY_MAX (16) limita il numero massimo di pag-out in sospeso per il default pager. Quando il laundry count supera tale limite, il daemon di page-out si sospende per permettere al default pager di raggiungerlo.

4.2.1 Page Faults


Un page fault il risultato del tentativo di un task di accedere a dati contenuti in una pagina che necessita lintervento del kernel prima di poter essere utilizzata dal task. Ci possono essere svariate cause per una page fault, tra le quali: invalid access lindirizzo non mappato nelladdress space del task. Questo comporta una EXC_BAD_ACCES eccezione Mach con il codice deccezione specifico KERN_INVALID_ADDRESS. Tale exception normalmente tradotta dal kernel nel segnale SIGSEGV. nonresident page la pagina virtuale non inserita nella pmap del task. Se la pagina non effettivamente nella memoria fisica ed i dati devono essere letti (paged in) dalla memoria secondaria, si dice che si verificato un hard page fault. Il kernel contatta il pager che gestisce la pagina richiesta che a sua volta accede al backing store associato. Se, incede, i dati sono presenti nella cache si ha un soft page fault. In questo caso, la pagina deve trovarsi ancora in memoria e le appropriate traduzioni di pagina devono ancora essere allestite. protection violation la pagina ha diritti daccesso oltre la possibilit del task. Se la violazione della protezione correggibile, il kernel gestir lerrore in modo trasparente; altrimenti, leccezione sar comunicata al task (normalmente mediante un segnale SIGBUS). Un esempio di violazione correggibile quando un task prova ad accedere in scrittura ad una pagina marcata read-only in seguito ad una operazione copy-on-write. Il gestore di page-fault implementato in osfmk/vm/vm_fault.c, con vm_fault() come punto dingresso principale. Andiamo ad esaminare i passi che compongono la gestione di un tipico page-fault. 129

Il sistema operativo Mac OS X

Un page fault sul PowerPC corrisponde ad una data access exception. Per gestire leccezione, il kernel chiama trap() [osfmk/ppc/trap.c] con il codice dinterruzione impostato su T_DATA_ACCESS; in funzione delle condizioni in cui si verificata leccezione95, la trap() pu affrontarla in diversi modi. In generale per questa chiamer vm_fault() per risolvere il page-fault: questultima prima di tutto cerca la data VM map attraverso il dato indirizzo virtuale. Se la ricerca ha successo, cerca un VM object, loffset nelloggetto e il valore di protezione associato. In seguito di deve assicurare che la pagina sia residente: o la pagina si trova nella memoria fisica mediante la ricerca nella VP table, oppure una nuova pagina residente allocata per la data coppia oggetto/offset e inserita nella tabella (in questo caso la pagina deve anche essere riempita di dati). Se il VM object ha un paginatore, il kernel chiamer la funzione memory_object_data_request() per richiedere al pager di recuperare i dati; alternativamente, se il VM object ha una shadow, il kernel attraversa la shadow chain alla ricerca della pagina. Le nuove pagine corrispondenti ai VM objects interni (memoria anonima) saranno zero-filled. Oltretutto, se il VM object ha un copy object associato e la pagina scritta, sar inserita nel copy object se non gi fatto. Infine, il gestore del pagefault inserir la pagina nella pmap del task attraverso la chiamata a pmap_enter(). Dopo questo, la pagina finalmente disponibile al task.

4.3 Universal Page Lists (UPLs)


Il kernel fornisce unastrazione chiamata universal page list (UPL) che descrive un set di pagine fisiche associate ad un range di indirizzi di un VM object. In particolare, una UPL fornisce unistantanea di varie propriet delle sue pagine, come ad esempio se non mappate, sporche, criptate , occupate o corrispondenti a memoria di I/O. Una UPL creata internamente da upl_create() [osfmk/vm/vm_pageout.c], che alloca ed inizializza la struttura struct upl [osfmk/vm/vm_pageout.h]. Se la UPL creata con il control flag UPL_SET_INTERNAL, tutte le informazioni sono
95

Ad esempio se si verificata nel kernel o nello spazio utente, se il debugger del kernel era attivo o meno, se la struttura thread del faulting thread contiene un puntatore valido ad un funzione di recupero e cos via.

130

Il sistema operativo Mac OS X

contenute in un singolo oggetto di memoria, permettendo un trasporto conveniente dellUPL nel kernel. Nel caso di un UPL interno, la funzione upl_create() alloca ulteriore memoria per memorizzare delle strutture upl_page_info

[osfmk/mach/memory_object_types.h], una per ogni pagina dellUPL. Il numero massimo delle pagine che possono essere gestite da un UPL

MAX_UPL_TRANSFER (256). I clients principali dellAPI UPL include i pagers, lo strato del file system e lUBC (unified buffer cache). Questi clients non chiamano direttamente upl_create() quando devono creare una UPL da un VM object, ma utilizzano funzioni ad alto livello come vm_object_upl_request(), vm_object_iopl_request() e

vm_map_get_upl(). Lultima particolarmente utile quando non si ha il VM object in questione, poich ricerca loggetto sottostante dato un range di indirizzi in una VM map. Una volta modificata una UPL, le modifiche possono essere confermate o scartate mediante le funzioni upl_commit() e upl_abort(), rispettivamente. Queste funzioni operano su tutta la struttura UPL, per agire su una parte specifica esistono le funzioni upl_commit_range() e upl_abort_range(). Le funzioni UBC ubc_upl_commit_range() e ubc_upl_abort_range() sono delle estensioni delle precedenti, in quanto deallocano lUPL dellassociato VM object se non ha pi pagine residenti dopo la conferma o lo scarto delle modifiche, rispettivamente.

4.4 Unified Buffer Cache (UBC)


Storicamente, lo UNIX alloca una porzione di memoria fisica per essere utilizzata come buffer cache, con lobiettivo di migliorare le prestazioni attraverso il caching di blocchi disco in memoria, evitando quindi di dover accedere al disco durante la lettura o scrittura dei dati. Prima dellavvento dellUBC, un buffer cached era identificato mediante un numero di periferica ed un numero di blocco. I sistemi operativi moderni, compreso il Mac OS X, utilizza un approccio unificato in cui il contenuto in memoria dei files risiede nello stesso namespace come memoria regolare. 131

Il sistema operativo Mac OS X

LUBC esiste concettualmente nella porzione BSD del kernel. Ogni vnode corrispondente ad un file regolare contiene un riferimento ad una struttura ubc_info, che assume il ruolo di ponte tra i vnodes ed i rispettivi VM objects. Notiamo che linformazione UBC non valida per i vnodes di sistema (marcati VSYSTEM), neanche se il vnode al contrario regolare. Quando un vnode creato, a seguito di una chiama di sistema open(), una struttura ubc_info viene allocata ed inizializzata.
// bsd/sys/ubc_internal.h struct ubc_info { memory_object_t memory_object_control_t long struct vnode struct ucred off_t struct cl_readahead struct cl_writebehind }; ui_pager; ui_control; ui_flags; *ui_vnode; *ui_cred; ui_size; *cl_rahead; *cl_wbehind;

// for example, the vnode pager // pager control port // // // // // our vnode credentials for NFS paging file size for vnode cluster read-ahead context cluster write-behind context

// bsd/sys/vnode_internal.h struct vnode { ... union { struct mount *vu_mountedhere; struct socket *vu_socket; struct specinfo *vu_specinfo; struct fifoinfo *vu_fifoinfo; struct ubc_info *vu_ubcinfo; } v_un; ... };

// // // // //

pointer to mounted vfs (VDIR) Unix IPC (VSOCK) device (VCHR, VBLK) fifo (VFIFO) regular file (VREG)

Il lavoro dellUBC di effettuare il cahing nella memoria fisica con un approccio avido: cerca di consumare tutta la memoria fisica disponibile. Questa particolarmente rilevante per i processi a 32-bit su macchine a 64-bit con oltre 4GB di memoria fisica. Anche se nessun singolo processo a 32.bit pu indirizzare pi di 4GB di memoria virtuale, la dimensione maggiore della memoria fisica avvantaggia tutti i processi cos come una maggiore buffer cache. LUBC esporta diverse routines ad uso dei file systems (figura 4-7). Ad esempio ubc_setsize(), che informa lUBC che un file ha cambiato dimensione, pu essere chiamata quando una routine di scrittura del file system estende un file. LUBC fornisce, inoltre, delle routine per lavorare con le UPLs: ubc_create_upl() crea una UPL dati un vnode, loffset e la dimensione. ubc_upl_map() mappa una intera UPL in un address space (la ubc_upl_unmap() effettua loperazione inversa). 132

Il sistema operativo Mac OS X

ubc_upl_commit(), ubc_upl_commit_range(), ubc_upl_abort() e ubc_upl_abort_range() sono le estensioni delle corrispondenti funzioni UPL per confermare o scartare le modifiche.
Figura 4-7 Esempi di routines UBC esportate

// convert logical block number to file offset off_t ubc_blktooff(vnode_t vp, daddr64_t blkno); // convert file offset to logical block number daddr64_t ubc_offtoblk(vnode_t vp, off_t offset); // retrieve the file size off_t ubc_getsize(vnode_t vp); // file size has changed int ubc_setsize(vnode_t vp, off_t new_size); // get credentials from the ubc_info structure struct ucred *ubc_getcred(vnode_t vp); // set credentials in the ubc_info structure, but only if no credentials // are currently set int ubc_setcred(vnode_t vp, struct proc *p); // perform the clean/invalidate operation(s) specified by flags on the range // specified by (start, end) in the memory object that backs this vnode errno_t ubc_msync(vnode_t vp, off_t start, off_t end, off_t *resid, int flags); // ask the memory object that backs this vnode if any pages are resident int ubc_pages_resident(vnode_t vp);

Non tutti i tipi di cache di sistema sono unificate, ed alcune non possono esserlo. Per esempio, i metadati del file system (che dal punto di vista dellutente non sono parte del file) devono essere messi in una cache indipendente. Daltra parte, in alcune circostanze pu essere vantaggioso (per le prestazioni) creare una buffer cache privata. Questo il caso dellimplementazione della NFS nel kernel del Mac OS X96, che utilizza una buffer cache privata con una struttura buffer specifica per lNFS (struct [bsd/nfs/nfsnode.h]). La versione 3 dellNFS fornisce una nuova operazione di COMMIT che permette ad un client di richiedere al server una unstable write, nella quale i dati sono scritti al server ma a questi non richiesta la verifica che tali dati siano stati impegnati in una memoria stabile. In questo modo il server pu rispondere immediatamente al client e, di conseguenza, questultimo mandare una richiesta COMMIT per impegnare i dati in una memoria stabile. La NFSv3, inoltre, fornisce un meccanismo che permette al client di
96

nfsbuf

Le versioni del Mac OS X precedenti la 10.3 non utilizzavano una buffer cache separata per lNFS.

133

Il sistema operativo Mac OS X

scrivere di nuovo i dati uncommitted al server nel caso di perdita, ad esempio a causa di un reboot del server.
int nfs_doio(struct nfsbuf *bp, kauth_cred_t cr, proc_t p){ ... if (ISSET(bp->nb_flags, NB_WRITE)) { // we are doing a write ... if (/* a dirty range needs to be written out */) { ... error = nfs_writerpc(...); // let this be an unstable write ... if (!error && iomode == NFSV3WRITE_UNSTABLE) { ... SET(bp->nb_flags, NB_NEEDCOMMIT); ... } ... } ... } ... }

Il buffer cache regolare ed il meccanismo del cluster I/O non sono a conoscenza del meccanismo dellunstable write, tipico dellNFS. In particolare, una volta che il client ha completato una unstable write, i corrispondenti buffers nella NFS buffer cache sono etichettati come NB_NEEDCOMMIT. LNFS utilizza il proprio daemon di I/O asincrono (nfsiod). Il regular buffer laundry thread, ossia bcleanbuf_thread() [bsd/vfs/vfs_bio.c], anchesso

alloscuro delle scritture instabili. Durante la pulizia dei buffers NFS sporchi, il laundry thread non pu aiutare il codice del client NFS a fondere le richieste di COMMIT corrispondenti a multipli buffers NB_NEEDCOMMIT, ma pu rimuovere un buffer alla volta dalla laundry queue e rilasciargli lI/O. di conseguenza lNFS dovrebbe spedire richieste di COMMIT singole, cosa che intaccherebbe le prestazioni e incrementerebbe il traffico di rete. Unaltra differenza tra NFS ed il regular buffer cache che il primo supporta esplicitamente i buffers con pagine multiple. Il secondo prevede un singolo bit (B_WASDIRTY) nella struttura buf per marcare una pagina trovata sporca nella cache. La struttura nfsbuf prevede fino a 32 pagine che possono essere marcate individualmente come pulite o sporche. Buffers NFS di dimensioni maggiori aiutano il miglioramento delle prestazioni dellI/O NFS.

134

Il sistema operativo Mac OS X

// bsd/nfs/nfsnode.h struct nfsbuf { ... u_int32_t nb_valid; // valid pages in the buffer u_int32_t nb_dirty; // dirty pages in the buffer ... }; #define #define #define #define NBPGVALID(BP,P) NBPGDIRTY(BP,P) NBPGVALID_SET(BP,P) NBPGDIRTY_SET(BP,P) (((BP)->nb_valid >> (P)) (((BP)->nb_dirty >> (P)) ((BP)->nb_valid |= (1 << ((BP)->nb_dirty |= (1 << & 0x1) & 0x1) (P))) (P)))

4.5 Il programma Dynamic Pager


Il programma dynamic pager (/sbin/dynamic_pager) un processo utente che crea e cancella files (di swap) nella directory /var/vm designata. Malgrado il nome, dynamic_pager non un paginatore Mach e non coinvolto in nessuna operazione di paging: si tratta solo di un gestore dello spazio di swap utilizzato dal kernel. Il Mac OS X utilizza di default dei paging files invece di partizioni di swap dedicate. I paging files hanno dimensioni variabili e sono creati dinamicamente; il kernel scrive i dati in tali files in gruppi di pagine (cluster). Nel suo modo di funzionamento tipico, il dynamic_pager opera con due limiti di byte: lhigh-water mark ed il lo-water mark. Quando ci sono meno bytes liberi negli swap files di quanti ne permette lhig-water mark, il dynamic_pager crea un nuovo file e lo aggiunge allo swap pool notificandolo al kernel. Quando ci sono pi bytes liberi nei files di paging rispetto a quanti previsti dal low-water mark, il kernel manda una notifica al dynamic_pager per attivare la cancellazione di uno swap file97. Quando avviato, il dynamic_pager determina i due marks ed altri limiti sulla base degli argomenti della linea di comando, lo spazio libero del file system, la memoria fisica istallata e gli hard limits incorporati. Nello specifico, stabilisce i seguenti limiti e regole: La dimensione minima assoluta (64MB) e la dimensione massima assoluta (1GB) di uno swap file. La dimensione massima di un file di scambio non pu essere maggiore n del 12.5% dello spazio disponibile sul volume che contiene il file, n del totale della

97

Ad ogni singola notifica corrisponde la cancellazione di un solo file. Notiamo che il file da cancellare probabile che abbia qualche pagina paged-out. Tali pagine sono portate nel kernel ed infine paged-out in un altro swap file.

135

Il sistema operativo Mac OS X

memoria fisica istallata nel sistema. Possono essere creati al massimo otto files di scambio. I primi due files di scambio hanno la stessa dimensione (quella minima di 64MB). I files successivi raddoppiano la loro dimensione fino a quella massima. Lhigh-water mark di default di 40000000 bytes (circa 38MB). Il Mac OS X 10.4 supporta il criptaggio dei dati scritti dal kernel negli swap files. Il kernel utilizza a questo scopo una variante dellalgoritmo di criptaggio AES. Anche senza il criptaggio, il kernel impedisce ai programmi utente di leggere direttamente i dati di scambio mediante limplementazione di una speciale chiamata di sistema read().

4.6 LUpdate Daemon


Lupdate daemon (/usr/sbin/update) ripulisce98 periodicamente i buffers sporchi del file system invocando la chiamata di sistema sync(). Il periodo di deafult di 30 secondi, ma pu essere modificato mediante linea di comando. Esiste, inoltre, un ulteriore intervallo di power-save che pu essere specificato: quando il sistema alimentato a batteria ed il disco in sleep, lintervallo di power-save utilizzato al posto di quello normale. La sync() itera la lista dei file systems montati, invocando sync_callback() [bsd/vfs/vfs_syscalls.c] su ogni file system. Ad ognuna segue VFS_SYNC() [bsd/vfs/kpi_vfs.c], che chiama la funzione di sincronizzazione specifica del file system mediante una tabella mantenuta dallo strato VFS.

4.7 La memoria condivisa di sistema


Il kernel fornisce un meccanismo di condivisione della memoria, il sottosistema Shared Memory Server, mediante il quale sia il kernel che i programmi utente possono condividere codice e dati tra tutti i task del sistema. anche possibile fornire ad uno o pi tasks delle versioni private della memoria condivisa.
98

Con ripulitura non sintende la scrittura immediata dei dati nel disco, ma solo laccodamento per la scrittura. La scrittura effettiva su disco avviene tipicamente in breve tempo. La chiamata di sistema fcntl(), mediante il controllo F_FULLSYNC realizza la vera pulizia di un file a disco.

136

Il sistema operativo Mac OS X

Limplementazione del sottosistema Shared Memory Server pu essere divisa in un BSD front-end (implementato in bsd/vm/vm_unix.c) ed un Mach back-end (implementato in osfmk/vm/vm_shared_memory_server.c). Il primo fornisce un set di system calls private dellApple che utilizzato dal dynamic link editor (dyld). Il secondo nasconde i dettagli della memoria virtuale del Mach e fornisce funzionalit di basso livello per la memoria condivisa che sono utilizzate dal front-end. Nonostante tutte le applicazioni utente tipiche beneficino dei servizi forniti dallo Shared Memory Server, le APIs corrispondenti sono riservate esclusivamente alle applicazioni fornite dalla Apple, con il dyld come unico client. Lutilizzo di queste APIs possono interessare tutte le applicazioni del sistema, anche in modo avverso: per questo motivo i programmi di terze parti non devono utilizzarle.

4.8 Task Working Set


Il kernel utilizza la memoria fisica come cache per la memoria virtuale. Quando delle nuove pagine devono essere caricate a causa dei page faults, il kernel deve decidere quali pagine reclamare fra quelle correntemente nella memoria fisica. Dal punto di vista di unapplicazione, il kernel dovrebbe idealmente mantenere in memoria quelle pagine che saranno presto necessarie. In un sistema operativo ideale, il kernel saprebbe prima del tempo quali pagine saranno riferite da una applicazione durante la propria esecuzione. Sono stati studiati diversi algoritmi per approssimare una sostituzione di pagina cos ottimale. Un altro approccio usa Principio di Localit, su cui si basa il Working Set Model. Come descritto nel documento intitolato Virtual Memory99, la localit pu essere intesa informalmente come laffinit di un programma per un sottogruppo delle sue pagine, in cui i membri cambiano lentamente. Da questo prende forma il concetto di working set, definito informalmente come il set delle pagine pi utili per un programma. Il Working Set Principle stabilisce la regola che un programma pu girare se e solo se il suo working set in memoria, ed una pagina non pu essere rimossa se fa parte del working set di un programma in esecuzione. Degli studi hanno dimostrato che mantenere
99

Virtual Memory di Peter J. Denning (ACM Computing Surveys 2:3, Settembre 1970, pp 153-189).

137

Il sistema operativo Mac OS X

il working set residente nella memoria fisica permette al programma relativo di girare con delle prestazioni accettabili, vale a dire senza causare un numero inaccettabile di page faults. Il kernel del Mac OS X include un meccanismo che, per ogni coppia {applicazione, utente}, costruisce i profili working set, salva le pagine corrispondenti in una directory designata e cerca di caricarle quando lapplicazione eseguita dallutente. Questo meccanismo, chiamato TWS (da task working set), integrato nel meccanismo di gestione del page-fault del kernel. La prima volta che una applicazione lanciata in un dato contesto utente, il TWS cattura il working set iniziale e lo memorizza in un file nella directory var/vm/app_profile/. Diversi aspetti dello schema TWS

contribuiscono alle prestazioni. Le informazioni del profilo sono utilizzate durante la gestione del page-fault per determinare se qualche pagina vicina debba essere portata dentro. Prendere pi pagine di quelle corrispondenti allimmediato page-fault porta ad una singola grande richiesta al pager, evitando le richieste multiple successive che dovrebbero al contrario essere fatte per portare le pagine che si pensa siano necessarie nell'immediato futuro. Questo vale solo per le pagine non sequenziali, tuttavia, poich le pagine sequenziali sono comunque paged-in per il cluster I/O. Il TWS cattura e memorizza su disco il working set iniziale di unapplicazione la prima volta che questa viene lanciata da un particolare utente. Questa informazione utilizzata per il preriscaldamento del working set quando lapplicazione lanciata di nuovo nello stesso contesto utente. In questo modo, il profilo dellapplicazione costruito nel tempo. La localit dei riferimenti di memoria sono spesso messe su disco, poich i files su disco hanno tipicamente una buona localit sui volumi HFS Plus. Normalmente i working sets possono essere letti da disco con dei piccoli overheads di ricerca. Il TWS memorizza i profili delle applicazioni per un dato user in due files nella directory var/vm/app_profile/. Questi files si chiamano #U_names e #U_data, dove #U la rappresentazione esadecimale dello user ID. Il file names un semplice database che 138

Il sistema operativo Mac OS X

contiene un header seguito dagli elementi del profilo, mentre il file data contiene il working set attuale. Gli elementi del profilo nel file names puntano ai working sets nel file data.
// bsd/vm/vm_unix.c // header for the "names" file struct profile_names_header { unsigned int number_of_profiles; unsigned int user_id; unsigned int version; off_t element_array; unsigned int spare1; unsigned int spare2; unsigned int spare3; }; // elements in the "names" file struct profile_element { off_t addr; vm_size_t size; unsigned int mod_date; unsigned int inode; char name[12]; };

Il kernel mantiene una struttura dati contenente un array di profili globali, ognuno dei quali le informazioni per un utente.
// bsd/vm/vm_unix.c // meta information for one user's profile struct global_profile { struct vnode *names_vp; struct vnode *data_vp; vm_offset_t buf_ptr; unsigned int user; unsigned int age; unsigned int busy; }; struct global_profile_cache { int max_ele; unsigned int age; struct global_profile profiles[3]; // up to 3 concurrent users }; ... struct global_profile_cache global_user_profile_cache = { 3, 0, { NULL, NULL, 0, 0, 0, 0 }, { NULL, NULL, 0, 0, 0, 0 }, { NULL, NULL, 0, 0, 0, 0 } };

Molte delle funzionalit del TWS sono implementate in bsd/vm_vm_unix.c, con il file osfmk/vm/task_working_set.c che ne utilizza le funzioni. prepare_profile_database() crea ununico pathname assoluto per i files names e data per il dato user ID. chiamata da setuid() per preparare questi files per un nuovo utente. 139

Il sistema operativo Mac OS X

bsd_search_page_cache_data_base() ricerca un profilo dapplicazione in un dato file names. bsd_open_page_cache_files() cerca di aprire (se presenti entrambi) o creare (se assenti entrambi) i files names e data. Nel caso solo uno fosse presente, il tentativo fallisce. bsd_close_page_cache_files() decrementa i riferimenti nei files names e data per il profilo utente specificato. bsd_read_page_cache_file() per prima cosa chiama

bsd_open_page_cache_files(), dopodich cerca il profilo dapplicazione dato nel file names usando bsd_search_page_cache_data_base(). Se il profilo trovato, la funzione ne legge i dati dal file data nel buffer specificato. bsd_write_page_cache_file() scrive nei files names e data.

4.9 Memory-mapped files


Il Mac OS X fornisce la chiamata di sistema mmap() per la mappatura (mapping) di files, dispositivi a carattere e descrittori POSIX di memoria condivisa nelladdress space del chiamante. Inoltre, la memoria anonima pu essere mappata impostando largomento flags di mmap() su MAP_ANON.
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

Quando mmap() usata per un file regolare o memoria anonima, la mappatura backed da un oggetto su disco come segue: La memoria anonima sempre backed dallo spazio di swap. La mappatura di un file regolare backed dal file stesso se la chiamata ha largomento flags settato a MAP_SHARED. Questo significa che ogni modifica fatta alla mappatura scritta nel file originale quando la corrispondente pagina rimossa. La mappatura di un file regolare backed dallo spazio di swap se la chiamata ha largomento flags settato a MAP_PRIVATE. Questo significa che ogni modifica fatta alla mappatura privata. 140

Il sistema operativo Mac OS X

Andiamo ora ad analizzare limplementazione di mmap() osservando la sequenza di operazioni che hanno luogo quando un programma mappa un file regolare. Per prima cosa il programma deve acquisire il file descriptor del file in questione. La figura 4-8 mostra le attivit rilevanti che avvengono in conseguenza di una chiamata di sistema open(). In questo caso, un preesistente file regolare residente in un volume HFS+ viene aperto per la prima volta.

Figura 4-8

Configurazione del vnode pager durante la chiamata di sistema open()

141

Il sistema operativo Mac OS X

La

struttura

vnode

(struct

vnode

[bsd/sys/vnode_internal.h])

corrispondente ad un file regolare contiene un puntatore ad una struttura informazioni UBC (struct ubc_info [bsd/sys/ubc_internal.h]). Questa contiene un puntatore al pager, in questo caso il vnode pager, come rappresentato da una struttura vnode_pager [osfmk/vm/bsd_vm.c]. La figura 4-9 mostra come queste strutture sonno connesse durante la creazione di un vnode.

Figura 4-9

Configurazione del vnode pager per la creazione di un nuovo vnode

Supponiamo che un programma utente chiami mmap() per mappare il file descriptor ottenuto in figura 4-8. La figura 4-10 mostra la conseguente attivit del kernel. La funzione mmap() chiama mach_vm_map() [osfmk/vm/vm_user.c] che, nel caso di un file regolare, chiamer vm_object_enter() [osfmk/vm/vm_object.c]. Siccome nessun VM object ancora stato assegnato al dato pager, questultima funzione ne creer uno nuovo. Inoltre inizializzer il pager, il che comporta anche lallocazione di una porta di controllo che verr passata come argomento a memory_object_init(). Infine la chiamata a vm_map_enter() [osfmk/vm/vm_map.c] comporter lallocazione di un virtual address range nello spazio dindirizzo virtuale del task. 142

Il sistema operativo Mac OS X

Figura 4-10

Elaborazione della chiamata di sistema mmap() da parte del kernel

Quando un programma cerca di accedere ad un indirizzo della memoria mappata per leggerlo, causa unattivit di page-in se la pagina corrispondente non ancora residente. Dato che il programma ha mappato il file con PROT_READ|PROT_WRITE come valori di protezione e MAP_SHARED specificato come flags, causer lattivit di page-out se modifica la memoria mappata.

143

Il sistema operativo Mac OS X

Le figure 4-11a e 4-11b mostrano i passi di unoperazione di page-in, con la seconda che specifica i dettagli del paging in da un vnode. Le figure 4-12a e 4-12b mostrano gli step analoghi per loperazione di page-out-

Figura 4-11a

Una visione dinsieme delloperazione di page-in

144

Il sistema operativo Mac OS X

Figura 4-11b

Il paging in da un vnode

145

Il sistema operativo Mac OS X

Figura 4-12a

Una visione dinsieme delloperazione di page-out

146

Il sistema operativo Mac OS X

Figura 4-12b

Il paging out da un vnode

147

Il sistema operativo Mac OS X

Capitolo 5
Interprocess Communication

I programmi complessi, anche solo moderatamente, sono di solito suddivisi in parti logicamente e funzionalmente separate. Questo permette un pi semplice sviluppo, una migliore manutenzione e flessibilit ed unagevolata compresione del software. Anche se tale suddivisione pu essere fatta in diversi modi, alcuni dei quali formali e standardizzati, c un risultato generale: in un tipico sistema operativo possono esserci diverse entit coinvolte in unoperazione. Queste entit spesso necessitano di condividere informazioni, sincronizzarsi e comunicare luna con laltra. Facendo girare il pi banale programma in C sul Mac OS X comporta linvocazione di dozzine di system calls. Programmi non banali possono comprendere threads multipli (o forse anche processi multipli) che debbano comunicare luno con laltro in modi arbitrari. Spesso, processi non coinvolti nello stesso programma devono comunque comunicare luno con laltro. Vale la pena chiedersi cosa si qualifica come comunicazione. In alcuni casi, la linea tra comunicazione e condivisione dellinformazione pu essere poco chiara. Per questo motivo intenderemo linterprocess communication (IPC) come un meccanismo ben definito, provvisto di uninterfaccia di programmazione, per il trasferimento dinformazioni tra due o pi entit. Le entit comunicanti erano, storicamente, i processi (da questo viene il termine comunicazione interprocesso). Tali entit possono attualmente essere anche dei threads di uno stesso task, dei threads di diversi tasks o 148

Il sistema operativo Mac OS X

threads nel kernel. Fin dai primi giorni dei sistemi timesharing, una variet di risorse di computazione sono state associate con i processi: IPC anche il mezzo di condivisione di tali risorse.100 A seconda del tipo di IPC, le parti possono richiedere una qualche forma di sincronizzazione per permettere al meccanismo di funzionare correttamente. In generale lIPC pu richiedere e pu consistere di una o pi delle seguenti operazioni: Condivisione dei dati Trasferimento dei dati Condivisione delle risorse Sincronizzazione tra i partecipanti allIPC Notifiche sincrone ed asincrone Operazioni di controllo I primi meccanismi IPC usavano dei files come mezzo di comunicazione. In seguito ci fu lapproccio della memoria condivisa, dove i processi utilizzavano regioni di memoria comunemente accessibili per implementare ad hoc lIPC e gli schemi di sincronizzazione. Infine il meccanismo dellIPC divenne unastrazione fornita dallo stesso sistema operativo. Il Mac OS X fornisce un gran numero di meccanismi IPC, alcuni con interfacce disponibili a pi strati del sistema. I seguenti sono esempi di meccanismi/interfacce di IPC nel Mac OS X: Mach IPC Eccezioni Mach Segnali Unix Pipes senza nome Pipes con nome (fifos) XSI/System V IPC POSIX IPC Oggetti distribuiti

100

Il termine IPC spesso usato come sinonimo di message passing, che pu essere pensato come uno specifico (e piuttosto popolare) meccanismo IPC.

149

Il sistema operativo Mac OS X

Apple Events Varie interfacce per spedire e ricevere notifiche Meccanismo Core Foundation IPC Ognuno di questi meccanismi ha i propri benefici, difetti e rischi. Un programmatore pu aver bisogno di usare un particolare meccanismo, o anche diversi, in base alle richieste del programma e lo strato di sistema per cui progettato.

5.1 LIPC del Mach


Il Mach fornisce una IPC orientata ai messaggi che rappresenta unevoluzione degli approcci utilizzati dai suoi precursori Accent e RIG. Limplementazione utilizza il sottosistema VM per trasferire efficientemente grandi quantit di dati mediante le ottimizzazioni copy-on-write101. Il kernel Mac OS X usa la primitiva generale del messaggio, fornita dallinterfaccia IPC del Mach, come mattone fondamentale. In particolare, le chiamate Mach mach_msg() e mach_msg_overwrite() possono essere utilizzate per spedire e ricevere (rispettivamente) i messaggi, permettendo uninterazione simile alla RPC come caso speciale dellIPC. Questo tipo di RPC utilizzata per implementare diversi servizi di sistema nel Mac OS X. LIPC del Mach si basa su due astrazioni kernel di base: le porte ed i messaggi. Una porta unentit poliedrica, mentre un messaggio una collezione, di dimensione arbitraria, di data objects.

5.1.1 Le porte Mach


Una porta fondamentalmente un canale di comunicazione, ossia una coda di lunghezza finita di messaggi gestita (e protetta) dal kernel. Le operazioni di base su una porta sono la spedizione e la ricezione di messaggi: spedire ad una porta permette ad un task di mettere i messaggi nella coda sottostante, ricevere su una porta permette al task di recuperare i messaggi dalla coda. Quando la coda corrispondente ad una porta piena o vuota, i
101

Lintegrazione dellIPC con la memoria virtuale permette la mappatura (copy-on-write, se possibile ed appropriato) dei messaggi nelladdress space del task ricevente. In teoria, un messaggio potrebbe essere grande quanto la dimesione delladdress space del task.

150

Il sistema operativo Mac OS X

senders ed i receivers sono (rispettivamente) bloccati, in generale. Per poter accedere ad una porta, un task deve avere un port right (send right o receive right). Questo meccanismo serve ad impedire ad i tasks di accedere in modo arbitrario sulle porte, limitando il set di operazioni che ogni task pu compiere su ogni porta. Le porte sono anche utilizzate per rappresentare risorse, servizi e mezzi che forniscono cos un accesso object-style a queste astrazioni. Ad esempio, il Mach usa le porte per rappresentare astrazioni come hosts, tasks, threads, memory objects, clocks, timers, processori e processor set. Le operazioni su un tale oggetto sono effettuate attraverso la spedizione di messaggi alla porta che lo rappresenta. Nel suo ruolo di canale di comunicazione, una porta Mach potrebbe sembrare una socket BSD, ma ci sono differenze importanti: La progettazione dellIPC Mach integrata con il sottosistema della memoria virtuale. Laddove i sockets sono usate principalmente per le comunicazioni remote, lIPC Mach utilizzata (ed ottimizzata) per la comunicazione intra-macchina102. I messaggi dellIPC Mach possono trasportare dati tipizzati. In generale, le interfacce dellIPC Mach sono pi potenti e flessibili di quelle del socket. Quando si parla di un messaggio spedito ad un task, sintende che il messaggio spedito alla porta di cui il task ricevente possiede i diritti di ricezione. Il messaggio viene poi rimosso dalla coda da un thread interno al task ricevente. Il Mac OS X definisce i seguenti tipi specifici di port rights: MACH_PORT_RIGHT_SEND un diritto di spedizione ad una porta implica che il possessore del diritto pu spedire messaggi a quella porta. Se un thread acquisisce un send right che il proprio task possedeva, il reference count relativo incrementato. Analogamente, se un thread rilascia il diritto viene decrementato il conteggio. Il task perde il proprio diritto di spedizione solo quando il reference
Il progetto dellIPC Mach pu essere esteso in modo trasparente alla rete, mediante dei tasks esterni (ossia utente) chiamati Network Servers, che agiscono come dei proxies per i tasks remoti . Anche se il kernel XNU mantiene la maggior parte delle semantiche dellIPC Mach, il Mac OS X non utilizza questestensione a livello di rete.
102

151

Il sistema operativo Mac OS X

count relativo si azzera. MACH_PORT_RIGHT_RECEIVE un diritto di ricezione su una porta implica che il possessore del diritto pu rimuovere i messaggi dalla coda di quella porta. Una porta pu avere qualsiasi numero di senders, ma un solo receiver; inoltre se un task ha il diritto di ricezione, ha automaticamente anche quello di spedizione. MACH_PORT_RIGHT_SEND_ONCE un diritto di unica spedizione permette al possessore di spedire un solo messaggio, dopo del quale il diritto viene cancellato. I send-once rights sono usati come porte di risposta: un client pu includere un diritto di send-once in una richiesta ed il server pu usare tale diritto per spedire una risposta. Un send-once right comporta sempre la spedizione di uno ed un solo messaggio. MACH_PORT_RIGHT_PORT_SET un nome port set pu essere considerato come un diritto di ricezione che comprende porte multiple. Un port set rappresenta un gruppo di porte di cui il task possiede il receive right. Questo diritto permette al task di ricevere un messaggio, il primo ottenibile, da una delle porte del set. Il messaggio identifica la porta sul quale stato ricevuto. MACH_PORT_RIGHT_DEAD_NAME un dead name non realmente un diritto, ma rappresenta un send (o send-once) right che diventato invalido in seguito alla distruzione della porta corrispondente. Quando il send right si trasforma in dead name, il suo reference count rimanda al dead name. Cercare di spedire un messaggio ad un dead name produce un errore, che permette ai senders di realizzare che la porta distrutta103. Andiamo ora ad analizzare alcuni aspetti degni di nota che riguardano i port rights. I diritti sono posseduti a livello di task. Per esempio, sebbene il codice per creare una porta eseguito in un thread, i diritti associati sono concessi al suo task. Di conseguenza, ogni altro thread interno a quel task pu usare o manipolare tali diritti.
Un porta considerata distrutta quando i suoi receive rights sono deallocato. Anche se i send (o send-once) rights esistenti si trasformano in dead names quando avviene la distruzione, i messaggi esistenti nella coda della porta vengono distrutti ed ogni memoria out-of-line associata viene liberata.
103

152

Il sistema operativo Mac OS X

Lo spazio dei nomi per le porte privato al task. In altre parole, un dato nome di porta valido solo allinterno dello spazio IPC di un task, in maniera analoga allo spazio dindirizzo virtuale di un task. Se un task possiede entrambi i diritti (di spedizione e ricezione) per una porta, allora i diritti hanno lo stesso nome. Due send-once rights detenuti da uno stesso task non possono avere lo stesso nome. I diritti possono essere trasferiti mediante lo scambio di messaggi. In particolare, loperazione (frequente) di ottenere laccesso ad una porta coinvolge la ricezione di un messaggio contenente un port right. Dopo che un task ha spedito un messaggio contenente uno o pi port rights, e prima che il messaggio venga rimosso dalla coda dal ricevente, i diritti sono mantenuti dal kernel. Poich il diritto di ricezione pu essere detenuto da un solo task alla volta, c la possibilit di messaggi spediti ad una porta il cui receive right in trasferimento. In tale caso, il kernel accoder i messaggi fino a che il task ricever i diritti e rimuover i messaggi dalla coda.

5.1.2 I messaggi IPC del Mach


I messaggi IPC Mach possono essere spediti e ricevuti attraverso la famiglia di funzioni mach_msg. La chiamata di sistema IPC fondamentale del Mac OS X una trap chiamata mach_msg_overwrite_trap() [osfmk/ipc/mach_msg.c], che pu essere usata per spedire un messaggio, per ricevere un messaggio o per spedire e ricevere in una singola chiamata.
// osfmk/ipc/mach_msg.c mach_msg_return_t mach_msg_overwrite_trap( mach_msg_header_t *snd_msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout, mach_port_name_t notify, mach_msg_header_t *rcv_msg, mach_msg_size_t scatterlist_sz);

// // // // // // // // //

message bitwise size of maximum port or timeout receive message size of

buffer to be sent OR of commands and modifiers outgoing message buffer size of receive buffer (rcv_msg) port set to receive on in milliseconds right for a notify port buffer for receiving scatter list control info

Il comportamento di tale funzione controllato dallargomento option: i suoi bits determinano cosa deve fare la chiamata e come lo deve fare. 153

Il sistema operativo Mac OS X

Lanatomia di un messaggio Mach si evoluta nel tempo, ma la struttura di base consistente in un header di dimensione fissa seguito da dati di dimensioni variabili rimasta immutata. I messaggi Mach nel Mac OS X contiene le seguenti parti: Un header di dimensione fissata (mach_msg_header_t). Un body di dimensione variabile (eventualmente vuoto) contenente dati utente e del kernel (mach_msg_body_t). Un trailer di dimensione variabile contenente degli attributi del messaggio, apposti dal kernel (mach_msg_trailer_t).

Figura 5-1

La struttura di un messaggio Mach complesso

154

Il sistema operativo Mac OS X

Un messaggio pu essere semplice o complesso. Un messaggio semplice contiene un header immediatamente seguito da dati senza tipo, mentre un messaggio complesso contiene anche un corpo del messaggio strutturato.

5.2 Mach IPC: implementazione nel Mac OS X


Il nucleo del sottosistema IPC implementato mediante i files della directory osfmk/ipc/ nel kernel source tree. Inoltre, il gruppo di files osfmk/kern/ipc_* implementano le funzioni di supporto allIPC per gli oggetti kernel come i tasks ed i threads. La figura 5-2 mostra una visione di insieme dellimplementazione del sistema IPC Mach allinterno del Mac OS X.

Figura 5-2

Implementazione dellIPC Mach nel Mac OS X

5.2.1 Gli spazi IPC


Ogni task ha un IPC space privato (un namespace per le porte), rappresentato dalla struttura dati ipc_space nel kernel, che ne definisce le capacit IPC. Lo spazio IPC incapsula la conoscenza necessaria a tradurre i nomi di porta locale (task-specific) in 155

Il sistema operativo Mac OS X

strutture dati di porta globali (kernel-wide). Questa traduzione implementata usando le translation entries per le port capabilities. Ogni capability registrata nel kernel mediante una struttura dati ipc_entry. Uno spazio IPC contiene sempre una tabella di IPC entries puntata dal campo is_table della struttura ipc_space. Essa pu contenere anche uno splay tree104 delle IPC entries, nel qual caso il campo is_tree risulta non-NULL. Notiamo che entrambe le strutture dati sono per-task.
Figura 5-3 Struttura dati dello spazio IPC di un task

// osfmk/ipc/ipc_space.h typedef natural_t ipc_space_refs_t; struct ipc_space { decl_mutex_data(,is_ref_lock_data) ipc_space_refs_t is_references; decl_mutex_data(,is_lock_data) boolean_t is_active; boolean_t is_growing; ipc_entry_t is_table; ipc_entry_num_t is_table_size; struct ipc_table_size *is_table_next; struct ipc_splay_tree is_tree; ipc_entry_num_t is_tree_total; ipc_entry_num_t is_tree_small; ipc_entry_num_t is_tree_hash; boolean_t is_fast; };

// // // // // // // // // //

is the space active? is the space growing? table (array) of IPC entries current table size information for larger table splay tree of IPC entries (can be NULL) number of entries in the tree number of "small" entries in the tree number of hashed entries in the tree for is_fast_space()

In generale i nomi di port right si adattano bene in una tabella perch il numero di porte che usa un task tipicamente ridotto. Il Mach permette di rinominare una porta, ed in particolare permette che sia allocata utilizzando un nome specificato dal chiamante. Questo significa che un nome di porta pu essere un indice che non rientra nei limiti della tabella del task. Tali rights possono essere allogiati mediante overflow dello splay tree del task. Per minimizzare il consumo di memoria, il kernel aggiusta dinamicamente il limite entro cui le entries sono mantenute nello splay tree. In realt, la tabella pu anche crescere in dimensioni. Quando il kernel accresce la tabella, la espande ad una nuova dimensione (espressa in numero di table entries) specificata nel campo is_table_next della struttura ipc_space. Il kernel mantiene un array chiamato ipc_table_entries di tali strutture. Questo array, popolato durante linizializzazione del sottosistema IPC, semplicemente una sequenza predefinita di dimensioni della tabella. Uno spazio IPC fast un caso speciale di IPC space che non usa uno splay tree. Pu essere
104

Uno splay tree un albero di ricerca binario particolarmente efficiente.

156

Il sistema operativo Mac OS X

utilizzato solo se esiste la garanzia che i nomi di porta rientrino nei limiti della tabella. Quando un port right la cui entry in tabella viene cancellato, lentry piazzata in un lista delle unused entries. La lista mantenuta nella tabella stessa mediante il concatenamento dei suoi elementi, attraverso i loro campi ie_next. Quando il prossimo port right allocato, si prende lultima entry liberata. Il campo ie_index implementa una tabella hash ordinata per la traduzione dalla coppia {IPC space, IPC object} al nome. Come mostrato in figura 5-2, una entry dello splay tree consiste in una struttura ipc_entry con i seguenti campi addizionali: nome, spazio IPC e i puntatori ai figli destro e sinistro. Il campo ite_next implementa una open hash table globale utilizzata per la traduzione di una coppia {IPC space, IPC object} in una coppia {name, IPC entry}.

5.2.2 Anatomia di una porta Mach


Una porta Mach rappresentata nel kernel da un puntatore ad una struttura ipc_port. Il campo ipc_object della struttura IPC entry punta ad una struttura ipc_object, che una logicamente sovrimpressa su una struttura ipc_port.

Figura 5-4

La struttura interna di una porta Mach

157

Il sistema operativo Mac OS X

I campi di una struttura ipc_port includono un puntatore allo spazio IPC del task che detiene il diritto di ricezione, uno al kernel object che la porta rappresenta e vari reference counts (come make-send count, il numero dei send rights e quello dei send-once rights). importante comprendere la differenza tra mach_port_t e mach_port_name_t: questi due tipi sono trattati allo stesso modo nello user space, ma non nel kernel. Un nome di porta rilevante solo in un particolare namespace, quindi mach_port_name_t rappresenta lidentit locale di una porta, senza implicare nessun diritto associato. Un mach_port_t rappresenta un riferimento aggiunto o cancellato ad un port right. Nel kernel i port rights sono rappresentati passando un puntatore (ipc_port_t) alla struttura dati port appropriata. Se un programma utente riceve un mach_port_name_t dal kernel, significa che il kernel non ha mappato nessun port rights associato: il nome semplicemente la rappresentazione intera della porta105. Quando, invece, il kernel ritorna un

mach_port_t, mappa i port rights associati al destinatario del messaggio. In entrambi i casi, il programma utente vede lo stesso intero anche se con differenti semantiche sottostanti. La stessa porta pu esistere con nomi differenti in diversi task e, inversamente, uno stesso nome di porta pu rappresentare differenti porte in differenti task. In un dato namespace, se esistono pi diritti per una particolare porta, i nomi posso fondersi in uno solo: in altre parole, un singolo nome pu denotare diversi diritti (tranne nel caso dei send-once rights). Il campo ie_bits della struttura ipc_entry mantiene i tipi di diritti che il dato nome rappresenta. Questo bitmap quello che permette ad un singolo nome in uno spazio IPC di rappresentare diritti multipli.
// osfmk/mach/mach_port.h typedef natural_t mach_port_right_t; #define MACH_PORT_RIGHT_SEND ((mach_port_right_t) #define MACH_PORT_RIGHT_RECEIVE ((mach_port_right_t) #define MACH_PORT_RIGHT_SEND_ONCE ((mach_port_right_t) #define MACH_PORT_RIGHT_PORT_SET ((mach_port_right_t) #define MACH_PORT_RIGHT_DEAD_NAME ((mach_port_right_t)
105

0) 1) 2) 3) 4)

Il tipo intero usato per rappresentare un nome di porta storicamente il tipo intero nativo della macchina. Questo tipo si chiama natural_t e vi si accede includendo <mach/machine/vm_types.h> (che a sua volta vi accede da <mach/ppc/vm_types.h> o <mach/i386/vm_types.h>, a seconda della macchina). Con lintroduzione dellABI Darwin a 64-bit, diversi tipi di dati Mach (come vm_offset_t e vm_size_t) sono stati scalati per coincidere con le dimensioni di un puntatore, tuttavia natural_t rimasto di 32-bits.

158

Il sistema operativo Mac OS X

#define typedef typedef #define #define #define #define #define #define #define

MACH_PORT_RIGHT_NUMBER ((mach_port_right_t) 5) natural_t mach_port_type_t; mach_port_type_t *mach_port_type_array_t; MACH_PORT_TYPE(right) \ ((mach_port_type_t)(((mach_port_type_t) 1) \ << ((right) + ((mach_port_right_t) 16)))) MACH_PORT_TYPE_NONE ((mach_port_type_t) 0L) MACH_PORT_TYPE_SEND MACH_PORT_TYPE(MACH_PORT_RIGHT_SEND) MACH_PORT_TYPE_RECEIVE MACH_PORT_TYPE(MACH_PORT_RIGHT_RECEIVE) MACH_PORT_TYPE_SEND_ONCE MACH_PORT_TYPE(MACH_PORT_RIGHT_SEND_ONCE) MACH_PORT_TYPE_PORT_SET MACH_PORT_TYPE(MACH_PORT_RIGHT_PORT_SET) MACH_PORT_TYPE_DEAD_NAME MACH_PORT_TYPE(MACH_PORT_RIGHT_DEAD_NAME)

Anche se i nomi di porta sono di solito assegnati dal kernel, un programma utente pu creare un port right con un nome specifico mediante la routine

mach_port_allocate_name(). Un valore mach_port_name_t assegnato dal kernel ha due componenti: index e generation number.
// osfmk/mach/port.h #define MACH_PORT_INDEX(name) ((name) >> 8) #define MACH_PORT_GEN(name) (((name) & 0xff) << 24) #define MACH_PORT_MAKE(index, gen) (((index) << 8) | (gen) >> 24)

Se un programma utente deve usare nomi di porta per mapparli nei dati utente, deve usare solo la parte index del port name, che il layout visibile allo user space del mach_port_name_t. Il kernel definisce il valore 0 come nome della porta null (MACH_PORT_NULL). La porta null un valore legale di porta che pu essere trasportato nei messaggi per indicare lassenza di qualunque porta o port rights. Una porta dead (MACH_PORT_DEAD) indica che un port right era presente ma ora non lo pi. Il suo valore numerico un natural_t con tutti i bit settati ed un valore legale di porta che pu comparire nei messaggi. Ad ogni modo, questi due valori non rappresentano delle porte valide, mentre tutti gli altri valori lo sono. Il codice di gestione delle IPC entries fornisce delle interfacce per ricercare un IPC object dato il suo nome in un IPC space (utile per spedire un messaggio) e, inversamente, per ricercare il nome di un IPC object in un dato IPC space (utile nella ricezione di un messaggio).

5.2.3 Tasks e IPC


I tasks ed i threads Mach cominciano entrambi la loro vita con dei sets di porte Mach standard. Il set di porte standard del task includono le seguenti: 159

Il sistema operativo Mac OS X

Una self port (conosciuta anche col nome di kernel port del task) rappresenta il task stesso. Il kernel mantiene i receive rights di questa porta. Un set di exception ports che include una porta per ogni tipo di eccezione supportata dal kernel. Il kernel spedisce un messaggio alla exception port appropriata quando avviene uneccezione in uno dei threads del task. Notiamo che le porte deccezione esistono anche a livello di thread (pi specifiche di quelle a livello task) ed a livello host (meno specifiche). Il kernel cerca sempre di mandare i messaggi deccezione alla porta pi specifica. Le porte deccezione sono utilizzate per implementare sia i meccanismi di gestione degli errori che il debugging. Una host port che rappresenta lhost sul quale il task sta girando. Una bootstrap port usata per spedire messaggi al Bootstrap Server, che essenzialmente un server dei nomi locale per i servizi accessibili attraverso le porte Mach. I programmi possono contattare il Bootstrap Server richiedendo il ritorno delle altre porte di system service. Un set di note porte di sistema (al massimo TASK_PORT_REGISTER_MAX) sono registrate per un task e sono usate dal sistema di runtime per inizializare il task. La routine mach_ports_register() pu essere usata per registrare un array di send rights, con ogni diritto in uno slot dellarray itk_registered contenuto nella struttura task. Quando viene creato un task, una nuova porta allocata nello spazio IPC del kernel. Il campo itk_self della struttura task impostato sul nome di questa porta, mentre il membro itk_sself contiene il send right a tale porta. Il campo itk_space contiene il riferimento al nuovo spazio IPC creato per il task. Il nuovo task eredita le porte registered, exception, host e bootstrap del padre. Il kernel crea dei diritti di spedizione naked106 per il figlio per ognuna di queste porte, a partire dagli esistenti naked rights del padre. Come sappiamo, a parte queste, le porte Mach non sono ereditate durante la creazione di task.

Un diritto naked esiste solo nel contesto del kernel task. chiamato in questo modo perch un tale diritto non inserito nel port namespace del kernel task.

106

160

Il sistema operativo Mac OS X

Le figure 5-5 e 5-6 mostrano le strutture dati relative allIPC associate al task ed al thread, rispettivamente.
Figura 5-5 Strutture dati relative allIPC associate ad un task Mach
10 3 // number of "registered" ports

// osfmk/mach/ppc/exception.h #define EXC_TYPES_COUNT // osfmk/mach/mach_param.h #define TASK_PORT_REGISTER_MAX

// osfmk/kern/task.h struct task { // task's lock decl_mutex_data(,lock) ... // IPC lock decl_mutex_data(,itk_lock_data) // not a right -- ipc_receiver does not hold a reference for the space // used for representing a kernel object of type IKOT_TASK struct ipc_port *itk_self; // "self" port -- a "naked" send right made from itk_self // this is the task's kernel port (TASK_KERNEL_PORT) struct ipc_port *itk_sself; // "exception" ports -- a send right for each valid element struct exception_action exc_actions[EXC_TYPES_COUNT]; // "host" port -- a send right struct ipc_port *itk_host; // "bootstrap" port -- a send right struct ipc_port *itk_bootstrap; // "registered" port -- a send right for each element struct ipc_port *itk_registered[TASK_PORT_REGISTER_MAX]; // task's IPC space struct ipc_space *itk_space; ... };

Figura 5-6

Strutture dati relative allIPC associate ad un thread Mach

// osfmk/kern/thread.h struct thread { ... struct ipc_kmsg_queue ith_messages; // reply port -- for kernel RPCs mach_port_t ith_rpc_reply; ... // not a right -- ip_receiver does not hold a reference for the space // used for representing a kernel object of type IKOT_THREAD struct ipc_port *ith_self; // "self" port -- a "naked" send right made from ith_self // this is the thread's kernel port (THREAD_KERNEL_PORT) struct ipc_port *ith_sself; // "exception" ports -- a send right for each valid element struct exception_action exc_actions[EXC_TYPES_COUNT]; ... };

5.2.4 Threads e IPC


Come un task, anche il thread contiene una self port ed un set di excption port usate per la gestione degli errori. Mentre le nuove porte deccezione di un task sono ereditate dal parent, ognuna delle porte deccezione del thread sono inizializzate alla porta null al momento della creazione del thread. Le exception ports, sia del task che del thread, 161

Il sistema operativo Mac OS X

possono essere cambiate in seguito in modo programmatico. Se una thread exception port per un tipo specifico deccezione la porta null, il kernel usa la successiva porta pi specifica: la corrispondente porta deccezione a livello task. Il campo ith_rpc_reply della struttura thread indica la reply port per le RPC del kernel. Quando il kernel deve spedire un messaggio al thread e ricevere una risposta, alloca una reply port sel il valore corrente di ith_rpc_reply IP_NULL.

5.2.5 Allocazione di una porta


Anche se mach_port_allocate() la routine tipicamente utilizzata per allocare un port right, esistono diverse varianti flessibili come mach_port_allocate_name() e mach_port_allocate_qos() che permettono di specificare maggiori propriet del nuovo port right. Tutte queste routines sono casi speciali di mach_port_allocate_full(), che rimane disponibile allo spazio utente.
typedef struct mach_port_qos { boolean_t name:1; // caller-specified port name boolean_t prealloc:1; // preallocate a message buffer boolean_t pad1:30; natural_t len; // length of preallocated message buffer } mach_port_qos_t; kern_return_t mach_port_allocate_full( ipc_space_t space, // target IPC space mach_port_right_t right, // type of right to be created mach_port_t proto, // subsystem (unused) mach_port_qos_t *qosp, // quality of service mach_port_name_t *namep); // new port right's name in target IPC space

La routine mach_port_allocate_full() crea uno dei tre tipi di port rights in base al valore passato nellargomento right: Un receive right (MACH_PORT_RIGHT_RECEIVE), che il tipo di diritto pi comune che viene creato da questa funzione Un empty right (MACH_PORT_RIGHT_PORT_SET) Un dead name (MACH_PORT_RIGHT_DEAD_NAME) con un riferimento utente possibile creare un port right con un nome specificato dal chiamante, a patto che il nome non sia gi in uso nello spazio IPC e che questultimo non sia fast. Il chiamante pu specificare il nome passandone un puntatore nellargomento namep e settando il bit-field

162

Il sistema operativo Mac OS X

name nella struttura QoS (Quality of Service) passata. La dimensione del buffer specificata nel campo len della stessa struttura. Il kernel utilizza, se disponibile, un buffer preallocato della porta quando manda messaggi dal kernel; in questo modo un mittente di messaggi critici pu evitare di rimanere bloccato sullallocazione di memoria.

Figura 5-7

Allocazione di un port right

Lallocazione di un oggetto IPC include i seguenti passi: Alloca una struct ipc_object [osfmk/ipc/ipc_object.h]

dallappropriata zona per il tipo di IPC object. Il puntatore a questa struttura la 163

Il sistema operativo Mac OS X

rappresentazione

nel

kernel

della

porta

(struct

ipc_port

[osfmk/ipc/ipc_entry.h]). Inizializza il mutex nella struttura IPC object. Alloca una struct ipc_entry [osfmk/ipc/ipc_entry]. Questa

operazione prova in primo luogo di trovare una entry libera, nella tabella dellIPC space indicato, utilizzando lhint first free. Se non ci dovessero essere entries libere nella tabella, la tabella viene accresciuta. La routine mach_port_names() pu essere utilizzata per recuperare una lista delle porte, con i loro tipi, in uno specifico spazio IPC.

5.2.6 Implementazione del messaging


Andiamo ora ad esaminare in che modo il kernel gestisce lo scambio di messaggi. Dato il fatto che la IPC soggiace a molte delle funzionalit del Mach, ovvio che il messaging sia unoperazione molto frequente nei sistemi basati sul Mach. Non sorprende neanche che una implementazione Mach sia pesantemente ottimizzata, specie quella usata in un prodotto commerciale come il Mac OS X. La funzione kernel fondamentale del messaging la mach_msg_overwrite_trap() [osfmk/ipc/mach_msg.c], che contiene numerosi casi speciali che cercano di migliorare le prestazioni nelle varie situazioni. Una delle ottimizzazioni utilizzate lhandoff scheduling, che consiste nel trasferimento diretto del controllo del processore da un thread ad un altro. Un handoff pu essere eseguito sia dai mittenti che dai destinatari di una RPC. Per esempio, se un server thread attualmente bloccato in una receive call, un client thread pu passare la palla al server thread e bloccare se stesso in attesa della risposta. Similmente, quando il server pronto a mandare una risposta al client, pu passare il controllo al client thread e bloccarsi nellattesa della prossima richiesta. In questo modo anche possibile evitare di accodare e rimuovere dalla coda i messaggi, visto che un messaggio pu essere trasferito direttamente al destinatario. Nel Mach il passaggio del messaggio assicurato e preserva lordine: un messaggio non pu essere perso ed sempre ricevuto nellordine con il quale stato spedito. Tuttavia, il 164

Il sistema operativo Mac OS X

kernel consegna i messaggi spediti con i send-once rights fuori ordine e senza assicurarsi della disponibilit nella coda della porta ricevente. La figura 5-8 mostra una visione dinsieme semplificata (ossia priva di casi particolari) dellelaborazione da parte del kernel riguardante la spedizione di un messaggio. La figura 5-9 mostra lanalogo per la ricezione di un messaggio.

Figura 5-8

Spedizione di un messaggio IPC del Mach

165

Il sistema operativo Mac OS X

Figura 5-9

Ricezione di un messaggio IPC del Mach

5.3 Lo standard POSIX


La Single UNIX Specification definisce un set di interfacce IPC come parte delle estensioni X/Open System Interface (XSI). Le interfacce XSI IPC sono essenzialmente le stesse delle precedenti interfacce IPC del System V, che sono state supportate da un vasto numeri di sistemi UNIX (anche quelli non standardizzati). Il Mac OS X fornisce delle chiamate di sistema per i meccanismi IPC del System V riguardanti le code di messaggi, i semafori e la memoria condivisa. Tali specifiche sono un superset delle caratteristiche richieste per lo standard POSIX.1. 166

Il sistema operativo Mac OS X

Lo standard POSIX 1003.1b-1993 (POSIX93) ha introdotto una serie di interfacce IPC come parte delle estensioni realtime POSIX. Collettivamente conosciute come POSIX IPC, queste interfacce definiscono le funzioni per le code di messaggi, i semafori e la memoria condivisa107. In contrasto con la XSI IPC che utilizza delle chiavi come identificatori IPC, il POSIX usa nomi di stringa per gli oggetti IPC. La Single UNIX Specification regolamenta diversi aspetti dei nomi IPC ma lascia molti parametri liberi e quindi permette una libera implementazione. Non specificato se un nome IPC compare nel file system. Il Mac OS X non richiede che il nome sia presente nel file system e, se lo fosse, la sua presenza non modificherebbe il comportamento delle chiamate POSIX IPC. Il Mac OS X permette ad un IPC name di essere al massimo di 31 caratteri (compreso il carattere di terminazione NUL). Se un nome IPC inizia con il carattere slash (/), ogni chiamante di una funzione di apertura (come ad esempio sem_open() o shm_open()) con lo stesso nome si riferisce allo stesso oggetto IPC, fino a che il nome non viene rimosso. Se un nome IPC non inizia con il carattere slash, leffetto dipende dallimplementazione. Il Mac OS X tratta questo caso in modo identico a quello in cui il nome comincia con lo slash. Linterpretazione dei caratteri slash, a parte quello iniziale, allinterno dei nomi definito dallimplementazione. Il Mac OS X tratta un carattere slash in un nome IPC come se fosse un carattere qualsiasi. Un semaforo POSIX (con nome108) creato usando sem_open() e distrutto mediante sem_unlink(). La prima anche utilizzata per connettere il processo chiamante con un semaforo esistente, mentre la sem_close() chiude un semaforo aperto109. I semafori
Il Mac OS X 10.4 supportava solo i semafori e la memoria condivisa dello standard POSIX. Con lavvento del Mac OS X 10.5 Leopard, il sistema stato dichiarato completamente compatibile con POSIX. 108 Oltre ai semafori POSIX con nome, esistono anche semafori POSIX senza nome. Questi possono essere inizializzati e distrutti chiamando sem_init() e sem_destroy(). Queste due chiamate di sistema non sono supportate dal Mac OS X 10.4. 109 Queste funzioni sono analoghe alle open(), unlink() e close() utilizzate con i files. Infatti, cos come open(), anche la funzione sem_open() accetta i flags O_CREAT e O_EXCL per determinare se loggetto con nome
107

167

Il sistema operativo Mac OS X

POSIX sono contatori: unoperazione di lock su un semaforo decrementa il suo valore di uno, mentre una unlock lo incrementa. Nel senso pi semplice, un semaforo POSIX una variabile intera a cui si accede attraverso due operazioni atomiche: sem_wait() e sem_post(). Dato un semaforo aperto le due precedenti funzioni effettuano, rispettivamente, le operazioni di lock e unlock. Se il valore del semaforo zero quando chiamata la sem_wait(), il chiamante si blocca. Tale blocco pu essere interrotto da un segnale. Un segmento di memoria condivisa POSIX con nome pu essere creata (o aperta se preesistente) utilizzando shm_open() e cancellata con shm_unlink(), in modo analogo ai semafori. La prima ritorna un descrittore di file che pu essere mappato in memoria attraverso la chiamata di sistema mmap(). Nel momento in cui laccesso alla memoria non dovesse essere pi necessario, esso pu essere unmapped attraverso munmap() ed il descrittore pu essere chiuso con la funzione close(). Per questo gli oggetti di memoria condivisa POSIX assomigliano i files mappati in memoria. Notiamo che la dimensione iniziale di un nuovo segmento zero. Una dimensione specifica pu essere impostata usando ftruncate(), mentre le informazioni riguardanti un segmento esistente possono essere recuperate chiamando stat() sul descrittore di file ottenuto da shm_open().

deve essere creato o solo acceduto. Ad ogni modo, invece di descrittori di file interi, le funzioni dei semafori trattano puntatori a strutture sem_t.

168

Il sistema operativo Mac OS X

Capitolo 6
Il file system HFS+

Il formato di volume utilizzato per default nel Mac OS X lo Hierarchical File System Plus (HFS+). Questo ha sostituito il file system HFS (utilizzato fino al Mac OS 8.1) che a sua volta sositu il Macintosh File System (MFS) dei primi sistemi operativi Macintosh. Noto anche col nome di Mac OS X Extended, mantiene unarchitettura simile allHFS ma fornisce diversi benefici rispetto al suo predecessore.

6.1 Concetti fondamentali


Andiamo ora ad analizzare la terminologia e le strutture fondamentali inerenti lHFS+. Se definiamo un file system come uno schema per organizzare i dati su uno storage medium, il volume rappresenta una istanza di un file system. Un volume HFS+ pu occupare un intero disco o usarne solo una porzione, cio una slice o partition. I volumi HFS+ possono anche abbracciare diversi dischi o partizioni, anche se tale spanning a livello di device e non specifico dellHFS+, che continua a vedere un singolo volume logico. In un volume HFS+ lo spazio allocato nei files in unit fondamentali chiamate allocation blocks. Per ogni volume, la dimensione del blocco di allocazione un multiplo della sector size del supporto di memorizzazione110. I blocchi sono concettualmente numerati sequenzialmente. Limplementazione del file system indirizzi i contenuti del volume

Delle dimensioni comuni sono 512 bytes per i disk drives e 2KB per gli optical drives. La dimensione di default dellallocation block di 4KB, valore ottimale per limplementazione HFS+ del Mac OS X.

110

169

Il sistema operativo Mac OS X

utilizzando delle quantit a 32-bit rappresentate dal tipo u_int32_t nel kernel. La dimensione dellallocation block una propriet fondamentale di ogni volume. possibile scegliere una diversa dimensione al momento della creazione di uno nuovo file system HFS+, mediante il programma newfs_hfs, a patto di rispettare le seguenti regole: Deve essere una potenza del 2. Deve essere un multiplo della sector size dello storage device. Deve essere minore di MAXBSIZE, definito in sys/param.h ad 1MB111. possibile che la capacit di un volume non sia un multiplo della dimensione del suo blocco di allocazione. In tal caso ci sar uno spazio finale del volume che non sar coperto da nessun allocation block.

Figura 6-1

Un disco contenente due volumi HFS+

111

Non si tratta di una limitazione del file system HFS+, ma del programma newfs_hfs. Per superare questo limite, se davvero necessario, si dovr utilizzare una versione modificata del programma (o un programma sostitutivo) per creare il file system.

170

Il sistema operativo Mac OS X

Un blocco di allocazione non pu essere condiviso tra due files e neanche tra due forks dello stesso file112. Un extent una sequenza contigua di allocation blocks ed rappresentata dellHFS+ da una struttura dati extent descriptor (struct HFSPlusExtentDescriptor

[bsd/hfs/hfs_format.h]). Tale descrittore contiene una coppia di numeri: il numero del blocco da cui parte lextent ed il numero di blocchi contenuti in esso.
struct HFSPlusExtentDescriptor { u_int32_t startBlock; // first allocation block in the extent u_int32_t blockCount; // number of allocation blocks in the extent }; typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor; typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8];

Un array di otto extent descriptors costituisce un extent record. LHFS+ usa lextent record come lista dextent inline per i contenuti di un file, cio fino ad i primi otto extents di un file sono memorizzati come parte dei metadata di base del file. Per un file che contenga pi di otto extents, lHFS+ mantiene uno o pi extent records aggiuntivi, ma non inline nei metadata. Un file tradizionalmente equivalente ad un singolo stream di bytes. LHFS+ supporta byte-streams multipli per un file, con due streams speciali sempre presenti (anche se uno o entrambi possono essere vuoti): il data fork ed il resource fork. Ogni fork una parte distinta del file e pu essere percepita come un file a se stante. Una fork rappresentata nellHFS+ dalla struttura HFSPlusForkData [bsd/hfs/hfs_format.h].
struct HFSPlusForkData { u_int64_t logicalSize; // fork's logical size in bytes u_int32_t clumpSize; // fork's clump size in bytes u_int32_t totalBlocks; // total blocks used by this fork HFSPlusExtentRecord extents; // initial set of extents }; typedef struct HFSPlusForkData HFSPlusForkData;

Entrambe le forks hanno le proprie strutture HFSPlusForkData (e quindi lextent records) che sono memorizzate insieme ai metadata standard del file. La visione tradizionale di un file riguarda la sua data fork. Molti files nellistallazione tipica del Mac OS X hanno solo questa, in quanto la loro resource fork vuota. Un altro aspetto degno di nota che i nomi delle forks data e resource non possono essere

LUFS del BSD (compreso quello implementato nel Mac OS X) impiega un'altra unit di allocazione oltre al blocco: il fragment. Il frammento una frazione del blocco che permette la condivisione del block tra diversi files.

112

171

Il sistema operativo Mac OS X

cambiati. Ogni byte-stream aggiuntiva creata ha un proprio nome Unicode. Queste streams con nome possono avere contenuti arbitrari, anche se unimplementazione HFS+ pu limitare il quantitativo di dati che possono contenere. Cos come un allocation block un gruppo a dimensione fissa (per un dato volume) di settori contigui, un clump un gruppo a dimensione fissa di allocation blocks contigui. Anche se ogni clump un extent, non vero che ogni extent un clump. Quando si alloca spazio per una fork, unimplementazione HFS+ pu farlo in termini di clumps, invece di allocation blocks individuali, per evitare la frammentazione esterna.

6.1.1 B-Trees
LHFS+ utilizza i B-Trees per implementare le strutture dati critiche per lindexing, che permettono di localizzare sia il contenuto del file che i metadata residenti in un volume. Un B-Tree una generalizzazione di un albero di ricerca binario bilanciato. Mentre un albero binario ha un fattore di ramificazione di due, un B-Tree pu avere un fattore di ramificazione arbitrariamente grande. Questo possibile grazie alluso di nodi molto grandi: un nodo B-Tree pu essere pensato come una incapsulazione di vari livelli di un albero binario. Il fatto di avere dei fattori di ramificazioni molto grandi, comporta una loro altezza molto ridotta e quindi sono lideale nel caso di utilizzo in periferiche ad accesso costoso (come un disk drive). Nello specifico, lHFS+ utilizza una variante dei B+ Trees, che a loro volta sono una variante dei B-Trees. In un B+ Tree tutti i dati risiedono nei nodi foglia (esterni), con i nodi indice (interni) contenenti solo chiavi e puntatori ai sottoalberi. Di conseguenza i nodi foglia (leaf) ed indice (index) possono avere differenti formati e dimensioni. I nodi foglia, che giacciono tutti sullo stesso livello in un albero bilanciato, sono concatenati insieme in una lista per formare un sequence set. La implementazione dei B+ Trees nellHFS+ differisce da quella standard nella struttura dei nodi indice. In un B+ Tree standard, un index node I contenente N chiavi ha N+1 puntatori (uno per ognuno dei suoi N+1 figli). In particolare il primo (leftmost) puntatore punta al figlio (subtree) contenente le chiavi minori della prima chiave del nodo I. Nellimplementazione HFS+ tale puntatore 172

Il sistema operativo Mac OS X

non esiste, poich non esiste il sottoalbero contenente chiavi minori di I. Nonostante utilizzi diversi B-Trees con chiavi e formati differenti, limplementazione HFS+ utilizza la stessa struttura di base in tutti gli alberi. Di conseguenza la maggior parte delle operazioni sui diversi alberi possono essere eseguite con lo stesso set di funzioni. Andiamo ora ad analizzare alcune delle caratteristiche comuni ai vari B-Trees: Ogni B-Tree implementato come un file speciale che non mai visibile allutente ne accessibile attraverso interfacce standard. Diversamente dai files regolari che hanno due forks predefinite, un file speciale ha una sola fork. Fa eccezione il BTree Hot File Clustering che nonostante sia un file di sistema, implementato come file regolare visibile allutente e con due forks predefinite (anche se la fork resource vuota). Lo spazio totale in un file B-Tree concettualmente diviso in nodes della stessa dimensione. Ogni B-Tree ha una dimensione fissata del nodo che deve essere una potenza del 2 (dai 512 ai 32768 bytes). La dimensione determinata al momento della creazione del volume e non pu essere modificata senza riformattarlo. I nodi sono numerati sequenzialmente a partire da zero. Loffset di un nodo N in un dato B-Tree ottenuto moltiplicando N per la dimensione del nodo. Il numero di nodo rappresentato da un unsigned integre a 32-bit. Ogni B-Tree ha un singolo header node (di tipo kBTHeaderNode) che il primo nodo dellalbero. Ogni B-Tree ha zero o pi map nodes (di tipo kBTMapNode) che sono essenzialmente dei bitmaps di allocazione usati per tracciare quale nodo in uso e quale libero. La prima parte del bitmap di allocazione risiede nellheader node, quindi ne sono necessari uno o pi map nodes solo se lintero bitmap non rientra nello spazio dellheader. Ogni B-Tree ha zero o pi index nodes (di tipo kBTIndexNode) che contengono keyed pointer records che portano ad altri nodi indice o foglia. Gli index nodes sono anche chiamati internal nodes. Ogni B-Tree ha uno o pi leaf nodes (di tipo kBTLeafNode) che contiene keyed 173

Il sistema operativo Mac OS X

records contenenti i dati associati alle chiavi. Tutti i tipi di nodo posono contenere records di lunghezza variabile.

Figura 6-2a

La struttura di un nodo di un B-Tree HFS+

La struttura del nodo mostrata in figura 6-2a condivisa da tutti i tipi di nodo. C un descrittore di nodo struct BTNodeDescriptor [bsd/hfs/hfs_format.h] allinizio di ogni nodo. I campi bLink e fLink della struttura concatenano insieme nodi di tipo particolare (indicato dal campo kind). Subito dopo il descrittore c il records segment che contiene i records del nodo. Poich tali records possono essere di dimensioni differenti, la parte finale del nodo contiene una lista di offsets a 16-bit, ognuno dei quali 174

Il sistema operativo Mac OS X

loffset di un record a partire dallinizio del nodo. Lultima vode della lista loffset dello spazio non utilizzato (se non ci dovesse essere spazio inutilizzato, tale elemento persisterebbe e punterebbe a se stesso).

Figura 6-2b

La struttura di un nodo header di un B-Tree HFS+

La figura 6-2b mostra la struttura di un header node. In un B-Tree lheader node formato da tre records: Lheader record contenente informazioni generali sul B-Tree, come la dimensione del nodo, la sua profondit (o altezza dipende dai punti di vista), il numero del root node (se esistente), il numero di records foglia ed il numero totale di nodi.

175

Il sistema operativo Mac OS X

Lo user data record che fornisce 128 bytes di spazio per memorizzare informazioni arbitrarie associate allalbero. Di tutti i B-Trees HFS+, solo lHot File Clustering usa questa area. Il map record contenente una bitmap che indica, mediante i suoi bit, se un nodo nellalbero in uso oppure no. Un albero pu avere pi nodi di quelli rappresentati dal map record dellheader node. La somma delle dimensioni del descrittore di nodo (14 bytes), lheader record (106 bytes), lo user data record (128 bytes) e le offset entries (4*2 bytes) 256 bytes. Lo spazio restante rimane per il map record. Se dovesse essere necessario ulteriore spazio, lalbero usa i map nodes per ospitare le estensioni del bitmap. Se un albero ha uno o pi map nodes, il campo fLink dellheader node conterr il numero del map node successivo o zero se lultimo della lista. I campi bLink di tutti i map nodes, e quello dellheader node, sono sempre settati a zero. Mentre lheader ed i map nodes di un B-Tree contengono informazioni amministrative, i nodi indice e foglia contengono informazioni del file system (dipendenti dallo specifico BTree in questione). I records nei nodi indice e foglia hanno, inoltre, la stessa struttura generale (vedi figura 6-2c).

Figura 6-2c

La struttura di un record di un B-Tree HFS+

Allinizio della struttura del record c la lunghezza della chiave (keyLength), memorizzata con uno o due bytes in funzione del bit kBTBigKeysMask nel campo attributes dellheader (bit clear=1 byte, bit set=2 bytes). Immediatamente dopo la 176

Il sistema operativo Mac OS X

lunghezza c la chiave attuale. Il fatto che la key length rappresenti o meno la lunghezza della chiave attuale determinato sulle seguenti basi: Nel caso di un nodo foglia, keyLength rappresenta la actual key length. Nel caso di un nodo indice, keyLength rappresenta la actual key length se il bit kBTVariableIndexKeyMask settato nel campo attributes del nodo header. Se il bit kBTVariableIndexKeyMask non settato nel campo attributes del nodo header, la actual key length il valore costante contenuto nel campo maxKeyLength del nodo header. I nodi indice e foglia contengono solo records indice e foglia, rispettivamente. Poich si tratta di B+ Trees, i dati attuali sono memorizzati solo nei nodi foglia. I dati di un record indice si riducono ad un semplice numero di nodo (un puntatore ad un altro nodo indice o foglia). In altre parole, i nodi index costituiscono nel loro insieme un indice per effettuare ricerche arbitrarie tra i dati memorizzati nei nodi foglia. Una operazione fondamentale riguardante laccesso e la manipolazione di un B-Tree la key comparison. Unimportante propriet di un nodo B-Tree che tutti i suoi records sono memorizzati secondo lordine crescente delle loro chiavi. Per le chiavi semplici (come ad esempio degli interi) la comparazione si riduce ad una semplice comparazione numerica. Nel caso di chiavi pi complesse, come quelle utilizzate nei B-Trees dellHFS+, la presenza di svariate componenti comporta operazioni di comparazione pi complicate. I vari componenti delle chiavi complesse hanno, tipicamente, dei valori di precedenza assegnati. Quando due chiavi complesse (ovviamente dello stesso tipo) sono comparate, i componenti individuali sono comparati in ordine decrescente di precedenza: se una comparazione individuale produce una identit, la comparazione globale prosegue con la componente successiva; questo procedimento prosegue fino a che non si verifica una disequit o fino allesaurimento delle componenti, caso in cui le chiavi sono considerate uguali.

177

Il sistema operativo Mac OS X

Figura 6-3

Il contenuto di un ipotetico B-Tree HFS+

La figura 6-3 mostra un B-Tree ipotetico che usa delle chiavi integrali a lunghezza fissa, con altezza pari a 3: in generale i nodi foglia, ognuno dei quali allo stesso livello e quindi alla stessa altezza, hanno unaltezza assegnata di 1; un nodo indice immediatamente sopra le foglie ha 2 come altezza e cos via. Il nodo indice con laltezza massima il nodo radice, riferito dal campo rootNode dellheader record. Laltezza di ogni nodo memorizzata nel campo height del proprio descrittore: nellheader il campo height posto a zero mentre il campo treeDepth

178

Il sistema operativo Mac OS X

contiene laltezza dellalbero (ossia quella del root node). In un albero vuoto non c il nodo radice. Un nodo radice non deve essere necessariamente un nodo indice: se tutti i records sono contenuti allinterno di un singolo nodo, questo sar sia il nodo radice che lunico nodo foglia.

6.2 La struttura di un volume HFS+


La figura 6-4 mostra la struttura di un volume HFS+. A parte i files regolari e le directories, un volume HFS+ pu contenere le seguenti entit: Reserved areas presente allinizio ed alla fine del volume. Il volume header contenente una variet di informazioni sul volume, inclusa la posizione delle altre strutture chiave del volume. Alla fine del volume presente una copia di queste informazioni denominata alternate volume header. Il Catalog B-Tree che immagazzina i metadata di base per files e directories, incluso il primo extent record per ogni file. La struttura gerarchica del file system inoltre catturata nel Catalog B-Tree attraverso dei records che memorizzano le relazioni padre-figlio intercorrenti tra gli oggetti del file system. LExtent Overflow B-Tree che immagazzina gli extent records eccedenti per quei files che hanno pi di otto extents. LAttribute B-Tree che immagazzina gli attributi estesi per files e directories. LAllocation file che una bitmap contenente un bit per ogni allocation block, indicante se il blocco in uso o meno. Il private metadata folder utilizzato per implementare gli hard links e per memorizzare i files che sono stati cancellati mentre erano aperti

(/\xC0\x80\xC0\x80\xC0\x80\xC0\x80HFS+ Private Data). LHot Files B-Tree utilizzato dal meccanismo di ottimizzazione Hot File Clustering per registrare informazioni riguardo ai files acceduti frequentemente

(/.hotfiles.btree). Lo Startup file concepito per contenere informazioni arbitrarie che un sistema operativo pu utilizzare per eseguire il boot da un volume HFS+. 179

Il sistema operativo Mac OS X

I Journal files utilizzati per mantenere informazioni riguardo il file system journal (/.journal_info_block) ed il contenuto del journal stesso (/.journal). I Quota files utilizzati per mantenere informazioni concernenti le user quotas (/.quota.user) e le group quotas (/.quota.group) a livello del volume.

Figura 6-4

La struttura di un volume HFS+

6.2.1 Frammentazione
La frammentazione in un file system sempre stata un importante freno alle prestazioni, anche se i moderni file systems sono generalmente meno inclini a frammentarsi rispetto ai loro predecessori. Numerosi algoritmi e schemi sono stati incorporati allinterno dei file

180

Il sistema operativo Mac OS X

systems per ridurre la frammentazione, sia nella sua formazione che rimuovendo quella esistente. In un tipico scenario, un sistema operativo usa un disk drive in modo tale che lo spazio di memorizzazione del drive appaia come una sequenza di blocchi logicamente contigua. Le prestazioni dei moderni driver sono migliori quando le richieste di I/O hanno dimensioni maggiori. Una maggiore contiguit nellallocazione del file permette maggiori richieste di I/O (oltre a ridurre ogni CPU overheads), comportando quindi migliori prestazioni di I/O sequenziale. Appare quindi chiaro che la contiguit dei dati in un disco desiderabile. La frammentazione esiste in diverse forme, dipendenti dal contesto: User-level data fragmentation anche se un file contiguo sul disco, potrebbe contenere informazioni che non sono contigue a livello utente. Per esempio un documento word processor pu essere contiguo sul disco ma non nel modo in cui il word processor lo legge. Quantificare o gestire tale frammentazione unoperazione complessa, ma degna di nota, poich dipende dallapplicazione in questione, il formato del file ed altri fattori difficili da controllare. Internal fragmentation in un volume con blocchi di allocazione da 4KB, un file di 1 byte andrebbe ad utilizzare 4096 bytes su disco: di conseguenza i restanti 4095 bytes andrebbero sprecati (a meno di una crescita successiva delle dimensioni del file). Questo spreco di spazio quello che comunemente viene indicato come frammentazione interna. External fragmentation la frammentazione esterna quella a cui tutti si riferiscono quando parlano di frammentazione. Un file esternamente frammentato se non tutto il suo contenuto risiede in blocchi contigui al livello del volume. Possiamo considerare un frammento come sinonimo di un extent HFS+. In altre parole, un file non frammentato ha esattamente un extent: ogni extent addizionale introduce una discontinuit nel file.

181

Il sistema operativo Mac OS X

6.3 Particolarit dellHFS+


Di default, lHFS+ un file system case-preserving ma case-insensitive, nonostante il fatto che i file systems tradizionali UNIX siano case-sensitive. Per codificare i nomi dei files, delle directories e gli attributi estesi utilizza lUnicode. I nomi dei files e delle directories sono rappresentati dalla struttura HFSUnitStr255, che consiste di 16-bit seguiti da fino a 255 caratteri (di due bytes) Unicode.

6.3.1 Permessi
Il sistema dei permessi del file system HFS+ nello stile UNIX. Entrambe le strutture HFSPlusCatalogFile e HFSPlusCatalogFolder includono una struttura HFSPlusBSDInfo che incapsula le informazioni relative al possesso, i permessi ed il tipo del file.
struct HFSPlusBSDInfo { u_int32_t ownerID; u_int32_t groupID; u_int8_t adminFlags; u_int8_t ownerFlags; u_int16_t fileMode; union { u_int32_t iNodeNum; u_int32_t linkCount; u_int32_t rawDevice; } special; }; // // // // // // // owner ID 99 ("unknown") is treated as the user ID of the calling process (substituted on the fly) group ID 99 ("unknown") is treated as the owner ID of the calling process (substituted on the fly) superuser-changeable BSD flags, see chflags(2) owner-changeable BSD flags, see chflags(2) file type and permission bits

// indirect inode number for hard links // links that refer to this indirect node // device number for block/character devices

Mentre i permessi sono obbligatori in un volume root, possono essere deattivati su un volume HFS+ nonroot. Disabilitare i permessi assegna essenzialmente la propriet dei files e dei folders del volume ad un singolo user ID, il cosiddetto replacement user ID113. Questo pu essere esplicitamente indicato, altrimenti il kernel user UNKNOWUID, lo user ID sconosciuto (99). La propriet speciale di questultimo che verifica tutti gli user ID quando comparato per la determinazione dei diritti di possesso. La figura 6-5 mostra come limplementazione HFS+ del Mac OS X determina se un dato processo ha i diritti di possesso di un oggetto del file system.

La sostituzione puramente comportamentale. Ogni oggetto del file system mantiene il proprio owner ID originale. La struttura hfsmount mantiene in memoria il replacement ID.

113

182

Il sistema operativo Mac OS X

Figura 6-5

Algoritmo per la determinazione degli ownership rights su un file system object

Linstaller del Mac OS X usa un bill of materials (bom) per ogni pacchetto istallato. Si tratta di un file contenente una lista di tutti i files nella directory ed i metadata per ogni file. In particolare, il file bom contiene i permessi UNIX di ogni file.

6.3.2 Journaling
LHFS+ supporta il journaling dei metadata, incluse le strutture dati del volume, in cui le modifiche del file system sono registrate in un file di log (il journal) che implementato come un buffer circolare su disco114. Lo scopo primario di un journal di assicurare la
114

Siccome il meccanismo di journaling scrive le modifiche prima nel file journal e poi nei blocchi di destinazione (tipicamente in un buffer cache), si dice che compia un write-ahead journaling.

183

Il sistema operativo Mac OS X

consistenza del file system in caso di guasto. Alcune operazioni del file system semanticamente atomiche possono avere una quantit di I/O considerevole. Se si dovesse verificare un guasto prima che tutte le modifiche siano riportate sulla memoria fisica, il file system si troverebbe in uno stato di inconsistenza. Il journaling permette di raggruppare le modifche tra loro correlate in transactions registrate nel file journal. Il journalling stato inserito nellHFS+ introducendo nel kernel uno strato di journaling al livello del VFS [bsd/vfs/vfs_journal.c]. Questo strato esporta una interfaccia che pu essere usata da qualsiasi file system per incorporare il journal.

Figura 6-6

Interfaccia di journaling dello strato VFS nel Mac OS X

La figura 6-6 mostra una visione di insieme dellinterfaccia di journaling ed il suo utilizzo da parte dellHFS+. Notiamo che dal punto di vista del journal, le modifiche sono eseguite in unit di journal block size, che deve essere specificato al momento della creazione del journal. LHFS+ usa la dimensione del blocco fisico (tipicamente 512 bytes per i dischi) come dimensione del blocco journal. Quando lHFS+ ha bisogno di modificare uno o pi blocchi come parte di unoperazione, inizia una journal transaction per incapsulare le 184

Il sistema operativo Mac OS X

modifiche relative; quando tutti i blocchi nella transazione sono stati modificati, il file system termina la transazione. Il volume header in un HFS+ journaled contiene la posizione di una struttura dati chiamata journal info block, che a sua volta contiene la locazione e la dimensione del journal appropriato consistente in un header ed un buffer circolare. Sia linfo block che il journal sono memorizzati come files contigui (occupanti esattamente un extent ciascuno), precisamente in .journal_info_block e .journal rispettivamente. Questi files sono normalmente invisibili e non direttamente accessibili attraverso le APIs del file system. La figura 6-7 mostra la struttura, indipendente dallo specifico file system, dei files di journal.

Figura 6-7

Journal dellHFS+

185

Il sistema operativo Mac OS X

6.3.3 Deframmentazione on-the-fly


Quando un file utente viene aperto in un volume HFS+, il kernel controlla se il file qualificato per la deframmentazione al volo. Per essere definito eleggibile un file deve soddisfare le seguenti condizioni: Il file system non a sola lettura. Il file system journaled. Il file un file regolare. Il file non gi aperto. La file fork acceduta nonzero e non supera i 20MB di dimensione. La fork frammentata in otto o pi extents. Il sistema stato attivo per pi di tre minuti (per assicurasi che il bootstrp sia terminato). Se tutte queste condizioni sono verificate, il file rilocato dalla chiamata hfs_relocate() [bsd/hfs/hfs_readwrite.c], che cerca di trovare blocchi di allocazione contigui per il file. Un rilocazione riuscita comporta un file deframmentato.

6.3.4 Zona metadata


Limplementazione HFS+ del Mac OS X 10.3 introdusse una politica di allocazione che riserva spazio per diverse strutture metadata del volume, piazzandole una vicina allaltra, se possibile, in unarea (la metadata allocation zone) nella parte iniziale del volume. Fino a che lo spazio non scarseggia, lallocatore HFS+ non consuma lo spazio della zona metadata per lallocazione dei files normali. In modo simile, fino a che non la zona metadata non si esaurisce, lHFS+ allocher spazio per i metadata nella zona. Quindi vari tipi di metadata sono probabilmente adiacenti fisicamente ed hanno, in generale, unalta contiguit: la conseguente riduzione dei seek times andranno a migliorare le prestazioni di sistema. La policy abilitata per un volume (journaled di almeno 10GB) al runtime quando il volume montato. La struttura hfsmount memorizza dettagli runtime della zona metadata.

186

Il sistema operativo Mac OS X

Figura 6-8

Layout della zona metadata dellHFS+

6.3.5 Hot File Clustering


LHot File Clustering (HFC) uno schema adattativo di clustering multistage basato sulla premessa che i files acceduti di frequente siano ridotti sia in numero che in dimensione. Tali files sono chiamati hot files nel contesto dellHFC. Come parte dellHFC, limplementazione Apple dellHFS+ esegue le seguenti operazioni per migliorare le prestazioni durante laccesso agli hot files: Mantiene traccia dei blocchi letti dalle file forks per identificare gli hot files candidati. Dopo un periodo predeterminato di registrazione, analizza la lista dei candidati per determinare quali debbano essere spostati nellarea Hot File nellultima parte della zona metadata (figura 6-8). Se necessario, toglie il files esistenti dallarea Hot File per far spazio a files pi nuovi e pi caldi. Sposta gli hot files selezionati nellarea Hot File, allocando spazio contiguo allatto del loro trasferimento. LHFC memorizza la temperature di gni file, che definita come il rapporto del numero di bytes letti dal file durante il periodo di registrazione e la dimensione del file: di 187

Il sistema operativo Mac OS X

conseguenza maggiore la frequenza con cui il file acceduto, maggiore la sua temperatura. LHFS+ utilizza il campo clumpSize della struttura HFSPlusForkData per memorizzare la quantit di dati letti da una fork.

Figura 6-9

Schema delle trasizioni tra le varie fasi dellHot File Clustering

In ogni momento, lHFC su un volume si trova in uno delle seguenti fasi: HFC_DISABLED lHFC attualmente disabilitato, generalmente perch non si tratta di un volume root oppure se il volume stato smontato mentra lHFC era nella fase di registrazione. 188

Il sistema operativo Mac OS X

HFC_IDLE lHFC in attesa di iniziare la registrazione. Si entra in questa fase dopo che lHFC stato inizializzato durante il montaggio. HFC_BUSY una fase temporanea in cui si trova lHFC mentra lavora sulla transizione da una fase allaltra. HFC_RECORDING lHFC sta registrando le temperature dei files. HFC_EVALUATION lHFC ha finito di registrare le temperature e sta elaborando la nuova lista degli hot files. HFC_EVICTION lHFC sta rilocando i files pi freddi e vecchi per recuperare dello spazio nellarea Hot File. HFC_ADOPTION lHFC sta rilocando i files pi caldi e nuovi nellarea Hot File. Se la fase corrente adoption, eviction, idle o recording, la transizione alla fase successiva innescata come effetto collaterale di unoperazione di sincronizzazione sul volume. LHFC utilizza un B-Tree, chiamato Hot Files B-Tree, per tenere traccia degli hot files o, specificatamente, le file forks. A differenza degli altri files speciali dellHFS+, le extents di questalbero non sono memorizzate nel volume header: si tratta di un file su disco a cui il kernel accede attraverso il suo pathname /.hotfiles.btree. lHot Files B-Tree simile al Catalog B-Tree nel fatto che ogni fork tracciata come un Thread Record ed un Hot File Record.

189

Il sistema operativo Mac OS X

Figura 6-10 Figura 6-11

Ricerca nell Hot Files B-Tree

Restrizioni adottate dallHot File Clustering


Value 300 Notes The maximum number of allocation blocks that can be movedwhether for eviction or adoptionduring a single sync-triggered HFC operation. Adoption does not move only parts of a file; therefore, this effectively limits the size of a hot file to 1.2MB for the default allocation block size of 4KB. The maximum number of files that can be moved during adoption or eviction. The default temperature-recording duration. The default number of hot file sto track. The upper limit on the number of hot files to track. The upper limit on the size of file sto track during recording. Files larger than this will not be tracked. The threshold temperature for residency in the Hot File area.

Name HFC_BLKSPERSYNC

HFC_FILESPERSYNC HFC_DEFAULT_DURATION HFC_DEFAULT_FILE_COUNT HFC_MAXIMUM_FILE_COUNT HFC_MAXIMUM_FILESIZE HFC_MINIMUM_TEMPERATURE

50 60 h 1000 5000 10 MB 24

190

Bibliografia

[1]

The Apple Museum 2006 History URL: www.theapplemuseum.com/index.php?id=53

[2]

Amit Singh 2006 Mac OS X Internals: A System Approach Ed. Addison Wesley URL: www.osxbook.com

[3]

Apple Developer Connection 2005-2007 Guides Mac OS X URL: developer.apple.com/documentation/MacOSX/index.html

191