Home | History | Annotate | Download | only in src
      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 
     11 namespace {
     12 
     13 static pthread_key_t s_thread_key;
     14 static pthread_once_t s_once = PTHREAD_ONCE_INIT;
     15 
     16 static void ThreadDataDestroy(void* data) { free(data); }
     17 
     18 static void InitThreadKey() {
     19   pthread_key_create(&s_thread_key, ThreadDataDestroy);
     20 }
     21 
     22 }  // namespace
     23 
     24 namespace crazy {
     25 
     26 void ThreadData::Init() {
     27   dlerror_ = dlerror_buffers_[0];
     28   dlerror_[0] = '\0';
     29 }
     30 
     31 void 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 
     39 void 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 
     47 void 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 
     54 ThreadData* GetThreadDataFast() {
     55   return reinterpret_cast<ThreadData*>(pthread_getspecific(s_thread_key));
     56 }
     57 
     58 ThreadData* 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.
     70 void SetLinkerErrorString(const char* str) { GetThreadData()->SetError(str); }
     71 
     72 // Set the formatted linker error for the current thread.
     73 void 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