shared_memory.cpp

Go to the documentation of this file.
00001 #ifndef SHARED_MEMORY_IMPLEMENTATION_FILE
00002 #define SHARED_MEMORY_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : shared_memory                                                     *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 2002-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
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;  // assume already existing until told otherwise.
00055   _locking->lock();  // force all others to wait on our finishing creation.
00056 #ifdef __UNIX__
00057   int flag = O_RDWR | O_CREAT | O_EXCL;
00058     // try to create the object if it doesn't exist yet, but fail if it does.
00059   int mode = 0700;  // rwx------ for just us.
00060   _the_memory = shm_open(special_filename(identity).s(), flag, mode);
00061     // create the shared memory object but fail if it already exists.
00062   if (negative(_the_memory)) {
00063     // failed to create the shared segment.  try without forcing exclusivity.
00064     flag = O_RDWR | O_CREAT;
00065     _the_memory = shm_open(special_filename(identity).s(), flag, mode);
00066     u_int err = portable::system_error();  // get last error.
00067     if (negative(_the_memory)) {
00068       // definitely a failure now...
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();  // release lock before return.
00073       return;
00074     }
00075     // getting to here means the memory was already allocated.  so we're fine.
00076   } else {
00077     // the shared memory segment was just created this time.
00078     int ret = ftruncate(int(_the_memory), size);
00079     u_int err = portable::system_error();  // get last 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();  // get last error.
00091   first_use = (err != ERROR_ALREADY_EXISTS);
00092   if (!_the_memory) {
00093     _locking->unlock();
00094     return;  // not healthy.
00095   }
00096   _valid = true;
00097 #else
00098 //this is junk; simulates shared memory poorly.
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     // initialize the new memory to all zeros.
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);  // release the memory for now.
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   //hmmm: fix.
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   // replace file delimiters in the name with a safer character.
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 //uhh.
00206 #endif
00207 }
00208 
00209 #endif // embedded.
00210 
00211 
00212 #endif //SHARED_MEMORY_IMPLEMENTATION_FILE
00213 

Generated on Fri Nov 21 04:29:55 2008 for HOOPLE Libraries by  doxygen 1.5.1