a8e3321fbd
We'd like to start using ##mixed## instead of ##var## for attribute types to be consistent with Hack. As a followup to this (once released), we would codemod all ##var## to ##mixed##.
168 linhas
4.9 KiB
C++
168 linhas
4.9 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
| Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. |
|
|
| If you did not receive a copy of the Zend license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@zend.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_REQUEST_LOCAL_H_
|
|
#define incl_HPHP_REQUEST_LOCAL_H_
|
|
|
|
#include "hphp/runtime/base/execution_context.h"
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* A RequestLocal<T> is automatically thread local, plus it has two handlers
|
|
* to do extra work on request init and shutdown times. T needs to derive from
|
|
* RequestEventHandler, so it will register itself with execution engines to
|
|
* be called at request shutdown time.
|
|
*
|
|
* Example:
|
|
*
|
|
* class MyRequestLocalClass : public RequestEventHandler {
|
|
* public:
|
|
* virtual void requestInit() {...}
|
|
* virtual void requestShutdown() {...}
|
|
* };
|
|
* static RequestLocal<MyRequestLocalClass> s_data;
|
|
*/
|
|
|
|
#if defined(USE_GCC_FAST_TLS)
|
|
|
|
template<typename T>
|
|
struct RequestLocal {
|
|
T *get() const {
|
|
if (m_node.m_p == nullptr) {
|
|
const_cast<RequestLocal<T>*>(this)->create();
|
|
}
|
|
if (!m_node.m_p->getInited()) {
|
|
m_node.m_p->setInited(true);
|
|
m_node.m_p->requestInit();
|
|
// this registration makes sure m_p->requestShutdown() will be called
|
|
g_context->registerRequestEventHandler(m_node.m_p);
|
|
}
|
|
return m_node.m_p;
|
|
}
|
|
|
|
void create() NEVER_INLINE;
|
|
|
|
static void OnThreadExit(void * p) {
|
|
ThreadLocalNode<T> * pNode = (ThreadLocalNode<T>*)p;
|
|
delete pNode->m_p;
|
|
pNode->m_p = nullptr;
|
|
}
|
|
|
|
T *operator->() const {
|
|
return get();
|
|
}
|
|
|
|
T &operator*() const {
|
|
return *get();
|
|
}
|
|
|
|
ThreadLocalNode<T> m_node;
|
|
};
|
|
|
|
template<typename T>
|
|
void RequestLocal<T>::create() {
|
|
if (m_node.m_on_thread_exit_fn == nullptr) {
|
|
m_node.m_on_thread_exit_fn = RequestLocal<T>::OnThreadExit;
|
|
m_node.m_next = ThreadLocalManager::s_manager.getTop();
|
|
ThreadLocalManager::s_manager.setTop((void*)(&m_node));
|
|
}
|
|
assert(m_node.m_p == nullptr);
|
|
m_node.m_p = new T();
|
|
}
|
|
|
|
#define IMPLEMENT_REQUEST_LOCAL(T,f) \
|
|
__thread RequestLocal<T> f
|
|
|
|
#define DECLARE_STATIC_REQUEST_LOCAL(T,f) \
|
|
static __thread RequestLocal<T> f
|
|
|
|
#define IMPLEMENT_STATIC_REQUEST_LOCAL(T,f) \
|
|
static __thread RequestLocal<T> f
|
|
|
|
#define DECLARE_EXTERN_REQUEST_LOCAL(T,f) \
|
|
extern __thread RequestLocal<T> f
|
|
|
|
#else // defined(USE_GCC_FAST_TLS)
|
|
|
|
template<typename T>
|
|
class RequestLocal {
|
|
public:
|
|
RequestLocal(ThreadLocal<T> & tl) : m_tlsObjects(tl) {}
|
|
T *operator->() const { return get();}
|
|
T &operator*() const { return *get();}
|
|
|
|
T *get() const {
|
|
T *obj = m_tlsObjects.get();
|
|
if (!obj->getInited()) {
|
|
obj->setInited(true);
|
|
obj->requestInit();
|
|
|
|
// this registration makes sure obj->requestShutdown() will be called
|
|
g_context->registerRequestEventHandler(obj);
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
private:
|
|
ThreadLocal<T> & m_tlsObjects;
|
|
};
|
|
|
|
/*
|
|
* How to use the request-local macros:
|
|
*
|
|
* Use DECLARE_STATIC_REQUEST_LOCAL to declare a *static* class field as
|
|
* request local:
|
|
* class SomeClass {
|
|
* DECLARE_STATIC_REQUEST_LOCAL(SomeFieldType, f);
|
|
* }
|
|
*
|
|
* Use IMPLEMENT_STATIC_REQUEST_LOCAL in the cpp file to implement the field:
|
|
* IMPLEMENT_STATIC_REQUEST_LOCAL(SomeFieldType, SomeClass::f);
|
|
*
|
|
* The DECLARE_REQUEST_LOCAL and IMPLEMENT_REQUEST_LOCAL macros are provided
|
|
* for declaring/implementing request locals in the global scope.
|
|
*
|
|
* Remember: *Never* write IMPLEMENT_STATIC_REQUEST_LOCAL in a header file.
|
|
*/
|
|
|
|
#define IMPLEMENT_REQUEST_LOCAL(T,f) \
|
|
IMPLEMENT_THREAD_LOCAL(T, f ## __tl); \
|
|
RequestLocal<T> f(f ## __tl)
|
|
|
|
#define DECLARE_STATIC_REQUEST_LOCAL(T,f) \
|
|
static DECLARE_THREAD_LOCAL(T,f ## __tl); \
|
|
static RequestLocal<T> f
|
|
|
|
#define IMPLEMENT_STATIC_REQUEST_LOCAL(T,f) \
|
|
static IMPLEMENT_THREAD_LOCAL(T, f ## __tl); \
|
|
static RequestLocal<T> f(f ## __tl)
|
|
|
|
#define DECLARE_EXTERN_REQUEST_LOCAL(T,f) \
|
|
extern DECLARE_THREAD_LOCAL(T,f ## __tl); \
|
|
extern RequestLocal<T> f
|
|
|
|
#endif // defined(USE_GCC_FAST_TLS)
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
#endif // incl_HPHP_REQUEST_LOCAL_H_
|