diff --git a/src/basegdl.cpp b/src/basegdl.cpp index 8f7a8fcd2..42c52c1a2 100644 --- a/src/basegdl.cpp +++ b/src/basegdl.cpp @@ -20,6 +20,7 @@ #include "basegdl.hpp" #include "nullgdl.hpp" #include "objects.hpp" +#include "shm_utils.hpp" using namespace std; @@ -840,7 +841,7 @@ void GDLDelete( BaseGDL* toDelete) { if( toDelete ==NULL) return; if( toDelete == NullGDL::GetSingleInstance()) return; - delete toDelete; + if (!toDelete->IsShared()) delete toDelete; else lib::shm_unreference(toDelete); } int GDL_NTHREADS=1; diff --git a/src/basegdl.hpp b/src/basegdl.hpp index 08aec4472..4d25390d1 100644 --- a/src/basegdl.hpp +++ b/src/basegdl.hpp @@ -385,6 +385,7 @@ class BaseGDL: private MemStats protected: dimension dim; + bool shared; public: // type of initalization @@ -446,7 +447,8 @@ class BaseGDL: private MemStats BaseGDL();//: dim() {} explicit BaseGDL(const dimension& dim_);//: dim(dim_) {} - + //shared + bool IsShared() {return shared;} // provide access to dim member inline const dimension& Dim() const { return dim;} inline SizeT Dim(SizeT d) const { return dim[d];} diff --git a/src/datatypes.cpp b/src/datatypes.cpp index db24bf31d..b3c60f885 100644 --- a/src/datatypes.cpp +++ b/src/datatypes.cpp @@ -331,6 +331,7 @@ template Data_::Data_(const dimension& dim_, BaseGDL::InitType iT, Sp( dim_), dd( (iT == BaseGDL::NOALLOC) ? 0 : this->dim.NDimElements(), false) { this->dim.Purge(); + if (iT == BaseGDL::NOALLOC) this->shared=true; if (iT == BaseGDL::NOZERO) return; //very frequent @@ -371,6 +372,7 @@ template Data_::Data_(const dimension& dim_, BaseGDL::InitType iT, template<> Data_::Data_(const dimension& dim_, BaseGDL::InitType iT, DDouble off, DDouble inc): SpDFloat( dim_), dd( (iT == BaseGDL::NOALLOC) ? 0 : this->dim.NDimElements(), false) { this->dim.Purge(); + if (iT == BaseGDL::NOALLOC) this->shared=true; if (iT == BaseGDL::NOZERO) return; //very frequent @@ -412,6 +414,7 @@ template<> Data_::Data_(const dimension& dim_, BaseGDL::InitType iT, D template<> Data_::Data_(const dimension& dim_, BaseGDL::InitType iT, DDouble off, DDouble inc): SpDComplex( dim_), dd( (iT == BaseGDL::NOALLOC) ? 0 : this->dim.NDimElements(), false) { this->dim.Purge(); + if (iT == BaseGDL::NOALLOC) this->shared=true; if (iT == BaseGDL::NOZERO) return; //very frequent diff --git a/src/gdlhelp.cpp b/src/gdlhelp.cpp index a2f443b90..cc95a76b3 100644 --- a/src/gdlhelp.cpp +++ b/src/gdlhelp.cpp @@ -123,6 +123,7 @@ extern "C" { #include "gdlhelp.hpp" #include "nullgdl.hpp" #include "terminfo.hpp" +#include "shm_utils.hpp" // for sorting compiled pro/fun lists by name @@ -901,7 +902,14 @@ void help_help(EnvT* e) else SortAndPrintStream(ostr); return; } - + static int sharedIx = e->KeywordIx("SHARED_MEMORY"); + if (e->KeywordSet(sharedIx)) { + help_shared(e, *ostrp); + if (briefKW) return; + if (doOutput) (*outputKW) = StreamToGDLString(ostr, true); + else SortAndPrintStream(ostr); + return; + } static int namesIx = e->KeywordIx("NAMES"); bool isKWSetNames = e->KeywordPresent(namesIx); diff --git a/src/libinit.cpp b/src/libinit.cpp index 38de869e5..b754071da 100644 --- a/src/libinit.cpp +++ b/src/libinit.cpp @@ -315,9 +315,8 @@ void LibInit() "INTERNAL_LIB_GDL","KEYS","LAST_MESSAGE","LIB","MEMORY","NAMES", "OBJECTS","OUTPUT","PATH_CACHE","PREFERENCES","PROCEDURES", "RECALL_COMMANDS","ROUTINES","SOURCE_FILES","STRUCTURES", - "SYSTEM_VARIABLES","TRACEBACK", "COMMON","LEVEL", KLISTEND}; - const string helpWarnKey[]={"BREAKPOINTS","DLM", "MESSAGES", - "SHARED_MEMORY", KLISTEND}; + "SYSTEM_VARIABLES","TRACEBACK", "COMMON","LEVEL", "SHARED_MEMORY", KLISTEND}; + const string helpWarnKey[]={"BREAKPOINTS","DLM", "MESSAGES", KLISTEND}; new DLibPro(lib::help_pro,string("HELP"),-1,helpKey,helpWarnKey); new DLibPro(lib::delvar_pro,string("DELVAR"),-1,NULL,NULL); diff --git a/src/shm.cpp b/src/shm.cpp index 39c40bb36..26179f4e3 100644 --- a/src/shm.cpp +++ b/src/shm.cpp @@ -23,12 +23,15 @@ #include #include "shm.hpp" #include "basic_fun.hpp" //for arr() -static std::map shmList; -typedef std::map::iterator shmListIter; +#include "gdlhelp.hpp" +#include "dinterpreter.hpp" + +std::map > shmList; enum { BYTE=0,COMPLEX,DCOMPLEX,DOUBLE,FLOAT,INTEGER,L64,LONG,UINT,UL64,ULONG, DIMENSION,SIZE, TEMPLATE, TYPE} common_options_shm; -//atom size of all types +//atom size of all types and names +static const std::string atomName[16]={"UNDEFINED","BYTE","INT","LONG","FLOAT","DOUBLE","COMPLEX","STRING","STRUCT","DCOMPLEX","POINTER","OBJREF","UINT","ULONG","LONG64","ULONG64"}; static const int atomSize[16]={0,1,2,4,4,8,8,0,0,16,0,0,2,4,8,8}; namespace lib { @@ -87,6 +90,7 @@ namespace lib { if (!gdl_type_lookup::IsConvertableType[type]) { //problems begins e->Throw("Objects, Pointers and Structures not allowed in this context."); } + if (type==GDL_STRING) e->Throw("Expression containing string data not allowed in this context."); return dimNotSet; } @@ -110,7 +114,7 @@ namespace lib { if (e->KeywordPresentAndDefined(offsetIx)) { e->AssureLongScalarKW(offsetIx, offset); } - + if (offset%atomSize[type] != 0) e->Throw("This machine cannot access data of type "+atomName[type]+" at this alignment: "+i2s(offset)+"."); length += offset; shm_fd = shm_open(segmentName.c_str(), O_RDWR, exist_perms); //minimal setup. @@ -190,10 +194,13 @@ namespace lib { int mmap_prot = PROT_READ | PROT_WRITE; void* mapAddress = mmap(NULL, length, mmap_prot, mmap_flags, shm_fd, 0); if (mapAddress == MAP_FAILED) e->Throw("shmmap failed, please report."); - var->SetBuffer(mapAddress); + var->SetBuffer(mapAddress); var->SetBufferSize(dim.NDimElements()); var->SetDim(dim); - shmList.insert(std::pair(segmentName, var)); + + BaseGDL** p = &var; + DPtr heapID = e->NewHeap(1, *p); + shmList.insert(std::pair>(segmentName, std::pair(new DPtrGDL(heapID), offset))); static int getnameIx = e->KeywordIx("GET_NAME"); if (e->WriteableKeywordPresent(getnameIx)) { @@ -207,18 +214,24 @@ namespace lib { e->AssureStringScalarPar(0, segmentName); if (segmentName.size() == 0) e->Throw("Null string not allowed in this context: "+e->GetParString(0)+"."); shmListIter i = shmList.find(segmentName); - BaseGDL* res; + DPtrGDL* ptr; void* was=NULL; SizeT length=0; + SizeT refc=0; if (i != shmList.end()) { - res = (*i).second; - was=res->DataAddr(); - length=res->NBytes(); - shmList.erase(i); + ptr = (*i).second.first; + BaseGDL* heapVar=e->GetHeap((*ptr)[0]); + was=heapVar->DataAddr(); + length=heapVar->NBytes(); +// GDLInterpreter::DecRef(ptr); //remove initial basegdl reference + SizeT refc = e->Interpreter()->RefCountHeap((*ptr)[0]); + if (refc < 2) shmList.erase(i); } else e->Throw("Shared Memory Segment not found: " + segmentName + "."); - int result=munmap(was,length); - if (result ==0) return; - e->Throw("Shared Memory Segment " + segmentName + " Unmapping unsucessfull, reason: "+ std::string(strerror(result))+"."); + if (refc == 1) { + int result=munmap(was,length); + if (result ==0) return; + e->Throw("Shared Memory Segment " + segmentName + " Unmapping unsucessfull, reason: "+ std::string(strerror(result))+"."); + } }; BaseGDL* shmvar_fun(EnvT* e) { @@ -227,12 +240,16 @@ namespace lib { std::string segmentName = ""; bool dimNotSet = get_shm_common_keywords(e, segmentName, dim, type); shmListIter i = shmList.find(segmentName); - BaseGDL* res; + DPtrGDL* ptr; if (i != shmList.end()) { - res = (*i).second; + ptr = (*i).second.first; + BaseGDL* heapVar=e->GetHeap((*ptr)[0]); //check if compatible - if (dimNotSet) return res; //no further problem, we take as it was - if (dim.NDimElements()*(atomSize[type]) > res->NBytes()) e->Throw("Requested variable is too long for the underlying shared memory segment: " + segmentName + "."); + if (dimNotSet) { + GDLInterpreter::IncRef(ptr); //is used. /???? check necessary ? + return heapVar; //no further problem, we take as it was + } + if (dim.NDimElements()*(atomSize[type]) > heapVar->NBytes()) e->Throw("Requested variable is too long for the underlying shared memory segment: " + segmentName + "."); //create a BaseGDL corresponding to that: BaseGDL* var; @@ -278,7 +295,8 @@ namespace lib { // case GDL_UNDEF: e->Throw(" internal error, please report."); } - var->SetBuffer(static_cast (res->DataAddr())); + var->SetBuffer(static_cast (heapVar->DataAddr())); + GDLInterpreter::IncRef(ptr); //is used. /???? check necessary ? var->SetBufferSize(dim.NDimElements()); var->SetDim(dim); return var; @@ -293,5 +311,30 @@ namespace lib { return new DIntGDL(0); } + void help_shared(EnvT* e, std::ostream& ostr) { + for (shmListIter it=shmList.begin(); it!=shmList.end(); ++it) { + DPtrGDL* ptr = (*it).second.first; + BaseGDL* heapVar = e->GetHeap((*ptr)[0]); + SizeT refc = BaseGDL::interpreter->RefCountHeap((*ptr)[0]); + lib::help_item(ostr, heapVar, DString("first + "\"), Offset("+i2s((*it).second.second)+"), Refcnt("+i2s(refc-1)+")>"), true); //note: -1 + } + return; + } + + //called from system + void shm_unreference(BaseGDL* var){ + void* pointer=var->DataAddr(); //the mapped address + for (shmListIter it=shmList.begin(); it!=shmList.end(); ++it) { + DPtrGDL* ptr = (*it).second.first; + BaseGDL* heapVar = BaseGDL::interpreter->GetHeap((*ptr)[0]); + void* pointed=heapVar->DataAddr(); + if (pointer == pointed) { + GDLInterpreter::DecRef(ptr); + return; + } + } + //unreference a BaseGDL::NOALLOC adress which is not in the shm list: best to delete the pointed memory + free (pointer); + } } // namespace #endif diff --git a/src/shm.hpp b/src/shm.hpp index 9ef8616aa..156b342bb 100644 --- a/src/shm.hpp +++ b/src/shm.hpp @@ -19,7 +19,12 @@ #include "datatypes.hpp" #include "envt.hpp" +#include // std::cout, std::ostream, std::ios +#include "shm_utils.hpp" #ifndef _MSC_VER +extern std::map > shmList; + +typedef std::map > ::iterator shmListIter; namespace lib { void shmmap_pro(EnvT* e); diff --git a/src/shm_utils.hpp b/src/shm_utils.hpp new file mode 100644 index 000000000..6217c3e68 --- /dev/null +++ b/src/shm_utils.hpp @@ -0,0 +1,30 @@ +/*************************************************************************** + shm_utils.hpp - Shared memory mapping, external utilities defs + ------------------- + begin : Dec 24 2023 + copyright : (C) 2023 by Gilles Duvert + email : surname dot name at free dot fr + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef SHM_UTILS_HPP_ +#define SHM_UTILS_HPP_ +#ifndef _MSC_VER +namespace lib { + void help_shared(EnvT* e, std::ostream& ostr); + void shm_unreference(BaseGDL* var); +} // namespace +#else +namespace lib { + void help_shared(EnvT* e, std::ostream& ostr){}; + void shm_unreference(BaseGDL* var){}; +} // namespace +#endif +#endif