37 static std::string s_prefix ;
38 static std::string s_help ;
39 static std::string s_filetext ;
44 std::string get_help(
const std::string & name ,
const std::string & os_name )
46 static const char * help_linux =
": try deleting /dev/shm/%S*" ;
47 static const char * help_bsd =
": try this (ayor)... "
48 "perl -e 'syscall($ARGV[0],$ARGV[1])' `awk '/shm_unlink/{print $NF}' /usr/include/sys/syscall.h` /%S" ;
50 std::string help = s_help ;
52 help = std::string( G::is_linux() ? help_linux : help_bsd ) ;
60 G::SharedMemory::Imp::Imp() :
67 G::SharedMemory::Imp::~Imp()
70 ::munmap( m_p , m_size ) ;
78 void G::SharedMemory::Imp::swap( Imp & other )
81 swap( m_fd , other.m_fd ) ;
82 swap( m_unlink_name , other.m_unlink_name ) ;
83 swap( m_p , other.m_p ) ;
84 swap( m_size , other.m_size ) ;
87 int G::SharedMemory::Imp::fd()
const
92 void G::SharedMemory::Imp::unlink()
94 if( !m_unlink_name.empty() )
97 ::shm_unlink( m_unlink_name.c_str() ) ;
98 m_unlink_name.clear() ;
106 G_ASSERT( size != 0U ) ;
107 init( std::string() , -1 , size , O_RDWR ,
false ) ;
112 G_ASSERT( fd >= 0 ) ;
113 init( std::string() , fd , 0U , O_RDWR ,
false ) ;
118 G_ASSERT( !name.empty() ) ;
119 init( name , -1 , 0U , O_RDWR ,
false ) ;
124 G_ASSERT( !name.empty() ) ;
125 G_ASSERT( size != 0U ) ;
126 bool exclusive = true ;
127 init( name , -1 , size , O_RDWR | O_CREAT | ( exclusive ? O_EXCL : O_TRUNC ) ,
false ) ;
132 G_ASSERT( size != 0U ) ;
133 init( std::string() , -1 , size , O_RDWR ,
true ) ;
138 G_ASSERT( fd >= 0 ) ;
139 init( std::string() , fd , 0U , O_RDWR ,
true ) ;
144 G_ASSERT( !name.empty() ) ;
145 init( name , -1 , 0U , O_RDWR ,
true ) ;
150 G_ASSERT( !name.empty() ) ;
151 G_ASSERT( size != 0U ) ;
152 bool exclusive = true ;
153 init( name , -1 , size , O_RDWR | O_CREAT | ( exclusive ? O_EXCL : O_TRUNC ) ,
true ) ;
160 void G::SharedMemory::init(
const std::string & name_in ,
int fd ,
size_t size ,
int open_flags ,
bool control_segment )
165 std::string os_name = osName( name_in ) ;
167 if( os_name.empty() && fd == -1 )
169 G_ASSERT( size != 0U ) ;
173 imp.m_p = ::mmap(
nullptr , imp.m_size , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS | mmap_flags , -1 , 0 ) ;
174 if( imp.m_p ==
nullptr )
175 throw Error(
"mmap error" ) ;
181 if( os_name.empty() )
190 imp.m_fd = ::shm_open( os_name.c_str() , open_flags , 0777 ) ;
195 std::stringstream ss ;
196 ss <<
"shm_open() failed for [" << os_name <<
"]" ;
197 ss <<
": " << G::Process::strerror(e) ;
198 if( (open_flags & O_CREAT) && e == EEXIST )
199 ss << get_help(name_in,os_name) ;
200 throw Error( ss.str() ) ;
202 if( open_flags & O_CREAT )
204 imp.m_unlink_name = os_name ;
205 if( control_segment )
206 createMarker( os_name ) ;
213 struct ::stat statbuf ;
214 if( 0 != fstat( imp.fd() , &statbuf ) )
215 throw Error( os_name ,
"fstat error" ) ;
216 if( statbuf.st_size == 0 )
217 throw Error( os_name ,
"empty shared memory file" ) ;
218 imp.m_size = statbuf.st_size ;
223 if( 0 != ::ftruncate( imp.fd() , size ) )
224 throw Error( os_name ,
"ftruncate error" ) ;
230 imp.m_p = ::mmap(
nullptr , imp.m_size , PROT_READ | PROT_WRITE , MAP_SHARED | mmap_flags , imp.m_fd , 0 ) ;
231 if( imp.m_p ==
nullptr )
232 throw Error( os_name ,
"mmap error" ) ;
242 if( m_imp.m_fd != -1 && 0 != ::ftruncate( m_imp.fd() , new_size ) )
243 throw Error(
"ftruncate error" ) ;
246 void * new_p = ::mremap( m_imp.m_p , m_imp.m_size , new_size , may_move ? MREMAP_MAYMOVE : 0 ) ;
247 if( new_p == MAP_FAILED )
250 throw Error(
"cannot resize the shared memory segment" ) ;
254 m_imp.m_size = new_size ;
260 if( name_in.empty() )
261 return std::string() ;
262 else if( name_in.at(0U) !=
'/' && !G::is_linux() )
263 return "/" + s_prefix + name_in ;
265 return s_prefix + name_in ;
271 int fd = ::shm_open( os_name , O_RDWR , 0 ) ;
272 ::shm_unlink( os_name ) ;
275 struct ::stat statbuf ;
276 if( fstat(fd,&statbuf) == 0 && statbuf.st_size > 0 )
278 void * p = ::mmap(
nullptr , statbuf.st_size , PROT_READ | PROT_WRITE , MAP_SHARED , fd , 0 ) ;
279 if( fn && p ) fn( signal_safe , p ) ;
280 ::munmap( p , statbuf.st_size ) ;
285 deleteMarker( signal_safe , os_name ) ;
291 int fd = ::shm_open( os_name , O_RDWR , 0 ) ;
294 struct ::stat statbuf ;
295 if( fstat(fd,&statbuf) == 0 && statbuf.st_size > 0 )
297 void * p = ::mmap(
nullptr , statbuf.st_size , PROT_READ | PROT_WRITE , MAP_SHARED , fd , 0 ) ;
298 if( fn && p ) fn( signal_safe , p ) ;
303 deleteMarker( signal_safe , os_name ) ;
308 ::fcntl( m_imp.fd() , F_SETFD , ::fcntl(m_imp.fd(),F_GETFD) & ~FD_CLOEXEC ) ;
323 return m_imp.m_size ;
331 void G::SharedMemory::createMarker(
const std::string & os_name )
333 std::string path =
"/tmp/" + os_name +
".x" ;
337 G_IGNORE_RETURN(
int , ::unlink( path.c_str() ) ) ;
338 fd = ::open( path.c_str() , O_WRONLY | O_CREAT , 0666 ) ;
342 if( !s_filetext.empty() )
344 G_IGNORE_RETURN(
int , ::write( fd , s_filetext.data() , s_filetext.length() ) ) ;
350 void G::SharedMemory::deleteMarker(
const std::string & os_name )
352 std::string path =
"/tmp/" + os_name +
".x" ;
355 G_IGNORE_RETURN(
int , ::unlink( path.c_str() ) ) ;
359 void G::SharedMemory::deleteMarker( SignalSafe signal_safe ,
const char * os_name )
363 std::string path = std::string(
"/tmp/") + os_name +
".x" ;
366 G_IGNORE_RETURN(
int , ::unlink( path.c_str() ) ) ;
374 std::vector<std::string> result ;
375 listImp( result ,
"/tmp" ,
"x" , os_names ) ;
376 listImp( result ,
"/run/shm" ,
"" , os_names ) ;
377 std::sort( result.begin() , result.end() ) ;
378 result.erase( std::unique(result.begin(),result.end()) , result.end() ) ;
382 void G::SharedMemory::listImp( std::vector<std::string> & out ,
const std::string & dir ,
const std::string & x ,
bool os_names )
386 if( !p.isDir() && p.filePath().extension() == x &&
387 ( prefix().empty() || p.fileName().find(prefix()) == 0U ) )
389 std::string basename = p.filePath().withoutExtension().basename() ;
390 std::string sname = prefix().empty() ? basename : basename.substr(prefix().length()) ;
391 out.push_back( os_names ? osName(sname) : sname ) ;
401 rc = ::shm_unlink( osName(name).c_str() ) ;
404 if( rc == 0 || e == ENOENT )
407 deleteMarker( osName(name) ) ;
408 return std::string() ;
412 return G::Process::strerror(e) ;
423 G_ASSERT( s.find(
'/') == std::string::npos ) ;
424 if( s.find(
"__") != 0U )
void * ptr() const
Returns the mapped address.
static void help(const std::string &)
Sets some error-message help text for the case when named shared memory cannot be created because it ...
An empty structure that is used to indicate a signal-safe, reentrant implementation.
static std::string prefix()
Returns the prefix, as set by by a call to the other overload.
void inherit()
Marks fd() as inherited across exec() ie. no-close-on-exec.
A combination of user-id and group-id, with a very low-level interface to the get/set/e/uid/gid funct...
A class which acquires the process's special privileges on construction and releases them on destruct...
static std::string delete_(const std::string &name, bool control_segment)
Unlinks the segment from the filesystem.
static Identity start(SignalSafe)
A signal-safe alternative to construction.
static std::vector< std::string > list(bool os_names=false)
Returns a list of possible control segment names.
int fd() const
Returns the file descriptor. Returns -1 for anonymous segments.
static void stop(SignalSafe, Identity)
A signal-safe alternative to destruction.
Overload discriminator for G::SharedMemory.
~SharedMemory()
Destructor.
An encapsulation of a file system directory that allows for iterating through the set of contained fi...
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurances of sub-string 'from' with 'to'...
bool remap(size_t, bool may_move, bool no_throw=false)
Resizes and remaps the shared memory.
static void trap(SignalSafe, const char *os_name, void(*fn)(SignalSafe, void *))
An exit handler that calls the user's function on the shared memory contents.
SharedMemory(size_t size)
Constructor for a new anonymous segment, typically used across a fork().
void unlink()
Unlinks the segment from the filesystem.
bool more()
Returns true if more and advances by one.
static void cleanup(SignalSafe, const char *os_name, void(*fn)(SignalSafe, void *))
An exit handler that unlinks the named shared memory segment and calls the user's function for the me...
static std::string osName(const std::string &name)
Converts the segment name to an internal form that can be passed to cleanup() or trap().
static void filetext(const std::string &)
Sets some help text that gets written into the placeholder files.
size_t size() const
Returns the segment size. This is affected by remap().