// %flair:license{ // This file is part of the Flair framework distributed under the // CECILL-C License, Version 1.0. // %flair:license} // created: 2014/02/10 // filename: SharedMem_impl.cpp // // author: Guillaume Sanahuja // Copyright Heudiasyc UMR UTC/CNRS 7253 // // version: $Id: $ // // purpose: Class defining a shared memory // // /*********************************************************************/ #include "SharedMem_impl.h" #include "SharedMem.h" #include #include #include #include using std::string; using namespace flair::core; SharedMem_impl::SharedMem_impl(const SharedMem *self, string name, size_t size, SharedMem::Type &type):self(self),type(type),size(size) { #ifdef __XENO__ heap_binded = false; int status = rt_heap_create(&heap, name.c_str(), size, H_SHARED | H_FIFO | H_NONCACHED); if (status == -EEXIST) { heap_binded = true; status = rt_heap_bind(&heap, name.c_str(), TM_INFINITE); } if (status != 0) { char errorMsg[256]; self->Err("rt_heap_create error (%s)\n", strerror_r(-status, errorMsg, sizeof(errorMsg))); return; } void *ptr; status = rt_heap_alloc(&heap, 0, TM_NONBLOCK, &ptr); if (status != 0) { char errorMsg[256]; self->Err("rt_heap_alloc error (%s)\n", strerror_r(-status, errorMsg, sizeof(errorMsg))); } mem_segment = (char *)ptr; #else if (type==SharedMem::Type::mutex) { sem = new Semaphore(self,1,"/" + name + "_mutex",Semaphore::Type::named); } else { //producerConsumer sem_producer=new Semaphore(self,0,"/" + name + "_producer", Semaphore::Type::named); sem_consumer=new Semaphore(self,0,"/" + name + "_consumer", Semaphore::Type::named); } shm_name = "/" + name; fd = shm_open(shm_name.c_str(), O_RDWR | O_CREAT, 0666); if (fd == -1) { self->Err("Error creating shared memory\n"); } ftruncate(fd, size); mem_segment = (char *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem_segment == MAP_FAILED) { self->Err("Failed to map memory\n"); } #endif } SharedMem_impl::~SharedMem_impl() { int status; #ifdef __XENO__ if (heap_binded == false) { status = rt_heap_delete(&heap); if (status != 0) { char errorMsg[256]; self->Err("rt_heap_delete error (%s)\n", strerror_r(-status, errorMsg, sizeof(errorMsg))); } } #else status = munmap(mem_segment, size); if (status != 0) { char errorMsg[256]; self->Err("Failed to unmap memory (%s)\n", strerror_r(-status, errorMsg, sizeof(errorMsg))); } status = close(fd); if (status != 0) { char errorMsg[256]; self->Err("Failed to close file (%s)\n", strerror_r(-status, errorMsg, sizeof(errorMsg))); } // do not check errors as it can be done by another process status = shm_unlink(shm_name.c_str()); /* if(status!=0) { char errorMsg[256]; self->Err("Failed to unlink memory (%s)\n",strerror_r(-status, errorMsg, sizeof(errorMsg))); } */ if (type==SharedMem::Type::mutex) { delete sem; } else { delete sem_producer; delete sem_consumer; } #endif } void SharedMem_impl::ReaderReady() { if (type==SharedMem::Type::producerConsumer) { sem_consumer->ReleaseSemaphore(); } else { self->Warn("Called on a non producerConsumer type of shared memory! (this is seriously wrong)"); } } void SharedMem_impl::Write(const char *buf, size_t size) { if (type==SharedMem::Type::mutex) { sem->GetSemaphore(); memcpy(mem_segment, buf, size); sem->ReleaseSemaphore(); } else if (type==SharedMem::Type::producerConsumer) { //wait until consumer took the data away before writing a new one //but should not block if nobody's there to read if (sem_consumer->TryGetSemaphore()) { memcpy(mem_segment, buf, size); sem_producer->ReleaseSemaphore(); } } } bool SharedMem_impl::Read(char *buf, size_t size, Time nsTimeout) { if (type==SharedMem::Type::mutex) { if (sem->GetSemaphore()) { //may block for ever memcpy(buf, mem_segment, size); sem->ReleaseSemaphore(); return true; } } else if (type==SharedMem::Type::producerConsumer) { if (sem_producer->GetSemaphore(nsTimeout)) { //if nobody ever writes we need to exit this after a while memcpy(buf, mem_segment, size); sem_consumer->ReleaseSemaphore(); return true; }; } return false; }