Files
GTSchoolShit/CS4210/Project 3/common/shared_memory/shared_memory.c
2025-06-07 01:59:34 -04:00

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);
}