1. Primers controls

1.1. SIGSTOP/SIGCONT, foreground/background, thread_suspend/thread_resume

SIGSTOP/SIGCONT, foreground/background, thread_suspend/thread_resume

  1. Quines semblances hi ha entre SIGSTOP/SIGCONT i thread_suspend/thread_resume? Explica-les

    Resposta

    Són dues maneres de gestionar l’execució dels processos i threads de Linux (SIGSTOP/SIGCONT) i els threads de Mach (thread_suspend/thread_resume). Ens permeten aturar i permetre la seva execució.

  2. Quines diferències hi ha entre SIGSTOP/SIGCONT i thread_suspend/thread_resume? Explica-les

    Resposta

    SIGSTOP/SIGCONT es basen en signals enviats - amb la crida kill - als processos/threads, que provoquen que la seva execució s’aturi o pugui continuar. Thread_supend/thread_resume es basen en crides a sistema específiques de Mach. Diversos SIGSTOP es perden, perquè no hi ha un comptador de suspend, en canvi a Mach, thread_suspend incrementa el comptador de suspend i només quan el comptador es zero, el thread pot executar-se.

  3. Quines semblances hi ha entre foreground/background i thread_resume? Explica-les

    Resposta

    Les dues funcionalitats permeten l’execució del procés/thread indicat.

  4. Quines diferències hi ha entre foreground/background i thread_resume? Explica-les

    Resposta

    fg/bg estan relacionades amb el terminal, fg posa el procés en primer pla al terminal. bg el posa en segon pla. thread_resume només s’aplica a fluxos i no interactua amb el terminal.

  5. Explica una situació en la qual es vegi clara la utilitat de fer SIGSTOP i background (bg) a un procés

    Resposta

    Estem executant una aplicació de càlcul, o que utilitza gràfics o finestres
    (podria ser un editor de text que obri la seva pròpia finestra per exemple)

    $ gedit prova.c

    I volem recuperar el control del terminal per executar altres comandes. Traiem
    el gedit del primer pla del terminal:

    ^Z
    $ <<< i executem les comandes que volem>>>

    En qualsevol moment podem fer

    $ bg
    per posar l'editor en segon pla i continuar editant el prova.c a la finestra
    de l'editor i continuar executant altres comandes al terminal.

    No serveix aquesta resposta:

    Estem editant un fitxer en el terminal amb "vi prova.c" i volem executar una comanda no relacionada, per veure/fer alguna acció sobre el sistema o altres processos. Enlloc d’obrir un altre terminal, podem fer

     <<<editem un fitxer (prova.c)>>>
       ^Z
    $ <<<executem la comanda>>>
    $ fg   <<<tornem al vi>>>

    perquè la pregunta demana un ús de bg i en aquest cas el vi en el terminal no
    es pot posar en bg, perquè demana entrada/sortida i necessitarà estar en fg.

1.2. Espais d’acdreces i més …​

Tenim dos processos corrent en el sistema, que contenen la mateixa aplicació, i, mirant el seu espai d’adreces amb la comanda de Linux “pmap” veiem el següent per a cadascun, quan sabem que aproximadament són en el mateix punt de l’execució. En aquests mapes de memòria les mides de les regions estan en KBytes:
proc1
proc2

  1. Quina penseu que és la principal diferència entre ells? En aquesta diferència, quina participació hi té el procés de compilació?

    Resposta

    Pel fet que en l’espai d’adreces del 1r apareixen llibreries compartides i en el del segon no, la diferència és que el primer executa un fitxer binari dinàmic i el segon un estàtic.

    El procés de compilació per defecte sol generar fitxers binaris dinàmics, mentre que si fem servir l’opció "-static" generarem un fitxer binari estàtic.

  2. Parlem d’alguns detalls:

    1. Les adreces on tenim proc1 i proc2 són molt diferents. Dóna una explicació a per què són tan diferents

      Resposta

      Al carregar un fitxer binari estàtic, s’utilitzen les adreces indicades en el mateix fitxer, habitualment baixes (0x400000 al procés proc2 vist). En canvi, al carregar binaris dinàmics, és el sistema operatiu el que decideix l’adreça, que pot canviar entre execucions i acostumen a ser més altes (com al proc, 0x55cffab59000).

    2. Segons els permisos de les regions, quines regions de memòria tenen proc1 i proc2 (fixa’t en les regions de Mapping proc1 i Mapping proc2 exclusivament)? Pots identificar quines són de codi i quines de dades? Entre les de dades, pots distingir-les segons alguna propietat?

      Resposta

      Tenen 5 regions de codi i dades

        offset
       - 0000   r--p capçalera del fitxer
       - 1000   r-xp codi - executable
       - 3000   r--p separació entre codi i dades(?)
       - 3000   r--p dades de només lectura - constants
       - 4000   rw-p variables globals de lectura/escriptura
    3. En el procés de proc1, què són libc-2.31.so i ld-2.31.so?

      Resposta

      Són les llibreries compartides de les que depèn…​ la llibreria de C i el
      carregador de Linux.

    4. Per la regió de mida aproximada 2002500 bytes…​

      1. Quina quantitat de dades s’han accedit realment fins aquest punt de l’execució?

        Resposta

        (no eren 2002500 bytes, sinó KBytes, però la resposta és la mateixa)

        s’han accedit RSS KB (o Referenced) → 918004 o 918008 KBytes

      2. Aquesta quantitat de dades que hem accedit, s’ha fet per llegir-les o escriure-les? Com ho saps?

        Resposta

        Per escriptura, perquè tots els KBytes estan "dirty", modificats.

    5. Què és la regió [heap]?

      Resposta

      la regió de heap és on s’allotjen les dades dinàmiques (malloc/free)

    6. Què és la regió [stack]?

      Resposta

      la regió de stack és on es guarden les variables locals de les funcions i les
      adreces de retorn quan es fan crides a funció.

1.3. Abstraccions

Observa detingudament el dibuix adjunt i respon a les preguntes raonadament.

  1. Quina abstracció creus que representen els cubs?

    Resposta

    Són threads, cadascun dels cubs emmagatzema registres (estats del processador), ressaltant especialment la pila (SP) i el comptador de programa (PC) que apunta al codi de programa, compartit per tots els threads. El fet que dos PCs apuntin a la mateixa línia no és cap problema, car tots dos threads poden executar el mateix codi.

  2. Anomena una crida al sistema que serveixi per crear aquestes abstraccions. Especifica de quin sistema operatiu.

    Resposta

    Per exemple, kern_return_t thread_create(task_t parent_task, thread_act_t *child_act); de macOS

  3. Els cubs formen part d’una altra abstracció. Quina?

    Resposta

    Els threads són els fluxos d’execució d’una task o d’un procés.

  4. Anomena una crida al sistema que serveixi per crear aquesta abstracció. Especifica de quin sistema operatiu

    Resposta

    Per exemple, kern_return_t task_create (mach_port_t parent_tas, boolean_t inherit_memory, mach_port_t* child_task); de Hurd

