#include #include #include #include #include #include #include #include struct sigaction prije; void obradi_dogadjaj(int sig) { printf("\n[signal SIGINT] proces %d primio signal %d\n", (int) getpid(), sig); //proslijedi ga ako se program izvodi u prvom planu } void obradi_signal_zavrsio_neki_proces_dijete(int id) { //ako je već dole pozvan waitpid, onda na ovaj signal waitpid ne daje informaciju (ponovo) pid_t pid_zavrsio = waitpid(-1, NULL, WNOHANG); //ne čeka if (pid_zavrsio > 0) if (kill(pid_zavrsio, 0) == -1) //možda je samo promijenio stanje ili je bas završio printf("\n[roditelj %d - SIGCHLD + waitpid] dijete %d zavrsilo s radom\n", (int) getpid(), pid_zavrsio); //else //printf("\n[roditelj %d - SIGCHLD + waitpid] waitpid ne daje informaciju\n", (int) getpid()); } //primjer stvaranja procesa i u njemu pokretanja programa pid_t pokreni_program(char *naredba[], int u_pozadini) { pid_t pid_novi; if ((pid_novi = fork()) == 0) { printf("[dijete %d] krenuo s radom\n", (int) getpid()); sigaction(SIGINT, &prije, NULL); //resetiraj signale setpgid(pid_novi, pid_novi); //stvori novu grupu za ovaj proces if (!u_pozadini) tcsetpgrp(STDIN_FILENO, getpgid(pid_novi)); //dodijeli terminal execvp(naredba[0], naredba); perror("Nisam pokrenuo program!"); exit(1); } return pid_novi; //roditelj samo dolazi do tuda } int main() { struct sigaction act; pid_t pid_novi; //ostale varijable su definirane neposredno prije koristenja //ali SAMO RADI jednostavnijeg praćenja //uobicajeno se sve varijable deklariraju ovdje! printf("[roditelj %d] krenuo s radom\n", (int) getpid()); //postavi signale SIGINT i SIGCHLD act.sa_handler = obradi_dogadjaj; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, &prije); act.sa_handler = obradi_signal_zavrsio_neki_proces_dijete; sigaction(SIGCHLD, &act, NULL); act.sa_handler = SIG_IGN; sigaction(SIGTTOU, &act, NULL); //zbog tcsetpgrp struct termios shell_term_settings; tcgetattr(STDIN_FILENO, &shell_term_settings); //primjer stvaranja procesa i u njemu pokretanja programa char *naredba_echo[] = {"echo", "-e", "Jedan\nDva\nTri", NULL}; pid_novi = pokreni_program(naredba_echo, 0); waitpid(pid_novi, NULL, 0); //čekaj da završi //uzmi natrag kontrolu nad terminalom tcsetpgrp(STDIN_FILENO, getpgid(0)); size_t vel_buf = 128; char buffer[vel_buf]; do { //unos teksta i parsiranje printf("[roditelj] unesi naredbu: "); if (fgets(buffer, vel_buf, stdin) != NULL) { #define MAXARGS 5 char *argv[MAXARGS]; int argc = 0; argv[argc] = strtok(buffer, " \t\n"); while (argv[argc] != NULL) { argc++; argv[argc] = strtok(NULL, " \t\n"); } //pokretanje "naredbe" (pretpostavljam da je program) printf("[roditelj] pokrecem program\n"); pid_novi = pokreni_program(argv, 0); printf("[roditelj] cekam da zavrsi\n"); pid_t pid_zavrsio; do { pid_zavrsio = waitpid(pid_novi, NULL, 0); //čekaj if (pid_zavrsio > 0) { if (kill(pid_novi, 0) == -1) { //nema ga više? ili samo mijenja stanje printf("[roditelj] dijete %d zavrsilo s radom\n", pid_zavrsio); //vraćam terminal ljusci tcsetpgrp(STDIN_FILENO, getpgid(0)); tcsetattr(STDIN_FILENO, 0, &shell_term_settings); } else { pid_novi = (pid_t) 0; //nije gotov } } else { printf("[roditelj] waitpid gotov ali ne daje informaciju\n"); break; } } while(pid_zavrsio <= 0); } else { //printf("[roditelj] neka greska pri unosu, vjerojatno dobio signal\n"); } } while(strncmp(buffer, "exit", 4) != 0); return 0; } /* primjer pokretanja: $ gcc lab2-sucelja.c $ ./a.out [roditelj 1621] krenuo s radom [dijete 1622] krenuo s radom Jedan Dva Tri [roditelj] unesi naredbu: sleep 5 [roditelj] pokrecem program [roditelj] cekam da zavrsi [dijete 1731] krenuo s radom [roditelj] dijete 1731 zavrsilo s radom [roditelj] unesi naredbu: bc -q [roditelj] pokrecem program [roditelj] cekam da zavrsi [dijete 1750] krenuo s radom 123-2*75+111 84 quit [roditelj] dijete 1750 zavrsilo s radom [roditelj] unesi naredbu: exit [roditelj] pokrecem program [roditelj] cekam da zavrsi [dijete 1787] krenuo s radom Nisam pokrenuo program!: No such file or directory [roditelj] dijete 1787 zavrsilo s radom $ */