# Lista 7 ###### tags: `sju21` `ćwiczenia` ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie w trakcie dyskusji (co najwyżej jedno!) oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 7-1 | 7-2 | 7-3 | 7-4 | 7-5 | 7-6 | | ---------------------:| --- | --- | --- | --- | --- | --- | | Jacek Bizub | X | X | X | X | X | X | 6 | Wojciech Jasiński | X | X | X | | | | 3 | Artur Juraszek | | | | | | | 0 | Michał Myczkowski | | | | | | | 0 | Michał Odorczuk | X | X | X | X | X. | X. | 6 | Damian Ratajski | | | | | | | 0 | Łukasz Siudek | | | | | | | 0 | Błażej Sowa | X | X |==X==| | X. | | 4 | Andrzej Turko | X |==X==| X | X | X | X | 6 | Maksymilian Zawartko | X | X | | | X. | X. | 4 ::: ## Zadanie 7-1 :::info Autor: Wojciech Jasiński ::: * jakie funkcje pełni terminal działający w trybie kanonicznym? - wejście przetwarzane w liniach (kończone '\n', EOF lub EOL) - wczytywanie blokuje aż cała linia zostanie wczytana (<= `MAX_CANON` znaków) - znaki specjalne: `ERASE` (ostatni znak w aktualnej linii), `KILL` (cała aktualna linia) - wyjście: - może buforować (zależnie od implementacji) - może podmieniać znaki (np. <TAB> na spacje albo CR -> NL) * wytłumacz w jaki sposób sterownik terminala przetwarza znaki (w tym kody sterujące) wchodzące do kolejki wejściowej i wyjściowej. 1) terminal -> proces 1. sterownik sprawdza, czy znak jest specjalny (i czy odpowiednia opcja jest włączona) 2. sterownik wykonuje specjalną akcję lub zapisuje znak (może zmodyfikowany) do kolejki wejściowej 3. proces odbiera znak z kolejki (przez stdin) 2) proces -> terminal 1. jakiś proces pisze do kolejki wyjściowej przez stdout 2. sterownik dostaje znak, być może go tłumaczy 3. sterownik decyduje, czy pora wypisać kolejkę wyjściową do urządzenia * wskaż kody sterujące w wydruku polecenia `stty -a` i wyjaśnij jaką pełnią funkcję ``` eof = ^D; eol = <undef>; eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V; quit = ^\; rprnt = ^R; start = ^Q; stop = ^S; susp = ^Z; swtch = <undef>; werase = ^W ``` Funkcje: [man termios(4)](http://man.netbsd.org/termios.4): Special Characters, `man stty(1)`: Special characters ## Zadanie 7-2 :::info Autor: Maksymilian Zawartko ::: Sterownik terminala zapewnia dostęp do urządzeń terminalowych (lokalnych i zdalnych). Odpowiada zarówno za przepływ danych, jak i ich format. Polecenia do modyfikacji `termios` i `winsize`: 1. `TIOCSETA struct termios *term` - ustawia `termios`; jest wołane przez `tcsetattr(3)` z opcją `TCSANOW`. `TCSANOW` - zmiana jest dokonywana od razu. 2. `TIOCSETAW struct termios *term` - czeka na zakończenie wyjścia i ustawia `termios`; jest wołane przez `tcsetattr(3)` z opcją `TCSADRAIN`. `TCSADRAIN` - zmiana jest dokonywana po przetransmitowaniu całego outputu zapisanego do deksryptora pliku do terminala. `TCSADRAIN` powinno być używane przy zmianie parametrów wyjścia. 3. `TIOCSETAF struct termios *term` - czeka na zakończenie wyjścia i wyczyszczenie wejścia, następnie ustawia `termios`; jest wołane przez `tcsetattr(3)` z opcją `TCSAFLUSH`. `TCSAFLUSH` - j.w., przy czym to, co zostało wpisane, ale jeszcze nie zatwierdzone, jest odrzucane. 4. `TIOCSFLAGS int *state` - bity inta pod wskaźnikiem `state` kodują stan portu szeregowego: * `TIOCFLAG_SOFTCAR` - ignore hardware carrier. * `TIOCFLAG_CLOCAL` - ustaw flagę `CLOCAL` przy otwarciu. * `TIOCFLAG_CRTSCTS` - ustaw flagę `CRTSCTS` przy otwarciu. * `TIOCFLAG_MDMBUF` - ustaw flagę `MDMBUF` przy otwarciu. 5. `TIOCSWINSZ struct winsize *ws` - ustawia rozmiar okna. Niektóre porty szeregowe mogą nie obsługiwać `TIOCSFLAGS`. Są 3 (1, 2 i 3 są bardzo podobne) polecenia do ustawiania konfiguracji terminala, bo 1, 2, 3 operują bezpośrednio na strukturze `termios`, 4 - na trochę innym poziomie abstrakcji, a 5 - na `winsize`. input flags: ```bash= -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 ``` output flags: ```bash= opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 ``` control flags: ```bash= -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts ``` local flags: ```bash= isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc ``` `ICRNL` - zamień CR na NL przy wejściu. `ONLCR` - zamień NL na CR-NL przy wyjściu. `ISIG` - po wpisaniu jednego ze znaków `INTR`, `QUIT`, `[D]SUSP` generowany jest odpowiedni sygnał (`SIGINT`, `SIGQUIT`, `SIGTSTP`). `ECHOCTL` - wypisuj otrzymywane znaki kontrolne jako `^(Char)`. ## Zadanie 7-3 :::info Autor: Błażej Sowa ::: > **Urządzenie terminala** zajmuje się interpretacją [znaków i sekwencji sterujących](https://en.wikipedia.org/wiki/ANSI_escape_code) oraz przetwarzaniem zdarzeń od użytkownika, które zostają zamienione na znaki lub sekwencje znaków. Posługując się poleceniem `«echo -e ’sterujacy’; read»` zaprezentuj działanie znaków sterujących oraz sekwencji `«CSI»`. Uruchom polecenie `«cat»` i sprawdź jak zachowuje się naciśnięcie klawiszy funkcyjnych i kursora. Czemu w tym przypadku zachowanie programu «cat» jest inne niż powłoki poleceń? Następnie ściągnij i zainstaluj bibliotekę [python-evdev] i przeczytawszy rozdział `„Quick start”` napisz prosty programik, przy pomocy którego zaprezentujesz dane zwracane przez pliki urządzenia myszki i klawiatury dostępne w katalogu `«/dev/input/by-path»`. [python-evdev]: https://python-evdev.readthedocs.io/en/latest/ Znaki sterujące: ```bash # Backspace echo -ne 'asdf\010\010 '; read # Form Feed echo -ne 'asdf\014asda'; read # Carriage Return echo -ne 'asdf\015asda'; read ``` Sekwencje sterujące CSI (`\033` to znak ESC): ```bash # Erase in Line echo -ne 'asdf\033[1Kfdsa'; read # Slow Blink echo -ne 'asdf\033[5mfdsa'; read # Cursor down echo -ne 'asdf\033[5Bfdsa'; read # Cursor position echo -ne 'asdf\033[20;20Hfdsa'; read # Set Background color echo -ne 'asdf\033[42m fdsa'; read ``` Co się dzieje jak uruchomimy `cat` i naciśniemy klawisze funkcyjne?: ``` ^[[D^[[C^[[A^[[D^[[B^[[A^A^K^K ``` Program `cat` nie obsługuje znaków i sekwencji sterujących. Przy włączonej opcji `ECHOCTL`, po naciśnięciu klawiszy funkcyjnych dostaje na wejściu ciąg znaków przetłumaczony przez sterownik terminala i nie interpretuje ich. programik: ```python= #!/usr/bin/env python3 from evdev import InputDevice from selectors import DefaultSelector, EVENT_READ mouse = InputDevice('/dev/input/by-path/platform-AMDI0010:03-event-mouse') keyboard = InputDevice('/dev/input/by-path/platform-i8042-serio-0-event-kbd') selector = DefaultSelector() selector.register(mouse, EVENT_READ) selector.register(keyboard, EVENT_READ) while True: for key, _ in selector.select(): device = key.fileobj for event in device.read(): if device.fd == mouse.fd: print("MOUSE: ", end='') else: print("KEYBOARD: ", end='') print(event) ``` ## Zadanie 7-4 :::info Autor: Michał Odorczuk ::: ``` // Setting up pipe rpipe = fp->f_pipe; lock = rpipe->pipe_lock; error = 0; mutex_enter(lock); wpipe = rpipe->pipe_peer; /* * Detect loss of pipe read side, issue SIGPIPE if lost. */ if (wpipe == NULL || (wpipe->pipe_state & PIPE_EOF) != 0) { mutex_exit(lock); return EPIPE; } ``` ``` while (uio->uio_resid) /* remaining bytes to copy */ ``` ``` space = bp->size - bp->cnt; // If not enough space and less than PIPE_BUF remains, wait if ((space < uio->uio_resid) && (uio->uio_resid <= PIPE_BUF)) space = 0; ``` Jeśli space > 0 to uiomove, w przeciwnym wypadku czekamy aż zwolni się miejsce ``` /* * Transfer size is minimum of uio transfer * and free space in pipe buffer. */ if (space > uio->uio_resid) size = uio->uio_resid; else size = space; segsize = bp->size - bp->in; if (segsize > size) segsize = size; /* Transfer first segment */ mutex_exit(lock); // Support atomic write for up to segment size error = uiomove((char *)bp->buffer + bp->in, segsize, uio); // We do not have to keep atomicity now if (error == 0 && segsize < size) { error = uiomove(bp->buffer, size - segsize, uio); } mutex_enter(lock); bp->in += size; // Move forward by size bytes if (bp->in >= bp->size) { KASSERT(bp->in == size - segsize + bp->size); bp->in = size - segsize; } bp->cnt += size; ``` else ``` /* * If the "read-side" has been blocked, wake it up now. */ cv_broadcast(&wpipe->pipe_rcv); /* * We have no more space and have something to offer, * wake up select/poll. */ if (bp->cnt) pipeselwakeup(wpipe, wpipe, POLL_IN); pipeunlock(wpipe); // Wait for write-pipe to have any interaction // It may mean that there is enough space now error = cv_wait_sig(&wpipe->pipe_wcv, lock); (void)pipelock(wpipe, false); /* * If read side wants to go away, we just issue a signal * to ourselves. */ if (wpipe->pipe_state & PIPE_EOF) { error = EPIPE; // SIGPIPE once again break; } ``` ## Zadanie 7-5 :::info Autor: Andrzej Turko ::: > Przeprowadź uczestników zajeć przez proces odczytu rekordu zdarzenia z **pliku urządzenia znakowego** myszy w systemieNetBSD. Plik ten jest przechowywany w systemie plików `specfs`, który zajmuje się wyłącznie przechowywaniem plików urządzeń. > Należy zacząć w implementacji wywołania systemowego [sys_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/sys_generic.c?r=1fe5c4da#sys_read) i poprzez operacje plikowe opisane w [file(9)](http://man.netbsd.org/file.9) dotrzeć do procedury wchodzącej do system plików przy użyciu [VOP_READ(9)](http://man.netbsd.org/VOP_READ.9). Przy założeniu, że typ v-węzła systemu plików to `VCHR`, należy kontynuować przez [spec_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/miscfs/specfs/spec_vnops.c?r=1fe5c4da#spec_read) do **tablicy funkcji pliku urządzenia** (ang. device switch table) myszki [ms_cdevsw](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/ms.c?r=1fe5c4da#ms_cdevsw). Stamtąd należy osiągnąć miejsce użycia [uiomove(9)](http://man.netbsd.org/uiomove.9) w funkcji [ev_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/event.c?r=1fe5c4da#ev_read), gdzie następuje wkopiowanie zdarzenia do przestrzeni użytkownika. --- **Plik urządzenia** – specjalny plik reprezentujący zasób (urządzenie). Dzięki takiemu zabiegowi zostaje znacznie uproszczona komunikacja z urządzeniem, np. chcąc wykonać kopię partycji, wystarczy skopiować plik, który ją przedstawia. **Urządzenie znakowe** (ang. character device) – służy do odczytywania/zapisywania danych z/do urządzenia znak po znaku; w większości przypadków pojęcie znak jest równoznaczne z pojęciem bajt. Urządzenia znakowe z zasady nie są buforowane i służą do komunikacji o charakterze strumieniowym. --- **The device switch tables** are arrays of operational pointers. Each entry in the table consists of a subarray of jump points. The routines pointed to are entered in a documented order and cover actions such as open, close, read, write, and several more. --- 1. [sys_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/sys_generic.c?r=1fe5c4da#121) -- pobieramy referencję na urządzenie 2. [dofileread](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/sys_generic.c?r=1fe5c4da#156) -- tworzymy uio, wołamy reada odpowiedniego dla tego pliku, po powrocie zwalniamy usuwamy referencję z 1. 3. [vn_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/vfs_vnops.c?r=1fe5c4da#552) -- przepisujemy flagi i przekazujemy sterowanie dalej... 4. ...[spec_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/miscfs/specfs/spec_vnops.c?r=1fe5c4da#713) -- wołamy cdev_read 5. [cdev_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/kern/subr_devsw.c?r=1fe5c4da&fi=cdev_read#903) -- szukamy device switch table (specyficzne dla character device, poprzedni struct był wspólny dla wszystkich plików) i wołamy ms_read z tego structa. 6. [ms_cdevsw](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/ms.c?r=1fe5c4da#136) 7. [ms_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/ms.c?r=1fe5c4da#487) -- znajdujemy kolejkę zdarzeń myszy i wołamy ev_read. 8. [ev_read](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/event.c?r=1fe5c4da#140) -- zapisujemy wydarzenia do uio z 2. ## Zadanie 7-6 :::info Autor: Jacek Bizub ::: > Na podstawie [1, 8.3], [1, 8.4] i [4, 10.1.2] uzasadnij potrzebę umieszczenia funkcji `d_open` i `d_close` w tabelach funkcji urządzeń `cdevsw` i `bdevsw` systemu NetBSD. Następnie zreferuj co robi implementacja tych funkcji w sterowniku stacji dyskietek [fd_cdevsw](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/fd.c?r=1fe5c4da#fd_cdevsw). Jakie zadania pełni funkcja `d_strategy` w tablicy funkcji pliku **urządzenia blokowego** (ang. block device switch table) [fd_bdevsw](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/fd.c?r=1fe5c4da#fd_bdevsw)? --- **Urządzenie blokowe** (ang. block device) – pozwala na odczytywanie/zapisywanie danych blokami, czyli większymi grupami bajtów mającymi postać: sektorów, kilobajtów czy klastrów. W większości przypadków konieczność operowania na blokach wymuszona jest fizyczną budową urządzenia. Urządzenia blokowe różnią się od znakowych tym, mogą być buforowane i pozwalają na swobodny dostęp do danych na nich zgromadzonych. --- A device driver for a character device is defined by its entries in a cdevsw structure: *open* Opens the device in preparation for I/O operations. A device’s open entry point will be called for each open system call on a special-device file or, internally, when a device is prepared for mounting a filesystem with the mount system call. The open() routine will commonly verify the integrity of the associated medium. For example, it will verify that the device was identified during the autoconfiguration phase and, for disk drives, that a medium is present and ready to accept commands. *close* Closes a device. The close() routine is called after the final client interested in using the device terminates. These semantics are defined by the higher-level I/O facilities. Disk devices have nothing to do when a device is closed and thus use a null close() routine. Devices that support access to only a single client must mark the device as available once again. --- *strategy* Starts a read or write operation, and return immediately. I/O requests to or from filesystems located on a device are translated by the system into calls to the block I/O routines bread() and bwrite(). These block I/O routines in turn call the device’s strategy routine to read or write data not in the memory cache. Each call to the strategy routine specifies a pointer to a buf structure containing the parameters for an I/O request. If the request is synchronous, the caller must sleep (on the address of the buf structure) until I/O completes. --- [open](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/fd.c?r=1fe5c4da#fdopen) sterownika `fd.c` waliduje dane, w razie potrzeby alokuje bufor dla cache'u i ładuje dysk. [close](https://mimiker.ii.uni.wroc.pl/source/xref/NetBSD/sys/arch/amiga/dev/fd.c?r=1fe5c4da#fdclose) flushuje bufory, odłącza partycję i jeśli to możliwe to wyłącza silnik dyskietki (lub czeka aż to będzie możliwe)