cubs

1.4. Puzzle de codi

  1. Tenim aquestes peces del codi de creació d’un BSD thread a macOS que inclou l’assignació de memòria per a la pila del nou thread. Ordena’ls en l’ordre que consideris correcte. Raona breument la teva elecció.
    puzzle codi

    Resposta

    L’enunciat parla explícitament de la creació d’un thread al qual assignem memòria, per tant haurem de començar amb el tros de codi E (creació del thread) i haurem d’acabar amb el tros de codi A (represa del thread). En mig hem de demanar memòria i assignar-li proteccions, per tant, el tros de codi B (les proteccions) anirà just abans d’A. Queda per decidir si cridem primer a vm_map (D) o a vm_allocate ©. Teniu la pista en el control d’error de C, si l’anterior syscall ha retornat error, llavors demana memòria, això implica que el primer intent ha estat infructuós. En conseqüència, el primer intent ha estat amb vm_map.
    En resum, la seqüència és E, D, C, B, A.

1.5. Afinitats

En un sistema Linux, obtenim la següent informació:

afinitats

  1. El programa a.out té dos processos que executen sengles loops idèntics de N iteracions. Escriu el tros de codi del fill que permet tenir aquesta thread affinity.

    Resposta

    El fill és el procés (no pas thread) amb el pid més alt. En aquest cas el 115947 ha d’executar-se als processadors (PU) 0 i 5.

    cpu_set_t set;
    CPU_ZERO(&set);
    CPU_SET(0, &set);
    CPU_SET(5, &set);
  2. Fem 3 execucions d’aquest programa amb les següents configuracions d’afinitat:
    a) Pare i fill al mateix processador (al 0).
    b) Pare i fill a diferents processadors, al mateix core (al 0 i al 1).
    c) Pare i fill a diferents processadors, diferent core (0 i 3).
    Ordena les 3 execucions de menor a major temps real d’execució. Raona la teva resposta

    Resposta

    Són dos processos (que no threads), que no comparteixen memòria (l’enunciat no diu res que així ho indiqui) i tots dos estan executant un llarg loop (consum de cpu). Per tant, el cas pitjor serà si executem al mateix processador i mateix core (a). El cas millor serà el (c), diferents processadors i diferent core (no es trepitgen la cache) i el cas intermedi serà el (b) a on cadascú té un processador (PU) però han de compartir L1 i L2.
    En resum c<b<a

1.6. Abstraccions a Mach

  1. Enumera i explica tres abstraccions de Mach. Indica una crida al sistema
    relacionada amb cadascun dels tres conceptes.

    Resposta

    Hi ha 5 cinc conceptes fonamentals o programming abstractions a Mach. Aquestes primitives són: Task, Thread, Port, Message i Memory Object. Expliquem nom és les tres primeres amb un exemple de syscall relacionada.

    1. Task: el procés cl`assic de Unix, a Mach es divideix en dos. La part que fa de contenidor de recursos, tals com memoria virtual o ports de comunicacions, se’n diu task. Es una entitat passiva, no s’executa a cap processador.

      kern_return_t
      task_create(mach_port_t parent_task,
                  boolean_t inherit_memory,
                  mach_port_t* child_task);
    2. Thread: és el segon component del procés. La part activa. L’entorn d’execució d’una task. Cada task pot suportar més d’un thread executant-se concurrentment, tots compartint els recursos de la task. Tots els threads tenen el mateix espai d’adreces de memòria virtual (VM), però es diferencien en l’estat d’execució, format per un conjunt de registres, tals com l'stack pointer (SP) i el programm counter (PC).

      kern_return_t
      thread_create(mach_port_t parent_task,
                    mach_port_t* child_thread);
    3. Port: el canal de comunicacions mitjan ̧cant el qual es comuniquen dos threads. Un port és un recurs, propietat d’una task. Un thread té accés a un port pel fet de pertànyer a una task.

      kern_return_t
      get_privileged_ports (host_priv_t *host_priv_ptr,
      device_t *device_master_ptr);

1.7. Comparativa: sbrk vs mmap

  1. Aquestes dues crides permeten demanar memòria:

    #include <unistd.h>
    // change data segment size
    void *sbrk(intptr_t increment);
    #include <sys/mman.h>
    // allocate memory, map files or devices into memory
    void *mmap(void *addr,size_t length,int prot,int flags,int fd,off_t offset);

Fes una comparació de les seves funcionalitats, basada en dibuixos de l’espai d’adreces d’un procés.

Resposta

La funció sbrk() modifica la mida del segment de dades tot canviant el program break, que defineix el final del data segment del procés. Incrementar el program break implica alocatar memòria pel procés, mentre que decrementar-lo implica alliberar memòria. La crida al sistema sbrk() retorna l’anterior program break.

process space

La funció mmap(), mapeja fitxers o dispositius a memòria tot creant un nou mapatge a la memòria virtual del procés. L’adreça d’inici la pot rebre com a par`metre, però si aquest és null, el kernel escull la nova adreça. El mapatge es crearà en un límit de pàgina proper. La crida al sistema mmap() retorna l’dreça del nou mapping.

1.8. Clones

  1. Explica les diferències que hi ha entre els clones de Linux i els threads de Mach. Quines diferències hi ha entre un thread de Mach i un PThread?

    Resposta

    La crida al sistema clone() de Linux crea un procés que, mitjançant els arguments de la crida, pot compartir una sèrie de recursos amb el procés que ha fet la crida. En aquest sentit, fork() és una crida concreta a clone() on no és comparteix res.
    En canvi, per tenir una situació semblant a Mach, hem de crear una task() (és a dir, un procés) i un thread de sistema d’aquesta tasca. Però, els threads de Mach comparteixen tots els recursos i es poden assignar a tasques diferents de la que ha fet la crida.
    Els Pthreads són threads d’usuari i es gestionen mitjançant una llibreria o runtime. Són portables entre diferents sistemes operatius. En aquest sentit, la llibreria Pthread es basa en la task i el thread de Mach o en el clone de Linux, depenent on s’executi.

1.9. Thread safe

A continuació tens un codi que no és thread safe.

while (lock==1) ; //spin
lock = 1;
// regio critica de codi
lock = 0;

Enumera i explica quins aspectes problemàtics li trobes i proposa un codi alternatiu.

Resposta

