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>
20 #include <basis/utf_conversion.h>
21 #include <basis/functions.h>
22 #include <basis/guards.h>
25 #include <filesystem/byte_filer.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 
40 using namespace basis;
41 using namespace configuration;
42 using namespace filesystem;
43 using namespace loggers;
44 using namespace processes;
45 using namespace structures;
46 
47 namespace application {
48 
49 shared_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 
142 const astring &shared_memory::identity() const { return *_identity; }
143 
144 astring 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);
156  to_return += application_configuration::application_name();
157  // replace file delimiters in the name with a safer character.
158  filename::detooth_filename(to_return);
159  return to_return;
160 }
161 
162 bool 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 
175 void shared_memory::unlock(abyte * &to_unlock)
176 {
177  locked_release_memory(to_unlock);
178  _locking->unlock();
179 }
180 
181 abyte *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 
203 void 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.
int size() const
returns the size of the shared chunk of memory.
Definition: shared_memory.h:51
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
An inter-process synchronization primitive.
Definition: rendezvous.h:34
bool lock(locking_methods how=ENDLESS_WAIT)
grab the lock, if possible.
Definition: rendezvous.cpp:141
void unlock()
releases a previously acquired lock.
Definition: rendezvous.cpp:181
#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:57
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.
Definition: byte_filer.cpp:37
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