blob: f9d6a2e15a6e371830b9bee1d0bf629e7a14a52d [file] [log] [blame]
// Copyright 2013 Google Inc. All Rights Reserved.
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "../../bionic/pthread_internal.h"
pthread_internal_t *__get_thread(void);
#define MAX_THREAD_ID ((1 << 15) - 1)
// 0 until the second thread other than the main thread is created.
// 2 <= g_next_tid < 32768 after the second thread is created.
// Note that bionic's mutex depends on 15 bit thread ID. See
// libc/bionic/pthread.c for detail.
static pid_t g_next_tid;
// g_tid_map[tid] will be zero if and only if the tid is not allocated.
static int8_t g_tid_map[MAX_THREAD_ID + 1];
// Protects global variables above.
static pthread_mutex_t g_mu = PTHREAD_MUTEX_INITIALIZER;
pid_t gettid() {
// Defined in libc/stdlib/exit.c. Updated to 1 at the beginning of
// pthread_create in libc/bionic/pthread.c. No lock is needed when
// accessing this variable since pthread_create is always a memory
// barrier as written in the __thread_entry function.
extern int __isthreaded;
if (!__isthreaded) {
// The second thread is not created yet. The thread ID of the main
// thread is always 1 on NaCl bionic. Note that we may not be able
// to access TLS yet. We should have this test first.
return 1;
}
int tid = __get_thread()->kernel_id;
if (tid)
return tid;
static const int kStderrFd = 2;
static const char kMsg[] =
"gettid is called for uninitialized thread\n";
write(kStderrFd, kMsg, sizeof(kMsg) - 1);
abort();
}
__attribute__((visibility("hidden")))
pid_t __allocate_tid() {
pthread_mutex_lock(&g_mu);
int cnt = 0;
// The main thread always uses TID=1.
while (g_next_tid < 2 || g_tid_map[g_next_tid]) {
g_next_tid++;
if (g_next_tid > MAX_THREAD_ID)
g_next_tid = 1;
// All thread IDs are being used.
if (++cnt > MAX_THREAD_ID) {
pthread_mutex_unlock(&g_mu);
return -1;
}
}
pid_t tid = g_next_tid;
g_tid_map[tid] = 1;
pthread_mutex_unlock(&g_mu);
return tid;
}
__attribute__((visibility("hidden")))
void __deallocate_tid(pid_t tid) {
pthread_mutex_lock(&g_mu);
if (!g_tid_map[tid]) {
static const int kStderrFd = 2;
if (!tid) {
static const char kMsg[] = "__deallocate_tid is called for tid=0\n";
write(kStderrFd, kMsg, sizeof(kMsg) - 1);
} else {
static const char kMsg[] =
"__deallocate_tid is called for uninitialized thread\n";
write(kStderrFd, kMsg, sizeof(kMsg) - 1);
}
abort();
}
g_tid_map[tid] = 0;
pthread_mutex_unlock(&g_mu);
}