libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
SharedMemory.hpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2002 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #pragma once
20 
21 #include"../NTSecuritySettings.hpp"
22 #include"../RegistryKey.hpp"
23 #include"../DumpWinMsg.hpp"
24 #include"../NTLocking.hpp"
25 
26 //#include<atlbase.h>
27 
28 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
29 
30  namespace NTUtils {
31 
32  class HeapID {
33  public:
34  unsigned long size;
35  std::pair< std::string, std::string > names;
37 
38  inline HeapID(void) : size( 0 ), names( std::pair< std::string, std::string >("", "") ), security( NULL ) {}
39  inline HeapID(const unsigned long s, const char * const mem_n, const char * const mtx_n, const NTUtils::SecuritySettings * const sec) : size( s ), names( std::pair< std::string, std::string >(mem_n, mtx_n) ), security( sec ) {}
40  inline HeapID(const unsigned long s, const std::pair< std::string, std::string > &n, const NTUtils::SecuritySettings * const sec) : size( s ), names( n ), security( sec ) {}
41  inline HeapID(const HeapID &h) : size( h.size ), names( h.names ), security( h.security ) {}
42  inline ~HeapID(void) {}
43  inline HeapID &operator=(const HeapID &h) {size=h.size;names=h.names;security=h.security;return *this;}
44 
45  private:
46  };
47 
48  // Create a named shared-memory area with no memory management of the shared area.
49  // It's just an array of type "contents".
50  template < class contents > class RawSharedMemory {
51  public:
52  typedef contents contents_type;
53  // Note this allocates memory in blocks of "sizeof(contents)" units.
54  // Yes - you can use a real file instead of the swap file! Who needs serialisation?!
55  inline RawSharedMemory(const HeapID &details, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
56  virtual inline ~RawSharedMemory(void);
57 
58  inline const std::string &Name(void) const noexcept(true);
59  // In units of "sizeof(contents)".
60  virtual inline unsigned long Capacity(void) const noexcept(true);
61  // This is very slow!!! This function has to delete and re-allocate the shared
62  // memory area, but keeps the same name. Note that it is likely to invalidate
63  // any stored pointers to the memory block area.
64  // In units of "sizeof(contents)".
65  virtual inline bool Capacity(const unsigned long sz, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
66  inline bool IsCreator(void) const noexcept(true);
67  // See warning by "MapDataPtr(...)". Also note the "const" and heed well.
68  // The pointer returned is *really* REALLY read-only. No amount of "const_cast<...>(...)"
69  // will get round it. NT will throw loads of access violations if you try and write
70  // into the data using any perversion of a pointer returned by this function.
71  // Use the non-const one below if you want read-write access.
72  // Also note that the two pointers returned by these functions may not be equal!!!
73  // i.e. "(const contents *)*this 'may not ==' (contents *)*this" !!! Tee hee!
74  inline operator const contents *() const;
75  // See warning by "MapDataPtr(...)".
76  inline operator contents *();
77  inline NTUtils::Mutex &Lock(void) noexcept(true);
78  // Handy for dumping the memory contents....
79  // Doesn't save the private bit.
80  virtual inline std::ostream &operator<<(std::ostream &strm) const;
81  // Might as well..... What the heck. Bit pointless, as it would probably be better to use
82  // a file handle in the contructor.
83  // Doesn't restore the private bit.
84  virtual inline std::istream &operator>>(std::istream &strm);
85  inline unsigned long UsageCount(void) const noexcept(true);
86 
87  protected:
88  const NTUtils::SecuritySettings * const ss;
92  contents *rw_raw_data;
93  // These public pointers are offset just beyond the private data area to protect them
94  // from joe public.
95  contents *rw_pub_data;
96  const contents *ro_pub_data;
97  // This usage counter is stored in the memory mapped file in a private data area.
98  // It is accessed using the "rw_raw_data" pointer.
100  unsigned long usage_ctr;
101  };
102 
103  // "p" in bytes, "s" in "sizeof(contents)".
104  inline RawSharedMemory(const unsigned long p, const HeapID &details, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
105  inline contents *MapDataPtr(HANDLE file, const DWORD access, const DWORD hi_offset, const DWORD low_offset, const unsigned long size);
106  inline void UnmapDataPtr(const contents *);
107  static inline unsigned long GetEndPrivateDataBlock(void) noexcept(true);
108 
109  private:
110  const std::string name;
111  // In bytes including the private data block.
112  unsigned long raw_size;
113  // In "sizeof(contents)" excluding the private data block.
114  unsigned long pub_size;
115  bool creator;
116  HANDLE rw_raw_mapping;
117 
118  inline bool Create(HANDLE file, const SECURITY_ATTRIBUTES * const security, const DWORD protection);
119  inline void Delete(void);
120 
121  // Don't allow copying or assignment.
122  inline RawSharedMemory(const RawSharedMemory &) : ss( NULL ) {assert(false);}
123  inline RawSharedMemory &operator=(const RawSharedMemory &) {assert(false);return *this;}
124  };
125 
126  // This is just an interface class, and does nothing, but let you test the object to see if it
127  // has a memory manager, so useable with, say objects that take an "std::allocator<...>" object.
128  template < class contents > class ManagedSharedMemory : public RawSharedMemory< contents > {
129  public:
130  inline ManagedSharedMemory(const std::string &mgr_name, const HeapID &details, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
131  virtual inline ~ManagedSharedMemory();
132 
133  // Can't use "new" and "delete" much as I'd like to as "new" is a static member
134  // funciton in C++, so doesn't have a "this" pointer, so I can't get at the current
135  // object (easily).
136  // "n" in units of "sizeof(contents)".
137  inline contents *Allocate(const unsigned long n, const void * const hint);
138  inline void Construct(contents * const ptr,const contents &val);
139  inline void Deallocate(const contents * const p, const unsigned long n);
140 
141  protected:
143  // In units of "sizeof(contents)".
144  unsigned long used_memory;
146  };
148 #ifdef _DEBUG
149  unsigned long allocating_pid;
151  unsigned long allocating_tid;
154  unsigned long block_size;
155  // For future use. Currently unused.
156  unsigned long allocating_line;
157  char allocating_src[MAX_PATH];
158 #endif _DEBUG
159  };
160 
161  inline ManagedSharedMemory(const unsigned long p, const std::string &mgr_name, const HeapID &details, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
162  virtual inline contents *BaseAllocate(const unsigned long n, const void * const hint) = 0;
163  virtual inline unsigned long BaseDeallocate(const contents * const p, const unsigned long n) = 0;
164  static inline unsigned long GetEndPrivateDataBlock(void) noexcept(true);
165 
166  private:
167  // Don't allow assignment.
168  inline ManagedSharedMemory &operator=(const ManagedSharedMemory &) {assert(false);return *this;}
169  };
170 
171  // Jason's unbeliveably crap memory manager. "It's top-tastic!"
172  // I apologise in advance for this implemetation.
173  // I've looked all over the web for a descent memory-manager implementation, (inc. "boost.org") &
174  // loads of other places. Couldn't find anything....
175  // I even looked over the M$ debug memory manager, but that was just too complex to re-
176  // implement.... Hence this lash-up.
177  // A few beers later: Check out K&R chapter 8.7 for a better example of a memory manager.
178 
179  const unsigned long CMSM_free_marker=~(unsigned long)NULL;
180 
181  template < class contents > class CrapManagedSharedMemory : public ManagedSharedMemory< contents > {
182  public:
183  inline CrapManagedSharedMemory(const HeapID &details);
184  inline ~CrapManagedSharedMemory(void);
185  // In units of "sizeof(contents)".
186  inline unsigned long Capacity(void) const noexcept(true);
187 
188  private:
189  struct private_data_block_type {
190  NTUtils::guid_type mem_id;
191  NTUtils::guid_type mtx_id;
192  };
193  // Warning: Crap implementation....
194  RawSharedMemory<unsigned long> in_use_list;
195 
196  inline contents *BaseAllocate(const unsigned long n, const void * const hint);
197  inline unsigned long BaseDeallocate(const contents * const p, const unsigned long n);
198  static inline std::pair<std::string, std::string> GetMgrAreaName(const bool first, contents * const rw_raw_data);
199  // Don't allow re-sizing.
200  inline bool Capacity(const unsigned long sz, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
201  // Don't allow assignment.
202  inline CrapManagedSharedMemory &operator=(const CrapManagedSharedMemory &) {assert(false);return *this;}
203  };
204 
205  // An implemetation of the K&R memory manager see chapter 8.7 in "The C Programming Language"..
206  template < class contents > class KnRManagedSharedMemory : public ManagedSharedMemory< contents > {
207  public:
208  inline KnRManagedSharedMemory(const HeapID &details);
209  inline ~KnRManagedSharedMemory(void);
210  // In units of "sizeof(contents)".
211  inline unsigned long Capacity(void) const noexcept(true);
212 
213  private:
214  // Don't use an STL list as we haven't implemented the SMAllocator yet, as this class is implementing it!!!
215  // (And it's easier to copy KnR...!)
216  struct free_memory_list_type {
217  free_memory_list_type *next;
218  // In units of "sizeof(contents)".
219  unsigned long size;
220  };
221  free_memory_list_type *free_list;
222 
223  inline contents *BaseAllocate(const unsigned long n, const void * const hint);
224  inline unsigned long BaseDeallocate(const contents * const p, const unsigned long n);
225  // Don't allow re-sizing.
226  inline bool Capacity(const unsigned long sz, const DWORD protection = PAGE_READWRITE, HANDLE file = INVALID_HANDLE_VALUE);
227  // Don't allow assignment.
228  inline KnRManagedSharedMemory &operator=(const KnRManagedSharedMemory &) {assert(false);return *this;}
229  };
230 
231  // This class is required to allow the allocator used in an STL object (which for
232  // complex STL types basically takes a default constructor) the ability to call back
233  // via a static member function to obtain the required heap details, so that it can
234  // connect to its heap.
235  // The "id" template paramter is crucial, and identifies the specific heap object
236  // that you want. i.e. if you have more that one heap of the same type, this parameter
237  // is used to identify the correct heap object.
238  template < class heap_manager, unsigned long id > class ManagedSharedMemorySTLIntf : public heap_manager {
239  public:
240  inline ManagedSharedMemorySTLIntf(const HeapID &details);
241  virtual inline ~ManagedSharedMemorySTLIntf(void);
242  // This function is declared here, but not defined. Why?
243  // Because it forces the user to implement it. Why? It is the way that the STL
244  // allocator-compatible class gets the information it needs to access the shared
245  // memory area it will use.
246  static HeapID GetHeapID();
247 
248  protected:
249  inline ManagedSharedMemorySTLIntf(const unsigned long p, const HeapID &details);
250 
251  private:
252  // Don't allow assignment.
253  inline ManagedSharedMemorySTLIntf &operator=(const ManagedSharedMemorySTLIntf &) {assert(false);return *this;}
254  };
255 
256  // Finally create an STL compatible allocator class. (Note: Don't inherit from "std::allocator<...>" to
257  // avoid picking up invalid implemetations.)
258  template < class heap_type, class heap_contents > class SMAllocator : private std::allocator<heap_type::contents_type> {
259  public:
260  typedef unsigned long size_type;
261  typedef long difference_type;
262  typedef heap_type::contents_type *pointer;
263  typedef const heap_type::contents_type *const_pointer;
264  typedef heap_type::contents_type &reference;
265  typedef const heap_type::contents_type &const_reference;
266  typedef heap_type::contents_type value_type;
267  // The "heap_type::GetHeap()" fn is a static template function used to get the
268  // parameters for linking to the shared memory heap. The "heap_type" class must derive from
269  // "ManagedSharedMemorySTLIntf<...>" (which contains the declaration for the public static member
270  // function "heap_type::GetHeap()".
271  inline SMAllocator() noexcept(true) : heap( heap_type::GetHeapID() ) {}
272  inline SMAllocator(const SMAllocator &) noexcept(true) : heap( heap_type::GetHeapID() ) {}
273  inline ~SMAllocator() noexcept(true) {};
274 
275  inline pointer allocate(const size_type _N, const void *hint) {return heap.Allocate(_N, hint);}
276  inline value_type *_Charalloc(const size_type _N) {return heap.Allocate(_N/sizeof(value_type)+1, NULL);}
277  inline void construct(pointer _P, const value_type &_V) {
278  value_type::allocator_type::value_type * const ptr=_P->get_allocator()._Charalloc(_V.size());
279  _P->get_allocator().construct(ptr, _V);
280  value_type::const_iterator i(_V.begin());
281  value_type::size_type j=0;
282  do {
283  _P[j]=*i;
284  ++i;
285  ++j;
286  } while (i!=_V.end());
287  }
288  inline void deallocate(void *_P, const size_type sz) {heap.Deallocate(static_cast<pointer>(_P), sz);}
289 // ???
290 // inline void destroy(pointer _P) {_P->get_allocator().deallocate(_P,sizeof(value_type));}
291  inline void destroy(pointer _P) {_P->heap_contents::~heap_contents();}
292  inline size_type max_size() const {return heap.Capacity();}
293  template <class alloc> inline bool operator==(const alloc &a) const {return heap.Name()==a.heap.Name();}
294  template <class alloc> inline bool operator!=(const alloc &a) const {return !operator==(a);}
295  inline const heap_type &Heap() const noexcept(true) {return heap;}
296 
297  private:
298  heap_type heap;
299 
300  // Don't allow assignment.
301  template < class ook, class ook1 > inline SMAllocator &operator=(const SMAllocator< ook, ook1 > &) noexcept(true) {assert(false);return *this;}
302  };
303 
304  template < class contents > inline RawSharedMemory<contents>::RawSharedMemory(const HeapID &details, const DWORD protection, HANDLE file) : ss( details.security ), mutex( details.names.second=="" ? NTUtils::GetGUID() : details.names.second, &(ss->SA()) ), pub_size(details.size), raw_size( sizeof(private_data_block_type)+details.size*sizeof(contents) ), name( details.names.first=="" ? NTUtils::GetGUID() : details.names.first ) {
305  // Use the swap-file for backing the memory-mapped file.
306  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
307  Create(file, &(ss->SA()), protection);
308  if (creator) {
309  reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr=0;
310  }
311  ++reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr;
312  }
313 
314  template < class contents > inline RawSharedMemory<contents>::~RawSharedMemory(void) {
315  assert(reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr);
316  --reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr;
317  Delete();
318  }
319 
320  template < class contents > const std::string &RawSharedMemory<contents>::Name(void) const {
321  return name;
322  }
323 
324  template < class contents > unsigned long RawSharedMemory<contents>::Capacity(void) const {
325  return pub_size;
326  }
327 
328  template < class contents > inline bool RawSharedMemory<contents>::Capacity(const unsigned long sz, const DWORD protection, HANDLE file) {
329  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
330  if (reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr==1) {
331  // Can only re-size if there is only one process connected to the shared
332  // memory area, otherwise the call to "Create(...)" will simply return the
333  // existinfg one.
334  // Get the total size - public and private.
335  std::auto_ptr<contents> tmp(new contents[raw_size]);
336  // Use our "pointer-to-everything".
337  memcpy(tmp.get(), rw_raw_data, raw_size);
338  Delete();
339  unsigned long old_raw_size=raw_size;
340  raw_size=sz*sizeof(contents)+sizeof(private_data_block_type);
341  if (Create(file, &(ss->SA()), protection)) {
342  std::cerr << "RawSharedMemory<...>::Capacity(...) : Failed to re-size the shared memory area to: " << raw_size << ", named: '" << name << "' - 'Create(...)' failed." << std::endl;
343  return true;
344  }
345  memcpy(rw_raw_data, tmp.get(), old_raw_size);
346  return false;
347  }
348  std::cerr << "RawSharedMemory<...>::Capacity(...) : Failed to re-size the shared memory area to: " << raw_size << ", named: '" << name << "' - reference count of: "<< reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr << ", must be 1." << std::endl;
349  return true;
350  }
351 
352  template < class contents > bool RawSharedMemory<contents>::IsCreator(void) const {
353  return creator;
354  }
355 
356  // See warning by "MapDataPtr(...)".
357  template < class contents > inline RawSharedMemory<contents>::operator const contents *() const {
358  return ro_pub_data;
359  }
360 
361  // See warning by "MapDataPtr(...)".
362  template < class contents > inline RawSharedMemory<contents>::operator contents *() {
363  return rw_pub_data;
364  }
365 
366  template < class contents > inline NTUtils::Mutex &RawSharedMemory<contents>::Lock(void) {
367  return mutex;
368  }
369 
370  template < class contents > inline std::ostream &RawSharedMemory<contents>::operator<<(std::ostream &strm) const {
371  unsigned long i=0;
372  do {
373 // ???
374 // strm << ro_pub_data[i];
375  } while (++i<pub_size);
376  return strm;
377  }
378 
379  template < class contents > inline std::istream &RawSharedMemory<contents>::operator>>(std::istream &strm) {
380  std::cerr << "RawSharedMemory<...>::operator>>(...) : Not implemented!!!" << std::endl;
381  unsigned long i=0;
382  do {
383 // ???
384 // strm >> rw_pub_data[i];
385  } while (++i<pub_size);
386  return strm;
387  }
388 
389  template < class contents > inline unsigned long RawSharedMemory<contents>::UsageCount(void) const {
390  return usage_ctr;
391  }
392 
393  template < class contents > inline RawSharedMemory<contents>::RawSharedMemory(const unsigned long p, const HeapID &details, const DWORD protection, HANDLE file) : ss( details.security ), mutex( details.names.second=="" ? NTUtils::GetGUID() : details.names.second, &(ss->SA()) ), pub_size(details.size), raw_size( p+sizeof(private_data_block_type)+details.size*sizeof(contents) ), name( details.names.first=="" ? NTUtils::GetGUID() : details.names.first ) {
394  // Use the swap-file for backing the memory-mapped file.
395  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
396  Create(file, &(ss->SA()), protection);
397  if (creator) {
398  reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr=0;
399  }
400  ++reinterpret_cast<private_data_block_type *>(rw_raw_data)->usage_ctr;
401  }
402 
403  template < class contents > inline contents *RawSharedMemory<contents>::MapDataPtr(HANDLE mapping, const DWORD access, const DWORD hi_offset, const DWORD low_offset, const unsigned long size) {
404  // Note this maps the pointer into the current process space. Therefore we need to
405  // re-map it as required, as different processes may be calling for the mapping.
406  // Note therefore that this handle is only valid in the context of the current process.
407  // Also note that the map may not work if the underlying memory mapped file has lower access
408  // than the requested access.
409  contents *raw_data=static_cast<contents *>(::MapViewOfFile(mapping, access, hi_offset, low_offset, size));
410  if (!raw_data) {
411  unsigned long err=::GetLastError();
412  std::cerr << "RawSharedMemory<...>::MapDataPtr(...) : Failed to map view of file. Name: '" << name
413  << "'. With access: 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex)
414  << access << " and offset: 0x" << hi_offset << ":" << low_offset << ", size: 0x"
415  << size << ". Windows error: '" << NTUtils::DumpWinMessage(err) << "'." << std::endl;
416  }
417  return raw_data;
418  }
419 
420  template < class contents > inline void RawSharedMemory<contents>::UnmapDataPtr(const contents *raw_data) {
421  if (raw_data) {
422  ::UnmapViewOfFile(raw_data);
423  }
424  }
425 
426  template < class contents > inline bool RawSharedMemory<contents>::Create(HANDLE file, const SECURITY_ATTRIBUTES * const security, DWORD protection) {
427  SYSTEM_INFO info;
428  ::GetSystemInfo(&info);
429  // Need to expand the private data area to align it on a virtual memory granularity boundary for the later mapped views.
430  raw_size=((raw_size-pub_size*sizeof(contents))/info.dwAllocationGranularity+1)*info.dwAllocationGranularity+pub_size*sizeof(contents);
431  rw_raw_mapping=::CreateFileMapping(file, const_cast<SECURITY_ATTRIBUTES * const>(security), protection, 0, raw_size, name.c_str());
432  if (!rw_raw_mapping || rw_raw_mapping==INVALID_HANDLE_VALUE) {
433  std::cerr << "RawSharedMemory<...>::Create() : Failed to allocate the read/write raw memory mapped file. Size: " << raw_size << ", name: '" << name << "'." << std::endl;
434  return true;
435  } else {
436  creator=(::GetLastError() != ERROR_ALREADY_EXISTS);
437  // We'll create another connection to the memory mapped file to allow creating the read-only
438  // mapped view of the file.
439  rw_pub_mapping=::CreateFileMapping(file, const_cast<SECURITY_ATTRIBUTES * const>(security), protection, 0, raw_size, name.c_str());
440  ro_pub_mapping=::CreateFileMapping(file, const_cast<SECURITY_ATTRIBUTES * const>(security), protection, 0, raw_size, name.c_str());
441  // We get access to everything - private, public, you name it....
442  rw_raw_data=MapDataPtr(rw_raw_mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0);
443  // Make sure joe public can't stamp over any private data.
444  rw_pub_data=MapDataPtr(rw_pub_mapping, FILE_MAP_ALL_ACCESS, 0, raw_size-pub_size*sizeof(contents), pub_size*sizeof(contents));
445  ro_pub_data=MapDataPtr(ro_pub_mapping, FILE_MAP_READ, 0, raw_size-pub_size*sizeof(contents), pub_size*sizeof(contents));
446  if (!rw_raw_data || !rw_pub_data || !ro_pub_data) {
447  Delete();
448  return true;
449  }
450  }
451  return false;
452  }
453 
454  template < class contents > inline void RawSharedMemory<contents>::Delete(void) {
458  ::CloseHandle(ro_pub_mapping);
459  ::CloseHandle(rw_pub_mapping);
460  ::CloseHandle(rw_raw_mapping);
461  }
462 
463  template < class contents > inline unsigned long RawSharedMemory<contents>::GetEndPrivateDataBlock(void) {
464  return sizeof(private_data_block_type);
465  }
466 
467  template < class contents > inline ManagedSharedMemory<contents>::ManagedSharedMemory(const std::string &mgr_name, const HeapID &details, const DWORD protection, HANDLE file) : RawSharedMemory<contents>( sizeof(private_data_block_type)+mgr_name.size()+1, details, protection, file) {
468  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
469  if (IsCreator()) {
470  reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->used_memory=0;
471  memcpy(&(reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name), mgr_name.c_str(), mgr_name.size()+1);
472  } else if (strcmp(&(reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name), mgr_name.c_str())) {
473  std::cerr << "ManagedSharedMemory<...>::ManagedSharedMemory(...) : Attempting to use wrong memory manager '"<< mgr_name << "', on existing shared memory, which is managed by '" << &(reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name) << "'." << std::endl;
474  throw;
475  }
476  }
477 
478  template < class contents > inline ManagedSharedMemory<contents>::~ManagedSharedMemory(void) {
479  }
480 
481  template < class contents > inline contents *ManagedSharedMemory<contents>::Allocate(const unsigned long n, const void * const hint) {
482  contents *ptr;
483  if (ptr=BaseAllocate(n, hint)) {
484  reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->used_memory+=n;
485  }
486  return ptr;
487  }
488 
489  template < class contents > inline void ManagedSharedMemory<contents>::Deallocate(const contents * const p, const unsigned long n) {
490  unsigned long amnt;
491  if (amnt=BaseDeallocate(p, n)) {
492  reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->used_memory-=amnt;
493  }
494  }
495 
496  template < class contents > inline void ManagedSharedMemory<contents>::Construct(contents * const ptr,const contents &val) {
497  assert(ptr);
498 // ???
499  // Problem:
500  // The pointer "ptr" is uninitialised memory, by definition of "Allocate".
501  // So if it points to an object that contains a non-default allocator, e.g. an SM STL string,
502  // how do I "kick-start" the allocator object? I could try:
503 // memcpy(ptr, &val, sizeof(val));
504  // But this links "ptr" to the contents of the std::string, which means that the reference counts
505  // on it are one less than it should be.
506 // ptr->get_allocator();
507 /* ptr->ss=val.ss;
508  ptr->mutex=Mutex(val.Name(), ss->SA());
509  ptr->pub_size=val.pub_size;
510  ptr->raw_size=sizeof(private_data_block_type)+val.pub_size*sizeof(contents);
511  ptr->name=val.name;
512 */
513  // This leaks memory...
514  contents tmp;
515  memcpy(ptr, &tmp, sizeof(contents));
516  // This won't work as the heap in "ptr" is uninitialised.
517  *ptr=val;
518 // assert(false);
519 // throw "Don't try this - it's not implemented!";
520  }
521 
522  template < class contents > inline ManagedSharedMemory<contents>::ManagedSharedMemory(const unsigned long p, const std::string &mgr_name, const HeapID &details, const DWORD protection, HANDLE file) : RawSharedMemory<contents>( p+sizeof(private_data_block_type)+mgr_name.size()+1, details, protection, file) {
523  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
524  if (IsCreator()) {
525  reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->used_memory=0;
526  memcpy(&(reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name), mgr_name.c_str(), mgr_name.size()+1);
527  } else if (strcmp(&(reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name), mgr_name.c_str())) {
528  std::cerr << "ManagedSharedMemory<...>::ManagedSharedMemory(...) : Attempting to use wrong memory manager '"<< mgr_name << "', on existing shared memory, which is managed by '" << reinterpret_cast<private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name << "'." << std::endl;
529  throw;
530  }
531  }
532 
533  template < class contents > inline unsigned long ManagedSharedMemory<contents>::GetEndPrivateDataBlock(void) {
534  return RawSharedMemory<contents>::GetEndPrivateDataBlock()+sizeof(private_data_block_type);
535  }
536 
538  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
539  if (IsCreator()) {
540  memset((unsigned long *)in_use_list, CMSM_free_marker, in_use_list.Capacity()*sizeof(unsigned long));
541  }
542  }
543 
544  template < class contents > inline CrapManagedSharedMemory<contents>::~CrapManagedSharedMemory(void) {
545 #ifdef _SMEM_DEBUG
546 #ifdef _DEBUG
547  if (reinterpret_cast<RawSharedMemory<contents>::private_data_block_type *>(rw_raw_data)->usage_ctr==1) {
548  // Check that all memory is freed.
549  const unsigned long *used=(const unsigned long *)in_use_list;
550  unsigned long s=0;
551  do {
552  unsigned long beginning_of_block=CMSM_free_marker;
553  if (beginning_of_block!=used[s+sizeof(allocated_data_block_info)/sizeof(unsigned long)]) {
554  beginning_of_block=used[s+sizeof(allocated_data_block_info)/sizeof(unsigned long)];
555  }
556  if (beginning_of_block!=CMSM_free_marker) {
557  std::cerr << "Allocating process ID: 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex) << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_pid << std::endl;
558  std::cerr << "Allocating process handle: 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex) << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_phandle << std::endl;
559  std::cerr << "Allocating thread ID: 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex) << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_tid << std::endl;
560  std::cerr << "Allocating thread handle: 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex) << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_thandle << std::endl;
561  std::cerr << "Allocating process name: '" << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_pname << "'" << std::endl;
562  std::cerr << "Line number in allocating file: " << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_line << std::endl;
563  std::cerr << "Allocating source file name: '" << reinterpret_cast<const allocated_data_block_info *>(used+s)->allocating_src << "'" << std::endl;
564  std::cerr << "Address: 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex) << ((contents *)*this)+s << std::endl;
565  std::cerr << "Block size: " << (reinterpret_cast<const allocated_data_block_info *>(used+s)->block_size<<2) << " bytes." << std::endl;
566  std::cerr << "Data: <";
567  const unsigned long start=s;
568  while (beginning_of_block==used[s+sizeof(allocated_data_block_info)/sizeof(unsigned long)]) {
569  std::cerr << *reinterpret_cast<char *>(&(((contents *)*this)[s]));
570  ++s;
571  }
572  std::cerr << ">" << std::endl;
573  std::cerr << "Hex: <";
574  for (s=start;beginning_of_block==used[s];++s) {
575  std::cerr << " 0x" << std::setw(8) << std::setfill('0') << std::setbase(std::ios_base::hex) << *reinterpret_cast<unsigned long *>(&(((contents *)*this)[s]));
576  }
577  std::cerr << ">" << std::endl;
578  }
579  s+=sizeof(allocated_data_block_info)/sizeof(unsigned long);
580  assert(used[s]==CMSM_free_marker);
581  } while (++s<in_use_list.Capacity());
582  }
583 #endif _DEBUG
584 #endif _SMEM_DEBUG
585  }
586 
587  template < class contents > inline unsigned long CrapManagedSharedMemory<contents>::Capacity(void) const {
588  return ManagedSharedMemory<contents>::Capacity();
589  }
590 
591  template < class contents > inline contents *CrapManagedSharedMemory<contents>::BaseAllocate(const unsigned long m, const void * const /*hint*/) {
592  // Need to find a block of memory of the correct size that is not in use.
593  // Warning: Crap algorithm!!!
594  // Poxy linear search coming up!
595  // Note - "m" in units of "sizeof(contents)" rounded up.
596  if (m>Capacity()) {
597  // Ran out of memory...
598  return NULL;
599  }
600  // Search through the in-use list for the first block of memory that is big enough.
601  NTUtils::MutexLock lock(in_use_list.Lock().Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
602  __asm {
603  int 3
604  }
605  unsigned long *used=(unsigned long *)in_use_list;
606  unsigned long s=sizeof(allocated_data_block_info)/sizeof(unsigned long);
607  do {
608  unsigned long e=s;
609  // Find a free element.
610  if (used[s]==CMSM_free_marker) {
611  // It's a free element.
612  // Is there enough free memory?
613  if ((s+m)<=in_use_list.Capacity()) {
614  // Now need to see if the block it begins is big enough...
615  e=s;
616  bool big_enough=true;
617  do {
618  if (used[e]!=CMSM_free_marker) {
619  // Block too small.
620  big_enough=false;
621  s=e;
622  break;
623  }
624  } while (++e<(s+m));
625  if (big_enough) {
626  // Mark each element as used in this block by using the value of the first
627  // pointer in the block.
628 #ifdef _SMEM_DEBUG
629 #ifdef _DEBUG
630  // "I did this!"
631  reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_pid=::GetCurrentProcessId();
632  reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_phandle=::GetCurrentProcess();
633  reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_tid=::GetCurrentThreadId();
634  reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_thandle=::GetCurrentThread();
635  ::GetModuleFileName(NULL, reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_pname, MAX_PATH);
636  reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->block_size=m;
637 // ???
638  // For future use. Currently unused. Put something in anyway.
639  reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_line=__LINE__;
640  strcpy(reinterpret_cast<allocated_data_block_info *>(used+s-sizeof(allocated_data_block_info)/sizeof(unsigned long))->allocating_src,__FILE__);
641 #endif _DEBUG
642 #endif _SMEM_DEBUG
643  e=s;
644  do {
645  used[e]=s;
646  } while (++e<(s+m));
647  return ((contents *)*this)+s;
648  }
649  } else {
650  // Ran out of memory...
651  return NULL;
652  }
653  } else {
654 #ifdef _SMEM_DEBUG
655 #ifdef _DEBUG
656  s+=sizeof(allocated_data_block_info)/sizeof(unsigned long)+reinterpret_cast<allocated_data_block_info *>(used-s)->block_size;
657 #else
658  ++s;
659 #endif _DEBUG
660 #endif _SMEM_DEBUG
661  }
662  } while (++s<in_use_list.Capacity());
663  return NULL;
664  }
665 
666  // Note: "m" in units of "contents".
667  template < class contents > inline unsigned long CrapManagedSharedMemory<contents>::BaseDeallocate(const contents * const p, const unsigned long m) {
668  // "p" must be from the same process space.
669  NTUtils::MutexLock lock(in_use_list.Lock().Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
670  // NOTE: Can't deallocate a "const" pointer (as in "(const contents * const)"), only non-const. Hence the cast and type declaration.
671  std::cerr<<p<<" "<<m<<std::endl;
672  contents * const beginning=(contents *)*this;
673  __asm {
674  int 3
675  }
676  assert(p>=beginning);
677  assert(m*sizeof(contents)<Capacity());
678  const unsigned long mgr_ptr=p-beginning;
679  assert((mgr_ptr+m*sizeof(contents))<Capacity());
680  unsigned long *used=(unsigned long *)in_use_list;
681  assert(mgr_ptr<in_use_list.Capacity());
682  assert((mgr_ptr+m*sizeof(contents))<in_use_list.Capacity());
683  std::cerr << used[(mgr_ptr+(m-1)*sizeof(allocated_data_block_info))/sizeof(unsigned long)] << " " << mgr_ptr << std::endl;
684  assert(used[(mgr_ptr+m*sizeof(allocated_data_block_info))/sizeof(unsigned long)]==mgr_ptr);
685  unsigned long s=mgr_ptr+sizeof(allocated_data_block_info)/sizeof(unsigned long);
686  do {
687  if (used[s]!=mgr_ptr) {
688  // End of block found.
689  // The block should be of the right size.
690  unsigned long i=(s-mgr_ptr-sizeof(allocated_data_block_info)/sizeof(unsigned long));
691  std::cerr<<i<<std::endl;
692  i/=sizeof(contents);
693  std::cerr<<i<<std::endl;
694 // assert(!m || ((s-mgr_ptr-sizeof(allocated_data_block_info)/sizeof(unsigned long))/sizeof(contents)==m));
695  // Mark the elements in the block as free.
696  memset(used+mgr_ptr, CMSM_free_marker, (s-mgr_ptr)*sizeof(unsigned long)+sizeof(allocated_data_block_info));
697 #ifdef _DEBUG
698  // Zero the main memory, so that in debug mode I can see it being released.
699  memset(beginning+mgr_ptr, 0, (s-mgr_ptr)*sizeof(contents));
700 #endif _DEBUG
701  return s-mgr_ptr;
702  }
703  // Check the block's integrity.
704  // It should be in use by someone.
705  assert(used[s]!=CMSM_free_marker);
706  } while (++s<in_use_list.Capacity());
707  // Couldn't find end of the block.
708  assert(false);
709  return 0;
710  }
711 
712  template < class contents > inline std::pair<std::string, std::string> CrapManagedSharedMemory<contents>::GetMgrAreaName(const bool first, contents * const rw_raw_data) {
713  std::pair<std::string, std::string> names;
714  if (first) {
715  names.first=NTUtils::GetGUID();
716  names.second=NTUtils::GetGUID();
717  // Write the names into the beginning of the raw data area for other processes to access.
718  memcpy(reinterpret_cast<private_data_block_type *>(rw_raw_data+ManagedSharedMemory<contents>::GetEndPrivateDataBlock()+strlen(&(reinterpret_cast<ManagedSharedMemory<contents>::private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name)))->mem_id, names.first.c_str(), sizeof(NTUtils::guid_type));
719  memcpy(reinterpret_cast<private_data_block_type *>(rw_raw_data+ManagedSharedMemory<contents>::GetEndPrivateDataBlock()+strlen(&(reinterpret_cast<ManagedSharedMemory<contents>::private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name)))->mtx_id, names.second.c_str(), sizeof(NTUtils::guid_type));
720  } else {
721  // The names are at the beginning of the shared raw data area. Extract it.
722  NTUtils::guid_type raw_name;
723  memcpy(raw_name, reinterpret_cast<private_data_block_type *>(rw_raw_data+ManagedSharedMemory<contents>::GetEndPrivateDataBlock()+strlen(&(reinterpret_cast<ManagedSharedMemory<contents>::private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name)))->mem_id, sizeof(NTUtils::guid_type));
724  assert(strlen(raw_name)==(sizeof(NTUtils::guid_type)-1));
725  names.first=raw_name;
726  memcpy(raw_name, reinterpret_cast<private_data_block_type *>(rw_raw_data+ManagedSharedMemory<contents>::GetEndPrivateDataBlock()+strlen(&(reinterpret_cast<ManagedSharedMemory<contents>::private_data_block_type *>(rw_raw_data+RawSharedMemory<contents>::GetEndPrivateDataBlock())->manager_name)))->mtx_id, sizeof(NTUtils::guid_type));
727  assert(strlen(raw_name)==(sizeof(NTUtils::guid_type)-1));
728  names.second=raw_name;
729  }
730  return names;
731  }
732 
733  template < class contents > inline bool CrapManagedSharedMemory<contents>::Capacity(const unsigned long, const DWORD, HANDLE) {
734  std::cerr << "CrapManagedSharedMemory<...>::Capacity(...) : Not supported!!!" << std::endl;
735  return true;
736  }
737 
738  template < class contents > inline KnRManagedSharedMemory<contents>::KnRManagedSharedMemory(const HeapID &details)
740  free_list=reinterpret_cast<free_memory_list_type *>(rw_pub_data);
741  free_list->next=free_list;
742  free_list->size=Capacity()*sizeof(contents);
743  }
744 
745  template < class contents > inline KnRManagedSharedMemory<contents>::~KnRManagedSharedMemory(void) {
746 #ifdef _DEBUG
747  if (reinterpret_cast<RawSharedMemory<contents>::private_data_block_type *>(rw_raw_data)->usage_ctr==1) {
748  // Check that all memory is freed.
749  assert(free_list->size==Capacity());
750  }
751 #endif _DEBUG
752  }
753 
754  template < class contents > inline unsigned long KnRManagedSharedMemory<contents>::Capacity(void) const {
755  return ManagedSharedMemory<contents>::Capacity();
756  }
757 
758  template < class contents > inline contents *KnRManagedSharedMemory<contents>::BaseAllocate(const unsigned long m, const void * const /*hint*/) {
759  // Need to find a block of memory of the correct size that is not in use.
760  // Note - "m" in units of "sizeof(contents)" rounded up.
761  if (m>Capacity()) {
762  // Ran out of memory...
763  return NULL;
764  }
765  __asm {
766  int 3
767  }
768  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
769  const unsigned long nunits=m*sizeof(contents)+sizeof(free_memory_list_type);
770  free_memory_list_type *prevp=free_list;
771  // (Linear) Search through the list to find a free block.
772  for (free_memory_list_type *p=prevp->next; ;prevp=p, p=p->next) {
773  if (p->size>=nunits) {
774  // The block is big enough.
775  if (p->size==nunits) {
776  // Exactly big enough.
777  prevp->next=p->next;
778  } else {
779  // Allocate tail end.
780  p->size-=nunits;
781  p+=p->size/sizeof(free_memory_list_type);
782  p->size=nunits;
783  }
784  free_list=prevp;
785 #ifdef _DEBUG
786  // Set the main memory, so that in debug mode I can see it being allocated.
787  memset(reinterpret_cast<void *>(p+1), 0xFE, m*sizeof(contents));
788 #endif _DEBUG
789  return reinterpret_cast<contents *>(p+1);
790  }
791  if (p==free_list) {
792  // Wrapped around the free list! Couldn't find a big enough free block.
793  return NULL;
794  }
795  }
796  return NULL;
797  }
798 
799  // Note: "m" in units of "contents".
800  template < class contents > inline unsigned long KnRManagedSharedMemory<contents>::BaseDeallocate(const contents * const ptr, const unsigned long m) {
801  // "p" must be from the same process space.
802  NTUtils::MutexLock lock(mutex.Name(), INFINITE, const_cast<SECURITY_ATTRIBUTES * const>(&(ss->SA())));
803  // NOTE: Can't deallocate a "const" pointer (as in "(const contents * const)"), only non-const. Hence the cast and type declaration.
804  free_memory_list_type *p;
805  free_memory_list_type * const bp=reinterpret_cast<free_memory_list_type * const>(const_cast<contents * const>(ptr))-1;
806  __asm {
807  int 3
808  }
809 #ifdef _DEBUG
810  // Ensure the block size is correct.
811  assert(m || (bp->size==m*sizeof(contents)+sizeof(free_memory_list_type)));
812  // Set the main memory, so that in debug mode I can see it being allocated.
813  memset(const_cast<contents * const>(ptr), 0xFD, m*sizeof(contents));
814 #endif _DEBUG
815  for (p=free_list; !(bp>p && bp<p->next); p=p->next) {
816  if (p>=p->next && (bp>p || bp<p->next)) {
817  break; // Freed block at the start or end of arena.
818  }
819  };
820  if (bp+bp->size/sizeof(free_memory_list_type)==p->next) { // Join to upper neighbour.
821  bp->size+=p->next->size;
822  bp->next=p->next->next;
823  } else {
824  bp->next=p->next;
825  }
826  if (p+p->size/sizeof(free_memory_list_type)==bp) { // Join to lower neighbour.
827  p->size+=bp->size;
828  p->next=bp->next;
829  } else {
830  p->next=bp;
831  }
832  free_list=p;
833  return bp->size/sizeof(contents);
834  }
835 
836  template < class contents > inline bool KnRManagedSharedMemory<contents>::Capacity(const unsigned long, const DWORD, HANDLE) {
837  std::cerr << "KnRManagedSharedMemory<...>::Capacity(...) : Not supported!!!" << std::endl;
838  return true;
839  }
840 
841  template < class heap_manager, unsigned long id > inline ManagedSharedMemorySTLIntf<heap_manager, id>::ManagedSharedMemorySTLIntf(const HeapID &details) : heap_manager(details) {
842  }
843 
844  template < class heap_manager, unsigned long id > inline ManagedSharedMemorySTLIntf<heap_manager, id>::~ManagedSharedMemorySTLIntf(void) {
845  }
846 
847  template < class heap_manager, unsigned long id > inline ManagedSharedMemorySTLIntf<heap_manager, id>::ManagedSharedMemorySTLIntf(const unsigned long p, const HeapID &details) : heap_manager(p, details) {
848  }
849 
850  }
851 
852 } }