View Single Post
Old Feb 12th, 2007, 2:11 AM   #1
Serinth
Programmer
 
Serinth's Avatar
 
Join Date: Sep 2005
Posts: 50
Rep Power: 4 Serinth is on a distinguished road
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?
__________________
A girl talked to me once.

http://www.latestanime.com
Serinth is offline   Reply With Quote