Arquivos
hhvm/hphp/util/shared_memory_allocator.h
T
2013-04-22 14:43:49 -07:00

243 linhas
8.7 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_MEMORY_SHARED_MEMORY_ALLOCATOR_H_
#define incl_HPHP_MEMORY_SHARED_MEMORY_ALLOCATOR_H_
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/containers/set.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include "base.h"
namespace HPHP {
/**
* HOW TO USE SHARED MEMORY FOR MY OBJECTS?
* ========================================
*
* 1. Make sure your class is POD (plain-old data object), simply meaning
* there cannot be virtual functions in the class. Derivation is okay, but
* just not virtual functions, because virtual function table has address
* pointers that are always local to creation process, and those are not
* pass-able between different processes. If you have it, the symptom would
* be, well it works for the creation process, but it will fail miserably
* when a 2nd process attaches to the same shared memory and call some
* functions (or other things) that use vtable.
*
* 2. Make sure ALL data members, no matter how deep it is, are shared memory
* safe. Primitive types are automatically shared memory safe, thanks to the
* allocator implemented in this file. For complex types, we just need to
* make sure all STL classes are converted to use their counterparts:
*
* std::string => SharedMemoryString
* std::vector => SharedMemoryVector
* std::list => SharedMemoryList
* std::set => SharedMemorySet
* std::map => SharedMemoryMap
*
* There is a macro DISABLE_SHARED_MEMORY for debugging purpose, turning off
* this conversion transparently.
*
* For any other complex types that are not covered here, they have to have
* a way to specify its memory allocator to use the allocator in this file.
* This normally means dirty work redirecting all malloc/free to call
* methods on the allocator and pass this allocator into the class. So it
* may not be trivial.
*
* 3. During application startup time, call this to initialize/attach to an
* existing piece of shared memory:
*
* SharedMemoryManager::Init(totalSizeInBytes);
*
* Shared memory can actually resizable, but it's not implemented in this
* file yet. Look up this web site for adding features in this file:
*
* http://www.boost.org/doc/libs/1_35_0/doc/html/interprocess.html
*
* 4. Now, we need a top level object to pull out anything from shared memory,
* right? This kind of top level objects always have a name to uniquely
* identify them:
*
* MyClass *top_level_object =
* SharedMemory<MyClass>::OpenOrCreate("a unique name for my object");
*
* Note SharedMemory<T> works just fine with primitive types:
*
* int *secret_integer = SharedMemory<int>::OpenOrCreate("secret");
*
* 5. If we are the sole owner of a shared memory object, we don't need locking
* at all. If not, we need to lock individual objects for accesses:
*
* int *shared = SharedMemory<int>::OpenOrCreate("shared");
* {
* SharedMemoryLock lock("any name for this lock");
* *shared = whatever;
* }
*
* Two things to notice, (1) SharedMemory<T>::OpenOrCreate() is atomic
* already, and there is no need to lock protect that. It also made sure
* same key/name never gets created twice by two concurrent processes.
* (2) lock's name has NOTHING to do with the object's name. So you can use
* the same lock for multiple objects. Or, more often than not, you can use
* multple locks for sub-component of the same object -- finer locking.
*
* It's a dumb simple mutex-based lock right now. It's possible to have
* read-write locks as well, just not implemented yet.
*/
///////////////////////////////////////////////////////////////////////////////
/**
* Helper class to hold a segment of shared-memory. We only need one instance
* of this class for one application for simplicity.
*/
class SharedMemoryManager {
public:
// an app needs to call this during startup time
static void Init(int size, bool clean);
static void Reset();
// called by allocator class
static boost::interprocess::managed_shared_memory *GetSegment() {
assert(Segment); // or Init() is missing
return Segment;
}
private:
static const char *Name;
static boost::interprocess::managed_shared_memory *Segment;
};
/**
* Helper class for STL classes to use our SharedMemoryManager for allocating
* elements.
*/
template<typename T>
class SharedMemoryAllocator : public boost::interprocess::allocator
<T, boost::interprocess::managed_shared_memory::segment_manager> {
public:
SharedMemoryAllocator() :
boost::interprocess::allocator
<T, boost::interprocess::managed_shared_memory::segment_manager>
(SharedMemoryManager::GetSegment()->get_segment_manager()) {
}
};
///////////////////////////////////////////////////////////////////////////////
/**
* Creating or destroying a top-level shared memory objects with names.
*/
template<typename T>
class SharedMemory {
public:
static T *OpenOrCreate(const char *name) {
assert(name && *name);
return SharedMemoryManager::GetSegment()->find_or_construct<T>(name)();
}
static bool Destroy(const char *name) {
assert(name && *name);
return SharedMemoryManager::GetSegment()->destroy<T>(name);
}
};
///////////////////////////////////////////////////////////////////////////////
#ifndef DISABLE_SHARED_MEMORY
/**
* Embeddable STL classes: string, vector, list, set, map.
*/
typedef boost::interprocess::string SharedMemoryString;
// This sucks, since C++ doesn't support partial template typedefs.
template<typename T>
class SharedMemoryVector :
public boost::interprocess::vector<T, SharedMemoryAllocator<T> > {
};
template<typename T>
class SharedMemoryList :
public boost::interprocess::list<T, SharedMemoryAllocator<T> > {
};
template<typename T>
class SharedMemorySet :
public boost::interprocess::set<T, std::less<T>,
SharedMemoryAllocator<T> > {
};
template<typename Key, typename T>
class SharedMemoryMap :
public boost::interprocess::map
<Key, T, std::less<Key>, SharedMemoryAllocator<std::pair<Key, T> > > {
};
template<typename Key, typename T, class C>
class SharedMemoryMapWithComp :
public boost::interprocess::map
<Key, T, C, SharedMemoryAllocator<std::pair<Key, T> > > {
};
#else
// falling back to regular std classes
typedef std::string SharedMemoryString;
template<typename T> class SharedMemoryVector : public std::vector<T> {};
template<typename T> class SharedMemoryList : public std::list<T> {};
template<typename T> class SharedMemorySet : public std::set<T> {};
template<typename K, typename T>
class SharedMemoryMap : public std::map<K, T> {};
#endif
///////////////////////////////////////////////////////////////////////////////
/**
* Lock/unlock a top level shared memory object for sole access.
*/
class SharedMemoryLock {
public:
static bool Destroy(const char *name) {
assert(name && *name);
return boost::interprocess::named_mutex::remove(name);
}
explicit SharedMemoryLock(const char *name) {
assert(name && *name);
m_mutex = new boost::interprocess::named_mutex
(boost::interprocess::open_or_create, name);
m_mutex->lock();
}
~SharedMemoryLock() {
m_mutex->unlock();
delete m_mutex;
}
private:
boost::interprocess::named_mutex *m_mutex;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_MEMORY_SHARED_MEMORY_ALLOCATOR_H_