Tres problemes:

  1. El compilador pot modificar el codi, buscant optimitzar-lo. Podem aprofitar el suport del compilador amb l’atribut volatile, que indica que un altre flux pot estar accedint a la mateixa variable al mateix temps.

  2. L’execució de l’entrada a la regió crítica no és atòmica. Podem fer servir intrínseques del compilador (gcc`)

    while (__sync_lock_test_and_set (&lock, 1)==1);
  3. Sobrecàrrega. Evitar la sobrecàrrega d’instruccions en els multicore d’Intel:
    instrucció PAUSE. Evitar la sobrecàrrega del bus, per la transacció atòmica: Test, test-and-set.

I una solució:

volatile int lock __attribute__ ((aligned(128)));
while (__sync_lock_test_and_set (&sync_var, BUSY)==BUSY)
    while (sync_var==BUSY) asm __volatile__ ("pause");

1.10. Mach

  1. Mach ofereix cinc abstraccions de programació que són el maons bàsics del sistema. D’aquestes, et
    demanem que defineixis només les quatre primitives següents: Thread, Task, Message i Port.

    Resposta
    • Thread es el segon component del procés. La part activa. L’entorn d’execució d’una task. Cada task pot suportar més d’un thread executant-se concurrentment, tots compartint els recursos de la task. Tots els threads tenen el mateix espai d’adreces de memòria virtual (VM), però es diferencien en l’estat d’execució, format per un conjunt de registres, tals com l’stack pointer (SP) i el program counter (PC).

    • Task el procés clàssic de Unix, a Mach es divideix en dos. La part que fa de contenidor de recursos, tals com memoria virtual o ports de comunicacions,se’n diu task. És una entitat passiva, no s’executa a cap processador.

    • Message Els threads de diferents tasques es comuniquen per missatges. Un missatge és una col·lecció de dades amb tipus

    • Port el canal de comunicacions mitjançant el qual es comuniquen dos threads. Un port és un recurs, propietat d’una task. Un thread té accés a un port pel fet de pertànyer a una task.

1.11. Linux

  1. A Linux existeix la crida al sistema int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);

    1. Quins efectes tindrà l’execució de les següents línies de codi per la resta del programa?

      CPU_ZERO(&mask);
      CPU_SET(2, &mask);
      CPU_SET(1, &mask);
      sched_setaffinity (getpid(), 4, &mask);
      Resposta
      CPU_ZERO(&mask);  //0000
      CPU_SET(2, &mask); //0100
      CPU_SET(1, &mask);  //0110
      sched_setaffinity (getpid(), 4, &mask); // cpus 1 and 2 set for pid==getpid()
    2. Descriu un escenari a on un thread en concret aprofiti aquesta syscall per millorar el seu rendiment.

      Resposta

      Restringir un thread perquè s’executi en una sola CPU evita el cost de rendiment causat per la invalidació de la memòria cau que es produeix quan un fil deixa d’executar-se en una CPU i després es torna a executar en una CPU diferent.

    3. Descriu un escenari a on els threads d’un procés en concret aprofitin aquesta syscall per millorar el seu rendiment.

      Resposta

      Dedicant una CPU (tots els seus cores) a cada thread (és a dir, establint la màscara d’afinitat d’un thread per especificar una única CPU i establir la màscara d’afinitat de tots els altres threads per excloure aquesta CPU), és possible garantir la màxima velocitat d’execució per a tots els threads.

    4. A POSIX, existeix la crida int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset), ¿quan seria recomanable fer-la servir en comptes de sched_setaffinity(…​)?

      Resposta

      Quan s’utilitza pthread_create() al mateix codi i el programa s’ha compilat i enllaçat amb -pthread. Tingueu en compte que la seva funció és una extensió GNU no estàndard; d’aquí el sufix "_np" (no portable) al nom.

1.12. Threads

  1. Per a cadascuna de les següents línies de codi, indica quina funció de més alt nivell estan implementant i a quin sistema operatiu.

    1. CreateThread( (LPSECURITY_ATTRIBUTES)security, stacksize, _threadstartex, (LPVOID)ptd, createflag, (LPDWORD)thrdaddr))

      Resposta

      Es la funció de la Windows API per crear un thread

    2. clone(child_stack,
      CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE
      _SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid, tls, child_tidptr)

      Resposta

      Crida per crear un thread a Linux. Amb aquests paràmetres és la implementació de pthread_create()

    3. clone(NULL, NULL, SIG_CHLD, NULL)

      Resposta

      Crida per crear un procés a Linux, implementa un fork()

    4. thread_create(self, &kernel_thread)

      Resposta

      Crida per crear un thread a Mach.

1.13. Eines de desenvolupament

  1. Entre les eines de desenvolupament tenim l’enllaçador (linker). GNU proporciona 2 enllaçadors, segons la transparència que vam veure a classe:

    ld / gold → linker

A la Wikipedia trobem aquesta explicació:

In software engineering, gold is a linker for ELF files. It became an official GNU package and was added to binutils in March, 2008 and first released in binutils version 2.19. Gold was developed by Ian Lance Taylor and a small team at Google. The motivation for writing gold was to make a linker that is faster than the GNU linker, especially for large applications coded in C++. Unlike the GNU linker, gold doesn’t use the BFD library to process object files. While this limits the object file formats it can process to ELF only, it is also claimed to result in a cleaner and faster implementation without an additional abstraction layer. The author cited complete removal of BFD as a reason to create a new linker from scratch rather than incrementally improve the GNU linker. This rewrite also fixes some bugs in old ld that break ELF files in various minor ways. To specify gold in a makefile, set the LD or LD environmental variable to ld.gold. To specify gold through a compiler option, one can use the gcc option -fuse-ld=gold.

Responeu:

  1. Per què tenim dues versions del “linker”?

    Resposta

    Un equip de Google va veure que el GNU ld és molt lent enllaçant fitxers objecte, i una de les raons és que manipula les estructures dels binaris a través la la llibreria de suport GNU bfd. Llavors, en col.laboració amb l’autor del GNU ld, Ian Lance Taylor, van desenvolupar el GNU gold. Com que el requeriment era que fos més ràpid, van fer-lo sense passar per la llibreria bfd, i només orientat a fitxers de format ELF. Però, en Linux, encara hi ha aplicacions en format COFF o a.out, i per això no es pot discontinuar l’antic GNU ld.

  2. Quines limitacions té el gold, si el comparem amb l' ld?

    Resposta

    Que només suporta fitxers de format ELF.

  3. En cas de tenir una aplicació formada per multitud de fitxers (C i/o C++) - per tant, usant compilació separada, i un Makefile, i per la qual volem generar un fitxer executable en format ELF, ordeneu per ordre de preferència aquestes alternatives que tenim per enllaçar-los:

    c1 export LD=ld.gold
    make

    c2 export CFLAGS=”-fuse-ld=gold”
    make

    c3 make

    c4 gcc -fuse-ld=ld *.c *.cpp`

    Expliqueu el perquè de l’ordre que heu decidit.

    Resposta

    la preferència és

    c2) export CFLAGS="-fuse-ld=gold"
    make

    Perquè

    • és millor informar al gcc que faci servir el gold

    • els Makefiles haurien de fer CFLAGS+="altres opcions" per afegir opcions i
      no esborrar la que els ve de fora per la variable d’entorn

    c1) export LD="ld.gold"
    make``

    Perquè

    • habitualment no usem $(LD) per enllaçar en els Makefiles, sinó que ho fem
      amb "gcc -o …​ " perquè així el gcc ja ens inclou totes les llibreries que calen
      segons les altres opcions que li passem.

    • Només si el Makefile usa $(LD) per enllaçar aquesta opció donaria com a
      resultat que el programa s’enllacés amb el gold

    c3) make

    Perquè

    • Encara que no enllaçaríem tampoc amb el gold, obtindriem l’executable correcte
      i funcional, potser després d’esperar més estona

    c4) gcc -fuse-ld=ld *.c *.cpp

    Perquè

    • En aquest cas li estem dient al gcc que enllaçi amb "ld"!!, no amb gold

    • A més ens saltem totes les opcions que pugui tenir el Makefile per compilar…​
      -O -g …​ altres …​ -o <nom-executable> …​

    • No es pot assegurar que la compilació sigui existosa, imaginem només que
      l’aplicació tingui alguns fitxers C/C++ en subdirectoris. Ja no els veuriem i
      tindríem símbols no resolts.

    No obstant això, a la correcció de la pregunta s’han donat per bons altres
    ordres, si estaven ben argumentats.

