263 lines
6.0 KiB
C
263 lines
6.0 KiB
C
#include "shared_memory.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/sem.h>
|
|
#include <semaphore.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
static shmemNode *head;
|
|
static shmemNode *tail;
|
|
|
|
int shmid[NBUFF]; /* Shared Memory Segment Array */
|
|
char* buffptr[NBUFF]; /* Used for each process to attach to */
|
|
int semprox; /* Proxy Shared Memory Semaphore */
|
|
int semserv; /* Server Shared Memory Semaphore */
|
|
|
|
static pthread_mutex_t shmem_mutex;
|
|
static pthread_cond_t shmem_cond;
|
|
|
|
void fast_exit(char* error) {
|
|
fprintf(stderr, "%s", error);
|
|
destroy_shared_memory();
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Retrieve a shared memory segment for use
|
|
*
|
|
* This is where it locks/waits
|
|
*/
|
|
shmemNode *getSharedMemorySegment() {
|
|
shmemNode *toRet;
|
|
|
|
//printf("Locking...");
|
|
pthread_mutex_lock(&shmem_mutex);
|
|
//printf("Done\n");
|
|
|
|
while (!head) {
|
|
//printf("Head is Null\n");
|
|
pthread_cond_wait(&shmem_cond, &shmem_mutex);
|
|
}
|
|
|
|
toRet = head;
|
|
head = head->next;
|
|
|
|
toRet->next = NULL;
|
|
|
|
pthread_mutex_unlock(&shmem_mutex);
|
|
pthread_cond_signal(&shmem_cond);
|
|
|
|
//printf("Returning..\n");
|
|
return toRet;
|
|
}
|
|
|
|
/*
|
|
* Release a shared memory segment into the pool
|
|
*
|
|
*/
|
|
void releaseSharedMemorySegment(shmemNode* node) {
|
|
pthread_mutex_lock(&shmem_mutex);
|
|
|
|
if (!head) {
|
|
head = tail = node;
|
|
head->next = NULL;
|
|
} else {
|
|
tail->next = node;
|
|
tail = node;
|
|
tail->next = NULL;
|
|
}
|
|
|
|
pthread_mutex_unlock(&shmem_mutex);
|
|
pthread_cond_signal(&shmem_cond);
|
|
}
|
|
|
|
/*
|
|
* NO locking done here, must be initialized before shared memory and threads
|
|
* can be used.
|
|
* Otherwise, there would be a deadlock. non-runtime Race > deadlock.
|
|
*
|
|
* This data structure is used by the proxy
|
|
*/
|
|
void init_queue() {
|
|
int i;
|
|
|
|
printf("** Initializing Queue\n");
|
|
|
|
/* Initialize Mutexes */
|
|
pthread_mutex_init(&shmem_mutex, NULL);
|
|
pthread_cond_init(&shmem_cond,NULL);
|
|
|
|
/* Initialize Queue */
|
|
head = tail = NULL;
|
|
|
|
for (i=0; i < NBUFF; i++) {
|
|
shmemNode *temp;
|
|
|
|
temp = malloc(sizeof(shmemNode));
|
|
|
|
if (!temp) {
|
|
printf("Malloc failed (init_queue), that stinks.\n");
|
|
exit(1);
|
|
}
|
|
|
|
temp->shmid = shmid[i];
|
|
temp->buff = buffptr[i];
|
|
temp->semIndex = i;
|
|
temp->next = NULL;
|
|
|
|
if (!head) {
|
|
head = tail = temp;
|
|
} else {
|
|
tail->next = temp;
|
|
tail = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize shared memory and semaphores
|
|
*/
|
|
int init_shared_memory() {
|
|
int i;
|
|
|
|
/* Initialize and attach Shared Memory Segments */
|
|
for (i = 0; i < NBUFF; ++i) {
|
|
shmid[i] = shmget(SHMKEY+i, BUFFSIZE, PERMS | IPC_CREAT);
|
|
buffptr[i] = shmat(shmid[i], (char*)0, 0);
|
|
|
|
if (shmid[i] < 0) {
|
|
fprintf(stderr, "Couldn't allocate Shared Memory Segment %d\n", i);
|
|
for (; i >= 0; --i) {
|
|
shmctl(shmid[i], IPC_RMID, NULL);
|
|
}
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
semserv = semget(SEMSERV, NBUFF, PERMS | IPC_CREAT);
|
|
|
|
if (semserv == -1) {
|
|
semserv_err:
|
|
printf("Error %d\n", errno);
|
|
fast_exit("Failed to initialize semserv.\n");
|
|
}
|
|
|
|
for (i=0; i < NBUFF; i++) {
|
|
if (semctl(semserv, i, SETVAL, 1) == -1) {
|
|
goto semserv_err;
|
|
}
|
|
}
|
|
|
|
|
|
semprox = semget(SEMPROX, NBUFF, PERMS | IPC_CREAT);
|
|
if (semprox == -1) {
|
|
semprox_err:
|
|
printf("Error %d\n", errno);
|
|
fast_exit("Failed to initialize semprox.\n");
|
|
}
|
|
for (i=0; i < NBUFF; i++) {
|
|
if (semctl(semprox, i, SETVAL, 0) == -1) {
|
|
goto semprox_err;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Attach the process to the shared memory segments
|
|
*
|
|
* The queue is used by the client, so it is initialized here
|
|
*
|
|
*/
|
|
int attach_shared_memory() {
|
|
int i;
|
|
|
|
for (i = 0; i < NBUFF; ++i) {
|
|
shmid[i] = shmget(SHMKEY+i, BUFFSIZE, 0);
|
|
buffptr[i] = shmat(shmid[i], (char*)0, 0);
|
|
|
|
if (shmid[i] < 0) {
|
|
fprintf(stderr, "Couldn't attach Shared Memory Segment %d\n", i);
|
|
for (; i >= 0; --i) {
|
|
shmctl(SHMKEY+i, IPC_RMID, NULL);
|
|
}
|
|
return shmid[i];
|
|
}
|
|
}
|
|
|
|
semserv = semget(SEMSERV, 0, PERMS);
|
|
|
|
if (semserv == -1) {
|
|
printf("Error %d\n", errno);
|
|
fast_exit("Failed to initialize semserv.\n");
|
|
}
|
|
|
|
semprox = semget(SEMPROX, 0, PERMS);
|
|
if (semprox == -1) {
|
|
printf("Error %d\n", errno);
|
|
fast_exit("Failed to initialize semprox.\n");
|
|
}
|
|
|
|
init_queue();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Destroy the shared memory segments
|
|
*/
|
|
void destroy_shared_memory() {
|
|
int i;
|
|
|
|
for (i = 0; i < NBUFF; ++i) {
|
|
if (shmdt(buffptr[i]) < 0) {
|
|
fprintf(stderr, "Failed to detach Shared Memory segment %d\n", i);
|
|
}
|
|
if (shmctl(shmid[i], IPC_RMID, NULL) < 0) {
|
|
fprintf(stderr, "Failed to free Shared Memory segment %d\n", i);
|
|
}
|
|
}
|
|
|
|
if (semctl(semprox, 0, IPC_RMID) == -1) {
|
|
fprintf(stderr, "Failed to cleanup semprox.\n");
|
|
}
|
|
if (semctl(semserv, 0, IPC_RMID) == -1) {
|
|
fprintf(stderr, "Failed to cleanup semserv.\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Detach self from shared memory
|
|
*/
|
|
void detach_shared_memory() {
|
|
int i;
|
|
|
|
for (i = 0; i < NBUFF; ++i) {
|
|
if (shmdt(buffptr[i]) < 0) {
|
|
fprintf(stderr, "Failed to free Shared Memory segment %d\n", i);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void *attach_shmem(int index) {
|
|
return shmat(SHMKEY+index, (void*)0, 0);
|
|
}
|
|
|
|
int detach_shmem(void *ptr) {
|
|
return shmdt(ptr);
|
|
}
|
|
|
|
|
|
|
|
|