#include "shared_memory.h" #include #include #include #include #include #include #include #include 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); }