Wywołania systemowe Uniksa: Różnice pomiędzy wersjami
[wersja przejrzana] | [wersja przejrzana] |
Usunięta treść Dodana treść
Nie podano opisu zmian |
m clean up przy użyciu AWB |
||
Linia 2:
W [[Unix|systemach uniksowych]] program jest całkowicie odizolowany od sprzętu, dlatego zawsze musi się odwoływać do odpowiednich funkcji [[Jądro systemu operacyjnego|jądra]].
Z punktu widzenia programu odwołania te są ukryte w [[Biblioteka standardowa języka C|bibliotece libc]]
Na x86 i innych systemach o podobnej architekturze <tt>libc</tt> (lub też czasem program bezpośrednio) komunikuje się z jądrem za pośrednictwem [[przerwanie|przerwań]] systemowych. W Linuksie funkcje systemowe są dostępne przez przerwanie <tt>0x80</tt>, argumenty są przekazywane w rejestrach w następującej kolejności: <tt>eax</tt>, <tt>ebx</tt>, <tt>ecx</tt>, <tt>edx</tt>, <tt>edi</tt>, <tt>esi</tt>, <tt>ebp</tt>. Numer funkcji systemowej jest przekazywany w <tt>eax</tt>, natomiast pozostałe argumenty zależą od rodzaju funkcji (nie wszystkie muszą być wykorzystane). Status operacji zwracany jest w rejestrze <tt>eax</tt>. Gdy operacja wykona się bezbłędnie, jego wartość jest równa 0, w przeciwnym razie jest to (ujemna) stała z pliku <tt>asm/errno.h</tt>[http://lxr.linux.no/linux/include/asm-generic/errno.h]. Pozostałe rejestry nie są zmieniane.
W przypadku innych procesorów wywołania systemowe są wykonywane przez specjalizowane instrukcje procesora
== Śledzenie wywołań ==
Linia 43:
Uwaga: szczegóły dotyczą jądra Linux 2.4, ale różnice nie są aż tak duże.
== Otwieranie i zamykanie plików
Pliki otwiera się za pomocą trzyargumentowego <tt>open</tt>, którego definicja znajduje się w <tt>fcntl.h</tt>[http://lxr.linux.no/linux/include/asm-generic/fcntl.h]:
<syntaxhighlight lang="c">
Linia 51:
Pierwszy argument <tt>pathname</tt> oznacza ścieżkę do pliku.
Drugi <tt>flags</tt>
* <tt>O_RDONLY</tt>
* <tt>O_WRONLY</tt>
* <tt>O_RDWR</tt>
* <tt>O_CREAT</tt>
* <tt>O_EXCL</tt>
* <tt>O_TRUNC</tt>
* <tt>O_APPEND</tt>
* <tt>O_NONBLOCK</tt>
'''Opcjonalny''' trzeci
<tt>open</tt> należy do nielicznych wywołań systemowych dopuszczających pomijanie argumentu:
<syntaxhighlight lang="c">
Linia 81:
zamyka otwarty deskryptor pliku. W dawnych czasach <tt>close</tt> nie zwracało kodu błędu,
więc nikt go nie sprawdzał. Współcześnie zwraca kod błędu, co z punktu widzenia architektury systemu
jest kompletnym nieporozumieniem
błąd przy zamykaniu pliku i co program ma z tym zrobić.
Kernel może zwracać błędy <tt>EBADF</tt> (deskryptor jest zły), <tt>[[EINTR]]</tt> i dość ogólny <tt>EIO</tt> (błąd wejścia/wyjścia).
== Tworzenie plików specjalnych
<tt>open</tt> i <tt>creat</tt> potrafią tworzyć tylko zwykłe pliki.
Do tworzenia innych plików stworzono osobne wywołania systemowe.
Linia 102:
gdzie <tt>pathname</tt> i <tt>mode</tt> mają to samo znaczenie a <tt>dev</tt> to informacje o typie urządzenia.
== Zakończenie pracy
<syntaxhighlight lang="c">
void _exit(int status);
Linia 109:
<tt>status</tt> zostanie zwrócony jako kod wyjścia.
== Zarządzanie pamięcią
<syntaxhighlight lang="c">
int brk(void *end_data_segment);
Linia 137:
w rzeczywistości odczytana.
Liczba ta może być mniejsza od żądanej z wielu przyczyn
na połączeniu sieciowym jest mniejsza od żądanej, lub też jeśli zanim odczytano wszystkie dane nastąpiło przerwanie.
I o ile wartości od <tt>1</tt> do <tt>count</tt> są poprawne, wartość <tt>0</tt> może oznaczać tylko jedno
jeśli zaś nie było aktualnie żadnych danych, a połączenie było otwarte w trybie nieblokującym
Inne możliwe błędy to:
* <tt>EBADF</tt>
* <tt>EINVAL</tt>
* <tt>EIO</tt>
* <tt>EISDIR</tt>
* <tt>EFAULT</tt>
=== <tt>write</tt> ===
Linia 156:
</syntaxhighlight>
Argumenty mają takie samo znaczenie jak w <tt>read</tt>
=== <tt>readv</tt> i <tt>writev</tt> ===
Linia 164:
# przepiąć dane tak, żeby były ciągłe w pamięci, po czym wywołać <tt>write</tt> tylko jeden raz
Nic nie stoi jednak na przeszkodzie, żeby kernel sam zajął się tą operacją
<syntaxhighlight lang="c">
int readv(int filedes, const struct iovec *vector, size_t count);
Linia 209:
</syntaxhighlight>
<tt>out_fd</tt> to deskryptor wyjściowy, <tt>in_fd</tt>
zmienną przechowującą offset w pliku wejściowym, od którego ma zacząć dane wywołanie, a <tt>count</tt>
na nową wartość.
Linia 218:
nie musi wielokrotnie duplikować deskryptora, a po ich rozłączeniu wielokrotnie go zamykać.
Offset pliku wyjściowego jest poprawiany normalnie
sam deskryptor nie miałoby większego sensu (sekwencyjnemu wysyłaniu oczywiście to nie przeszkadza).
Linia 258:
</syntaxhighlight>
Ponieważ dane nie wędrują przez pamięć procesu, można podawać
i kernel dobrze sobie z nimi radzi. Powyższy program kopiuje plik 32219641-bajtowy (<tt>linux-2.4.19.tar.gz</tt>) prawie dwukrotnie szybciej niż <tt>cat</tt> (który robi to 4-kilobajtowymi odwołaniami <tt>read</tt> i <tt>write</tt>),
czy standardowy <tt>cp</tt> (niektóre nowsze wersje używają <tt>mmap</tt> lub <tt>sendfile</tt>).
Linia 280:
Tryb to maska złożona z:
* <tt>R_OK</tt>
* <tt>W_OK</tt>
* <tt>X_OK</tt>
* <tt>F_OK</tt>
Semantyka wywołania <tt>access</tt> nie jest jednak prosta.
Linia 293:
* itd.
<tt>access</tt> zwraca tylko prawa przysługujące uprawnieniom '''real''', nie zaś '''effective'''
ma pewne zastosowanie w programach używających praw '''setuid''' czy też '''setgid'''.
Naiwne stosowanie
Przykład działania:
|