|
|||||||
|
|
|
![]() |
|
|
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: 06:48.



















