Postavke

Simulacija

Dnevnik događaja t = takt, jedan korak poziva po taktuEvent log t = tick, one step of the call per tick

Vremenska crta svaki stupac je jedan takt, traka je mjesto izvođenjaTimeline each column is one tick, a lane is where the code runs

Gotovi scenariji

Teorija

Literatura: Stallings, Operating Systems: Internals and Design Principles, 9. izd., pogl. 2 (odjeljci 2.1, 2.2 i 2.8) i pogl. 3 (odjeljci 3.4 i 3.5); alternativno Tanenbaum & Bos, Modern Operating Systems, pogl. 1 (odjeljak 1.6, sl. 1-17 i 1-18).Reading: Stallings, Operating Systems: Internals and Design Principles, 9th ed., ch. 2 (sec. 2.1, 2.2 and 2.8) and ch. 3 (sec. 3.4 and 3.5); alternatively Tanenbaum & Bos, Modern Operating Systems, ch. 1 (sec. 1.6, Figs. 1-17 and 1-18).

Korisnički i jezgreni način rada

Procesor radi u jednom od dvaju načina: user mode (korisnički način rada) ili kernel mode (jezgreni način rada). Trenutni način zapisan je bitom u program status word (PSW, riječ stanja programa); u simulatoru je to polje M. U korisničkom načinu procesor ne izvodi privileged instruction (privilegirana instrukcija): U/I instrukcije, maskiranje prekida, promjenu bita načina rada ni podešavanje timera, a zaštita memorije ne pušta program u memoriju jezgre. Tako program ne može sam čitati disk ni isključiti timer, pa jezgra zadržava kontrolu nad računalom: timer interrupt (prekid timera) redovito joj vraća procesor (Stallings §2.2 i §3.4; vidi Prekidi).

User and kernel mode

The processor runs in one of two modes: user mode or kernel mode. The current mode is recorded in a bit of the program status word (PSW); in the simulator it is the field M. In user mode the processor does not execute privileged instructions: I/O instructions, masking interrupts, changing the mode bit or setting the timer, and memory protection keeps the program out of kernel memory. So a program cannot read the disk on its own or turn off the timer, and the kernel keeps control of the computer: the timer interrupt regularly gives the processor back to it (Stallings, Sections 2.2 and 3.4; see Interrupts).

Sistemski poziv kao sučelje

Uslugu koju smije obaviti samo jezgra program traži sa system call (sistemski poziv; Stallings ga zove supervisor call). Program pritom ne ulazi u jezgru izravno, nego poziva library procedure (knjižnična procedura) istog imena, npr. read iz C knjižnice. Skup tih funkcija je API, npr. POSIX (Tanenbaum, sl. 1-18: fork, execve, waitpid, open, read, write, close …), a ABI određuje kako poziv izgleda na razini stroja: gdje su parametri, u kojem je registru broj poziva i kako se vraća rezultat (Stallings §2.1). Za Stallingsa je sučelje sistemskih poziva granica prema korisniku (§2.8). Ljuska koristi sistemske pozive neprestano, vidi tijek fork, exec, wait na stranici Procesi.

The system call as an interface

A program uses a system call (Stallings: supervisor call) to ask for a service that only the kernel may perform. The program does not enter the kernel directly; it calls the library procedure of the same name, e.g. read from the C library. The set of these functions is the API, e.g. POSIX (Tanenbaum, Fig. 1-18: fork, execve, waitpid, open, read, write, close …), and the ABI defines what a call looks like at the machine level: where the parameters are, which register holds the call number and how the result comes back (Stallings, Section 2.1). For Stallings the system call interface is the boundary to the user (Section 2.8). The shell uses system calls all the time; see the fork, exec, wait sequence on the Processes page.

Jedanaest koraka poziva read

Tanenbaum poziv count = read(fd, buffer, nbytes) dijeli na 11 koraka (sl. 1-17). Program gura parametre na stog obrnutim redom (koraci 1–3), pa je prvi parametar na vrhu, i poziva knjižničnu proceduru (4). Ona stavlja broj poziva u registar (5) i izvodi instrukciju TRAP (6), koja prebacuje procesor u jezgreni način i skače na fiksnu adresu u jezgri. Dispatcher (dispečer) jezgre koristi broj poziva kao indeks u system call table (tablica sistemskih poziva) i poziva handler (obrađivač) tog poziva (7, 8). Obrađivač provjerava file descriptor (opisnik datoteke), koji je program dobio pozivom open (vidi Datotečni sustav), i adresu međuspremnika, prenese podatke i vrati se u knjižničnu proceduru (9), a ona programu (10). Program na kraju očisti parametre povećanjem stack pointer (SP, pokazivač stoga) (11). Simulator, kao i slika, parametre prenosi na stogu. Linux na x86-64 to ne radi: parametre prenosi u registrima rdi, rsi, rdx, r10, r8 i r9, broj poziva u rax, a u jezgru ulazi instrukcijom syscall. Starija 32-bitna inačica ulazi s int 0x80 (kao na stranici Prekidi) i ima vlastitu tablicu brojeva (u njoj je read broj 3, a ne 0); i ona parametre prenosi u registrima. Tablica na ovoj stranici koristi brojeve inačice x86-64.

