Wywołania systemowe Uniksa

Z Nonsensopedii, polskiej encyklopedii humoru
Przejdź do nawigacji Przejdź do wyszukiwania
Linux jest darmowy, o ile twój czas jest bezwartościowy.
Jamie Zawinski
Kompatybilne jednocześnie z POSIX i Linux? W jakim świecie ty żyjesz, że w to wierzysz?

Wywołania systemowe Uniksa – zbiorowisko luźno powiązanych ze sobą funkcji ukrytych gdzieś w trzewiach biblioteki libc. Wywołana funkcja może się wykonać i (jeśli ma na to ochotę) zwrócić nic nie mówiące errno. Standardowe wywołania opisuje dokumentacja POSIX, którą można streścić następująco:



Cquote2.svg

Zachowanie jest niezdefiniowane.
Cquote2.svg

Początkującym programistom zalecamy wyrycie sobie tej złotej sentencji na ścianie nad monitorem i spoglądanie na nią w razie jakichkolwiek wątpliwości.

Zanim przejdziemy do części właściwej artykułu, warto zastanowić się kogo właściwie obchodzi coś nazwane tak cudacznie jak wywołania systemowe Uniksa? W normalnych warunkach powinno to być kilku piwniczaków, którzy piszą niskopoziomowe programy na Linuxie. Jednak z jakiegoś niejasnego powodu wykładowcy kierunków informatycznych katują studentów bezużytecznymi syscallami, rozszerzając grupę wtajemniczonych piwniczaków kilkukrotnie.

Zarządzanie procesami

W celu skuteczniejszego siania chaosu i pszenicy wśród procesora, RAMu i peryferiów, system jednocześnie uruchamia wiele procesów, które nieustannie konkurują o dostęp do zasobów. Rezultatem jest nieokiełznany bajzel, do kontrolowania którego zostaje zmuszony Bogu ducha winny programista, a za jego błędy cierpi użytkownik. Sam sprawca całego pierdolnika – Szatan system operacyjny jest święty i ma zawsze rację.

  • fork – zaczynamy z grubej rury, czyli od funkcji, która potrafi stworzyć coś z niczego, zwrócić dwie różne wartości i na dodatek debilnie się nazywać. Jak sama nazwa wskazuje, fork dziabie kernel widelcem gdzieś pomiędzy planistą, a zarządzaniem pamięcią. Wkurzony nie na żarty kernel dla świętego spokoju robi procesowi dziecko i na odchodne wsadza mu widelec w wiadome miejsce.
  • exec – funkcja zazwyczaj wykonywana po fork żeby nieco złagodzić ból po bo bolesnej interakcji z jądrem. Pozwala procesowi przeszczepić sobie wszystkie organy innego programu, zostawiając jedynie PID i parę niezdefiniowanych interakcji. Jak łatwo się domyślić, funkcja exec wcale nie istnieje, a programista powinien skorzystać z execl, execle, execlp, execv, execve lub execvp. Zrozumienie co robią poszczególne wersje zostawiam jako ćwiczenie dla studentów.
  • exit – kiedy proces ma już dość życia na ziemskim padole łez, decyduje się na krok ostateczny i wykonuje funkcję exit. Za argument można podać 0 (czyli jest dobrze), albo jeden z pierdyliarda kodów błędu, które są kompletnie niezdefiniowane i nie mają żadnego znaczenia. W momencie popełnienia seppuku proces wysyła jeszcze rodzicowi liścik pożegnalny w postaci SIGCHLD. Jest to jeden z nielicznych sygnałów, który nie zabije trafionego procesu, ale za to musi zostać obsłużony bo tak.
  • wait – jak sama nazwa wskazuje, wait służy do czekania na dzieci aż się zabiją, za wyjątkiem sytuacji, gdy na nie nie czekamy. Przy okazji możemy otrzymać kod, jaki dziecko przekazało do exit, co oczywiście nic nam nie mówi, bo może znaczyć cokolwiek. Jeśli nie zaczekamy na martwe dziecko to zamieni się ono w zombie. Dodatkowo, jeśli rodzic umrze niewywaitowawszy dzieci, to zombie staną się sierotami i… No generalnie syf się robi, lepiej waitować.

Sygnały

kill(-1, SIGKILL);
  • kill – jak mawia stare polskie przysłowie: nie machaj tym drągiem baranie na oślep bo jeszcze komuś przypCenzura2.svgisz. Zasada ta nie dotyczy sygnałów w Uniksie, bo strzelanie sygnałami przypomina nieco operowanie drewnianą armatą po pijaku. Tutaj nie da się nie machać na oślep, bo nigdy nie wiadomo w co trafisz i jak zareaguje na to dany proces. Równie dobrze armata może ci wybuchnąć w twarz i przedwcześnie zakończyć zabawę.
  • sigaction – coby nieco okiełznać pierdolnik wywoływany przez różnorakie sygnały, można kazać procesowi reagować w określony sposób na niektóre z nich. Sposób bardzo biedny, bo przerywający działanie głównego wątku interruptem i przerzucający kontrolę w pizdu do handlera.
  • sigsuspend – funkcja zawieszająca program aż do otrzymania jednego z sygnałów z podanej maski. Wtedy wykonuje domyślną dyspozycję (zazwyczaj wywalenie procesu) albo odpala handler ustawiony przy pomocy sigaction. Podobno jest lepsze od zwykłego sleep.
  • sigwait – ucywilizowana wersja powyższego. Zamiast cudować z handlerami po prostu zwraca numerek otrzymanego sygnału. Brawo. Nie można tak było od razu?

Obsługa plików

  • open – otwiera plik/socket/urządzenie blokowe/pralkę/piwo/cokolwiek co może być traktowane jako plik w Uniksie. Żeby było śmieszniej, nie zwraca wskaźnika na jakąś strukturę (jak np. wysokopoziomowy fopen), tylko numerek deskryptora, który nic nie mówi. Całością zajmuje się jądro i programista jest zdany na jego łaskę lub niełaskę. Można też podać jakieś śmieszne flagi, w stylu O_RDONLY, czy O_APPEND, ale efekt końcowy i tak jest losowy.
  • close – tu nawet nie musimy się wysilać, wystarczy że zacytujemy ciocię Wikipedię: W dawnych czasach close 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 – nikt tak naprawdę nie zdefiniował co konkretnie ma znaczyć błąd przy zamykaniu pliku i co program ma z tym zrobić.
Powyższy tekst można śmiało uzupełnić o informację, że cały POSIX to jedno wielkie nieporozumienie.
  • read/write – jak już se plik otworzymy to wreszcie możemy z niego czytać (lub zapisywać doń) surowe bajty. Pokazujemy funkcji jakiś bufor i modlimy się, żeby się nie przepełnił. Obie te funkcje zwracają całą gamę błędów, od złej flagi, przez przeciekające rury, po interwencję siły wyższej.