1.14. User space pagers

  1. Volem dissenyar un sistema de memòria compartida distribuïda, fent servir el model de Mach. Quin paper podrien tenir els object managers en aquest disseny? Descriu, pas a pas, com es resol una fallada de pàgina a Mach. Les paraules memory_object, vm_map i vm_allocate han d’apareixer a la teva resposta.

Resposta

Considereu una situació en què les tasques de dues màquines diferents intenten modificar la mateixa pàgina d’un objecte alhora. Correspon al gestor decidir si aquestes modificacions s’han de serialitzar. Un gestor conservador que implementés una coherència estricta de la memòria forçaria la serialització de les modificacions concedint accés d’escriptura només a un nucli alhora. Un gestor més sofisticat podria permetre que els dos accessos es desenvolupin simultàniament (per exemple, si el gestor sàpiga que les dues tasques modificaven àrees diferents dins de la pàgina i que podria combinar les modificacions amb èxit en el futur). La majoria de gestors de memòria externs escrits per a Mach (per exemple, els que implementen mapegen fitxers ) no implementen la lògica per tractar amb diversos nuclis, degut a la complexitat d’aquesta.

La memòria física no s’assigna fins que s’accedeix a les pàgines d’aquest objecte. El backing store d’objectes està gestiopnat pel default pager.
Quan es produeix un error de pàgina, el kernel intercepta aquest error de pàgina i comprova l’objecte vm_map per veure si la pàgina està present a l’espai de memòria virtual del procés.

Quan un thread provoca un error de pàgina a la pàgina d’un objecte de memòria, el kernel crida a memory_object_data_request() al port de l’objecte de memòria en nom del thread amb error.
El thread es bloquejat fins que el gestor de memòria retorna la pàgina en una crida a memory_object_data_return().

Si la pàgina no està present a l’espai de memòria virtual, el nucli pot assignar una pàgina física, via vm_allocate(), llegir les dades necessàries del disc i assignar l’adreça virtual a la pàgina física via vm_map().

1.15. Operating System

  1. Hi ha qui ha identificat l’objectiu d’un sistema operatiu com el de proveir un entorn en el qual un usuari pugui executar programes en un ordinador de manera convenient i eficient.
    Hi estàs d’acord? Desenvolupa breument els teus arguments. Quin creus més prioritari dels dos objectius (convenient, eficient)? Creus necessària l’existència d’un SO pel bon funcionament del sistema (entenent per sistema el conjunt de hardware, SO, programes i usuaris). Finalment, defineix sistema operatiu (sent coherent amb els teus arguments).

Resposta

(resposta estudiant) Hi estic d’acord però crec que és important remarcar que un SO ha de ser, sobretot, segur i garantir protecció entre usuaris. Crec que és més important el fet de que sigui convenient, entenent per convenient que tot funciona com ha de funcionar i no es vulnera la seguretat dels usuaris. Crec que l’existència de un SO és necessari per a una bona gestió ja que en cas contrari requeriria un nivell tècnic molt avançat per a poder fer servir les màquinesi el més segur és que si depèn dels usuaris no se’n faci un bon ús.

Un SO és un programa que fa d’intermediari entre l’usuari i la màquina. Proporciona un entorn d’execució convenient i eficient per a executar programes. Gestiona la màquina d’una manera segura i proporciona proteccío als usuaris.

1.16. KBuild

  1. Explica què són les crides al sistema (system calls), quin paper juguen en la definició d’un sistema operatiu. Com i quan (temps d’execució o de compilació) es pot afegir al kernel una crida al sistema? Com es fa la comunicació entre el kernel i el procés que fa la crida? Contextualitza el teu raonament pels casos de Linux i Mach. Pots ajudar-te d’aquest esquema i aquest codi per guiar la teva explicació.

kbuild

mov rax, 0x2000004 ; sys_write call id
mov rdi, 1         ; STDOUT fd
mov rsi, usrBuf    ; buffer to print
mov rdx, usrBufLen ; length of buffer
syscall            ; make the syscall
Resposta

El sistema operatiu interactua amb el hardware, proveint als programes de serveis comuns i aïllant-los de les idiosincràsies del maquinari. Els programes interactuen amb el kernel invocant un conjunt ben definit d’operacions, anomenat crides al sistema. Les crides al sistema indiquen al kernel fer diverses funcions per al programa que les criden i intercanviar dades entre el kernel i el programa.

Tant en Mach com en Linux, la manera bàsica d’afegir codi al sistema operatiu és afegir els teus fitxers font a l’arbre del codi font del kernel i recompilar-lo. Però, en el cas de Linux, hi ha també la possibilitat d’afegir aquest codi mentre el kernel s’està executant. El tros de codi (els rectangles verds, a la figura) que afegim d’aquesta manera se’n diu mòdul de kernel carregable. Els mòduls poden ser des de manegadors de dispositius a gestors de sistemes de fitxers, passant per crides al sistema.

La comunicació de la crida al sistema entre kernel i procés es fa mitjantçant el trap. En el cas de Mach, s’usa IPC per entrar dins el kernel. A l’exemple de l’enunciat, el trap es fa amb la instrucció syscall. A partir d’aquest moment ja no es poden fer servir funcions d’usuari per comunicar-se. A l’exemple, a la informació a escriure que està a usrBuf, s’haurà d’accedir amb funcions de kernel, com copy_from_user (Linux) o copyin (BSD) o d’altres mecanismes de més baix nivell.

2. Segons controls

