ProvaPratica 2005.02.10
Jump to navigation
Jump to search
Esercizio 1
In una rete token-ring, i nodi sono organizzati ad anello e si scambiano un “token” che passa da un nodo al successivo.
Quando un processo riceve il token:
● stampa “pid: ho ricevuto il token”
● attende 1 secondo
● stampa “pid: spedisco il token al processo x”
● spedisce il token al processo x
dove pid è l'identificatore del processo che stampa, e x è l'identificatore del processo successivo.
Scrivere un programma che genera N processi che comunicano tramite "token-ring". Viene lasciata allo studente la scelta
del meccanismo di sincronizzazione/comunicazione (ma vedi punto 2).
/*
Prova Pratica di Laboratorio di Sistemi Operativi
10 febbraio 2005
Esercizio 1
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2005.02.10.pdf
Nota: variazione che prevede un gestore (Master), di un token ring
composto da n processi figli (Slaves).
@author: Tommaso Ognibene
*/
// Dependencies
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
// Constants
#define True 1
#define False 0
// Data types
struct tokenRing
{
pid_t Pid;
int Token[2];
int Output[2];
struct tokenRing *Next, *Prev;
};
typedef struct tokenRing TokenRing;
// Function declarations
static inline void errorAndDie(const char *msg);
static inline void printAndDie(const char *msg);
static inline void testTokenRing(int n);
static inline int isNumber(char *text);
// Entry point
extern void run(int argc, char *argv[])
{
// Pre-conditions
if (argc != 2)
printAndDie("The function requires one parameter to be passed in.");
if (!isNumber(argv[1]))
printAndDie("The parameter should be a natural number.");
testTokenRing(atoi(argv[1]));
}
/*
* Check whether a string is a natural number or not
* Input: str, the string
* Output: 1, if the string is a natural number
* 0, else
*/
static inline int isNumber(char *str)
{
int i;
i = 0;
while (i < strlen(str) && isdigit(str[i]))
i++;
return i == strlen(str);
}
/*
* Create a token ring of n processes.
* The parent shall manage the token ring.
* Run a test showing the main logical steps in the parent standard output.
* Input: n, the number of processes
*/
static inline void testTokenRing(int n)
{
const char fifoPath[] = "token.fifo";
char token[5] = "token";
char buffer[512];
int i, fifo;
pid_t pid;
ssize_t count;
TokenRing *it, *first, *temp;
// First element of the token ring
first = it = (TokenRing *) malloc(sizeof (TokenRing));
// Create the named pipe if it does not yet exist
if (access(fifoPath, F_OK) < 0)
if (mkfifo(fifoPath, S_IRWXU) < 0)
errorAndDie("mkfifo");
for (i = 0; i < n; i++)
{
// Create a pipe for token communication
if (pipe(it->Token) < 0)
errorAndDie("pipe");
// Create a pipe for output redirection
if (pipe(it->Output) < 0)
errorAndDie("pipe");
// Fork
pid = fork();
if (pid < 0)
errorAndDie("fork");
// Child process
if (pid == 0)
{
// Open named pipe for writing
fifo = open(fifoPath, O_WRONLY);
if (fifo < 0)
errorAndDie("open");
// Close output side
if (close(it->Token[1]) < 0)
errorAndDie("close");
// Close input side
if (close(it->Output[0]) < 0)
errorAndDie("close");
// Re-direct the standard output
if (dup2(it->Output[1], STDOUT_FILENO) < 0)
errorAndDie("dup2");
while (True)
{
// Clear the buffer
memset(buffer, 0, sizeof (buffer));
// Wait for the token
count = read(it->Token[0], buffer, sizeof (buffer));
if (count < 0)
errorAndDie("read");
fprintf(stdout, "[slave #%d] Received the token from Master.\n", getpid());
fprintf(stdout, "[slave #%d] I'm gonna do some stuff now.\n", getpid());
fflush(stdout);
sleep(2);
fprintf(stdout, "[slave #%d] Giving back the token to Master.\n", getpid());
fflush(stdout);
// Give the token back
count = write(fifo, token, sizeof (token));
if (count < 0)
errorAndDie("write");
}
// Close the pipes
if (close(it->Token[0]) < 0 || close(it->Output[1]) < 0 || close(fifo) < 0)
errorAndDie("close");
exit(EXIT_SUCCESS);
}
// Close unused sides of the pipes
if (close(it->Token[0]) < 0 || close(it->Output[1]) < 0)
errorAndDie("close");
it->Pid = pid;
if (i + 1 == n)
break;
it->Next = (TokenRing *) malloc(sizeof (TokenRing));
temp = it;
it = it->Next;
it->Prev = temp;
}
it->Next = first;
first->Prev = it;
// Open named pipe for reading
fifo = open(fifoPath, O_RDONLY);
if (fifo < 0)
errorAndDie("open");
// Manage the token ring
it = first;
while (True)
{
// Clear the buffer
memset(buffer, 0, sizeof (buffer));
// Assign the token
printf("[Master] Assigning the token to slave #%d\n", it->Pid);
count = write(it->Token[1], token, sizeof (token));
if (count < 0)
errorAndDie("write");
// Redirect the children output
for (i = 0; i < 2; i++)
{
count = read(it->Output[0], buffer, sizeof (buffer));
if (count < 0)
errorAndDie("read");
if (write(STDOUT_FILENO, buffer, count) < 0)
errorAndDie("write");
}
// Wait for the token in return
count = read(fifo, buffer, sizeof (buffer));
if (count < 0)
errorAndDie("read");
printf("[Master] Received the token from slave #%d\n", it->Pid);
it = it->Next;
}
// Close the pipes
if (close(it->Token[1]) < 0 || close(it->Output[0]) < 0 || close(fifo) < 0)
errorAndDie("close");
// Remove the named pipe
if (unlink(fifoPath) < 0)
errorAndDie("unlink");
}
/*
* Print error message and exit
* Input: msg, the error message
*/
static inline void errorAndDie(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
/*
* Print message and exit
* Input: msg, the message
*/
static inline void printAndDie(const char *msg)
{
printf("%s\n", msg);
exit(EXIT_FAILURE);
}
Esercizio del professore da revisionare
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static int token=42;
int main(int argc, char *argv[])
{
int i;
int n=atoi(argv[1]);
char *s;
pid_t firstproc,nextproc,newproc;
firstproc=newproc=fork();
nextproc=0;
for (i=0; i<n; i++) {
if (newproc==0) {
int fdin, fdout;
//nextproc e' il successivo
if (nextproc != 0) {
asprintf(&s,"/tmp/np%03d",nextproc);
mknod(s,S_IFIFO | 0644, 0);
fdout=open(s,O_WRONLY);
free(s);
asprintf(&s,"/tmp/np%03d",getpid());
mknod(s,S_IFIFO | 0644, 0);
fdin=open(s,O_RDONLY);
free(s);
} else {
asprintf(&s,"/tmp/np%03d",getpid());
mknod(s,S_IFIFO | 0644, 0);
fdin=open(s,O_RDONLY);
free(s);
read(fdin,&nextproc,sizeof(nextproc));
asprintf(&s,"/tmp/np%03d",nextproc);
mknod(s,S_IFIFO | 0644, 0);
fdout=open(s,O_WRONLY);
free(s);
write(fdout, &token, sizeof(token));
}
while (1) {
int buf;
read(fdin, &buf, sizeof(buf));
printf("%d ricevuto il token\n",getpid());
sleep(1);
printf("%d spedisco il token a %d\n",getpid(),nextproc);
write(fdout, &token, sizeof(token));
}
exit(0);
}
nextproc=newproc;
if (i<n-1) newproc=fork();
}
int fdout;
asprintf(&s,"/tmp/np%03d",nextproc);
mknod(s,S_IFIFO | 0644, 0);
fdout=open(s,O_WRONLY);
free(s);
write(fdout, &firstproc, sizeof(firstproc));
close(fdout);
for (i=0; i<n; i++) {
int status;
wait(&status);
}
}