00001 #ifndef SHARED_MEMORY_IMPLEMENTATION_FILE
00002 #define SHARED_MEMORY_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef EMBEDDED_BUILD
00019
00020 #include "byte_filer.h"
00021 #include "filename.h"
00022 #include "rendezvous.h"
00023 #include "shared_memory.h"
00024
00025 #include <basis/byte_array.h>
00026 #include <basis/convert_utf.h>
00027 #include <basis/function.h>
00028 #include <basis/guards.h>
00029 #include <basis/portable.h>
00030 #include <data_struct/string_hasher.h>
00031
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #ifdef __UNIX__
00035 #include <fcntl.h>
00036 #include <sys/ipc.h>
00037 #include <sys/mman.h>
00038 #include <sys/shm.h>
00039 #include <sys/types.h>
00040 #endif
00041
00042 #ifdef EMBEDDED_BUILD
00043 #error "This build platform does not provide shared memory currently."
00044 #endif
00045
00046 shared_memory::shared_memory(int size, const char *identity)
00047 : _locking(new rendezvous(identity)),
00048 _the_memory(NIL),
00049 _valid(false),
00050 _identity(new istring(identity)),
00051 _size(size)
00052 {
00053 FUNCDEF("constructor");
00054 bool first_use = false;
00055 _locking->lock();
00056 #ifdef __UNIX__
00057 int flag = O_RDWR | O_CREAT | O_EXCL;
00058
00059 int mode = 0700;
00060 _the_memory = shm_open(special_filename(identity).s(), flag, mode);
00061
00062 if (negative(_the_memory)) {
00063
00064 flag = O_RDWR | O_CREAT;
00065 _the_memory = shm_open(special_filename(identity).s(), flag, mode);
00066 u_int err = portable::system_error();
00067 if (negative(_the_memory)) {
00068
00069 printf("error allocating shared segment for %s, was told %s.\n",
00070 special_filename(identity).s(), portable::system_error_text(err).s());
00071 _the_memory = 0;
00072 _locking->unlock();
00073 return;
00074 }
00075
00076 } else {
00077
00078 int ret = ftruncate(int(_the_memory), size);
00079 u_int err = portable::system_error();
00080 if (ret) {
00081 printf("error truncating shared segment for %s, was told %s.",
00082 special_filename(identity).s(), portable::system_error_text(err).s());
00083 }
00084 first_use = true;
00085 }
00086 _valid = true;
00087 #elif defined(__WIN32__)
00088 _the_memory = ::CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE,
00089 0, size, to_unicode_temp(identity));
00090 u_int err = portable::system_error();
00091 first_use = (err != ERROR_ALREADY_EXISTS);
00092 if (!_the_memory) {
00093 _locking->unlock();
00094 return;
00095 }
00096 _valid = true;
00097 #else
00098
00099 #pragma message("simulating shared memory since unknown for this platform.")
00100 if (!_bogus_shared_space().length()) {
00101 _bogus_shared_space().reset(size);
00102 first_use = true;
00103 }
00104 _the_memory = _bogus_shared_space().access();
00105 _valid = true;
00106 #endif
00107 if (first_use) {
00108
00109 byte *contents = locked_grab_memory();
00110 if (!contents) {
00111 _valid = false;
00112 _locking->unlock();
00113 return;
00114 }
00115 memset(contents, 0, size);
00116 locked_release_memory(contents);
00117 }
00118 _locking->unlock();
00119 }
00120
00121 shared_memory::~shared_memory()
00122 {
00123 #ifdef __UNIX__
00124 if (_the_memory) {
00125 close(int(_the_memory));
00126 shm_unlink(special_filename(identity()).s());
00127 }
00128 #elif defined(__WIN32__)
00129 ::CloseHandle(_the_memory);
00130 #else
00131
00132 _the_memory = NIL;
00133 #endif
00134 WHACK(_locking);
00135 WHACK(_identity);
00136 _valid = false;
00137 }
00138
00139 const istring &shared_memory::identity() const { return *_identity; }
00140
00141 istring shared_memory::special_filename(const istring &identity)
00142 {
00143 istring shared_file = identity;
00144 filename::detooth_filename(shared_file);
00145 shared_file = istring("/tmp_") + "sharmem_" + shared_file;
00146 return shared_file;
00147 }
00148
00149 istring shared_memory::unique_shared_mem_identifier(int sequencer)
00150 {
00151 istring to_return("SMID-");
00152 to_return += isprintf("%d-%d-", portable::process_id(), sequencer);
00153 to_return += portable::application_name();
00154
00155 filename::detooth_filename(to_return);
00156 return to_return;
00157 }
00158
00159 bool shared_memory::first_usage(byte *contents, int max_compare)
00160 {
00161 for (int i = 0; i < max_compare; i++)
00162 if (contents[i] != 0) return false;
00163 return true;
00164 }
00165
00166 byte *shared_memory::lock()
00167 {
00168 _locking->lock();
00169 return locked_grab_memory();
00170 }
00171
00172 void shared_memory::unlock(byte * &to_unlock)
00173 {
00174 locked_release_memory(to_unlock);
00175 _locking->unlock();
00176 }
00177
00178 byte *shared_memory::locked_grab_memory()
00179 {
00180 byte *to_return = NIL;
00181 if (!_the_memory) return to_return;
00182 #ifdef __UNIX__
00183 to_return = (byte *)mmap(NIL, _size, PROT_READ | PROT_WRITE,
00184 MAP_SHARED, int(_the_memory), 0);
00185 #elif defined(__WIN32__)
00186 to_return = (byte *)::MapViewOfFile((HANDLE)_the_memory, FILE_MAP_ALL_ACCESS,
00187 0, 0, 0);
00188 #else
00189 to_return = (byte *)_the_memory;
00190 #endif
00191 if (!to_return)
00192 non_continuable_error("shared_memory", "lock",
00193 "no data was accessible in shared space.");
00194 return to_return;
00195 }
00196
00197 void shared_memory::locked_release_memory(byte * &to_unlock)
00198 {
00199 if (!_the_memory || !to_unlock) return;
00200 #ifdef __UNIX__
00201 munmap(to_unlock, _size);
00202 #elif defined(__WIN32__)
00203 ::UnmapViewOfFile(to_unlock);
00204 #else
00205
00206 #endif
00207 }
00208
00209 #endif // embedded.
00210
00211
00212 #endif //SHARED_MEMORY_IMPLEMENTATION_FILE
00213