1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "crazy_linker_thread.h" 6 7#include <pthread.h> 8#include <stdio.h> 9#include <stdlib.h> 10 11namespace { 12 13static pthread_key_t s_thread_key; 14static pthread_once_t s_once = PTHREAD_ONCE_INIT; 15 16static void ThreadDataDestroy(void* data) { free(data); } 17 18static void InitThreadKey() { 19 pthread_key_create(&s_thread_key, ThreadDataDestroy); 20} 21 22} // namespace 23 24namespace crazy { 25 26void ThreadData::Init() { 27 dlerror_ = dlerror_buffers_[0]; 28 dlerror_[0] = '\0'; 29} 30 31void ThreadData::SwapErrorBuffers() { 32 if (dlerror_ == dlerror_buffers_[0]) 33 dlerror_ = dlerror_buffers_[1]; 34 else 35 dlerror_ = dlerror_buffers_[0]; 36 dlerror_[0] = '\0'; 37} 38 39void ThreadData::SetErrorArgs(const char* fmt, va_list args) { 40 if (fmt == NULL) { 41 dlerror_[0] = '\0'; 42 return; 43 } 44 vsnprintf(dlerror_, kBufferSize, fmt, args); 45} 46 47void ThreadData::AppendErrorArgs(const char* fmt, va_list args) { 48 if (fmt == NULL) 49 return; 50 size_t len = strlen(dlerror_); 51 vsnprintf(dlerror_ + len, kBufferSize - len, fmt, args); 52} 53 54ThreadData* GetThreadDataFast() { 55 return reinterpret_cast<ThreadData*>(pthread_getspecific(s_thread_key)); 56} 57 58ThreadData* GetThreadData() { 59 pthread_once(&s_once, InitThreadKey); 60 ThreadData* data = GetThreadDataFast(); 61 if (!data) { 62 data = reinterpret_cast<ThreadData*>(calloc(sizeof(*data), 1)); 63 data->Init(); 64 pthread_setspecific(s_thread_key, data); 65 } 66 return data; 67} 68 69// Set the linker error string for the current thread. 70void SetLinkerErrorString(const char* str) { GetThreadData()->SetError(str); } 71 72// Set the formatted linker error for the current thread. 73void SetLinkerError(const char* fmt, ...) { 74 va_list args; 75 va_start(args, fmt); 76 GetThreadData()->SetErrorArgs(fmt, args); 77 va_end(args); 78} 79 80} // namespace crazy 81