Sophie

Sophie

distrib > Mandriva > 9.1 > i586 > by-pkgid > f1098342ec4a2b28475e34123ce17201 > files > 529

howto-html-it-9.1-0.5mdk.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
 <TITLE>KernelAnalysis-HOWTO: Rapido tour del Linux Kernel</TITLE>
 <LINK HREF="KernelAnalysis-HOWTO-4.html" REL=next>
 <LINK HREF="KernelAnalysis-HOWTO-2.html" REL=previous>
 <LINK HREF="KernelAnalysis-HOWTO.html#toc3" REL=contents>
</HEAD>
<BODY>
<A HREF="KernelAnalysis-HOWTO-4.html">Avanti</A>
<A HREF="KernelAnalysis-HOWTO-2.html">Indietro</A>
<A HREF="KernelAnalysis-HOWTO.html#toc3">Indice</A>
<HR>
<H2><A NAME="s3">3. Rapido tour del Linux Kernel</A></H2>

<H2><A NAME="ss3.1">3.1 Cos'e' il Kernel?</A>
</H2>

<P>Il Kernel e' il cuore di ogni sistema operativo: e' quel software che permette
agli utenti di condividere ed utilizzare al meglio le risorse del sistema di
elaborazione.
<P>Il Kernel puo' essere visto come il principale software del Sistema Operativo
che potrebbe anche includere la gestione grafica: ad esempio sotto Linux (come
nella maggiorparte dei sistemi Unix-like), l'ambiente XWindow non fa parte
del Kernel di Linux perche' gestisce soltanto operazioni grafiche (grazie ad
istruzioni I/O eseguite in User Mode e accesso diretto alla scheda video).
Com'e' noto, invece, gli ambienti Windows (Win9x, WinME, WinNT, Win2K, WinXP,
e cosi' via) sono un mix tra ambiente grafico e kernel.
<H2><A NAME="ss3.2">3.2 Qual e' la differenza tra User Mode e Kernel Mode?</A>
</H2>

<H3>Introduzione</H3>

<P>Molti anni fa, quando i computers erano grandi come stanze, gli utenti
lanciavano le loro applicazioni con molta difficolta' e, a volte, il sistema
di elaborazione andava in crash.
<H3>Modi operativi</H3>

<P>Per evitare tale crash si e' pensato di introdurre 2 modi di funzionamento
(ancora presenti nei nuovi microprocessori):
<P>
<OL>
<LI>Kernel Mode: in cui la macchina opera con risorse critiche, come l'hardware
(IN/OUT o memory mapped), accesso diretto alla memoria, IRQ, DMA, e cosi' via.</LI>
<LI>User Mode: in cui gli utenti possono far girare le loro applicazioni senza
preoccuparsi di inchiodare il sistema.</LI>
</OL>
<P>
<PRE>
                      
               |          Applicazioni           /|\
               |         ______________           |
               |         | User Mode  |           |  
               |         ______________           | 
               |               |                  |  
Dettaglio      |        _______ _______           |   Astrazione
Implementazione|        | Kernel Mode |           |
               |        _______________           |
               |               |                  |
               |               |                  | 
               |               |                  |
              \|/          Hardware               |
</PRE>
<P>Kernel Mode impedisce alle applicazioni User Mode di danneggiare il sistema
o le sue caratteristiche.
<P>I moderni microprocessori implementano in hardware almeno 2 stati differenti.
Ad esempio l'architettura Intel possiede 4 stati che determinano il PL (Privilege
Level) permettendo quindi di avere gli stati 0,1,2,3 , con 0 usato in modo
Kernel.
<P>I sistemi Unix-like richiedono soltanto 2 livelli di privilegio e utilizzeremo
questo come punto di riferimento.
<H2><A NAME="ss3.3">3.3 Passaggio tra User Mode a Kernel Mode</A>
</H2>

<H3>Quando si salta?</H3>

<P>Una volta capito che ci sono 2 modi operativi differenti, dobbiamo vedere
quando avviene il ''salto'' tra uno e l'altro:
<P>
<OL>
<LI>Quando viene chiamata una System Call il task volontariamente inizia ad
eseguire del codice nello stato Kernel.</LI>
<LI>Quando arriva un IRQ (o eccezione) viene eseguito un gestore IRQ (o gestore
eccezione), dopodiche' il controllo ritorna al task interrotto come se non
fosse successo niente.</LI>
</OL>
<H3>System Calls</H3>

