Ćwiczenie 4
Pakiet QNX Momentics IDE 4.7
Uruchamianie programów z maszyny wirtualnej systemu QNX.
Ćwiczenie
1. Uruchamiamy QNX na maszynie wirtualnej. Tworzymy w systemie QNX foldery / mnt/tmp – dla foldera TMP nadajemy prawa wykonywania x.
2. Udostępniamy folder naszego Workbench z QNXMomentics w Windows (przy zaawansowanych zabezpieczeniach – Narzędzia/Opcje/użyj prostego udostępniania - można wypróbować nadanie uprawnień dla użytkownika
_VMWare_user_
oraz
w
zabezpieczeniach
dodać/wyszukać
użytkownika
_VM_machine_user_ oraz nadać mu wszystkie prawa).
3. Wykonujemy udostępnienie poleceniem fs-cifs (jak w instrukcji ćw. 2 lub jak na poniższym rysunku, wykorzystując IP karty wirtualnej VMNet1 (lub VMNet8) (ipconfig w Windows). Treść polecenia fs-cifs w dzia-
łającej wersji zapisujemy w pliku o nazwie ud_qnx w katalogu bin, plikowi nadajemy prawo x dla właści-ciela ( roota). Odtąd na każdych zajęciach będziemy mogli łatwo uruchomić udostępnienie – wykonanie utworzonego pliku jako polecenia (z dowolnej lokalizacji):
ud_qnx
4. Sprawdzamy zwartość katalogu tmp – powinny tam się pojawić foldery naszych dotychczasowych projektów.
5. Wykonujemy działający program napisany w czasie poprzedniego ćwiczenia z lokalizacji projekt/x86/o:
./ projekt
6. Dopiero teraz uruchamiamy w terminalu agenta qconn i otwieramy środowisko QNX Momentics.
Przekształcenie procesu w inny proces
execl
Funkcja execl przekształca bieżący proces w inny proces o kodzie zawartym w pliku wykonywalnym fname, przekazując mu parametry arg0, arg1,arg2, itd.
execl(path/fname,arg0,arg1,...,NULL)
Ćwiczenie
1. W QNX Momentics napisać programy ex1 i ex2. W pierwszym z nich zastosować funkcję execl:
execl("/mnt/tmp/drugi/x86/o/ex2","tekst",10","20",NULL); Uzupełnić obydwa programy w odpowiednie komunikaty i akcje. Wykonać program w QNX z efektem jak na rysunku:
2. Wypróbować przekazanie argumentów do procesu ex2. W drugim programie wydrukować wartości argumentów w pętli, wykorzystując zmienną argc (liczba argumentów): int x;
printf("Liczba argumentów=%d\n",argc);
for (x=0;x<argc;x++)
{
printf("x=%s\n",argv[x]);
}
3. Zmodyfikować obydwa programy tak, aby jeden z argumentów określał liczbę przebiegów pętli w programie drugim. Zastosować konwersję typu danych (funkcja: int atoi(string s) ).
4. Wykonać program bezpośrednio na maszynie wirtualnej z terminala.
Zakończenie procesu
exit
Funkcja exit jest przeznaczona do normalnego zakończenia procesu. Zwraca procesowi macierzystemu kod za-kończenia, który może być przez niego zinterpretowany.
void exit( int status );
Zwykle status jest ustawiany na EXIT_SUCCESS, w przypadku normalnego zakończenia procesu lub ustawiany na EXIT_FAILURE w przypadku błędu.
wait
Funkcja wait umożliwia synchronizację procesów. W przypadku napotkania funkcji wait proces macierzysty oczekuje na zakończenie procesu potomnego (pierwszego, jeśli jest ich wiele) – wówczas dostępny jest status.
Wcześniejsze zakończenie procesu macierzystego niż potomnego spowodowałoby, że potomny straciłby swojego przodka. Funkcja zwraca PID procesu potomnego.
pid_t wait (int *status)
Gdy status jest różny od NULL, stan procesu potomnego jest wskazywany przez zmienną status. Istnieją makro, jak np. WIFEXITED(status), umożliwiające odczytanie informacji ze zmiennej status: 1 – jeśli normalne zakończenie procesu
0 - jeśli błąd
Ćwiczenie
1. Napisać program tworzący proces potomny funkcją fork. W procesie potomnym wykonać dłuższą akcję (np. 100-krokową pętlę). W procesie macierzystym zastosować funkcję wait i wypisać wartość statusu oraz identyfikatory procesu macierzystego oraz zakończonego procesu potomnego. Porównać wykonanie programu w przypadku braku funkcji wait.
2. Sprawdzić, i wyjaśnić dlaczego, jeśli w procesie potomnym będzie wykonywana pętla: for (x=5;x>-5;x--)
printf("x=%d\n",x);
to wykonane w procesie macierzystym instrukcje:
pid = wait(&status);
printf("KONIEC pid:%u status%i\n",pid,WIFEXITED(status)); zwrócą wartość statusu 1, natomiast pętla:
for (x=5;x>-5;x--)
printf("x=%d\n",1/x);
zwróci status równy 0.
Tworzenie procesów współbieżnych
spawnl
Funkcja spawnl używana jest do tworzenia nowych procesów, z możliwością wyboru trybu pracy procesu macierzystego, który może być zakończony, wykonywany współbieżnie lub z oczekiwaniem na zakończenie potomnego.
pid_t spawnl(int mode, char * path, arg0, arg1,..., argN, NULL) mode - tryb wykonania procesu: P_WAIT, P_NOWAIT, P_OVERLAY, P_NOWAITO, path – ścieżka z nazwą pliku wykonywalnego,
arg0 - argument 0 przekazywany do funkcji main tworzonego procesu. Powinna być to nazwa pliku wykonywalnego ale bez ścieżki,
arg1, ...argN – argumenty przekazywane do funkcji main tworzonego procesu.
Funkcja zwraca PID (typ pid_t lub integer) utworzonego procesu lub -1 gdy wystąpi błąd.
Tryby wykonania:
P_WAIT - proces czeka na zakończenie procesu potomnego
P_NOWAIT - proces potomny wykonywany jest współbieżnie
P_OVERLAY - proces bieżący zastępowany jest przez proces potomny
Ćwiczenie
Przetestować i wyjaśnić działanie poniższego programu. Wcześniej utworzyć program sp2 wykonujący pętlę o liczbie kroków zadaną parametrem funkcji spawnl. Wypróbować wszystkie trzy wersje trybów i wyjaśnić róż-
nice wykonania.
#include <stdio.h>
#include <process.h>
#include <sys/wait.h>
main(void){
int pid,i,res,status;
char buf[10];
//res=spawnl(P_WAIT,"/mnt/tmp/sp2/x86/o/sp2","sp2","10",NULL);
//res=spawnl(P_OVERLAY,"/mnt/tmp/sp2/x86/o/sp2","sp2","10",NULL);
//res=spawnl(P_NOWAIT,"/mnt/tmp/sp2/x86/o/sp2","sp2","10",NULL); if(res < 0) {
perror(""); exit(0);// wymuszenie zakończenia
}
for(i=1;i<10;i++) {
printf("Proces macierzysty - krok %d \n",i);
sleep(1);
}
pid = wait(&status);
printf("Proces %d zakonczony, status %d\n",pid,WEXITSTATUS(status));
}
Zwrócić uwagę na wykorzystanie funkcji perror.