2.1. Què és un Sistema Operatiu?

  1. Al 1982 es va llançar el mercat oficialment el MSDOS, el sistema operatiu del IBM PC i ordinadors compatibles. Aquesta màquina tenia un processador Intel 8088, de 8 bits i només un mode d’execució. A continuació mostrem un petit fragment del codi del MSDOS:
    msdos
    Dóna una definició de Sistema Operatiu, identificant els objectius principals que hauria de complir. Contextualitza la teva definició de sistema operatiu amb el MSDOS. Creus que aquest software compleix els teus criteris? Linux va sortir 9 anys més tard, sobre un Intel 80386, un processador de 32 bits amb 4 modes d’execució. ¿Quins dels objectius que has descrit es va veure beneficiat per la diferència de hardware respecte al MSDOS?

    Resposta

    El nombre de bits del processador no era rellevant per a la pregunta, però vistes les vostres respostes, faig un petit aclariment. Si ens diuen que un processador és de 8 bits vol dir que el bus de dades és de 8 bits, ie, l’i8088 només podia llegir 8 bits cada vegada. Això, la Bus Interface Unit (BIU), el diferenciava de l’i8086 de 16 bits, tot i que tots dos tenien la mateixa Execution Unit (EU) i eren compatibles quant a codi assemblador. Feien servir adreçament segmentat, amb registres de segment de 16 bits i 4 bits d’offset. En conseqüència, la mida màxima de l’espai d’adreces era d'1 MB (\(2^{20}\)Bytes).

    Un sistema operatiu és un programa que fa d’intermediari entre l’usuari i la màquina.
    Proporciona un entorn d’execució entre convenient i eficient per executar programes.
    Gestiona la màquina d’una manera segura i proporciona protecció als usuaris. Protecció és un mecanisme per a controlar l’accés de programes, processos o usuaris als recursos de l’ordinador. La seguretat protegeix la integritat de la informació emmagatzemada al sistema, així com els recursos físics d’aquest d’accessos no autoritzats. Protecció i seguretat no es poden aconseguir amb un sol mode d’execució.

    Sense dos modes d’execució el sistema operatiu no pot comprovar si el procés que està executant té privilegis suficients per llançar segons quines instructions. Quan tenim dos modes d’execució i executem una syscall, el codi de kernel comprova, dins la rutina d’atenció al trap, que el procés està en mode privilegiat, si no és així genera una interrupció (a Intel, la int 13) associacda a la General Protection Fault (GPF). La resposta del sistema operatiu acostuma a ser treure al procés del sistema. Al codi es pot apreciar que les interrupcions estan inhibides (la instrucció CLI, clear interrupt-enable, posa a 0 el flag IF, veure el comentari al mateix codi). No es produeix aquest mecanisme de control.

    Linux va ser creat el 1991 per Linus Torvalds quan era estudiant. S’inspirà en un microkernel didàctic anomenat MINIX, creat pel professor Andrew S. Tanenbaum el 1987. La primera versió de Linux corria sobre l’i386, aquest processador permetria anar i tornar fàcilment del mode protegit. L’i386 heretà la part de 16 bits de l’i286 (que introduí els modes d’execució a Intel) i
    afegí els 32 bits. Arrancava en real-address mode, inicialitzava les estructures de dades de sistema i els registres, preparant-se per passar a protected mode. Per fi es podia implementar la protecció i seguretat, punt bàsic en la definició de sistema operatiu.

2.2. SAN o NAS?

  1. A la figura teniu l’esquema d’una xarxa, a on storage és la unitat d’emmagatzematge que guarda els fitxers dels usuaris de diferents sistemes operatius.

san

  1. ¿Quin entorn creus que representa, SAN o NAS?

    Resposta

    Es tracta d’una SAN. La pista està en el out-of-ban management típic de les Storage Area Networks. A la figura es poden veure dues xarxes, la fiber-channel i l’ethernet (dedicada a la gestió de la SAN).

  2. Explica breument, basant-te en el dibuix, com funciona

    Resposta

    Cada client (Unix, Windows i VMware) connecta directament als discos, via fiber-channel. Cadscun d’ells veu un dispositiu de blocs propi. Un sistema de fitxers específic per aquest tipus d’instal·lacions gestionarà l’accés concurrent de tos els clients de la SAN.

    L’array de discos està connectat directament a la xarxa fiber-channel i a l’ethernet, la qual cosa permet gestionar la SAN fins i tot si algun disc ha caigut. Tot el tràfic de gestió està separat del tràfic de dades.

  3. Quina és la diferència fonamental entre SAN i NAS?

    Resposta

    La diferència fonamental és que NAS accedeix a nivell de fitxer i SAN a nivell de bloc.

  4. Cita algun sistema de fitxers pensat explícitament per aquest entorn.

    Resposta

    Hi ha molts. Alguns dels esmentats a classe són: cxfs i ocfs.

2.3. Enginyeria Inversa

  1. Hem executat la comanda strace sobre un binari. A partir d’aquest extracte de la seva sortida, intenta deduir alguna de les crides de més alt nivell que s’han executat.

strace

Resposta

Hi ha dues crides a clone() per crear sengles threads dins el mateix grup de threads (CLONE_THREAD) amb els flags típics (quant a compartició de memòria: shared file descriptors CLONE_FILES, file system information CLONE-FS, table of signals handler CLONE_SIGHAND) de crear un flux d’execució (i no pas un procés). Per tant no pot ser la implementació d’un fork(). Més aviat seran quelcom semblant a:

ret = pthread_create(&thread->pthread, &thread->attr, func, (void *)thread)))

La resta són menys unívoques, però ens donen algunes pistes. Tal com vau poder comprovar amb l’exercici del factorial amb pthreads, la crida al sistema mprotect()
pot estar involucrada amb la implementació de:

pthread_mutex_init(3),
pthread_mutex_lock(3),
pthread_mutex_unlock(3)

També apunta als mutex la línia

futex(0x7ffa6d9ead18, FUTEX\_WAKE\_PRIVATE, 1) = 1;

sabent que la família de funcions relacionades amb l’exclusió mútua de la llibreria pthread s’implementen amb futex().

