Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

unix, windows: add thread-local storage API #906

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/uv-unix.h
Expand Up @@ -131,7 +131,7 @@ typedef pthread_mutex_t uv_mutex_t;
typedef pthread_rwlock_t uv_rwlock_t;
typedef UV_PLATFORM_SEM_T uv_sem_t;
typedef pthread_cond_t uv_cond_t;

typedef pthread_key_t uv_key_t;

#if defined(__APPLE__) && defined(__MACH__)

Expand Down
4 changes: 4 additions & 0 deletions include/uv-win.h
Expand Up @@ -250,6 +250,10 @@ typedef struct {
uv_sem_t turnstile2;
} uv_barrier_t;

typedef struct {
DWORD tls_index;
} uv_key_t;

#define UV_ONCE_INIT { 0, NULL }

typedef struct uv_once_s {
Expand Down
12 changes: 12 additions & 0 deletions include/uv.h
Expand Up @@ -2012,6 +2012,18 @@ UV_EXTERN void uv_barrier_wait(uv_barrier_t* barrier);
*/
UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));

/* Thread-local storage. These functions largely follow the semantics of
* pthread_key_create(), pthread_key_delete(), pthread_getspecific() and
* pthread_setspecific().
*
* Note that the total thread-local storage size may be limited.
* That is, it may not be possible to create many TLS keys.
*/
UV_EXTERN int uv_key_create(uv_key_t* key);
UV_EXTERN void uv_key_delete(uv_key_t* key);
UV_EXTERN void* uv_key_get(uv_key_t* key);
UV_EXTERN void uv_key_set(uv_key_t* key, void* value);

UV_EXTERN int uv_thread_create(uv_thread_t *tid,
void (*entry)(void *arg), void *arg);
UV_EXTERN unsigned long uv_thread_self(void);
Expand Down
21 changes: 21 additions & 0 deletions src/unix/thread.c
Expand Up @@ -441,3 +441,24 @@ void uv_barrier_wait(uv_barrier_t* barrier) {
}

#endif /* defined(__APPLE__) && defined(__MACH__) */

int uv_key_create(uv_key_t* key) {
return -pthread_key_create(key, NULL);
}


void uv_key_delete(uv_key_t* key) {
if (pthread_key_delete(*key))
abort();
}


void* uv_key_get(uv_key_t* key) {
return pthread_getspecific(*key);
}


void uv_key_set(uv_key_t* key, void* value) {
if (pthread_setspecific(*key, value))
abort();
}
33 changes: 33 additions & 0 deletions src/win/thread.c
Expand Up @@ -680,3 +680,36 @@ void uv_barrier_wait(uv_barrier_t* barrier) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
}


int uv_key_create(uv_key_t* key) {
key->tls_index = TlsAlloc();
if (key->tls_index == TLS_OUT_OF_INDEXES)
return UV_ENOMEM;
return 0;
}


void uv_key_delete(uv_key_t* key) {
if (TlsFree(key->tls_index) == FALSE)
abort();
key->tls_index = TLS_OUT_OF_INDEXES;
}


void* uv_key_get(uv_key_t* key) {
void* value;

value = TlsGetValue(key->tls_index);
if (value == NULL)
if (GetLastError() != ERROR_SUCCESS)
abort();

return value;
}


void uv_key_set(uv_key_t* key, void* value) {
if (TlsSetValue(key->tls_index, value) == FALSE)
abort();
}
1 change: 1 addition & 0 deletions src/win/winapi.h
Expand Up @@ -23,6 +23,7 @@
#define UV_WIN_WINAPI_H_

#include <windows.h>
#include <winioctl.h> /* DEVICE_TYPE */


/*
Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Expand Up @@ -203,6 +203,7 @@ TEST_DECLARE (threadpool_cancel_getaddrinfo)
TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (thread_local_storage)
TEST_DECLARE (thread_mutex)
TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_create)
Expand Down Expand Up @@ -496,6 +497,7 @@ TASK_LIST_START
TEST_ENTRY (threadpool_cancel_work)
TEST_ENTRY (threadpool_cancel_fs)
TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (thread_local_storage)
TEST_ENTRY (thread_mutex)
TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_create)
Expand Down
26 changes: 26 additions & 0 deletions test/test-thread.c
Expand Up @@ -55,6 +55,7 @@ static void fs_do(struct fs_req* req);
static void fs_cb(uv_fs_t* handle);

static volatile int thread_called;
static uv_key_t tls_key;


static void getaddrinfo_do(struct getaddrinfo_req* req) {
Expand Down Expand Up @@ -181,3 +182,28 @@ TEST_IMPL(threadpool_multiple_event_loops) {

return 0;
}


static void tls_thread(void* arg) {
ASSERT(NULL == uv_key_get(&tls_key));
uv_key_set(&tls_key, arg);
ASSERT(arg == uv_key_get(&tls_key));
uv_key_set(&tls_key, NULL);
ASSERT(NULL == uv_key_get(&tls_key));
}


TEST_IMPL(thread_local_storage) {
char name[] = "main";
uv_thread_t threads[2];
ASSERT(0 == uv_key_create(&tls_key));
ASSERT(NULL == uv_key_get(&tls_key));
uv_key_set(&tls_key, name);
ASSERT(name == uv_key_get(&tls_key));
ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0));
ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1));
ASSERT(0 == uv_thread_join(threads + 0));
ASSERT(0 == uv_thread_join(threads + 1));
uv_key_delete(&tls_key);
return 0;
}