/** * Simple program demonstrating shared memory in POSIX systems. * * @author Gagne, Galvin, Silberschatz * Operating System Concepts - Seventh Edition * Copyright John Wiley & Sons - 2005. * Modified by Prof. Krishna Sivalingam UMBC, Feb. 2006 * to add producer consumer problem, as in Fig. 3.14 and 3.15 * Added Semaphore based process synch. */ #include #include #include #include #include #include #include #include #include #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including */ #else /* according to X/OPEN we have to define it ourselves */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* array for GETALL, SETALL */ /* Linux specific part: */ struct seminfo *__buf; /* buffer for IPC_INFO */ } ; #endif #define BUFFER_SIZE 10 typedef struct { int pc_buffer[BUFFER_SIZE]; int in; int out; } my_buffer; int full, empty, mutex; /* Initialize a semaphore's value. Assumes that there is only 1 */ /* semaphore in the semaphore set specified by semid. */ int set_semvalue(int semid, int value) { union semun sem_value; sem_value.val = value; if (semctl(semid, 0, SETVAL, sem_value) == -1) { perror("Error in setting semaphore value"); return(-1); } else return(0); } int print_semvalue(int semid, char *name) { int value; if ((value = semctl(semid, 0, GETVAL)) == -1) { perror("Error in getting semaphore value"); return(-1); } else fprintf(stdout,"Semaphore '%s' value is: %d\n", name, value); } int main() { /* the identifier for the shared memory segment */ int segment_id; /* a pointer to the shared memory segment */ my_buffer *shared_memory1, *shared_memory2; /* the size (in bytes) of the shared memory segment */ int segment_size, i; pid_t pid; struct sembuf sem_wait = {0, -1, 0}, sem_signal = {0, 1, 0}; segment_size = sizeof(my_buffer); /** allocate a shared memory segment */ segment_id = shmget(IPC_PRIVATE, segment_size, S_IRUSR | S_IWUSR); /** attach the shared memory segment */ shared_memory1 = (my_buffer *) shmat(segment_id, NULL, 0); if (shared_memory1 < 0) { perror("Error in Attach"); exit(-1); } /* Initialize in and out values */ shared_memory1 -> in = 0; shared_memory1 -> out = 0; full = semget(IPC_PRIVATE, 1, 0660 | IPC_CREAT); /* Create full semap. */ set_semvalue(full, 0); /* Initial value is 0. */ empty = semget(IPC_PRIVATE, 1, 0660 | IPC_CREAT); /* Create full semap. */ set_semvalue(empty, BUFFER_SIZE); /* print_semvalue(empty, "empty");*/ mutex = semget(IPC_PRIVATE, 1, 0660 | IPC_CREAT); /* Create full semap. */ set_semvalue(mutex, 1); /* Initial value is 1. */ pid = fork(); if (pid < 0) { /* error occurred */ fprintf (stderr, "Fork Failed\n"); exit (-1); /* Get out. */ } else if (pid == 0) { /* child process is producer */ srandom(10000); /* Initialize random seed. */ /** attach the shared memory segment */ shared_memory2 = (my_buffer *) shmat(segment_id, NULL, 0); if (shared_memory2 < 0) { perror("Child: Error in Attach"); exit(-1); } for (i = 0; i < 20; i++) { semop(empty, &sem_wait, 1); /* Wait on empty */ semop(mutex, &sem_wait, 1); /* Wait on mutex */ /* Add item to buffer */ shared_memory2->pc_buffer[shared_memory2->in] = (int) random() % 1000; fprintf(stdout," Item %d produced: %d\n", i, shared_memory2->pc_buffer[shared_memory2->in]); /* Update in pointer. */ shared_memory2->in = (shared_memory2->in + 1) % BUFFER_SIZE; semop(mutex, &sem_signal, 1); /* Wait on mutex */ semop(full, &sem_signal, 1); /* Wait on empty */ sleep(random() % 2); } /* End for; produces 20 items */ /** now detach the shared memory segment */ if ( shmdt(shared_memory2) == -1) { fprintf(stderr, "Unable to detach\n"); } exit(0); } else { /* parent process is consumer */ srandom(10000); /* Initialize random seed. */ for (i = 0; i < 20; i++) { semop(full, &sem_wait, 1); /* Wait on full */ semop(mutex, &sem_wait, 1); /* Wait on mutex */ fprintf(stdout,"\t\t\t Item %d consumed: %d\n", i, shared_memory1->pc_buffer[shared_memory1->out]); /* Update out pointer. */ shared_memory1->out = (shared_memory1->out + 1) % BUFFER_SIZE; semop(mutex, &sem_signal, 1); /* Wait on mutex */ semop(empty, &sem_signal, 1); /* Wait on empty */ sleep(random() % 2); } /* End for; consumes 20 items */ /** now detach the shared memory segment */ if ( shmdt(shared_memory1) == -1) { fprintf(stderr, "Unable to detach\n"); } wait (NULL); /* Wait for child to complete. */ /** now remove the shared memory segment */ shmctl(segment_id, IPC_RMID, NULL); exit (0); } return 0; }