2.4. Memòria amb mmap

  1. La crida al sistema mmap(), segons el manual, allocate memory, or map files or devices into memory , per tant, té funcionalitats semblants a malloc() i read(), respectivament.
    Compara, per separat, mmap() amb cadascuna d’elles i assenyala situacions on faries servir una o l’altre.

    Resposta

    La crida al sistema mmap() assigna memòria a un procés a qualsevol punt de l’espai lògic d’aquest. Aquest fet la diferencia de sbrk() i `sbrk()', més antigues, que assignen la memória dins el heap.

    Fer servir mmap() per llegir un fitxer a memòria és millor que llegir-lo amb read() si el fitxer és gran (però no massa), es farà servir moltes vegades i es compartirà (cas de les llibreries). Fer-ho així evita la funció copy_to_user() del kernel, i estalvia les crides a lseek(). Però cal tenir en compte que: hi ha un overhead significatiu en la creació del mapeig, que el fitxer hi ha de cabre dins l’espai d’adreces del procés i que el mapeig serà sempre un nombre enter de pàgines.

    La funció malloc() no és una crida al sistema, sinó que pertany a la libC. Quan un procés crida a malloc() per una mida petita, malloc() crida a brk() amb una mida bastant més gran, per millorar el rendiment reduïnt el nombre de crides al sistema i administra les següents crides a malloc() sense haver d’entrar en mode privilegiat. Però si la mida demanada és molt gran, malloc() fa servir mmap() i no pas brk(), per evitar la fragmentació de memòria. Com en el cas anterior, l’overhead de mmap() només es justifica per a mides grans. Aquest llindar de separació entre cridar a brk() o a mmap() és ajustable. Veure man mallopt(3).

2.5. Transferir dades

  1. El sistema operatiu ha de transferir dades entre l’espai dels processos i el del sistema operatiu per tal de i) llegir informació dels dispositius amb seguretat i protecció i passar-la a l’usuari; o bé, ii) per llegir informació de l’espai d’usuari d’un procés i passar-la a dins del sistema operatiu per dur-la a un dispositiu. Així implementem les lectures i escriptures a dispositius, respectivament.

Una de les rutines típiques de UNIX/Linux per dur a terme aquesta tasca és:

long  copy_to_user ( void __user * to, const void * from, unsigned long n );

Aquesta funció rep el punter destí a l’espai d’usuari (“to”), el punter origen de la informació a l’espai de sistema (“from”) i la longitud en bytes que volem copiar (“n”). A més, retorna el número de bytes que no s’han pogut copiar, per exemple perquè s’ha trobat amb què una de les adreces de l’espai de l’usuari no és vàlida.
Per tant, si retorna 0 (zero) vol dir que tot ha anat bé. I si retorna una quantitat més gran que 0 (zero), vol dir que ha trobat un error en el byte “n - la quantitat retornada”. En aquest cas posa la variable d’error (“errno”) a EFAULT, per exemple, que és l’error que es retornarà a la crida a sistema que es trobi amb aquesta situació.
El dibuix que representa l’actuació d’aquesta funció és:

pregunta5

Responeu:

  1. Doneu una possible implementació bàsica d’aquesta funció “copy_to_user”. Es valoraran les indicacions del control d’errors. Podeu usar una funció bool bad_address (void * ptr);
    que us retorna 1 (cert) si el punter “ptr” apunta a una adreça que l’usuari no és vàlida.

    Resposta

    Per exemple, podriem copiar byte a byte, mirant per a cadascun que la seva adreça destí en el "to" sigui vàlida. Si no ho és, posem l’error a EFAULT i retornem els bytes que ens faltaven per copiar. Si tot va bé, retornem n-i, que serà zero (correcte).

    long copy_to_user(void __user * to, const void * from, unsigned long n)
    {
        int i;
    
        char * to_c = to;
        const char * from_c = from;
    
        for (i = 0; i < n; i++) {
           if (!bad_address(&to_c[i])) to_c[i] = from_c[i];
           else {
              set_errno(-EFAULT);
              return n-i;
    
         ++i;
        }
    
        return n-i;
    }

    S’hi poden fer optimitzacions, com ara veure si es pot fer la còpia de 8 bytes en 8 bytes i fer-la mentre la mida a copiar sigui més gran de 8.

    O també es pot intentar fer el bad_address només un cop per pàgina, i fer còpies de pàgines senceres sense haver de fer comprovacions que son redundants.

  2. Tenint present el tema del com s’accedeix a les variables pròpies d’un thread (recordar la pràctica de Mach, exercicis 8 i 9), com podrieu implementar l’atribut “user” que s’aplica al punter que apunta a l’espai de l’usuari (void user * to, en l’exemple)?

    Resposta

    A la pràctica de Mach vam veure que la llibreria de C de Hurd usa el segment gs dels processados Intel per accedir a variables que anomenem “thread local” i que estan a una secció especial (TLS). Això ens fa pensar que el SO podria tenir l’espai d’usuari accessible només a través del registre gs. Això protegiria l’espai d’usuari, perquè complicaria els atacs que alteren dades dels processos o que agafen dades dels processos, perquè s’haurien de dissenyar per usar el registre gs per accedir-hi.

2.6. Suport per Temps Real

  1. Classifica els següents escenaris com a hard, firm o soft realtime (1 punt)

    1. Els tres threads del Mars Pathfinder.

    2. Un servidor de vídeo descodifica els codis de temps per saber quan han d’aparèixer els fotogrames per pantalla. Si va tard, el fotograma no es mostra.

    3. Una impressora d’injecció de tinta té un capçal d’impressió amb programari de control per dipositar la quantitat correcta de tinta en una part específica del paper. Si va tard, surt massa tinta.

    4. Una consola de video-jocs calcula l’escena quan el personatge entra en ella. Si va tard, parts de l’escenari (textures) no es mostren correctament.

      Resposta

      1-hard,
      2-firm,
      3-hard,
      4-soft.

  2. Enumera i explica 2 funcions POSIX que t’ajudin a programar per temps real (1 punt).

Resposta

mlockall(int flags);

Bloqueja tot l’espai d’adreces virtual del procés a la RAM, evitant que la memòria pugui ser paginada a l’àrea d swap.

pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
int prioceiling);

Defineix la prioritat sostre a l’atribut del mutex, que hauria de ser igual o superior a la de qualsevol thread que pugui bloquejar el mutex.

2.7. Memòria

  1. La següent traça correspon a un procés Linux que ha demanat memòria dinàmica. Pots endevinar les quatre crides a funcions del codi font del programa? Pista: el procés ha obtingut tota la memòria demanada i no més.

    $ strace -f ./a.out
    brk(NULL)                               = 0x560f5c04f000
    brk(0x560f5c04f004)                     = 0x560f5c04f004
    clone(child_stack=0x7fdf6a965fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTIDstrace: Process 10371 attached
    , parent_tid=[10371], tls=0x7fdf6a966700, child_tidptr=0x7fdf6a9669d0) = 10371
    [pid 10370] futex(0x7fdf6a9669d0, FUTEX_WAIT, 10371, NULL <unfinished ...>
    [pid 10371] futex(0x7fdf6a1651e0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    [pid 10371] exit(0)                     = ?
    [pid 10370] <... futex resumed>)        = 0
    [pid 10371] +++ exited with 0 +++
    exit_group(0)                           = ?
    +++ exited with 0 +++
    Resposta
    sbrk(4)
    pthread_create()
    pthread_exit(255) ?
    pthread_join(NULL) ?
    exit(0)
  2. El següent codi d’un programa Mach genera un error en executar-se (Segmentation fault), però status sempre val KERN_SUCCESS. A què és degut?

    define SZ vm_page_size
    void dummy() {
            printf("Dummy funciona!\n");
            exit(0);
    }
    int main() {
            vm_address_t regio;
            mach_port_t task_self = mach_task_self();
            kern_return_t status;
            status = vm_allocate(task_self, &regio, SZ, TRUE);
            if (status != KERN_SUCCESS)
                    printf("error assignant memoria.\n");
            status = vm_protect(task_self, (vm_address_t) dummy, vm_page_size, FALSE, VM_PROT_NONE);
            if (status != KERN_SUCCESS)
                    printf("error en protegir el segment de text.\n");
            dummy();
            printf("vaig acabant!\n");
            exit(0);
    }
    Resposta

    vm_protec() desactiva l’accés a la memòria que conté la funció dummy(), i en intentar accedir el programa termina per SIGSEGV.

3. Tercers controls

3.1. Què és un Sistema Operatiu?

  1. Per a la familia de supercomputadors BlueGene d’IBM es va implementar un lightweight kernel anomenat oficialment CNK (i Blrts extraoficialment). Suportava una gran quantitat de crides al sistema de Linux, tot i que només es dedicava a computació (Compute node a la figura); totes les crides d’entrada/sortida eren redireccionades cap a un únic node Linux (al Node Card de la figura).

BGL

El CNK no permetia operacions fork/exec, en canvi, un compute node estava orientat a executar un procés MPI multithread, amb rigorosa afinitat. Tenint present la definició de Sistema Operatiu que has estudiat:

  1. Creus que el CNK és un sistema operatiu?

    Resposta

    El CNK (Compute Node Kernel) és un sistema operatiu (protegeix al sistema i el gestiona per a un ús òptim) si fitem el hardware de la màquina al node sobre el que s’executa. De la resta del supercomputador, el CNK no sap res i per tant no pot fer d’interfície entre el programador i el supercomputador. El CNK és un sistema operatiu per al compute node, però necessita del FWK (Full Weight Kernel) per a comunicar-se amb l’exterior. En aquest sentit, CNK és un co-kernel.

    LWK
  2. En quina de les funcionalitats atribuïdes a un SO, el CNK té una mancança important?

    Resposta

    Tot i això, encara que només ens fixem en el compute node, el CNK té mancances com a sistema operatiu. En no poder fer fork/exec, no pot tenir un shell, no pot tenir un intèrpret de comandes, ni tampoc pot suportar llenguatges d’scripting. Per tant, la funcionalitat de proveir una interfície a l’usuari no la pot satisfer. Aquesta funcionalitat la dona el FWK, en el cas de BG/L, un node Linux.

3.2. Mach tasks vs Unix processes

  1. A les figures estan representats els models de memòria d’una task de Mach i d’un procés Unix. Aquesta representació data de mitjans dels anys 80.

mach vs linux
  1. Quina era (és) la syscall (o les syscalls) per crear l’abstracció d’aquest dibuix a Mach? I a Unix?

    Resposta

    A Mach cal crear una task i dos threads per tenir el dibuix de la figura. Amb aquestes crides:

    kern_return_t   task_create
                    (task_t                             parent_task,
                     ledger_port_array_t                    ledgers,
                     int                               ledger_count,
                     boolean_t                       inherit_memory,
                     task_t                              child_task);
    kern_return_t   thread_create
                    (task_t                             parent_task,
                     thread_act_t                      child_thread);

    A Unix, cal crear un procés per a tenir el dibuix de la figura. Amb aquesta crida:

    pid_t fork(void);

    Noteu que no és clone()`, donat que aquesta és només per Linux.

    Centrant-nos en el model de memòria, respón a les següents preguntes:

  2. Quina és la diferència més significativa entre els dos dibuixos? Quina era (és) la syscall per gestionar la zona ratllada a Unix (Linux)? I a Mach?

    Resposta

    El que més sobta és l’organització de la memòria dinàmica. Mentre que en el cas de Unix, la zona ratllada és continua, en el cas de Mach, la zona ratllada està trocejada.

    A Unix, les syscall per gestionar la zona ratllada eren int brk(void *addr); i void *sbrk(intptr_t increment); que movien el final del segment de dades (program break) del procés.

    A Mach, des del seu inici, un programa podia assignar, desassignar, protegir i compartir zones de memòria arbitràries entre tasks. Aquestes zones no han de ser contínues, sinó que poden estar disperses per tot l’espai lògic del programa. A laboratori hem treballat la crida

    kern_return_t   vm_allocate
                    (vm_task_t                          target_task,
                     vm_address_t                           address,
                     vm_size_t                                 size,
                     boolean_t                             anywhere);
  3. A POSIX (i per tant, s’implementa tant a Linux com a BSD), es defineix una system call per gestionar la memòria de manera semblant a Mach. Quina és? Quina funció de més alt nivel coneixes que la faci servir? En quines circumstàncies?

    Resposta

    A Linux existeix la crida:

     void *mmap(void *addr, size_t length, int prot, int flags,
                      int fd, off_t offset);

    que, com la crida de Mach, treballa en unitats de pàgina. La funció de LibC void *malloc(size_t size) que fa servir brk() o mmap() depenent del valor de size.

  4. Explica quins advantatges veus al model actual de Linux. Creus que necessita d’un suport hardware?

    Resposta

    Al Unix original, la gestió de memòria buscava tractar amb espais continus. La memòria dinàmica s’assignava movent el program break amb la crida int brk(void *addr);. Quan apareixen màquines amb mides grans d’espai d’adreces aquest model orientat a fer crèixer el segment bss començar a trontollar. Amb l’inclusió de la crida al sistema mmap() es poden administrar moltes zones de memòria separades per forats, disperses per tot l’espai d’adreces del programa.

    No necessita més suport hardware que l’inherent al model de memòria de paginació sota demanda.

