Merge "Make ThreadLocalBuffer a class rather than a macro."
This commit is contained in:
commit
72035734af
@ -36,6 +36,9 @@
|
|||||||
|
|
||||||
#include "private/ThreadLocalBuffer.h"
|
#include "private/ThreadLocalBuffer.h"
|
||||||
|
|
||||||
|
static ThreadLocalBuffer<char, MAXPATHLEN> g_basename_tls_buffer;
|
||||||
|
static ThreadLocalBuffer<char, MAXPATHLEN> g_dirname_tls_buffer;
|
||||||
|
|
||||||
__LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
|
__LIBC64_HIDDEN__ int basename_r(const char* path, char* buffer, size_t buffer_size) {
|
||||||
const char* startp = NULL;
|
const char* startp = NULL;
|
||||||
const char* endp = NULL;
|
const char* endp = NULL;
|
||||||
@ -147,17 +150,14 @@ __LIBC64_HIDDEN__ int dirname_r(const char* path, char* buffer, size_t buffer_si
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(basename);
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(dirname);
|
|
||||||
|
|
||||||
char* basename(const char* path) {
|
char* basename(const char* path) {
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, basename, MAXPATHLEN);
|
char* buf = g_basename_tls_buffer.get();
|
||||||
int rc = basename_r(path, basename_tls_buffer, basename_tls_buffer_size);
|
int rc = basename_r(path, buf, g_basename_tls_buffer.size());
|
||||||
return (rc < 0) ? NULL : basename_tls_buffer;
|
return (rc < 0) ? NULL : buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* dirname(const char* path) {
|
char* dirname(const char* path) {
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, dirname, MAXPATHLEN);
|
char* buf = g_dirname_tls_buffer.get();
|
||||||
int rc = dirname_r(path, dirname_tls_buffer, dirname_tls_buffer_size);
|
int rc = dirname_r(path, buf, g_dirname_tls_buffer.size());
|
||||||
return (rc < 0) ? NULL : dirname_tls_buffer;
|
return (rc < 0) ? NULL : buf;
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,13 @@
|
|||||||
|
|
||||||
#include "private/ThreadLocalBuffer.h"
|
#include "private/ThreadLocalBuffer.h"
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(getmntent_mntent);
|
static ThreadLocalBuffer<mntent> g_getmntent_mntent_tls_buffer;
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(getmntent_strings);
|
static ThreadLocalBuffer<char, BUFSIZ> g_getmntent_strings_tls_buffer;
|
||||||
|
|
||||||
mntent* getmntent(FILE* fp) {
|
mntent* getmntent(FILE* fp) {
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(mntent*, getmntent_mntent, sizeof(mntent));
|
return getmntent_r(fp, g_getmntent_mntent_tls_buffer.get(),
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, getmntent_strings, BUFSIZ);
|
g_getmntent_strings_tls_buffer.get(),
|
||||||
return getmntent_r(fp, getmntent_mntent_tls_buffer,
|
g_getmntent_strings_tls_buffer.size());
|
||||||
getmntent_strings_tls_buffer, getmntent_strings_tls_buffer_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mntent* getmntent_r(FILE* fp, struct mntent* e, char* buf, int buf_len) {
|
mntent* getmntent_r(FILE* fp, struct mntent* e, char* buf, int buf_len) {
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
|
|
||||||
#include "private/ThreadLocalBuffer.h"
|
#include "private/ThreadLocalBuffer.h"
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(ptsname);
|
static ThreadLocalBuffer<char, 32> g_ptsname_tls_buffer;
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(ttyname);
|
static ThreadLocalBuffer<char, 64> g_ttyname_tls_buffer;
|
||||||
|
|
||||||
int getpt() {
|
int getpt() {
|
||||||
return posix_openpt(O_RDWR|O_NOCTTY);
|
return posix_openpt(O_RDWR|O_NOCTTY);
|
||||||
@ -54,9 +54,9 @@ int posix_openpt(int flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* ptsname(int fd) {
|
char* ptsname(int fd) {
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, ptsname, 32);
|
char* buf = g_ptsname_tls_buffer.get();
|
||||||
int error = ptsname_r(fd, ptsname_tls_buffer, ptsname_tls_buffer_size);
|
int error = ptsname_r(fd, buf, g_ptsname_tls_buffer.size());
|
||||||
return (error == 0) ? ptsname_tls_buffer : NULL;
|
return (error == 0) ? buf : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ptsname_r(int fd, char* buf, size_t len) {
|
int ptsname_r(int fd, char* buf, size_t len) {
|
||||||
@ -80,9 +80,9 @@ int ptsname_r(int fd, char* buf, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* ttyname(int fd) {
|
char* ttyname(int fd) {
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, ttyname, 64);
|
char* buf = g_ttyname_tls_buffer.get();
|
||||||
int error = ttyname_r(fd, ttyname_tls_buffer, ttyname_tls_buffer_size);
|
int error = ttyname_r(fd, buf, g_ttyname_tls_buffer.size());
|
||||||
return (error == 0) ? ttyname_tls_buffer : NULL;
|
return (error == 0) ? buf : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ttyname_r(int fd, char* buf, size_t len) {
|
int ttyname_r(int fd, char* buf, size_t len) {
|
||||||
|
@ -31,16 +31,16 @@
|
|||||||
|
|
||||||
extern "C" const char* __strerror_lookup(int);
|
extern "C" const char* __strerror_lookup(int);
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(strerror);
|
static ThreadLocalBuffer<char, NL_TEXTMAX> g_strerror_tls_buffer;
|
||||||
|
|
||||||
char* strerror(int error_number) {
|
char* strerror(int error_number) {
|
||||||
// Just return the original constant in the easy cases.
|
// Just return the original constant in the easy cases.
|
||||||
char* result = const_cast<char*>(__strerror_lookup(error_number));
|
char* result = const_cast<char*>(__strerror_lookup(error_number));
|
||||||
if (result != NULL) {
|
if (result != nullptr) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strerror, NL_TEXTMAX);
|
result = g_strerror_tls_buffer.get();
|
||||||
strerror_r(error_number, strerror_tls_buffer, strerror_tls_buffer_size);
|
strerror_r(error_number, result, g_strerror_tls_buffer.size());
|
||||||
return strerror_tls_buffer;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
extern "C" const char* __strsignal_lookup(int);
|
extern "C" const char* __strsignal_lookup(int);
|
||||||
extern "C" const char* __strsignal(int, char*, size_t);
|
extern "C" const char* __strsignal(int, char*, size_t);
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(strsignal);
|
static ThreadLocalBuffer<char, NL_TEXTMAX> g_strsignal_tls_buffer;
|
||||||
|
|
||||||
char* strsignal(int signal_number) {
|
char* strsignal(int signal_number) {
|
||||||
// Just return the original constant in the easy cases.
|
// Just return the original constant in the easy cases.
|
||||||
@ -41,6 +41,6 @@ char* strsignal(int signal_number) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(char*, strsignal, NL_TEXTMAX);
|
return const_cast<char*>(__strsignal(signal_number, g_strsignal_tls_buffer.get(),
|
||||||
return const_cast<char*>(__strsignal(signal_number, strsignal_tls_buffer, strsignal_tls_buffer_size));
|
g_strsignal_tls_buffer.size()));
|
||||||
}
|
}
|
||||||
|
@ -49,25 +49,12 @@
|
|||||||
// functions to share state, but <grp.h> functions can't clobber <passwd.h>
|
// functions to share state, but <grp.h> functions can't clobber <passwd.h>
|
||||||
// functions' state and vice versa.
|
// functions' state and vice versa.
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(group);
|
|
||||||
|
|
||||||
struct group_state_t {
|
struct group_state_t {
|
||||||
group group_;
|
group group_;
|
||||||
char* group_members_[2];
|
char* group_members_[2];
|
||||||
char group_name_buffer_[32];
|
char group_name_buffer_[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
static group_state_t* __group_state() {
|
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(group_state_t*, group, sizeof(group_state_t));
|
|
||||||
if (group_tls_buffer != NULL) {
|
|
||||||
memset(group_tls_buffer, 0, sizeof(group_state_t));
|
|
||||||
group_tls_buffer->group_.gr_mem = group_tls_buffer->group_members_;
|
|
||||||
}
|
|
||||||
return group_tls_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLOBAL_INIT_THREAD_LOCAL_BUFFER(passwd);
|
|
||||||
|
|
||||||
struct passwd_state_t {
|
struct passwd_state_t {
|
||||||
passwd passwd_;
|
passwd passwd_;
|
||||||
char name_buffer_[32];
|
char name_buffer_[32];
|
||||||
@ -75,9 +62,16 @@ struct passwd_state_t {
|
|||||||
char sh_buffer_[32];
|
char sh_buffer_[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
static passwd_state_t* __passwd_state() {
|
static ThreadLocalBuffer<group_state_t> g_group_tls_buffer;
|
||||||
LOCAL_INIT_THREAD_LOCAL_BUFFER(passwd_state_t*, passwd, sizeof(passwd_state_t));
|
static ThreadLocalBuffer<passwd_state_t> g_passwd_tls_buffer;
|
||||||
return passwd_tls_buffer;
|
|
||||||
|
static group_state_t* __group_state() {
|
||||||
|
group_state_t* result = g_group_tls_buffer.get();
|
||||||
|
if (result != nullptr) {
|
||||||
|
memset(result, 0, sizeof(group_state_t));
|
||||||
|
result->group_.gr_mem = result->group_members_;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_getpw_r(int by_name, const char* name, uid_t uid,
|
static int do_getpw_r(int by_name, const char* name, uid_t uid,
|
||||||
@ -361,7 +355,7 @@ static group* app_id_to_group(gid_t gid, group_state_t* state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
||||||
passwd_state_t* state = __passwd_state();
|
passwd_state_t* state = g_passwd_tls_buffer.get();
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -374,7 +368,7 @@ passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
|
|||||||
}
|
}
|
||||||
|
|
||||||
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
||||||
passwd_state_t* state = __passwd_state();
|
passwd_state_t* state = g_passwd_tls_buffer.get();
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,6 @@
|
|||||||
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
|
||||||
#include <sys/_system_properties.h>
|
#include <sys/_system_properties.h>
|
||||||
|
|
||||||
#include "private/ThreadLocalBuffer.h"
|
|
||||||
|
|
||||||
/* Set to 1 to enable debug traces */
|
/* Set to 1 to enable debug traces */
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
|
||||||
@ -105,7 +103,11 @@ _res_thread_free( void* _rt )
|
|||||||
free(rt);
|
free(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR(_res_key, _res_thread_free);
|
static pthread_key_t _res_key;
|
||||||
|
|
||||||
|
__attribute__((constructor)) static void __res_key_init() {
|
||||||
|
pthread_key_create(&_res_key, _res_thread_free);
|
||||||
|
}
|
||||||
|
|
||||||
static _res_thread*
|
static _res_thread*
|
||||||
_res_thread_get(void)
|
_res_thread_get(void)
|
||||||
|
@ -32,32 +32,30 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
// libstdc++ currently contains __cxa_guard_acquire and __cxa_guard_release,
|
// TODO: use __thread instead?
|
||||||
// so we make do with macros instead of a C++ class.
|
|
||||||
// TODO: move __cxa_guard_acquire and __cxa_guard_release into libc.
|
|
||||||
|
|
||||||
// We used to use pthread_once to initialize the keys, but life is more predictable
|
template <typename T, size_t Size = sizeof(T)>
|
||||||
// if we allocate them all up front when the C library starts up, via __constructor__.
|
class ThreadLocalBuffer {
|
||||||
#define BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR(key_name, key_destructor) \
|
public:
|
||||||
static pthread_key_t key_name; \
|
ThreadLocalBuffer() {
|
||||||
__attribute__((constructor)) static void __bionic_tls_ ## key_name ## _key_init() { \
|
// We used to use pthread_once to initialize the keys, but life is more predictable
|
||||||
pthread_key_create(&key_name, key_destructor); \
|
// if we allocate them all up front when the C library starts up, via __constructor__.
|
||||||
|
pthread_key_create(&key_, free);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GLOBAL_INIT_THREAD_LOCAL_BUFFER(name) \
|
T* get() {
|
||||||
static void __bionic_tls_ ## name ## _key_destroy(void* buffer) { \
|
T* result = reinterpret_cast<T*>(pthread_getspecific(key_));
|
||||||
free(buffer); \
|
if (result == nullptr) {
|
||||||
} \
|
result = reinterpret_cast<T*>(calloc(1, Size));
|
||||||
BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR(__bionic_tls_ ## name ## _key, __bionic_tls_ ## name ## _key_destroy)
|
pthread_setspecific(key_, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Leaves "name_tls_buffer" and "name_tls_buffer_size" defined and initialized.
|
size_t size() { return Size; }
|
||||||
#define LOCAL_INIT_THREAD_LOCAL_BUFFER(type, name, byte_count) \
|
|
||||||
type name ## _tls_buffer = \
|
private:
|
||||||
reinterpret_cast<type>(pthread_getspecific(__bionic_tls_ ## name ## _key)); \
|
pthread_key_t key_;
|
||||||
if (name ## _tls_buffer == NULL) { \
|
};
|
||||||
name ## _tls_buffer = reinterpret_cast<type>(calloc(1, byte_count)); \
|
|
||||||
pthread_setspecific(__bionic_tls_ ## name ## _key, name ## _tls_buffer); \
|
|
||||||
} \
|
|
||||||
const size_t name ## _tls_buffer_size __attribute__((unused)) = byte_count
|
|
||||||
|
|
||||||
#endif // _BIONIC_THREAD_LOCAL_BUFFER_H_included
|
#endif // _BIONIC_THREAD_LOCAL_BUFFER_H_included
|
||||||
|
@ -72,22 +72,26 @@ enum {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Bionic uses some pthread keys internally. All pthread keys used internally
|
* Bionic uses some pthread keys internally. All pthread keys used internally
|
||||||
* should be created in constructors, except for keys that may be used in or before constructors.
|
* should be created in constructors, except for keys that may be used in or
|
||||||
|
* before constructors.
|
||||||
|
*
|
||||||
* We need to manually maintain the count of pthread keys used internally, but
|
* We need to manually maintain the count of pthread keys used internally, but
|
||||||
* pthread_test should fail if we forget.
|
* pthread_test should fail if we forget.
|
||||||
* Following are current pthread keys used internally by libc:
|
*
|
||||||
* basename libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* These are the pthread keys currently used internally by libc:
|
||||||
* dirname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
*
|
||||||
|
* basename libc (ThreadLocalBuffer)
|
||||||
|
* dirname libc (ThreadLocalBuffer)
|
||||||
* uselocale libc (can be used in constructors)
|
* uselocale libc (can be used in constructors)
|
||||||
* getmntent_mntent libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* getmntent_mntent libc (ThreadLocalBuffer)
|
||||||
* getmntent_strings libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* getmntent_strings libc (ThreadLocalBuffer)
|
||||||
* ptsname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* ptsname libc (ThreadLocalBuffer)
|
||||||
* ttyname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* ttyname libc (ThreadLocalBuffer)
|
||||||
* strerror libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* strerror libc (ThreadLocalBuffer)
|
||||||
* strsignal libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* strsignal libc (ThreadLocalBuffer)
|
||||||
* passwd libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* passwd libc (ThreadLocalBuffer)
|
||||||
* group libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
|
* group libc (ThreadLocalBuffer)
|
||||||
* _res_key libc (BIONIC_PTHREAD_KEY_WITH_CONSTRUCTOR)
|
* _res_key libc (constructor in BSD code)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LIBC_PTHREAD_KEY_RESERVED_COUNT 12
|
#define LIBC_PTHREAD_KEY_RESERVED_COUNT 12
|
||||||
|
@ -68,8 +68,7 @@ TEST(pthread, pthread_key_many_distinct) {
|
|||||||
|
|
||||||
for (int i = 0; i < nkeys; ++i) {
|
for (int i = 0; i < nkeys; ++i) {
|
||||||
pthread_key_t key;
|
pthread_key_t key;
|
||||||
// If this fails, it's likely that GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT is
|
// If this fails, it's likely that LIBC_PTHREAD_KEY_RESERVED_COUNT is wrong.
|
||||||
// wrong.
|
|
||||||
ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << nkeys;
|
ASSERT_EQ(0, pthread_key_create(&key, NULL)) << i << " of " << nkeys;
|
||||||
keys.push_back(key);
|
keys.push_back(key);
|
||||||
ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void*>(i)));
|
ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void*>(i)));
|
||||||
|
Loading…
Reference in New Issue
Block a user