Tentamen Systemnära programmering, 7.5hp 5 november 2012 Skrivtid: 9 13 Hjälpmedel: EN av följande böcker Bilting & Skansholm: Vägen till C ELLER J.R. Hanly & E.B. Koffman: C Program Design for Engineers ELLER J.R. Hanly & E.B. Koffman: Problem Solving and Program Design in C ELLER A. Kelley & I. Pohl: A Book on C ELLER Brian W. Kernighan & Dennis M. Ritchie: C Programming Language Maxpoäng: 40 (Gräns för 3: 20p (50%), 4: 26p (65%), 5: 32p (80%)) Börja varje uppgift på nytt blad och fyll i koden på varje blad. Jag planerar att besöka skrivsalen ungefär 11.00. Vid tveksamheter beskriv er tolkning. Tänkpåattmankanfåpoängävenommanelyckaslösahelauppgiften. Lycka Till! Uppgift 1 (4 p) Förklara kortfattat följande begrepp och dess användning: Reentrant function Nonblocking I/O Process Race condition Uppgift 2 (3 p) Vad är en hård länk? Vad är en symbolisk länk? Beskriv likheter och skillnader dem emellan. 1
Uppgift 3 (3 p) Man kan hantera signaler på olika sätt. Till exempel kan man ignorera signalen. Vilka är de 2 övriga sätten att hantera signaler? Ett par signaler kan e ignoreras, varför? En del andra signaler bör e ignoreras även om det går. Vilken typ av signaler hör dit och varför bör de e ignoreras? Uppgift 4 (5 p) Beskriv vad som händer när följande kommando exekveras av csh(alltså e vad kommandot utför). Ta med bland annat, Hur startas processer och program? När, och av vilken process skapas pipor. Hur hanteras omdirigering etc. Beskriv utförligt och rita gärna figurer. % coma < infil.txt comb comc -o fout Uppgift 5 (5 + 1 p) #include <...> static g = 10; main( argc, char *argv[]) { v = 10; pid_t p; } while (++v > 8) if ((p = fork()) < 0) { perror("fork error"); return 1; } else if (p == 0) { v-=2; g++; } else { g--; v-=3; if (waitpid(p, NULL, 0)!= p) { perror("waitpid error"); return 1; } } prf("mypid = %d parentpid = %d p = %d v = %d g = %d\n", getpid(), getppid(), p, v, g); return 0; (a) Vad skrivs ut av programmet ovan? PID-nummer får ni hitta på, bara relationen mellan de olika numren framgår. (Rita gärna en figur.) (b) Blir det någon skillnad om man plockar bort waitpid? Motivera ditt svar. 2
Uppgift 6 (1 + 3 + 1 p) Enligt Stevens finns det 3 strukturer (file table, process table entry, v-node table) som kärnan använder för att hantera öppna filer. (a) Hur är dessa relaterade? (b) Ge exempel på information som finns i varje struktur. (c) Om två processer öppnar samma fil vilken/vilka (om någon) strukturer är gemensamma? Uppgift 7 (8 p) Skriv ett ANSI C-program argtst (för att prova olika optioner till ett kommando) argtst command opt1 [opt2...] file som tar ett kommando, minst ett option och en fil som argument, t ex % argtst ls -l -g -i -n main.c och startar en process för varje option som angetts till kommandot. Varje process ska exekvera kommandot med en option och filen som argument. Programmet ska utföra ungefär samma sak som om man ger kommandoraden % command opt1 file; command opt2 file;... Till exempel motsvarar argtst-exemplet ovan följande kommandorad % ls -l main.c; ls -g main.c; ls -i main.c; ls -n main.c dvs varje kommando får en egen process, men utförs i sekvens och man får e tillbaka promten direkt utan först när alla optioner testats. (Kom ihåg att testa saker och ting. Funktionen system() får ej användas.) 3
Uppgift 8 (2 + 4 p) (a) Nämn en likhet och olikhet mellan en semafor och mutex (från pthread). (b) Betrakta följande synkroniseringsproblem: I ett system finns det tre typer av processer kallade A, B och C. De använder en gemensam resurs R. Resursen R kan användas samtidigt av ett godtyckligt antal processer, men högst två olika typer av processer får använda R samtidigt. Till exempel så kan R användas samtidigt av 5 processer av typ B och 3 processer av typ C, men om sedan en process av typ A också vill använda R så måste den vänta tills antingen alla processer av typ B eller alla processer av typ C har släppt resursen. Lös detta genom att implementera en entry section (dvs kodavsnitt att exekvera före) och exit section (kodavsnitt efter) till den kritiska region i vilken R används. Dvs entry section använd R här exit section Använd vanliga, räknande semaforer för synkronisering och en C-liknande pseudokod. Din lösning måste säkerställa korrekt synkronisering och den ska vara deadlock-fri, men den behöver e vara fri från utsvältning. Du måste också tydligt deklarera och initialisera alla variabler och semaforer. Din lösning ska vidare vara symmetrisk, dvs koden för de tre processtyperna ska vara identisk så när som på namnen på vissa variabler och semaforer. Därför behöver du bara skriva koden för en av processtyperna förutsatt att namnen på variabler och semaforer gör det uppenbart hur koden ska ändras för att passa övriga processtyper. (Använd t ex suffixet A för variabler och semaforer som är specifika för processer av typ A.) Tips: Använd en räknande semafor initialiserad till 2 för att garantera att högst två olika typer av processer samtidigt kan gå in i den kritiska region där R används. T ex: semaphore ok_to_use = 2; Glömejattdeendaoperationernasomkananvändaspåenvanligräknande semafor är wait och signal. 4
Funktionsprototyper execl(const char *pathname, const char *arg0,.../* (char *) 0 */); execle(const char *pathname, const char *arg0,.../* (char *) 0, char *const envp[] */); execlp(const char *filename, const char *arg0,.../* (char *) 0 */); execv(const char *pathname, char *const argv[]); execve(const char *pathname, char *const argv[], char *const envp[]); execvp(const char *filename, char *const argv[]); void FILE pid t exit( status); fclose(file *fp); feof(file *fp); fgetc(file *fp); This function never returns Returns: 0 if OK, -1 on error Returns: nonzero (true) if end of file on stream, 0 (false) otherwise Returns: next character if OK, EOF on end of file or error fgets(char *buf, n, FILE *fp); Returns: buf if OK, NULL on end of file or error *fopen(const char *filename, const char *type); type: "r", "w", "a", "r+", "w+", "a+" Returns: file poer if OK, NULL on error fork(void); <sys/types.h> Returns: 0 in child, process ID of child in parent, -1 on error fprf(file *fp, const char *format,...); Returns: #characters output if OK, negative value if output error fputc( c, FILE *fp); Returns: c if OK, EOF on error fputs(const char *str, FILE *fp); Returns: nonnegative value if OK, EOF on error void free(void *ptr); fscanf(file *fp, const char *format,...); Returns: #input items assigned, EOF if input error or EOF before any conversion getc(file *fp); Returns: next character if OK, EOF on end of file or error getchar(void); Returns: next character if OK, EOF on end of file or error 5
void void FILE *malloc(size t size); Returns: nonnull poer if OK, NULL on error pclose(file *fp); Returns: 0 if OK, -1 on error perror(const char *msg); pipe( fildes[2]); Returns: 0 if OK, -1 on error *popen(const char *cmdstring, const char *type); type: "r", "w" Returns: file poer if OK, NULL on error prf(const char *format,...); putc( c, FILE *fp); putchar( c); Returns: #characters output if OK, negative value if output error Returns: c if OK, EOF on error Returns: c if OK, EOF on error puts(const char *str); Returns: nonnegative value if OK, EOF on error scanf(const char *format,...); Returns: #input items assigned, EOF if input error or EOF before any conversion system(const char *cmdstring); Returns: termination status of shell pid t wait( *statloc); <sys/types.h> <sys/wait.h> Returns: process ID if OK, 0, or -1 on error pid t waitpid(pid t pid, *statloc, options ); <sys/types.h> <sys/wait.h> options: 0, WNOHANG, WUNTRACED Returns: process ID if OK, 0, or -1 on error 6