<P>Le System Calls sono come delle normali funzioni, soltanto che operano
in Kernel Mode per eseguire operazioni sull'OS (in effetti le System Calls
sono parte integrante dell'OS).
<P>Una System Call puo' essere chiamata quando:
<P>
<UL>
<LI>si deve accedere ad un device di I/O device o ad un file (come le SC read
e write )</LI>
<LI>e' richiesto un elevato livello di privilegio per accedere ad alcune informazioni
riservate (come il pid, o per cambiare la politica di scheduling e cosi' via)</LI>
<LI>e' richiesto un cambiamento di contesto esecutivo (come eseguire la ''fork''
o eseguire un'altra applicazione con la SC ''exec'').</LI>
<LI>si deve eseguire un particolare tipo di comando (come ''chdir'', ''kill",
''brk'', o ''signal'')</LI>
</UL>
<P>
<PRE>
                                 |                |
                         -------&gt;| System Call i  | (Accesso ai Devices)
|                |       |       |  [sys_read()]  |
| ...            |       |       |                |
| system_call(i) |--------       |                |
|   [read()]     |               |                |
| ...            |               |                |
| system_call(j) |--------       |                |  
|   [get_pid()]  |       |       |                |
| ...            |       -------&gt;| System Call j  | (Accesso alle strutture dati del kernel)
|                |               |  [sys_getpid()]|
                                 |                | 
 
    USER MODE                        KERNEL MODE
 
  
                        Funzionamento System Calls Unix
</PRE>
<P>Le System Calls teoricamente sono l'unica interfaccia disponibile in User
Mode per accedere alle risorse hardware. In realta' esiste la SC ''ioperm''
che permette ad un Task di accedere direttamente ad un device (benche' senza
IRQs).
<P>NOTA: Non tutte le funzioni di libreria ''C'' sono delle system call, solo
un piccolo sottoinsieme di esse.
<P>Segue una lista delle System Calls presenti nel Linux Kernel 2.4.17, ricavabili
dal file [ arch/i386/kernel/entry.S ]
<P>
<PRE>
        .long SYMBOL_NAME(sys_ni_syscall)       /* 0  -  old &quot;setup()&quot; system call*/
        .long SYMBOL_NAME(sys_exit)
        .long SYMBOL_NAME(sys_fork)
        .long SYMBOL_NAME(sys_read)
        .long SYMBOL_NAME(sys_write)
        .long SYMBOL_NAME(sys_open)             /* 5 */
        .long SYMBOL_NAME(sys_close)
        .long SYMBOL_NAME(sys_waitpid)
        .long SYMBOL_NAME(sys_creat)
        .long SYMBOL_NAME(sys_link)
        .long SYMBOL_NAME(sys_unlink)           /* 10 */
        .long SYMBOL_NAME(sys_execve)
        .long SYMBOL_NAME(sys_chdir)
        .long SYMBOL_NAME(sys_time)
        .long SYMBOL_NAME(sys_mknod)
        .long SYMBOL_NAME(sys_chmod)            /* 15 */
        .long SYMBOL_NAME(sys_lchown16)
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old break syscall holder */
        .long SYMBOL_NAME(sys_stat)
        .long SYMBOL_NAME(sys_lseek)
        .long SYMBOL_NAME(sys_getpid)           /* 20 */
        .long SYMBOL_NAME(sys_mount)
        .long SYMBOL_NAME(sys_oldumount)
        .long SYMBOL_NAME(sys_setuid16)
        .long SYMBOL_NAME(sys_getuid16)
        .long SYMBOL_NAME(sys_stime)            /* 25 */
        .long SYMBOL_NAME(sys_ptrace)
        .long SYMBOL_NAME(sys_alarm)
        .long SYMBOL_NAME(sys_fstat)
        .long SYMBOL_NAME(sys_pause)
        .long SYMBOL_NAME(sys_utime)            /* 30 */
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old stty syscall holder */
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old gtty syscall holder */
        .long SYMBOL_NAME(sys_access)
        .long SYMBOL_NAME(sys_nice)
        .long SYMBOL_NAME(sys_ni_syscall)       /* 35 */                /* old ftime syscall holder */
        .long SYMBOL_NAME(sys_sync)
        .long SYMBOL_NAME(sys_kill)
        .long SYMBOL_NAME(sys_rename)
        .long SYMBOL_NAME(sys_mkdir)
        .long SYMBOL_NAME(sys_rmdir)            /* 40 */
        .long SYMBOL_NAME(sys_dup)
        .long SYMBOL_NAME(sys_pipe)
        .long SYMBOL_NAME(sys_times)
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old prof syscall holder */
        .long SYMBOL_NAME(sys_brk)              /* 45 */
        .long SYMBOL_NAME(sys_setgid16)
        .long SYMBOL_NAME(sys_getgid16)
        .long SYMBOL_NAME(sys_signal)
        .long SYMBOL_NAME(sys_geteuid16)
        .long SYMBOL_NAME(sys_getegid16)        /* 50 */
        .long SYMBOL_NAME(sys_acct)
        .long SYMBOL_NAME(sys_umount)                                   /* recycled never used phys() */
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old lock syscall holder */
        .long SYMBOL_NAME(sys_ioctl)
        .long SYMBOL_NAME(sys_fcntl)            /* 55 */
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old mpx syscall holder */
        .long SYMBOL_NAME(sys_setpgid)
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old ulimit syscall holder */
        .long SYMBOL_NAME(sys_olduname)
        .long SYMBOL_NAME(sys_umask)            /* 60 */
        .long SYMBOL_NAME(sys_chroot)
        .long SYMBOL_NAME(sys_ustat)
        .long SYMBOL_NAME(sys_dup2)
        .long SYMBOL_NAME(sys_getppid)
        .long SYMBOL_NAME(sys_getpgrp)          /* 65 */
        .long SYMBOL_NAME(sys_setsid)
        .long SYMBOL_NAME(sys_sigaction)
        .long SYMBOL_NAME(sys_sgetmask)
        .long SYMBOL_NAME(sys_ssetmask)
        .long SYMBOL_NAME(sys_setreuid16)       /* 70 */
        .long SYMBOL_NAME(sys_setregid16)
        .long SYMBOL_NAME(sys_sigsuspend)
        .long SYMBOL_NAME(sys_sigpending)
        .long SYMBOL_NAME(sys_sethostname)
        .long SYMBOL_NAME(sys_setrlimit)        /* 75 */
        .long SYMBOL_NAME(sys_old_getrlimit)
        .long SYMBOL_NAME(sys_getrusage)
        .long SYMBOL_NAME(sys_gettimeofday)
        .long SYMBOL_NAME(sys_settimeofday)
        .long SYMBOL_NAME(sys_getgroups16)      /* 80 */
        .long SYMBOL_NAME(sys_setgroups16)
        .long SYMBOL_NAME(old_select)
        .long SYMBOL_NAME(sys_symlink)
        .long SYMBOL_NAME(sys_lstat)
        .long SYMBOL_NAME(sys_readlink)         /* 85 */
        .long SYMBOL_NAME(sys_uselib)
        .long SYMBOL_NAME(sys_swapon)
        .long SYMBOL_NAME(sys_reboot)
        .long SYMBOL_NAME(old_readdir)
        .long SYMBOL_NAME(old_mmap)             /* 90 */
        .long SYMBOL_NAME(sys_munmap)
        .long SYMBOL_NAME(sys_truncate)
        .long SYMBOL_NAME(sys_ftruncate)
        .long SYMBOL_NAME(sys_fchmod)
        .long SYMBOL_NAME(sys_fchown16)         /* 95 */
        .long SYMBOL_NAME(sys_getpriority)
        .long SYMBOL_NAME(sys_setpriority)
        .long SYMBOL_NAME(sys_ni_syscall)                               /* old profil syscall holder */
        .long SYMBOL_NAME(sys_statfs)
        .long SYMBOL_NAME(sys_fstatfs)          /* 100 */
        .long SYMBOL_NAME(sys_ioperm)
        .long SYMBOL_NAME(sys_socketcall)
        .long SYMBOL_NAME(sys_syslog)
        .long SYMBOL_NAME(sys_setitimer)
        .long SYMBOL_NAME(sys_getitimer)        /* 105 */
        .long SYMBOL_NAME(sys_newstat)
        .long SYMBOL_NAME(sys_newlstat)
        .long SYMBOL_NAME(sys_newfstat)
        .long SYMBOL_NAME(sys_uname)
        .long SYMBOL_NAME(sys_iopl)             /* 110 */
        .long SYMBOL_NAME(sys_vhangup)
        .long SYMBOL_NAME(sys_ni_syscall)       /* old &quot;idle&quot; system call */
        .long SYMBOL_NAME(sys_vm86old)
        .long SYMBOL_NAME(sys_wait4)
        .long SYMBOL_NAME(sys_swapoff)          /* 115 */
        .long SYMBOL_NAME(sys_sysinfo)
        .long SYMBOL_NAME(sys_ipc)
        .long SYMBOL_NAME(sys_fsync)
        .long SYMBOL_NAME(sys_sigreturn)
        .long SYMBOL_NAME(sys_clone)            /* 120 */
        .long SYMBOL_NAME(sys_setdomainname)
        .long SYMBOL_NAME(sys_newuname)
        .long SYMBOL_NAME(sys_modify_ldt)
        .long SYMBOL_NAME(sys_adjtimex)
        .long SYMBOL_NAME(sys_mprotect)         /* 125 */
        .long SYMBOL_NAME(sys_sigprocmask)
        .long SYMBOL_NAME(sys_create_module)
        .long SYMBOL_NAME(sys_init_module)
        .long SYMBOL_NAME(sys_delete_module)
        .long SYMBOL_NAME(sys_get_kernel_syms)  /* 130 */
        .long SYMBOL_NAME(sys_quotactl)
        .long SYMBOL_NAME(sys_getpgid)
        .long SYMBOL_NAME(sys_fchdir)
        .long SYMBOL_NAME(sys_bdflush)
        .long SYMBOL_NAME(sys_sysfs)            /* 135 */
        .long SYMBOL_NAME(sys_personality)
        .long SYMBOL_NAME(sys_ni_syscall)       /* for afs_syscall */
        .long SYMBOL_NAME(sys_setfsuid16)
        .long SYMBOL_NAME(sys_setfsgid16)
        .long SYMBOL_NAME(sys_llseek)           /* 140 */
        .long SYMBOL_NAME(sys_getdents)
        .long SYMBOL_NAME(sys_select)
        .long SYMBOL_NAME(sys_flock)
        .long SYMBOL_NAME(sys_msync)
        .long SYMBOL_NAME(sys_readv)            /* 145 */
        .long SYMBOL_NAME(sys_writev)
        .long SYMBOL_NAME(sys_getsid)
        .long SYMBOL_NAME(sys_fdatasync)
        .long SYMBOL_NAME(sys_sysctl)
        .long SYMBOL_NAME(sys_mlock)            /* 150 */
        .long SYMBOL_NAME(sys_munlock)
        .long SYMBOL_NAME(sys_mlockall)
        .long SYMBOL_NAME(sys_munlockall)
        .long SYMBOL_NAME(sys_sched_setparam)
        .long SYMBOL_NAME(sys_sched_getparam)   /* 155 */
        .long SYMBOL_NAME(sys_sched_setscheduler)
        .long SYMBOL_NAME(sys_sched_getscheduler)
        .long SYMBOL_NAME(sys_sched_yield)
        .long SYMBOL_NAME(sys_sched_get_priority_max)
        .long SYMBOL_NAME(sys_sched_get_priority_min)  /* 160 */
        .long SYMBOL_NAME(sys_sched_rr_get_interval)
        .long SYMBOL_NAME(sys_nanosleep)
        .long SYMBOL_NAME(sys_mremap)
        .long SYMBOL_NAME(sys_setresuid16)
        .long SYMBOL_NAME(sys_getresuid16)      /* 165 */
        .long SYMBOL_NAME(sys_vm86)
        .long SYMBOL_NAME(sys_query_module)
        .long SYMBOL_NAME(sys_poll)
        .long SYMBOL_NAME(sys_nfsservctl)
        .long SYMBOL_NAME(sys_setresgid16)      /* 170 */
        .long SYMBOL_NAME(sys_getresgid16)
        .long SYMBOL_NAME(sys_prctl)
        .long SYMBOL_NAME(sys_rt_sigreturn)
        .long SYMBOL_NAME(sys_rt_sigaction)
        .long SYMBOL_NAME(sys_rt_sigprocmask)   /* 175 */
        .long SYMBOL_NAME(sys_rt_sigpending)
        .long SYMBOL_NAME(sys_rt_sigtimedwait)
        .long SYMBOL_NAME(sys_rt_sigqueueinfo)
        .long SYMBOL_NAME(sys_rt_sigsuspend)
        .long SYMBOL_NAME(sys_pread)            /* 180 */
        .long SYMBOL_NAME(sys_pwrite)
        .long SYMBOL_NAME(sys_chown16)
        .long SYMBOL_NAME(sys_getcwd)
        .long SYMBOL_NAME(sys_capget)
        .long SYMBOL_NAME(sys_capset)           /* 185 */
        .long SYMBOL_NAME(sys_sigaltstack)
        .long SYMBOL_NAME(sys_sendfile)
        .long SYMBOL_NAME(sys_ni_syscall)               /* streams1 */
        .long SYMBOL_NAME(sys_ni_syscall)               /* streams2 */
        .long SYMBOL_NAME(sys_vfork)            /* 190 */
        .long SYMBOL_NAME(sys_getrlimit)
        .long SYMBOL_NAME(sys_mmap2)
        .long SYMBOL_NAME(sys_truncate64)
        .long SYMBOL_NAME(sys_ftruncate64)
        .long SYMBOL_NAME(sys_stat64)           /* 195 */
        .long SYMBOL_NAME(sys_lstat64)
        .long SYMBOL_NAME(sys_fstat64)
        .long SYMBOL_NAME(sys_lchown)
        .long SYMBOL_NAME(sys_getuid)
        .long SYMBOL_NAME(sys_getgid)           /* 200 */
        .long SYMBOL_NAME(sys_geteuid)
        .long SYMBOL_NAME(sys_getegid)
        .long SYMBOL_NAME(sys_setreuid)
        .long SYMBOL_NAME(sys_setregid)
        .long SYMBOL_NAME(sys_getgroups)        /* 205 */
        .long SYMBOL_NAME(sys_setgroups)
        .long SYMBOL_NAME(sys_fchown)
        .long SYMBOL_NAME(sys_setresuid)
        .long SYMBOL_NAME(sys_getresuid)
        .long SYMBOL_NAME(sys_setresgid)        /* 210 */
        .long SYMBOL_NAME(sys_getresgid)
        .long SYMBOL_NAME(sys_chown)
        .long SYMBOL_NAME(sys_setuid)
        .long SYMBOL_NAME(sys_setgid)
        .long SYMBOL_NAME(sys_setfsuid)         /* 215 */
        .long SYMBOL_NAME(sys_setfsgid)
        .long SYMBOL_NAME(sys_pivot_root)
        .long SYMBOL_NAME(sys_mincore)
        .long SYMBOL_NAME(sys_madvise)
        .long SYMBOL_NAME(sys_getdents64)       /* 220 */
        .long SYMBOL_NAME(sys_fcntl64)
        .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for TUX */
        .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
        .long SYMBOL_NAME(sys_gettid)
        .long SYMBOL_NAME(sys_readahead)        /* 225 */

</PRE>
<H3>Eventi IRQ</H3>

<P>Quando arriva un IRQ, il task in esecuzione viene interrotto per far eseguire
un gestore IRQ.
<P>Dopo l'esecuzione di tale gestore il controllo ritorna tranquillamente
al processo che non si accorge di nulla.
<P>
<PRE>

           
          Task in esecuzione
             |-----------|          (3)
ESECUZIONE   |   |       |  [stop esecuzione] IRQ Handler
NORMALE  (1) |   |       |     -------------&gt;|---------| 
             |  \|/      |     |             |gestisce |         
 IRQ (2)----&gt;| ..        |-----&gt;             | alcuni  |      
             |   |       |&lt;-----             |  dati   |       
RITORNO  (6) |   |       |     |             |  ..(4). |
ALLA NORMALE |  \|/      |     &lt;-------------|_________|
ESECUZIONE   |___________|  [ritorno al codice]
                                    (5)
               USER MODE                     KERNEL MODE

         Transizione User-&gt;Kernel Mode causata da evento IRQ
     
</PRE>
<P>I seguenti passi si riferiscono al diagramma precedente:
<P>
<OL>
<LI>Processo in esecuzione</LI>
<LI>Arriva un IRQ mentre il task sta' ''girando''</LI>
<LI>Il Task viene interrotto per chiamare un gestore Interrupt.</LI>
<LI>Il gestore Interrupt viene eseguito.</LI>
<LI>Il controllo ritorna al Task interrotto</LI>
<LI>Il Task torna ad essere eseguito dove era stato interrotto.</LI>
</OL>
<P>Un IRQ di particolare interesse e' quello relativo al Timer che arriva
ogni tot millisecondi per gestire
<P>
<OL>
<LI>Allarmi</LI>
<LI>Contatori di Task e di Sistema (usati dallo scheduler per decidere quando
un processo deve venir interrotto o per l'accounting)</LI>
<LI>Multitasking basato sul meccanismo di wake up dopo un periodo lungo TIMESLICE.</LI>
</OL>
<H2><A NAME="ss3.4">3.4 Multitasking</A>
</H2>

<H3>Funzionamento</H3>

<P>La punto chiave di ogni moderno sistema operativo e' il ''Task''. Il Task
e' un'applicazione che ''gira'' in memoria e codivide tutte le risorse del
sistema (inclusi CPU e Memoria) con gli altri Tasks.
<P>Questa ''condivisione di risorse'' viene gestita dal meccanismo di MultiTasking.
Ogni tot (''timeslice'') millisecondi avviene il cambiamento di contesto (Task
Switching'') grazie al quale gli utenti hanno l'illusione di possedere tutte
le risorse; se consideriamo un solo utente si avra' invece l'illusione di poter
eseguire piu' Tasks nello stesso istante.
<P>Per implementare il Multitasking i Task utilizzano una variabile ''state''
che puo' assumere i valori:
<P>
<OL>
<LI>READY, pronto per l'esecuzione</LI>
<LI>BLOCKED, in attesa di una risorsa</LI>
</OL>
<P>Lo stato del Task viene gestito dalla presenza o meno dello stesso nella
lista relativa: 
<P>
<UL>
<LI>lista READY</LI>
<LI>lista BLOCKED</LI>
</UL>
<H3>Cambiamento di contesto (Task Switching)</H3>

<P>La commutazione da un Task ad un altro si chiama ''Task Switching''. Molti
elaboratori hanno una istruzione hardware che esegue automaticamente questa
operazione. Il Task Switching avviene nei seguenti casi:
<P>
<OL>
<LI>Dopo che il tempo ''Timeslice' si e' esaurito</LI>
<LI>Quando un Task deve rimanere in attesa di un device *</LI>
</OL>
<P>In entrambi i casi abbiamo bisogno di schedulare un nuovo processo pronto
per l'esecuzione (dalla ''Ready List'') ed eseguirlo.
<P>* Questo serve ad evitare la ''Busy Form Waiting'', cioe' l'esecuzione
inutile di un loop del processo in attesa della risorsa.
<P>Il Task Switching viene gestito dall'entita' ''Schedule''.
<P>
<PRE>
 
Timer    |           |
 IRQ     |           |                            Schedule
  |      |           |                     ________________________
  |-----&gt;|   Task 1  |&lt;------------------&gt;|(1)Scegli un nuovo Task |
  |      |           |                    |(2)Task Switching       |
  |      |___________|                    |________________________|   
  |      |           |                               /|\
  |      |           |                                | 
  |      |           |                                |
  |      |           |                                |
  |      |           |                                |      
  |-----&gt;|   Task 2  |&lt;-------------------------------|
  |      |           |                                |
  |      |___________|                                |
  .      .     .     .                                .
  .      .     .     .                                .
  .      .     .     .                                .
  |      |           |                                |
  |      |           |                                |
  ------&gt;|   Task N  |&lt;--------------------------------
         |           |
         |___________| 
    
            Task Switching basato sul TimeSlice
 
</PRE>
<P>Un tipico Timeslice per Linux e' di circa 10 ms (in alcune architetture
1 ms).
<P>
<PRE>

 

 |           |            
 |           | Accesso     _____________________________
 |   Task 1  |-----------&gt;|(1) Accoda richiesta risorsa |
 |           | Risorsa    |(2) Marca Task come bloccato |
 |           |            |(3) Scegli un Task Pronto    |
 |___________|            |(4)    Task Switching        |
                          |_____________________________|
                                       |
                                       |
 |           |                         |
 |           |                         |
 |   Task 2  |&lt;-------------------------
 |           |  
 |           |
 |___________|
 
     Task Switching basato sull'attesa di una risorsa
 
</PRE>
<H2><A NAME="ss3.5">3.5 Microkernel vs Monolitico OS</A>
</H2>

<H3>Indtroduzione</H3>

<P>Fino adesso abbiamo visto i cosiddetti OS Monolitici, ma esiste anche un'altra
famiglia di OS, quella basata sui ''Microkernel''.
<P>Un OS basato su Microkernel utilizza i Tasks, non solo per i processi in
User Mode, ma anche come gestori del Kernel, come il Floppy-Task, l'HDD-Task,
il Net-Task e cosi' via. Alcuni esempi sono Amoeba e Mach. 
<H3>PRO e CONTRO degli OS basati su Microkernel</H3>

<P>PRO:
<P>
<UL>
<LI>L'OS e' piu' semplice da gestire perche' il Task e' l'unita' base di tutti
i devices: quindi per gestisce ad esempio la rete basta modificare il Net-Task
(in teoria e se non e' necessaria una modifica strutturale).</LI>
</UL>
<P>CONTRO:
<P>
<UL>
<LI>Le prestazioni sono peggiori rispetto agli OS Monolitici in quanto e' necessario
un periodo di 2*TASK_SWITCHING in piu' per gestire i devices (il primo per
entrare nel Task mentre il secondo per ritornare al processo interrotto): in
effetti questo tempo e' assolutamente necessario nel caso di sistema Monolotico.</LI>
</UL>
<P>La mia opinione personale e' che gli OS Microkernel sono un buon esempio
didattico (come Minix) ma non sono ''ottimali'' (cioe' partono gia' male come
prestazioni) quindi non sono da considerarsi come buoni OS. 
<P>Linux utilizza alcuni Tasks, chiamati "Kernel Threads" per implementare un
mini struttura microkernel, laddove e' evidente che le il tempo di accesso
di un Task Switching sia notevolmente trascurabile (come ''kswapd'', che serve
per recuperare pagine dalla memoria di massa).
<H2><A NAME="ss3.6">3.6 Rete</A>
</H2>

<H3>Livelli ISO OSI</H3>

<P>Lo Standard ISO-OSI descrive un'architettura di rete con i seguenti livelli:
<P>
<OL>
<LI>Livello Fisico (esempi: PPP ed Ethernet)</LI>
<LI>Livello Data-link (esempi: PPP ed Ethernet)</LI>
<LI>Livello di Rete (esempi: IP, e X.25)</LI>
<LI>Livello di Transporto (esempi: TCP, UDP)</LI>
<LI>Livello di Sessione (esempio: SSL)</LI>
<LI>Livello di Presentazione (esempio: codifica binary-ascii sul protocollo
FTP)</LI>
<LI>Livello Applicazione (esempio: Netscape)</LI>
</OL>
<P>I primi 2 livelli sono di solito implementati in hardware mentre i livelli
successivi in software (o in firmware per i routers).
<P>Un OS e0 capace di gestire molti protocolli: uno di questi e' il TCP/IP
(il piu' importante sui livelli 3-4).
<H3>Che cosa fa il kernel?</H3>

<P>Il Kernel non conosce nulla dei primi 2 livelli
<P>In RX l'OS:
<P>
<OL>
<LI>Gestisce il dialogo a basso livello con i devices (come schede ethernet
o modem) ricevendo i pacchetti dall'hardware,</LI>
<LI>Costruisce ''pacchetti'' TCP/IP partendo da ''frames" (come Ethernet o PPP),
 </LI>
<LI>Converte i ''pacchetti in ''sockets'' passandoli al giusto applicativo
(grazie al numero di porta) oppure</LI>
<LI>Instrada i ''pacchetti'' nella giusta coda</LI>
</OL>
<P>
<PRE>
frames         pacchetti            sockets
NIC ---------&gt; Kernel ----------&gt; Applicazione
                  |    pacchetti 
                  --------------&gt; Instradamento
                        - RX - 
</PRE>
<P>Nello stadio di TX l'OS:
<P>
<OL>
<LI>Converte i ''sockets'' oppure </LI>
<LI>I dati accodati in ''pacchetti'' TCP/IP</LI>
<LI>Espande i ''pacchetti" in ''frames'' (come Ethernet o PPP)</LI>
<LI>Manda i ''frames'' utilizzando i devices Hardware</LI>
</OL>
<P>
<PRE>
sockets       packets                     frames
Application ---------&gt; Kernel ----------&gt; NIC
              packets     /|\    
Forward  -------------------
                        - TX -  

</PRE>
<H2><A NAME="ss3.7">3.7 Memoria Virtuale</A>
</H2>

<H3>Segmentazione</H3>

<P>La Segmentazione e' il primo metodo per risolvere i problemi di allocazione
di memoria: questa tecnica permette di compilare il codice sorgente senza preoccuparsi
di dove i dati verranno eseguiti o memorizzati. In effetti questa feature e'
di grande aiuto nello sviluppare di applicazioni in modo indipendente dall'OS
e dall'Hardware.
<P>
<PRE>
     
            |       Stack          |
            |          |           |
            |         \|/          |
            |    Spazio Libero     | 
            |         /|\          |     Segmento &lt;---&gt; Processo
            |          |           |
            |        Heap          |
            |Dati non inizializzati|
            |  Dati inizializzati  |
            |       Codice         |
            |______________________|  
 
                   Segmento
</PRE>
<P>Possiamo dire che un segmento e' la trasposizione logica di un'applicazione
in memoria, o anche l'immagine dell'applicazione.
<P>Quando si programmiamo non ci interessiamo di dove esattamente i dati vadano
a finire in memoria, ci preoccupiamo soltanto dell'offset all'interno del segmento
(quindi dell'applicazione).
<P>Siamo soliti attribuire quindi, un Segment ad ogni Processo e viceversa.
In Linux questo non e' vero fino in fondo, in quanto vengono usati soltanto
4 segmenti per il Kernel e tutti i Processi.
<H3>Problemi della Segmentazione</H3>

<P>
<PRE>
 
                                 ____________________
                          -----&gt;|                    |-----&gt;
                          | IN  |     Segmento A     | OUT
 ____________________     |     |____________________|   
|                    |____|     |                    |   
|     Segmento B     |          |     Segmento B     |
|                    |____      |                    |   
|____________________|    |     |____________________|   
                          |     |     Segmento C     |   
                          |     |____________________|
                          -----&gt;|     Segmento D     |-----&gt; 
                            IN  |____________________| OUT 
 
                     Problema della Segmentazione

</PRE>
<P>Nel diagramma vogliamo disallocare i processi A e D ad allocare il processo
B. 
<P>Come si puo' vedere ci sarebbe abbastanza spazio per B, ma in pratica non
possiamo splittarlo in 2 pezzi e quindi NON POSSIAMO caricarlo (manca memoria!).
<P>La ragione di fondo di cio' e che i segmenti puri sono aree contigue proprio
perche' sono aree logiche (di processo) e quindi non possono essere divise.
<H3>Paginazione</H3>

<P>
<PRE>
 
             ____________________
            |     Pagina 1       |
            |____________________|
            |     Pagina 2       |
            |____________________| 
            |      ..            |     Segmento &lt;---&gt; Processo    
            |____________________|
            |     Pagina n       |
            |____________________|
            |                    |
            |____________________|
            |                    |
            |____________________|  
 
                   Segmento  
 
</PRE>
<P>La Paginazione divide la memoria in &quot;N&quot; pezzi, tutti a lunghezza
fissa.
<P>Un processo puo' essere caricato in una o piu' pagine. Quando un processo
viene disallocato, tutte le sue pagine vengono liberate (vedi Problema della
Segmentazione, prima).
<P>La Paginazione viene sfruttata anche per un altro importante scopo: lo
"Swapping": se una pagina infatti non e' presente in memoria fisica viene generata
un'ECCEZIONE , che fara' cercare al Kernel una pagina in memoria di massa.
Questo meccanismo permette all'OS di caricare piu' applicazioni rispetto a
quelle realmente caricabili soltanto in memoria fisica.
<H3>Problema della Paginazione</H3>

<P>
<PRE>
             ____________________
   Pagina X |     Processo Y     |
            |____________________|
            |                    |
            |       SPAZIO       |
            |    INUTILIZZATO    |
            |____________________|  
   
          Problema della Paginazione
 
</PRE>
<P>Nel diagramma possiamo notare qual e' il problema della Paginazione: quando
un Processo Y viene caricato nella Pagina X, TUTTO la spazio di memoria viene
allocato, cosicche' il rimanente spazio in fondo alla pagina rimanga inutilizzato.
<H3>Segmentazione Paginata</H3>

<P>Come possiamo risolvere i problemi di segmentazione e paginazione? Utilizzando
entrambe le politiche.
<P>
<PRE>
 
                                  |      ..            |
                                  |____________________|
                            -----&gt;|      Pagina 1      |
                            |     |____________________|
                            |     |      ..            |
 ____________________       |     |____________________|
|                    |      |----&gt;|      Pagina 2      |
|     Segmento X     |  ----|     |____________________|
|                    |      |     |       ..           |
|____________________|      |     |____________________|
                            |     |       ..           |
                            |     |____________________|
                            |----&gt;|      Pagina 3      |
                                  |____________________|
                                  |       ..           |
 
</PRE>
<P>Il Processo X, identificato dal Segmento X, viene diviso in 3 pezzi ognino
poi caricato in una pagina.
<P>Non abbiamo:
<P>
<OL>
<LI>Problemi di Segmentazione perche' allochiamo per Pagine, quindi liberiamo
anche per Pagine e gestiamo lo spazio libero in maniera ottimale.</LI>
<LI>Problemi di Paginazione: soltanto l'ultima pagina lascia dello spazio inutilizzato,
ma possiamo decidere di utilizzare delle pagine molto piccole, ad esempio lunghe
4096 bytes (perdendo cosi' al massimo 4096*N_Tasks bytes) e attuando una allocazione
di tipo gerarchico (con 2 o 3 levelli di paginazione)</LI>
</OL>
<P>
<PRE>
 
 

                          |         |           |         |
                          |         |   Offset2 | Valore  |
                          |         |        /|\|         |
                  Offset1 |         |-----    | |         |
                      /|\ |         |    |    | |         |
                       |  |         |    |   \|/|         | 
                       |  |         |    ------&gt;|         |
                      \|/ |         |           |         |
 Indirizzo Base ---------&gt;|         |           |         |
 Paginazione              | ....... |           | ....... |
                          |         |           |         |    
 
                      Paginazione Gerarchica
</PRE>
<HR>
<A HREF="KernelAnalysis-HOWTO-4.html">Avanti</A>
<A HREF="KernelAnalysis-HOWTO-2.html">Indietro</A>
<A HREF="KernelAnalysis-HOWTO.html#toc3">Indice</A>
</BODY>
</HTML>