3.3. Què li va passar al Pathfinder?

  1. Al juliol de 1997 es va iniciar la missió de la NASA “Mars Pathfinder” que va estar a punt de fracassar. Pocs dies després d”aterrar” el sistema va començar a patir resets. Explica en què va consistir el problema i com es va resoldre. Com a guia, mira de respondre a aquestes preguntes:

    1. Quin sistema operatiu es va fer servir a la missió? Encara té suport actualment?

      Resposta

      VxWorks i sí, encara té suport actualment.

    2. Quin va ser el problema? Com el van poder diagnosticar?

      Resposta

      Inversió de prioritats.

      VxWorks es pot executar en un mode on enregistra una traça de tots esdeveniments interessants del sistema, incloent canvis de context, usos d’objectes de sincronització i interrupcions. Després de la fallada, enginyers del JPL van passar hores i hores fent servir una rèplica exacta de la nau espacial amb les traces activades, intentant replicar les condicions exactes en què creien que s’havia produït el reset. De matinada, quan només un enginyer encara no s’havia anat a casa, finalment va reproduir el reset a la rèplica. L’anàlisi de la traça revelava la inversió de prioritats.

    3. Quants threads estaven involucrats en el problema? Què feia cadascun?

      Resposta

      Hi va haver tres threads involucrats.

      El Pathfinder tenia una zona de memòria compartida (de fet, un bus de dades). Un thread d’alta prioritat gestionava aquesta memòria sovint, per posar i treure dades. L’accés a aquest bus estava sincronitzat amb mutex. Hi havia un altre thread de baixa prioritat dedicat a les dades meteorològiques que de tant en tant accedia al bus per deixar les seves dades, és a dir, adquiria el mutex, escrivia al bus i alliberava el mutex. També hi havia un thread de prioritat intermedia, dedicat a les comunicacions que no feia servir el bus.

      La cosa funcionava bé gairebé sempre. Si el thread d’alta prioritat es trobava el mutex agafat, es bloquejava fins que el thread de baixa prioritat alliberava el mutex. Però, en rares ocasions succeia que el thread de prioritat intermèdia accedia durant el breu període de temps que el thread d’alta prioritat estava bloquejat al mutex. El thread de baixa perdia el processador, sense alliberar el mutex, en favor del d’intermedia. Llavors es produïa un timeout quan el bus de dades feia massa temps que no era gestionat i el sistema feia un reset.

    4. Com es va resoldre? Quins dels mecanismes disponibles a la llibreria de threads van fer servir?

      Resposta

      Quan VxWorks s’executa en mode debug, conté un intèrpret de C que permet als programadors executar funcions i expressions on the fly. Els enginyers del JPL, sortossament, van decidir enviar el Pathfinder amb el mode debug activat. Els atributs del mutex estaven enmagatzemats amb les variables globals, les adreces de les quals quedaven a la taula de símbols i accessibles des de l’intèrpret de C. Els enginyers van carregar, des de la Terra, un petit program en C al Pathfinder, que un cop executat va canviar els atributs del mutex.

      El mecanisme de la llibreria de threads emprat va ser l’herència de prioritats. És a dir, quan un thread està bloquejant threads de més prioritat que ell, aquest s’executa a la prioritat més alta d’aquells bloquejats per aquest mutex. Es va aprofitar un dels atributs del mutex, canviant el seu valor a PTHREAD_PRIO_INHERIT.

