Skip to content

Commit

Permalink
hack to get shm variables recognized as such and not deleteing their …
Browse files Browse the repository at this point in the history
…mapped memory when destroyed.

probably better to replace all that by a simpler variant of the Assoc mechanism, but the use of a DPtrGDL here permits to get the memory cleaned when the referenc count drops to zero.
  • Loading branch information
GillesDuvert committed Dec 31, 2023
1 parent 92b8fec commit 58d2bd5
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 25 deletions.
3 changes: 2 additions & 1 deletion src/basegdl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "basegdl.hpp"
#include "nullgdl.hpp"
#include "objects.hpp"
#include "shm_utils.hpp"

using namespace std;

Expand Down Expand Up @@ -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;

Expand Down
4 changes: 3 additions & 1 deletion src/basegdl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ class BaseGDL: private MemStats

protected:
dimension dim;
bool shared;

public:
// type of initalization
Expand Down Expand Up @@ -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];}
Expand Down
3 changes: 3 additions & 0 deletions src/datatypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ template<class Sp> Data_<Sp>::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

Expand Down Expand Up @@ -371,6 +372,7 @@ template<class Sp> Data_<Sp>::Data_(const dimension& dim_, BaseGDL::InitType iT,
template<> Data_<SpDFloat>::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

Expand Down Expand Up @@ -412,6 +414,7 @@ template<> Data_<SpDFloat>::Data_(const dimension& dim_, BaseGDL::InitType iT, D
template<> Data_<SpDComplex>::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

Expand Down
10 changes: 9 additions & 1 deletion src/gdlhelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down
5 changes: 2 additions & 3 deletions src/libinit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
81 changes: 62 additions & 19 deletions src/shm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
#include <string.h>
#include "shm.hpp"
#include "basic_fun.hpp" //for arr()
static std::map<DString, BaseGDL*> shmList;
typedef std::map<DString, BaseGDL*>::iterator shmListIter;
#include "gdlhelp.hpp"
#include "dinterpreter.hpp"

std::map<DString, std::pair<DPtrGDL*, int> > 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 {

Expand Down Expand Up @@ -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;
}

Expand All @@ -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.
Expand Down Expand Up @@ -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<DString, BaseGDL*>(segmentName, var));

BaseGDL** p = &var;
DPtr heapID = e->NewHeap(1, *p);
shmList.insert(std::pair<DString, std::pair<DPtrGDL*, int>>(segmentName, std::pair<DPtrGDL*, int>(new DPtrGDL(heapID), offset)));

static int getnameIx = e->KeywordIx("GET_NAME");
if (e->WriteableKeywordPresent(getnameIx)) {
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -278,7 +295,8 @@ namespace lib {
// case GDL_UNDEF:
e->Throw(" internal error, please report.");
}
var->SetBuffer(static_cast<void*> (res->DataAddr()));
var->SetBuffer(static_cast<void*> (heapVar->DataAddr()));
GDLInterpreter::IncRef(ptr); //is used. /???? check necessary ?
var->SetBufferSize(dim.NDimElements());
var->SetDim(dim);
return var;
Expand All @@ -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("<Posix(\"" +it->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
5 changes: 5 additions & 0 deletions src/shm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@

#include "datatypes.hpp"
#include "envt.hpp"
#include <iostream> // std::cout, std::ostream, std::ios
#include "shm_utils.hpp"
#ifndef _MSC_VER
extern std::map<DString, std::pair<DPtrGDL*, int> > shmList;

typedef std::map<DString, std::pair<DPtrGDL*, int> > ::iterator shmListIter;
namespace lib {

void shmmap_pro(EnvT* e);
Expand Down
30 changes: 30 additions & 0 deletions src/shm_utils.hpp
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 58d2bd5

Please sign in to comment.