Oto zadanie poświęcone funkcji systemowej fork.

Wydawać by sie mogło, że nic się nie da tutaj wymyślić, gdyż fork dobrze wykonuje swoją robotę. Można jednak usprawnić tą funkcję w przypadku, gdy proces potomny wywołuje jedną z funkcji z rodziny exec. W takim przypadku nie musi być kopiowana żadna ze struktur vm_area_struct opisujaca pamieć wirtualną procesu. Odpowiada to wywołaniu funkcji do_fork z ustawioną flagą CLONE_VM. Tak więc, chciałoby się mieć nową funkcję, powiedzmy fork2, która wywoływałaby w ten sposób do_fork, a którą byśmy używali w naszych programach testowych (zmiana funkcji sys_fork w jądrze na pewno by zawiesiła system). Są na to dwie metody.

Sposób 1.

Stworzyć własną funkcję w standardowej bibliotece lib.c, ktora by korzystała z funkcji systemowej sys_clone (sys_clone(0, SIGCLD | CLONE_VM)) Co prawda dawniej istniała stadardowa funkcja C clone wywołująca sys_clone, ale zniknęła z powodu złego działania.

Sposób 2.

Zmodyfikować istniejacą w źródłach jądra funkcję execve. Np. jeśli jej pierwszym parametrem jest NULL wówczas dziala jak nasz fork2. Odpowiednia zmiana funkcji w pliku process.c wygląda tak:

asmlinkage int sys_execve(struct pt_regs regs) {

int error;

char * filename;

/********************* poczatek dodanego kodu *****************/

/********************* koniec dodanego kodu ******************/

}

Osobiście polecam raczej drugi sposób, choć jest mniej elegancki. Kompilacja biblioteki C jest równie czasochłonna jak jądra oraz przy tworzeniu wlasnej funkcji wywołującej funkcję systemową trzeba stworzyć kilka plików bazujących w dużej mierze na niezrozumiałych na pierwszy rzut oka makrach. Próbowałem to uzyskać, ale się zniechęciłem - nie miałem pewności, czy będzie to działać.

Pozostaje ponownie skompilować jądro, a następnie zrobić jakiś eksperyment. Np. porównać czasy wykonania programów zawierających fork i exec, dla normalnego forka i fork2 (czyli dla naszego execve(NULL,NULL,NULL)).

Oczekiwane wyniki eksperymentu:

Skopiowanie listy i drzewa AVL struktur vm_area_strukt, ktore nam udało się wyeliminować z tak wywołanej funkcji fork2, znacznie przyspieszy samą operację tworzenia nowego procesu. Wydaje się jednak, że operacją dominującą jest wywołanie funkcji exec. Mimo wszystko w sytuacji gdy proces-rodzic jest dosyć duży, a sam plik uruchamiany w funkcji exec niewielki, możemy uzyskać nawet niezłą poprawę szybkości takiego programu.

P.S. Wydawać by sie mogło, że to, co opisuję odpowiada w pewnym stopniu istniejącej w unixowych systemach funkcji vfork. Otóż, nic takiego nie ma miejsca, jak można przekonać się ze źródeł biblioteki libc.a funkcja vfork dokładnie pokrywa sie z fork.

Autor: Michał Smoktunowicz