3.4. Jitter i les interrupcions

En el nostre sistema, mirem l’assignació que tenen les interrupcions a processadors (CPUs), usant el fitxer d’informació /proc/interrupts:

$ cat /proc/interrupts # mostra els comptadors d'interrupcions arribades a cada CPU
      CPU0     CPU1     CPU2      CPU3
 0:    115        0        0         0   IO-APIC    timer               # rellotge
 1:  66487        0        0         0   IO-APIC    i8042               # teclat
 8:      0       65        0         0   IO-APIC    rtc0         # real time clock
 9:      0   286280        0         0   IO-APIC    acpi    # interprocessor interrupt
18:      0        0        0   1609132   IO-APIC    i801_smbus # system management bus
40:      0        0        0    387057   PCI-MSI    ahci                # USB 1
41:      0        0   712702         0   PCI-MSI  xhci_hcd              # USB 2
42:      0        0        0    102754   PCI-MSI    eth0                # xarxa
45:    926        0        0         0   PCI-MSI    snd_hda_intel:card1 # soundcard
46:      0  3626057        0         0   PCI-MSI  iwlwifi               # wifi
47:      0        0  2897210         0   PCI-MSI    i915            # tarjeta gràfica
48:      0        0        0       150   PCI-MSI    snd_hda_intel:card0 # soundcard
NMI:     0        0        0         0   Non-maskable interrupts
LOC: 52380920 48263461  51959641  48009742   Local timer interrupts # rellotge per CPU
RES:  3338614  2688932   2320548   1848684   Rescheduling interrupts(*)
CAL:  4492766  4433077   4450137   4561569   Function call interrupts(*)
TLB:  4490349  4430039   4448187   4558658   TLB shootdowns(*)

Fem algunes estadístiques sobre la recepció i distribució de les interrupcions:

- Totals:
       CPU0       CPU1      CPU2       CPU3
   64770177   63727911  66788425   61077746
- En percentatge sobre el total:
       CPU0       CPU1      CPU2       CPU3
      25.26%     24.85%    26.05%     23.82%

(*) Aquestes interrupcions s’anomenen Inter-Processor Interrupts (IPIs), i les utilitza l’SO per enviar avisos d’un processador (CPU) a una altra i donar ordres, per exemple: “fes una replanificació (RES)”, o bé “executa aquesta funció (CAL)”, o bé “fes un flush del teu TLB, perquè he canviat l’espai d’adreces del procés on estàs executant (TLB)”.

Per donar una referència de quant de temps ha passat mentre es rebien totes aquestes interrupcions, aquest és l’uptime de la màquina:

$ uptime
16:38:31 up 2 days,  9:20, 16 users,  load average: 0.07, 0.06, 0.01

I aquesta és la distribució d’interrupcions per segon:

                         CPU0      CPU1      CPU2      CPU3
interrupcions per segon  313.8     308.8     323.6     295.9
total: 1242 interrupcions per segon

També mirem la configuració del kernel, pel que fa a la interrupció de rellotge:

# CONFIG_HZ_100 is not set
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
CONFIG_HZ_1000=y
CONFIG_HZ=1000
  1. Expliqueu el tema del jitter en el sistema operatiu, com afecta als processos i també a les aplicacions paral·leles, i relacioneu-lo amb l’assignació de les interrupcions que veieu en aquesta informació prèvia que hem vist.

    Resposta

    El jitter consisteix en l’entrada en execució de serveis, dimonis, interrupcions, que son necessaris pel funcionament normal del sistema, però que interfereixen en l’execució d’una aplicació. Si l’aplicació és paral·lela, l’afectació és habitualment major, perquè es propaga del procés/flux afectat a la resta de processos/fluxos.

    Respecte al sistema donat, veiem que és un sistema de propòsit general, en el que l’arribada de les interrupcions d’ha distribuït entre els 4 cores que té l’ordinador. D’aquesta manera, qualsevol procés corrent en el sistema patirà el jitter. Podriem millorar la situació concentrant més les interrupcions a un sol core, per exemple el 0 i deixant la resta lliures d’interrupcions.

  2. Doneu la vostra opinió sobre si un sistema amb aquestes característiques podria servir per donar algun tipus de servei de temps real en mode hard.

    Resposta

    Aquesta opció d’aïllar les interrupcions a un sol core també seria
    recomanable per usar el sistema per suportar temps real en mode hard, perquè
    tal i com està no es pot garantir que no tinguis una ràfaga de 2 o més tipus
    d’interrupció en el core que té un deadline.

3.5. OBEX i accés a sistemes de fitxers remots

  1. Explica com OBEX - Object Exchange - ens permet accedir a dades exportades per altres dispositius (ordinadors, telèfons mòbils…). Usa el següent dibuix per millorar l’explicació.
    Per no haver d’entregar un dibuix, en l’explicació pots fer referència als punts numerats amb (1) .. (6)

OBEX
Resposta

(1) la comanda que usa Obex, utilitza el fusermount (setuid) per fer el muntatge del sistema de fitxers, usant File System in User Space - FUSE, a través de bluetooth.
(2) llavors ja es poden usar comandes com cp/play…​ que faran les seves crides a sistema (read/write) per anar al punt de muntatge,
(3) de forma que el sistema detectarà que ha de parlar amb el procés inicial d’Obex, a través del FUSE
(4) i enviarà les peticions de read/write…​ al procés obexfs, que les traduirà a missatges en el protocol bluetooth (5), per arribar fins el dispositiu mòbil (6).