The eleven steps of read

Tanenbaum divides the call count = read(fd, buffer, nbytes) into 11 steps (Fig. 1-17). The program pushes the parameters onto the stack in reverse order (steps 1–3), so the first parameter is on top, and calls the library procedure (4). The library procedure puts the call number in a register (5) and executes the TRAP instruction (6), which switches the processor to kernel mode and jumps to a fixed address in the kernel. The kernel's dispatcher uses the call number as an index into the system call table and calls the handler of that call (7, 8). The handler checks the file descriptor, which the program got from an open call (see File system), and the buffer address, transfers the data and returns to the library procedure (9), which returns to the program (10). Finally the program cleans up the parameters by incrementing the stack pointer (SP) (11). The simulator, like the figure, passes the parameters on the stack. Linux on x86-64 does not: it passes them in the registers rdi, rsi, rdx, r10, r8 and r9, the call number in rax, and enters the kernel with the syscall instruction. The older 32-bit version enters with int 0x80 (as on the Interrupts page) and has its own table of numbers (there read is number 3, not 0); it also passes the parameters in registers. The table on this page uses the x86-64 numbers.

Promjena načina rada i promjena konteksta

Svaki sistemski poziv ima dvije mode switch (promjena načina rada): ulazak u jezgru (korak 6) i povratak (korak 9). Proces pritom ostaje isti, pa je to jeftino: procesor sprema samo PC, PSW i SP na stog jezgre. Process switch (promjena konteksta) je nešto drugo: jezgra spremi cijeli kontekst procesa u njegov PCB i otpremi drugi proces. Kod read se to događa tek kad podataka nema. Obrađivač tada pokrene čitanje preko upravljačkog programa, proces P prelazi u Blocked (blokiran), a procesor dobiva proces Q. Kad disk prekidom javi da je blok stigao, prekidna rutina (u Linuxu njezina donja polovica) prebaci P u Ready (spreman), a P zatim nastavlja u jezgri. Blokirajući read zato ima dvije promjene konteksta i četiri promjene načina rada. Stallings u tablici 3.8 navodi tri mehanizma kojima jezgra preuzima procesor: prekid, trap (iznimka) i supervisor call (§3.4). Stanja procesa detaljno prikazuje stranica Procesi, a put jednog čitanja kroz sve slojeve Put jednog poziva. Tanenbaumov dispečer iz koraka 7 bira obrađivač poziva; Stallingsov dispatcher bira proces kojem se daje procesor.

Mode switch and process switch

Every system call has two mode switches: entering the kernel (step 6) and returning (step 9). The process stays the same, so this is cheap: the processor saves only PC, PSW and SP on the kernel stack. A process switch is something else: the kernel saves the whole context of the process in its PCB and dispatches another process. With read this happens only when the data is not there. The handler then starts the read through the device driver, process P moves to Blocked, and the processor goes to process Q. When the disk reports with an interrupt that the block has arrived, the interrupt service routine (in Linux its bottom half) moves P to Ready, and P then continues in the kernel. A blocking read therefore has two process switches and four mode switches. In Table 3.8 Stallings lists three mechanisms by which the kernel takes over the processor: interrupt, trap and supervisor call (Section 3.4). The Processes page shows the process states in detail, and Journey of a call follows one read through all the layers. Tanenbaum's dispatcher in step 7 picks the handler of the call; Stallings's dispatcher picks the process that gets the processor.

Iznimke, zaštita i nazivlje

Privilegirana instrukcija u korisničkom načinu se ne izvrši, nego izazove exception (iznimka): procesor sam prelazi u jezgreni način i skače na obrađivač iznimke, a jezgra takav proces obično prekine. Pogreška u parametrima poziva nije iznimka: loš opisnik ili adresu izvan korisničkog prostora obrađivač otkrije provjerom, a poziv se vraća uobičajenim putem, koracima 9–11, s rezultatom −1 i razlogom u varijabli errno (EBADF, EFAULT). Nazivlje se u knjigama razlikuje. Stallings riječju trap zove iznimku, grešku koju izazove instrukcija, a sistemski poziv zove supervisor call. Tanenbaum TRAP zove instrukciju kojom program namjerno ulazi u jezgru, pa je u prikazu ona označena kao TRAP (Tanenbaum); na x86 to su int 0x80 i syscall.

Exceptions, protection and terminology

A privileged instruction in user mode is not executed; it causes an exception: the processor itself switches to kernel mode and jumps to the exception handler, and the kernel usually terminates such a process. An error in the parameters of a call is not an exception: the handler finds a bad descriptor or an address outside user space by checking, and the call returns the usual way, through steps 9–11, with the result −1 and the reason in the variable errno (EBADF, EFAULT). The books differ in their terms. Stallings uses the word trap for an exception, an error caused by an instruction, and calls a system call a supervisor call. Tanenbaum uses TRAP for the instruction with which a program deliberately enters the kernel, so the simulator labels it TRAP (Tanenbaum); on x86 these are int 0x80 and syscall.