| Serinth |
Feb 12th, 2007 2:11 AM |
token ring simulation
This is my assignment and i'm having a little trouble understanding how to set up and pass around the tokens/data. Any part of the code with /* ... */ is the stuff i can't get working. More specifically the token_node function and the bit at the end where it generates random data.
:
/*
* The program simulates a Token Ring LAN by forking off a process
* for each LAN node, that communicate via shared memory, instead
* of network cables. To keep the implementation simple, it jiggles
* out bytes instead of bits.
*
* It keeps a count of packets sent and received for each node.
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
/*
* N_NODE defines how many nodes to simulate and MAX_DATA is the maximum data
* size.
*/
#define N_NODE 7
#define SIM_PACKETS 500
/*
* Define any handy constants and structures.
* Also define the functions.
*/
#define MAX_DATA 250
#define TOKEN_FLAG 1
#define TO 2
#define FROM 3
#define LEN 4
#define DATA 5
#define DONE 6
struct data_pkt {
char token_flag; /* 'T' for token, 'D' for data */
char to; /* Destination node # */
char from; /* Source node # */
unsigned char length; /* Data length 1<->MAX_DATA */
char data[MAX_DATA]; /* Up to MAX_DATA bytes of data */
};
void token_node(int), send_pkt(int), send_byte(int, unsigned char);
void panic(char *);
unsigned char rcv_byte(int);
/*
* The shared memory region includes a byte used to transfer data between
* the nodes, a packet structure for each node with a packet to send and
* sent/received counts for the nodes.
*/
struct node_data {
unsigned char data_xfer;
struct data_pkt to_send;
int sent;
int received;
int terminate;
};
struct shared_data {
struct node_data node[N_NODE];
};
/*
* Assign a number/name to each semaphore.
* Semaphores are used to co-ordinate access to the data_xfer and
* to_send shared data structures and also to indicate when data transfers
* occur between nodes.
* Macros with the node # as argument are used to access the sets of
* semaphores.
*/
#define EMPTY0 0
#define FILLED0 (N_NODE)
#define TO_SEND0 (FILLED0 + N_NODE)
#define CRIT (TO_SEND0 + N_NODE)
#define NUM_SEM (CRIT + 1)
#define EMPTY(n) (EMPTY0 + (n))
#define FILLED(n) (FILLED0 + (n))
#define TO_SEND(n) (TO_SEND0 + (n))
/*
* The Linux semaphore ops are done using the fields of sembuf.
* sem_num - Which semaphore of the set, as defined below
* sem_op - set to 1 for "signal" and -1 for "wait"
* sem_flg - set to 0 for our purposes
* The macros WAIT_SEM, SIGNAL_SEM and INITIALIZE_SEM are defined
* to, hopefully, simplify the code.
*/
/*
* POSIX Now says this can't be in sem.h, so we have to put it in
* ourselves? (It was in sys/sem.h in RedHat 5.2)
*/
union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
#define WAIT_SEM(s) do { \
struct sembuf sb; \
sb.sem_num = (s); \
sb.sem_op = -1; \
sb.sem_flg = 0; \
if (semop(semid, &sb, 1) < 0) { \
fprintf(stderr, "Wait sem failed errno=%d\n", errno); \
exit(4); \
} \
} while (0)
#define SIGNAL_SEM(s) do { \
struct sembuf sb; \
sb.sem_num = (s); \
sb.sem_op = 1; \
sb.sem_flg = 0; \
if (semop(semid, &sb, 1) < 0) { \
fprintf(stderr, "Signal sem failed errno=%d\n", errno); \
exit(4); \
} \
} while (0)
#define INITIALIZE_SEM(s, n) do { \
union semun semarg; \
semarg.val = (n); \
if (semctl(semid, (s), SETVAL, semarg) < 0) { \
fprintf(stderr, "Initialize sem failed errno=%d\n", errno); \
exit(4); \
} \
} while (0)
/*
* Global data, (not shared between processes).
*/
int semid, snd_state, debugprintf = 0;
struct shared_data *shared_ptr;
extern int errno;
char *alphabits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/*
* This function is the body of a child process emulating a node.
*/
void
token_node(int num)
{
/*
* If this is node #0, start the ball rolling by creating the
* token.
*/
/* ... */
if(num==0){
shared_ptr->node[num].to_send.token_flag='T';
}
/*
* Loop around processing data, until done.
*/
while (not_done) {
/* ... */
/*
* Handle the byte, based upon current state.
*/
/* ... */
if (debugprintf)
fprintf(stderr, "Got token flag %c\n", byte);
/* ... */
}
exit(0);
}
/*
* This function sends a data packet followed by the token, one byte each
* time it is called.
*/
void
send_pkt(int num)
{
/* ... */
if(shared_ptr->node[num].to_send.token_flag=='T'){
if(shared_ptr->node[num].to_send.length!=0){
}
}
/*
* Start sending data packet
*/
if (debugprintf)
fprintf(stderr, "Sending data packet\n");
/* ... */
}
/*
* Send a byte to the next node on the ring.
*/
void
send_byte(int num, unsigned char byte)
{
/* ... */
}
/*
* Receive a byte for this node.
*/
unsigned char
rcv_byte(int num)
{
/* ... */
}
/*
* The main program creates the shared memory region and forks off the
* processes to emulate the token ring nodes.
* This process generates packets at random and inserts them in
* the to_send field of the nodes. When done it waits for each process
* to be done receiving and then tells them to terminate and waits
* for them to die and prints out the sent/received counts.
*/
int
main(int argc, char **argv)
{
int shmid, child_status, num, to, i, j;
/* Turn on debugging if "-d" argument specified */
if (argc == 2 && !strcmp(argv[1], "-d"))
debugprintf = 1;
/*
* Seed the random number generator.
*/
srandom(time(0));
/*
* Create the shared memory region.
*/
shmid = shmget(IPC_PRIVATE, sizeof (struct shared_data), 0600);
if (shmid < 0) {
fprintf(stderr, "Can't create shared memory region\n");
exit(1);
}
/*
* and map the shared data region into our address space at an
* address selected by Linux.
*/
shared_ptr = (struct shared_data *)shmat(shmid, (char *)0, 0);
if (shared_ptr == (struct shared_data *)0) {
fprintf(stderr, "Can't map shared memory region\n");
exit(2);
}
/*
* Now, create the semaphores, by creating the semaphore set.
* Under Linux, semaphore sets are stored in an area of memory
* handled much like a shared region. (A semaphore set is simply
* a bunch of semaphores allocated to-gether.)
*/
semid = semget(IPC_PRIVATE, NUM_SEM, 0600);
if (semid < 0) {
fprintf(stderr, "Can't create semaphore set\n");
exit(3);
}
/*
* and initialize them.
* Semaphores are meaningless if they are not initialized.
*/
for (i = 0; i < N_NODE; i++) {
INITIALIZE_SEM(EMPTY(i), 1);
INITIALIZE_SEM(FILLED(i), 0);
INITIALIZE_SEM(TO_SEND(i), 1);
}
INITIALIZE_SEM(CRIT, 1);
/*
* And initialize the shared data
*/
for (i = 0; i < N_NODE; i++) {
shared_ptr->node[i].to_send.length = 0;
shared_ptr->node[i].sent = 0;
shared_ptr->node[i].received = 0;
shared_ptr->node[i].terminate = 0;
}
if (debugprintf)
fprintf(stderr, "main after initialization\n");
/*
* Fork off the children that simulate the disks.
*/
for (i = 0; i < N_NODE; i++)
if (fork() == 0)
token_node(i);
/*
* Loop around generating packets at random.
* (the parent)
*/
for (i = 0; i < SIM_PACKETS; i++) {
/*
* Add a packet to be sent to to_send for that node.
*/
if (debugprintf)
fprintf(stderr, "Main in generate packets\n");
num = random() % N_NODE;
/* Only semaphore call(s) deleted ... */
if (shared_ptr->node[num].to_send.length > 0)
panic("to_send filled\n");
shared_ptr->node[num].to_send.token_flag = 'D';
do {
to = random() % N_NODE;
} while (to == num);
shared_ptr->node[num].to_send.to = (char)to;
shared_ptr->node[num].to_send.from = (char)num;
shared_ptr->node[num].to_send.length = (random() % MAX_DATA) + 1;
for (j = 0; j < shared_ptr->node[num].to_send.length; j++)
shared_ptr->node[num].to_send.data[j] =
alphabits[random() % 26];
/* Only semaphore call(s) deleted ... */
}
/*
* Now wait for all nodes to finish sending and then tell them
* to terminate.
*/
/* ... */
for (i = 0; i < N_NODE; i++)
shared_ptr->node[i].terminate = 1;
/* ... */
if (debugprintf)
fprintf(stderr, "wait for children to terminate\n");
/*
* Wait for the node processes to terminate.
*/
for (i = 0; i < N_NODE; i++)
wait(&child_status);
/*
* All done, just print out the results.
*/
for (i = 0; i < N_NODE; i++)
printf("Node %d: sent=%d received=%d\n", i,
shared_ptr->node[i].sent,
shared_ptr->node[i].received);
if (debugprintf)
fprintf(stderr, "parent at destroy shared memory\n");
/*
* And destroy the shared data area and semaphore set.
* First detach the shared memory segment via shmdt() and then
* destroy it with shmctl() using the IPC_RMID command.
* Destroy the semaphore set in a similar manner using a semctl()
* call with the IPC_RMID command.
*/
shmdt((char *)shared_ptr);
shmctl(shmid, IPC_RMID, (struct shmid_ds *)0);
semctl(semid, 0, IPC_RMID, (union semun)0);
}
/*
* Panic: Just print out the message and exit.
*/
void
panic(char *str)
{
fprintf(stderr, str);
exit(5);
}
I understand that i should be setting up the token in the token_node bit but what additional processing should be done in that while(not_done) loop? Maybe i should be calling the token_node function more times as i'm trying to send it (near the bottom after the generating packets bit) Any thoughts?
|