|
|
|
![]() |
|
Strumenti |
![]() |
#21 |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Allora questa è la struttura dati dell'history (lista doppiamente concatenata con ultimo nodo circolare):
|
![]() |
![]() |
![]() |
#22 |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Questa è la struttura dati del job controller (lista singolarmente concatenata di liste singolarmente concatenate. La principale rappresenta i job da eseguire, le sottoliste sono i processi del job.
Notare: Tutte le immagini create con "The Gimp" ![]() |
![]() |
![]() |
![]() |
#23 |
Senior Member
Iscritto dal: Mar 2002
Città: Italy/Usa
Messaggi: 2817
|
tempo fa per una cosa del genere mi ritornò utile questo tipo di esempio:
http://linux.disco.unimib.it/~levan/...I/ux2-0510.pdf
__________________
"Utilizzando atomi pentavalenti drogheremo il silicio di tipo n; Utilizzando atomi trivalenti drogheremo il silicio di tipo p; Utilizzando della cannabis ci drogheremo noi e vedremo il silicio fare cose impossibili" - DSDT-HowTo |
![]() |
![]() |
![]() |
#24 |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Questo è l'header principale del job controller:
Codice:
/* -*-linux-c-*- */ /*************************************** * jobs.h - Header file per jobs.c * xxxxxx xxxxxx - Matricola xxxxxx * Lab. di Sistemi Operativi. * Progetto "SHELL" * Universita' degli Studi di xxxxxxxx. ***************************************/ #ifndef __JOBS_H__ #define __JOBS_H__ #include <termios.h> /* Tipi di dato che definiscono processo e job */ /* Un processo. */ typedef struct process { struct process * next; /* Il prossimo processo nella pipeline di processi. */ char ** argv; /* Per exec */ pid_t pid; /* Process ID (PID) */ char completed; /* TRUE se il processo e' terminato. */ char stopped; /* TRUE se il processo e' stoppato. */ int status; /* Valore di status riportato da un processo. */ } process; /* Un job. */ typedef struct job { struct job * next; /* Il prossimo job attivo. */ char * command; /* Linea di comando, usata per il messaggi. */ process * first_process; /* La lista di processi attivi in questo job. */ pid_t pgid; /* Process Group ID (PGID) */ char notified; /* TRUE se l'utente e' stato avvertito di job stoppati. */ struct termios tmodes; /* Per il salvataggio delle informazioni sul terminale. */ int stdin, stdout, stderr; /* Canali I/O standard. */ int state; /* Possibile stato di un job: FG (1), BG (0) */ } job; /* Variabili globali che tengono traccia degli attributi della shell. */ pid_t shell_pgid; struct termios shell_tmodes; int shell_terminal; int shell_is_interactive; /* Prototipi di funzione. */ void init_shell(void); int mark_process_status(pid_t pid, int status); void mark_job_as_running(job * j); job * find_job(pid_t pgid); int job_is_stopped(job * j); int job_is_completed(job * j); void format_job_info(job * j, const char * status); void wait_for_job(job * j); void put_job_in_foreground(job * j, int cont); void put_job_in_background(job * j, int cont); void continue_job(job * j, int foreground); void launch_process(process * p, pid_t pgid, int infile, int outfile, int errfile, int foreground); void launch_job(job * j); void update_status(void); void free_job(job * j); void free_all_job(void); void do_job_notification(void); process * build_process(char ** argv); job * build_job(char * command, int filein, int fileout, int filerr, int state); void attach_process_to_job(job * j, process * p); void launch_all_job(void); #endif /* !__JOBS_H__ */ |
![]() |
![]() |
![]() |
#25 |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
E finalmente il job controller:
Codice:
/* -*-linux-c-*- */ /*************************************************** * jobs.c - Funzioni per la manipolazione dei jobs * xxxxxx xxxxxx - Matricola xxxxxx * Lab. di Sistemi Operativi. * Progetto "SHELL" * Universita' degli Studi di xxxxxxx. ***************************************************/ #include "config.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/wait.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <termios.h> #include <ncurses.h> #include "jobs.h" #include "signalh.h" #include "error.h" /* I job attivi sono memorizzati in una lista concatenata. Questa e' la testa. */ job * first_job = NULL; /* Variabili esterne definite altrove. */ extern int verbose; extern int x, y; /********* * Inizializza la shell. Si accerta che la shell stia girando * interattivamente come un processo in foreground prima di procedere. * Questo e' fondamentale nel caso la shell sia avviata da un'altra shell. *********/ void init_shell(void) { /* Vede se stiamo girando in modo interattivo. */ shell_terminal = STDIN_FILENO; shell_is_interactive = isatty(shell_terminal); if (shell_is_interactive) { /* Cicla fino a quando non siamo in foreground. */ while (tcgetpgrp(shell_terminal) != (shell_pgid = getpgrp())) kill(- shell_pgid, SIGTTIN); /* Ignoriamo i segnali interattivi e quelli di job control. */ signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGCHLD, SIG_IGN); #ifdef __DEBUG /* Per stampare un backtrace prima di un eventuale crash. */ signal(SIGSEGV, sigsegv_handler); #endif /* Mettiamo noi stessi nel nostro process group. */ shell_pgid = getpid(); if (setpgid(shell_pgid, shell_pgid) < 0) { perror("Impossibile mettere la shell nel suo stesso process group."); exit(1); } /* Prende possesso del terminale. */ tcsetpgrp(shell_terminal, shell_pgid); /* Salva gli attributi di default del terminale. */ tcgetattr(shell_terminal, &shell_tmodes); } /* Pare tutto ok? :-) */ return; } /* init_shell() */ /********* * Memorizza lo status del processo associato al pid `pid', * ritornato dalla funzione waitpid(). * Ritorna 0 se tutto e' andato per il verso giusto, -1 in * caso di errore. *********/ int mark_process_status(pid_t pid, int status) { if (pid > 0) { /* Aggiorniamo il campo per il processo. */ for (job * j = first_job; j; j = j->next) for (process * p = j->first_process; p; p = p->next) if (p->pid == pid) { p->status = status; if (WIFSTOPPED(status)) p->stopped = 1; else { p->completed = 1; if (WIFSIGNALED(status)) fprintf(stderr, "%d: Terminato dal segnale %d: %s\n", (int)pid, WTERMSIG(p->status), strerror(errno)); } return 0; } /* Il processo con il PID=pid non e' presente nella lista. */ fprintf(stderr, "Nessun processo figlio %d.\n", pid); return -1; } else if (pid == 0 || errno == ECHILD) /* Il processo non e' ancora pronto. */ return -1; else { unix_error("waitpid"); return -1; } } /* mark_process_status() */ /********* * Setta un job stoppato `j' nello stato di "esecuzione". *********/ void mark_job_as_running(job * j) { for (process * p = j->first_process; p; p = p->next) p->stopped = 0; /* `Running' significa `non stopped' */ j->notified = 0; return; } /* mark_job_as_running() */ /********* * Trova il job attivo con lo specificato pgid. *********/ job * find_job(pid_t pgid) { for (job * j = first_job; j; j = j->next) if (j->pgid == pgid) return j; return NULL; } /* find_job() */ /********* * Ritorna TRUE se tutti i processi nel job sono * stati stoppati o hanno completato la loro esecuzione. *********/ int job_is_stopped(job * j) { for (process * p = j->first_process; p; p = p->next) if (!p->completed && !p->stopped) return 0; return 1; } /* job_is_stopped() */ /********* * Ritorna TRUE se tutti i processi nel job hanno * terminato la loro esecuzione. *********/ int job_is_completed(job * j) { for (process * p = j->first_process; p; p = p->next) if (!p->completed) return 0; return 1; } /* job_is_completed() */ /********* * Fornisce informazioni sullo stato dei job per l'utente. *********/ void format_job_info(job * j, const char * status) { fprintf(stderr, "%ld (%s): %s\n", (long int)j->pgid, status, j->command); return; } /* format_job_info() */ /********* * Controlla i processi che hanno le informazioni di stato disponibili * bloccandoli fino a quanto tutti i processi nel job hanno terminato * la loro esecuzione. *********/ void wait_for_job(job * j) { int status; pid_t pid; do { pid = waitpid(WAIT_ANY, &status, WUNTRACED); } while (!mark_process_status(pid, status) && !job_is_stopped(j) && !job_is_completed(j)); return; } /* wait_for_job() */ /********* * Imposta il job j in foreground. Se `cont' e' diverso da zero * ripristina le impostazioni del terminale precedentemente salvate * e invia al process group un SIGCONT per aspettarlo prima di bloccarlo. *********/ void put_job_in_foreground(job * j, int cont) { /* Ok. Mettiamo il job in foreground. */ j->state = 1; tcsetpgrp(shell_terminal, j->pgid); /* Se necessario inviamo al job un segnale di continuazione. */ if (cont) { tcsetattr(shell_terminal, TCSADRAIN, &j->tmodes); if (kill(- j->pgid, SIGCONT) < 0) unix_error("kill (SIGCONT)"); } /* Attendiamo il job che ritorni. */ wait_for_job(j); /* Ripristiniamo la shell in foreground. */ tcsetpgrp(shell_terminal, shell_pgid); /* Ripristiniamo lo stato del terminale della shell. */ tcgetattr(shell_terminal, &j->tmodes); tcsetattr(shell_terminal, TCSADRAIN, &shell_tmodes); /* Fatto tutto? ;-) */ return; } /* put_job_in_foreground() */ /********* * Imposta il job j in background. Se `cont' e' diverso da zero * invia al process group un segnale SIGCONT per aspettarlo. *********/ void put_job_in_background(job * j, int cont) { j->state = 0; /* Invia al job un segnale di continuazione se necessario. */ if (cont) if (kill(- j->pgid, SIGCONT) < 0) unix_error("kill (SIGCONT)"); return; } /* put_job_in_background() */ /********* * Continua l'esecuzione di un job `j'. *********/ void continue_job(job * j, int foreground) { mark_job_as_running(j); if (foreground) put_job_in_foreground(j, 1); else put_job_in_background(j, 1); return; } /* continue_job() */ void launch_process(process * p, pid_t pgid, int infile, int outfile, int errfile, int foreground) { pid_t pid; /*** * Cicla all'infinito in modo da "non avviare" l'esecuzione del child process * fin quando non si setta a 0 la variabile `i' tramite il debugger. ***/ #if __DEBUG /* Consente al debugger di seguire un processo dopo una fork() */ volatile int i = 1; while(i); #endif if (shell_is_interactive) { /* Mettiamo il processo nel proprio process group * e diamo al process group il controllo del terminale. * Questo dev'essere fatto sia dalla shell che dai processi, * per evitare il verificarsi di potenziali race conditions. */ pid = getpid(); if (pgid == 0) pgid = pid; setpgid(pid, pgid); if (foreground) tcsetpgrp(shell_terminal, pgid); /* Ripristiniamo gli handler dei segnali per il processo in corso. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTSTP, SIG_DFL); signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); signal(SIGCHLD, SIG_DFL); } /* Setta i canali standard di I/O per il nuovo processo. */ if (infile != STDIN_FILENO) { dup2(infile, STDIN_FILENO); TEMP_FAILURE_RETRY(close(infile)); } if (outfile != STDOUT_FILENO) { dup2(outfile, STDOUT_FILENO); TEMP_FAILURE_RETRY(close(outfile)); } if (errfile != STDERR_FILENO) { dup2(errfile, STDERR_FILENO); TEMP_FAILURE_RETRY(close(errfile)); } /* Esegue il nuovo processo. Ci si accerta che usciamo. */ execvp(p->argv[0], p->argv); app_error(p->argv[0]); _exit(EXIT_FAILURE); } /* launch_process() */ void launch_job(job * j) { pid_t pid; int mypipe[2]; /* pipe per redirezione (`>' e pipe `|') */ int infile, outfile; infile = j->stdin; for (process * p = j->first_process; p; p = p->next) { /* Setta una pipe, se necessario. */ if (p->next) { if (pipe(mypipe) < 0) { unix_error("pipe"); exit(1); } outfile = mypipe[1]; } else /* Catturiamo l'output */ outfile = j->stdout; /* Forka il processo figlio. */ pid = fork(); if (pid == 0) /* Questo e' il processo figlio. */ launch_process(p, j->pgid, infile, outfile, j->stderr, j->state); else if (pid < 0) { /* La fork() ha fallito. */ unix_error("fork()"); exit(1); } else { /* Questo e' il processo genitore. */ p->pid = pid; if (shell_is_interactive) { if (!j->pgid) j->pgid = pid; setpgid(pid, j->pgid); } } /* Da' una pulitina dopo le pipe. :-) */ if (infile != j->stdin) close(infile); if (outfile != j->stdout) close(outfile); infile = mypipe[0]; } /* for() */ if (verbose) format_job_info(j , "eseguito"); if (!shell_is_interactive) wait_for_job(j); else { if (j->state) put_job_in_foreground(j, 0); else put_job_in_background(j, 0); } } /* launch_job() */ /********* * Controlla i processi che hanno le informazioni di status * disponibili senza bloccarli. *********/ void update_status(void) { int status; pid_t pid; do { pid = waitpid(WAIT_ANY, &status, WUNTRACED | WNOHANG); } while (!mark_process_status(pid, status)); return; } /* update_status() */ /********* * Scorre la pipeline dei processi del job `j' * deallocando la memoria delle strutture. *********/ void free_job(job * j) { process * p; assert(j != NULL); while (j->first_process) { p = j->first_process; j->first_process = j->first_process->next; if (verbose) printw("Libero il processo %s del job %s\n", *p->argv, j->command); free(p); } j->first_process = NULL; free(j); return; } /* free_job() */ /********* * Scorre l'intera pipeline dei jobs, * chiamando per ogni job incontrato free_job() *********/ void free_all_job(void) { job * j = first_job; assert(first_job != NULL); /* Scorriamo l'intera pipeline dei jobs. */ while (first_job) { first_job = first_job->next; free_job(j); j = first_job; } assert(first_job == NULL); return; } /* free_all_job() */ /********* * Notifica all'utente i job stoppati o terminati. * Inoltre cancella i job terminati dalla lista dei job attivi. *********/ void do_job_notification(void) { job * jlast; job * jnext; /* Aggiorniamo le informazioni di stato per il processo figlio. */ update_status(); jlast = NULL; for (job * j = first_job; j; j = jnext) { jnext = j->next; /* Se tutti i processi hanno completato la loro esecuzione, * dice all'utente che il job ha terminato e lo cancella * dalla lista dei job attivi. */ if (job_is_completed(j)) { format_job_info(j, "completato"); if (jlast) jlast->next = jnext; else first_job = jnext; free_job(j); } else /* Notifica l'utente della presenza di job stoppati, * marcando questo evento, cosi' che sia impossibile * stoppare un job per piu' di una volta. */ if (job_is_stopped(j) && !j->notified) { format_job_info(j, "stoppato"); j->notified = 1; jlast = j; } else /* Inutile dire qualcosa se il processo * sta ancora girando. ;-) */ jlast = j; } /* for() */ return; } /* do_job_notification() */ /********* * Alloca la memoria per un processo e compila * i campi base per la sua esecuzione. *********/ process * build_process(char ** argv) { process * p; p = (process *)malloc(sizeof(struct process)); p->next = NULL; p->argv = argv; return p; } /* build_process() */ /********* * Alloca la memoria per un job. Scorre la lista dei job * gia' presente e determina la corretta posizione per * inserire il nuovo job. Compila i campi della struttura in base * ai seguenti parametri: * command: Il nome del job. * filein, fileout, filerr: I canali standard che il job deve usare. * state: foreground (1) o background (0)? *********/ job * build_job(char * command, int filein, int fileout, int filerr, int state) { job * j = NULL; if (first_job) { /* C'e' gia' un job in esecuzione. */ for (job * aux = first_job; aux; aux = aux->next) { /* Scorre la lista dei job */ if (aux->next == NULL) { /* Siamo nell' ultimo job. */ j = (job *)malloc(sizeof(struct job)); j->next = NULL; aux->next = j; /* Compilazione campi job. */ j->command = command; j->first_process = NULL; j->stdin = filein; j->stdout = fileout; j->stderr = filerr; j->state = state; } } } else { /* Il primo job in esecuzione. */ j = (job *)malloc(sizeof(struct job)); j->next = NULL; first_job = j; /* Compilazione dei campi job. */ j->command = command; j->first_process = NULL; j->stdin = filein; j->stdout = fileout; j->stderr = filerr; j->state = state; } return j; } /* build_job() */ /********* * Aggiunge il processo p in coda alla pipeline dei processi * del job j. *********/ void attach_process_to_job(job * j, process * p) { if (!j->first_process) j->first_process = p; else /* Scorriamo la pipeline dei processi del job. */ for (process * aux = j->first_process; aux; aux = aux->next) if (aux->next == NULL) { /* Siamo nell'ultimo processo. */ aux->next = p; return; } return; } /* attach_process_to_job() */ /********* * Scorre la pipeline dei job, eseguendoli uno per uno. * Questo si verifica nel caso viene utilizzato l'operatore * `;' nella riga di comando. *********/ void launch_all_job(void) { assert(first_job != NULL); /* Scorre la lista dei job e li esegue tutti. */ for (job * j = first_job; j; j = j->next) launch_job(j); return; } /* launch_all_job() */ |
![]() |
![]() |
![]() |
#26 |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Tutto questo per rispondere a chi dice che IL MODELLO E' UNA GROTTA
![]() ![]() ![]() ![]() |
![]() |
![]() |
![]() |
#27 | |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Quote:
![]() ![]() ![]() |
|
![]() |
![]() |
![]() |
#28 |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Kleidemos, sei soddisfatto??
![]() |
![]() |
![]() |
![]() |
#29 | |
Senior Member
Iscritto dal: Mar 2002
Città: Italy/Usa
Messaggi: 2817
|
Quote:
![]() ![]()
__________________
"Utilizzando atomi pentavalenti drogheremo il silicio di tipo n; Utilizzando atomi trivalenti drogheremo il silicio di tipo p; Utilizzando della cannabis ci drogheremo noi e vedremo il silicio fare cose impossibili" - DSDT-HowTo |
|
![]() |
![]() |
![]() |
#30 | |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Quote:
![]() |
|
![]() |
![]() |
![]() |
#31 |
Senior Member
Iscritto dal: Mar 2002
Città: Italy/Usa
Messaggi: 2817
|
intendevo fare una metafora un pò azzardata forse tra la GROTTA(e non so perchè mi è venuta in mente la grotta del Gesù bambino...)e quindi di conseguenza, il bue e l'asinello
![]() ![]() ![]() P.S:non mi ero accorto di essere ridotto così male....vado a prendere un saldatore per ricongiungere le poche sinapsi che mi son rimaste.....
__________________
"Utilizzando atomi pentavalenti drogheremo il silicio di tipo n; Utilizzando atomi trivalenti drogheremo il silicio di tipo p; Utilizzando della cannabis ci drogheremo noi e vedremo il silicio fare cose impossibili" - DSDT-HowTo |
![]() |
![]() |
![]() |
#32 | |
Bannato
Iscritto dal: Nov 2002
Città: PV
Messaggi: 1210
|
Quote:
E che sto anche traducendo delle versioni greche (sai i ripassi pre-scuola e i ![]() ![]() ![]() |
|
![]() |
![]() |
![]() |
#33 | |
Bannato
Iscritto dal: Mar 2002
Città: Pescara - 未婚・恋人なし Moto: Honda CBR 1000 RR Casco: XR1000 Diabolic 3
Messaggi: 27578
|
Quote:
![]() ![]() ![]() ![]() |
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:47.