feisty meow concerns codebase 2.140
shared_memory.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : shared_memory *
4* Author : Chris Koeritz *
5* *
6*******************************************************************************
7* Copyright (c) 2002-$now By Author. This program is free software; you can *
8* redistribute it and/or modify it under the terms of the GNU General Public *
9* License as published by the Free Software Foundation; either version 2 of *
10* the License or (at your option) any later version. This is online at: *
11* http://www.fsf.org/copyleft/gpl.html *
12* Please send any updates to: fred@gruntose.com *
13\*****************************************************************************/
14
15#include "shared_memory.h"
16
18#include <basis/astring.h>
19#include <basis/byte_array.h>
21#include <basis/functions.h>
22#include <basis/guards.h>
26#include <filesystem/filename.h>
28
29#include <stdio.h>
30#include <stdlib.h>
31#ifdef __UNIX__
32 #include <fcntl.h>
33 #include <sys/ipc.h>
34 #include <sys/mman.h>
35 #include <sys/shm.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38#endif
39
40using namespace basis;
41using namespace configuration;
42using namespace filesystem;
43using namespace loggers;
44using namespace processes;
45using namespace structures;
46
47namespace application {
48
49shared_memory::shared_memory(int size, const char *identity)
50: _locking(new rendezvous(identity)),
51 _the_memory(NULL_POINTER),
52 _valid(false),
53 _identity(new astring(identity)),
54 _size(size)
55{
56 FUNCDEF("constructor");
57 bool first_use = false; // assume already existing until told otherwise.
58 _locking->lock(); // force all others to wait on our finishing creation.
59#ifdef __UNIX__
60 int flag = O_RDWR | O_CREAT | O_EXCL;
61 // try to create the object if it doesn't exist yet, but fail if it does.
62 int mode = 0700; // rwx------ for just us.
63 _the_memory = shm_open(special_filename(identity).s(), flag, mode);
64 // create the shared memory object but fail if it already exists.
65 if (negative(_the_memory)) {
66 // failed to create the shared segment. try without forcing exclusivity.
67 flag = O_RDWR | O_CREAT;
68 _the_memory = shm_open(special_filename(identity).s(), flag, mode);
69 basis::un_int err = critical_events::system_error(); // get last error.
70 if (negative(_the_memory)) {
71 // definitely a failure now...
72 printf("error allocating shared segment for %s, was told %s.\n",
73 special_filename(identity).s(), critical_events::system_error_text(err).s());
74 _the_memory = 0;
75 _locking->unlock(); // release lock before return.
76 return;
77 }
78 // getting to here means the memory was already allocated. so we're fine.
79 } else {
80 // the shared memory segment was just created this time.
81 int ret = ftruncate(_the_memory, size);
82 basis::un_int err = critical_events::system_error(); // get last error.
83 if (ret) {
84 printf("error truncating shared segment for %s, was told %s.",
85 special_filename(identity).s(), critical_events::system_error_text(err).s());
86 }
87 first_use = true;
88 }
89 _valid = true;
90#elif defined(__WIN32__)
91 _the_memory = ::CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE,
92 0, size, to_unicode_temp(identity));
93 basis::un_int err = critical_events::system_error(); // get last error.
94 first_use = (err != ERROR_ALREADY_EXISTS);
95 if (!_the_memory) {
96 _locking->unlock();
97 return; // not healthy.
98 }
99 _valid = true;
100#else
101//this is junk; simulates shared memory poorly.
102 #pragma message("simulating shared memory since unknown for this platform.")
103 if (!_bogus_shared_space().length()) {
104 _bogus_shared_space().reset(size);
105 first_use = true;
106 }
107 _the_memory = _bogus_shared_space().access();
108 _valid = true;
109#endif
110 if (first_use) {
111 // initialize the new memory to all zeros.
112 abyte *contents = locked_grab_memory();
113 if (!contents) {
114 _valid = false;
115 _locking->unlock();
116 return;
117 }
118 memset(contents, 0, size);
119 locked_release_memory(contents); // release the memory for now.
120 }
121 _locking->unlock();
122}
123
125{
126#ifdef __UNIX__
127 if (_the_memory) {
128 close(int(_the_memory));
129 shm_unlink(special_filename(identity()).s());
130 }
131#elif defined(__WIN32__)
132 ::CloseHandle(_the_memory);
133#else
134 //hmmm: fix.
135 _the_memory = NULL_POINTER;
136#endif
137 WHACK(_locking);
138 WHACK(_identity);
139 _valid = false;
140}
141
142const astring &shared_memory::identity() const { return *_identity; }
143
144astring shared_memory::special_filename(const astring &identity)
145{
146 astring shared_file = identity;
147 filename::detooth_filename(shared_file);
148 shared_file = astring("/tmp_") + "sharmem_" + shared_file;
149 return shared_file;
150}
151
153{
154 astring to_return("SMID-");
155 to_return += a_sprintf("%d-%d-", application_configuration::process_id(), sequencer);
157 // replace file delimiters in the name with a safer character.
159 return to_return;
160}
161
162bool shared_memory::first_usage(abyte *contents, int max_compare)
163{
164 for (int i = 0; i < max_compare; i++)
165 if (contents[i] != 0) return false;
166 return true;
167}
168
170{
171 _locking->lock();
172 return locked_grab_memory();
173}
174
175void shared_memory::unlock(abyte * &to_unlock)
176{
177 locked_release_memory(to_unlock);
178 _locking->unlock();
179}
180
181abyte *shared_memory::locked_grab_memory()
182{
183 FUNCDEF("locked_grab_memory")
184 abyte *to_return = NULL_POINTER;
185 if (!_the_memory) return to_return;
186#ifdef __UNIX__
187 to_return = (abyte *)mmap(NULL_POINTER, _size, PROT_READ | PROT_WRITE,
188 MAP_SHARED, int(_the_memory), 0);
189#elif defined(__WIN32__)
190 to_return = (abyte *)::MapViewOfFile((HANDLE)_the_memory, FILE_MAP_ALL_ACCESS,
191 0, 0, 0);
192#else
193 to_return = (abyte *)_the_memory;
194#endif
195 if (!to_return) {
196// FUNCTION(func);
197//not working yet. callstack tracker or whatever is hosed up.
198 throw(astring(astring(class_name()) + "::" + func + ": no data was accessible in shared space."));
199 }
200 return to_return;
201}
202
203void shared_memory::locked_release_memory(abyte * &to_unlock)
204{
205 if (!_the_memory || !to_unlock) return;
206#ifdef __UNIX__
207 munmap(to_unlock, _size);
208#elif defined(__WIN32__)
209 ::UnmapViewOfFile(to_unlock);
210#else
211//uhh.
212#endif
213}
214
215} //namespace.
216
#define close
Definition Xos2defs.h:13
#define O_CREAT
Definition Xw32defs.h:52
#define O_EXCL
Definition Xw32defs.h:54
#define O_RDWR
Definition Xw32defs.h:50
const basis::astring & identity() const
provides a peek at the name that this chunk was constructed with.
shared_memory(int size, const char *identity)
a shared chunk of the "size" specified will be created.
int size() const
returns the size of the shared chunk of memory.
static basis::astring unique_shared_mem_identifier(int sequencer)
returns a unique identifier for a shared memory chunk.
void unlock(basis::abyte *&to_unlock)
returns control of the shared memory so others can access it.
basis::abyte * lock()
locks the shared memory and returns a pointer to the storage.
bool first_usage(basis::abyte *locked_memory, int max_compare)
returns true if the "locked_memory" was just created.
virtual ~shared_memory()
cleans up the shared bit of memory as far as we're concerned.
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
static basis::astring application_name()
returns the full name of the current application.
static basis::un_int process_id()
returns the process id for this task, if that's relevant on the OS.
static void detooth_filename(basis::astring &to_clean, char replacement='_')
takes any known illegal file system characters out of "to_clean".
Definition filename.cpp:452
static basis::astring system_error_text(basis::un_int error_to_show)
returns the OS's string form of the "error_to_show".
static basis::un_int system_error()
gets the most recent system error reported on this thread.
An inter-process synchronization primitive.
Definition rendezvous.h:34
bool lock(locking_methods how=ENDLESS_WAIT)
grab the lock, if possible.
void unlock()
releases a previously acquired lock.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
unsigned char abyte
A fairly important unit which is seldom defined...
Definition definitions.h:51
unsigned int un_int
Abbreviated name for unsigned integers.
Definition definitions.h:62
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition functions.h:43
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
Support for unicode builds.
Aids in achievement of platform independence.
void * HANDLE