Sophie

Sophie

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

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">Next</A>
<A HREF="KernelAnalysis-HOWTO-2.html">Previous</A>
<A HREF="KernelAnalysis-HOWTO.html#toc3">Contents</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">Next</A>
<A HREF="KernelAnalysis-HOWTO-2.html">Previous</A>
<A HREF="KernelAnalysis-HOWTO.html#toc3">Contents</A>
</BODY>
</HTML>