Copy fbjni library from react-native
This commit is contained in:
118
lib/fb/include/fb/ThreadLocal.h
Normal file
118
lib/fb/include/fb/ThreadLocal.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fb/assert.h>
|
||||
|
||||
namespace facebook {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A thread-local object is a "global" object within a thread. This is useful
|
||||
* for writing apartment-threaded code, where nothing is actullay shared
|
||||
* between different threads (hence no locking) but those variables are not
|
||||
* on stack in local scope. To use it, just do something like this,
|
||||
*
|
||||
* ThreadLocal<MyClass> static_object;
|
||||
* static_object->data_ = ...;
|
||||
* static_object->doSomething();
|
||||
*
|
||||
* ThreadLocal<int> static_number;
|
||||
* int value = *static_number;
|
||||
*
|
||||
* So, syntax-wise it's similar to pointers. T can be primitive types, and if
|
||||
* it's a class, there has to be a default constructor.
|
||||
*/
|
||||
template<typename T>
|
||||
class ThreadLocal {
|
||||
public:
|
||||
/**
|
||||
* Constructor that has to be called from a thread-neutral place.
|
||||
*/
|
||||
ThreadLocal() :
|
||||
m_key(0),
|
||||
m_cleanup(OnThreadExit) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* As above but with a custom cleanup function
|
||||
*/
|
||||
typedef void (*CleanupFunction)(void* obj);
|
||||
explicit ThreadLocal(CleanupFunction cleanup) :
|
||||
m_key(0),
|
||||
m_cleanup(cleanup) {
|
||||
FBASSERT(cleanup);
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Access object's member or method through this operator overload.
|
||||
*/
|
||||
T *operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
T &operator*() const {
|
||||
return *get();
|
||||
}
|
||||
|
||||
T *get() const {
|
||||
return (T*)pthread_getspecific(m_key);
|
||||
}
|
||||
|
||||
T* release() {
|
||||
T* obj = get();
|
||||
pthread_setspecific(m_key, NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void reset(T* other = NULL) {
|
||||
T* old = (T*)pthread_getspecific(m_key);
|
||||
if (old != other) {
|
||||
FBASSERT(m_cleanup);
|
||||
m_cleanup(old);
|
||||
pthread_setspecific(m_key, other);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void initialize() {
|
||||
int ret = pthread_key_create(&m_key, m_cleanup);
|
||||
if (ret != 0) {
|
||||
const char *msg = "(unknown error)";
|
||||
switch (ret) {
|
||||
case EAGAIN:
|
||||
msg = "PTHREAD_KEYS_MAX (1024) is exceeded";
|
||||
break;
|
||||
case ENOMEM:
|
||||
msg = "Out-of-memory";
|
||||
break;
|
||||
}
|
||||
(void) msg;
|
||||
FBASSERTMSGF(0, "pthread_key_create failed: %d %s", ret, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnThreadExit(void *obj) {
|
||||
if (NULL != obj) {
|
||||
delete (T*)obj;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_key_t m_key;
|
||||
CleanupFunction m_cleanup;
|
||||
};
|
||||
|
||||
}
|
Reference in New Issue
Block a user