1 /*****************************************************************************\
3 * Name : shared_memory *
4 * Author : Chris Koeritz *
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 \*****************************************************************************/
15 #include "shared_memory.h"
17 #include <application/windoze_helper.h>
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>
23 #include <configuration/application_configuration.h>
24 #include <loggers/critical_events.h>
25 #include <filesystem/byte_filer.h>
26 #include <filesystem/filename.h>
27 #include <structures/string_hasher.h>
36 #include <sys/types.h>
40 using namespace basis;
41 using namespace configuration;
42 using namespace filesystem;
43 using namespace loggers;
44 using namespace processes;
45 using namespace structures;
47 namespace application {
49 shared_memory::shared_memory(int size, const char *identity)
50 : _locking(new rendezvous(identity)),
51 _the_memory(NULL_POINTER),
53 _identity(new astring(identity)),
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.
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());
75 _locking->unlock(); // release lock before return.
78 // getting to here means the memory was already allocated. so we're fine.
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.
84 printf("error truncating shared segment for %s, was told %s.",
85 special_filename(identity).s(), critical_events::system_error_text(err).s());
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);
97 return; // not healthy.
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);
107 _the_memory = _bogus_shared_space().access();
111 // initialize the new memory to all zeros.
112 abyte *contents = locked_grab_memory();
118 memset(contents, 0, size);
119 locked_release_memory(contents); // release the memory for now.
124 shared_memory::~shared_memory()
128 close(int(_the_memory));
129 shm_unlink(special_filename(identity()).s());
131 #elif defined(__WIN32__)
132 ::CloseHandle(_the_memory);
135 _the_memory = NULL_POINTER;
142 const astring &shared_memory::identity() const { return *_identity; }
144 astring shared_memory::special_filename(const astring &identity)
146 astring shared_file = identity;
147 filename::detooth_filename(shared_file);
148 shared_file = astring("/tmp_") + "sharmem_" + shared_file;
152 astring shared_memory::unique_shared_mem_identifier(int sequencer)
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);
162 bool shared_memory::first_usage(abyte *contents, int max_compare)
164 for (int i = 0; i < max_compare; i++)
165 if (contents[i] != 0) return false;
169 abyte *shared_memory::lock()
172 return locked_grab_memory();
175 void shared_memory::unlock(abyte * &to_unlock)
177 locked_release_memory(to_unlock);
181 abyte *shared_memory::locked_grab_memory()
183 FUNCDEF("locked_grab_memory")
184 abyte *to_return = NULL_POINTER;
185 if (!_the_memory) return to_return;
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,
193 to_return = (abyte *)_the_memory;
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."));
203 void shared_memory::locked_release_memory(abyte * &to_unlock)
205 if (!_the_memory || !to_unlock) return;
207 munmap(to_unlock, _size);
208 #elif defined(__WIN32__)
209 ::UnmapViewOfFile(to_unlock);