mfbt/ThreadLocal.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/ThreadLocal.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,152 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Cross-platform lightweight thread local data wrappers. */
    1.11 +
    1.12 +#ifndef mozilla_ThreadLocal_h
    1.13 +#define mozilla_ThreadLocal_h
    1.14 +
    1.15 +#if defined(XP_WIN)
    1.16 +// This file will get included in any file that wants to add a profiler mark.
    1.17 +// In order to not bring <windows.h> together we could include windef.h and
    1.18 +// winbase.h which are sufficient to get the prototypes for the Tls* functions.
    1.19 +// # include <windef.h>
    1.20 +// # include <winbase.h>
    1.21 +// Unfortunately, even including these headers causes us to add a bunch of ugly
    1.22 +// stuff to our namespace e.g #define CreateEvent CreateEventW
    1.23 +extern "C" {
    1.24 +__declspec(dllimport) void* __stdcall TlsGetValue(unsigned long);
    1.25 +__declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void*);
    1.26 +__declspec(dllimport) unsigned long __stdcall TlsAlloc();
    1.27 +}
    1.28 +#else
    1.29 +#  include <pthread.h>
    1.30 +#  include <signal.h>
    1.31 +#endif
    1.32 +
    1.33 +#include "mozilla/Assertions.h"
    1.34 +#include "mozilla/Attributes.h"
    1.35 +#include "mozilla/NullPtr.h"
    1.36 +
    1.37 +namespace mozilla {
    1.38 +
    1.39 +// sig_safe_t denotes an atomic type which can be read or stored in a single
    1.40 +// instruction.  This means that data of this type is safe to be manipulated
    1.41 +// from a signal handler, or other similar asynchronous execution contexts.
    1.42 +#if defined(XP_WIN)
    1.43 +typedef unsigned long sig_safe_t;
    1.44 +#else
    1.45 +typedef sig_atomic_t sig_safe_t;
    1.46 +#endif
    1.47 +
    1.48 +/*
    1.49 + * Thread Local Storage helpers.
    1.50 + *
    1.51 + * Usage:
    1.52 + *
    1.53 + * Only static-storage-duration (e.g. global variables, or static class members)
    1.54 + * objects of this class should be instantiated. This class relies on
    1.55 + * zero-initialization, which is implicit for static-storage-duration objects.
    1.56 + * It doesn't have a custom default constructor, to avoid static initializers.
    1.57 + *
    1.58 + * API usage:
    1.59 + *
    1.60 + * // Create a TLS item.
    1.61 + * //
    1.62 + * // Note that init() should be invoked exactly once, before any usage of set()
    1.63 + * // or get().
    1.64 + * mozilla::ThreadLocal<int> tlsKey;
    1.65 + * if (!tlsKey.init()) {
    1.66 + *   // deal with the error
    1.67 + * }
    1.68 + *
    1.69 + * // Set the TLS value
    1.70 + * tlsKey.set(123);
    1.71 + *
    1.72 + * // Get the TLS value
    1.73 + * int value = tlsKey.get();
    1.74 + */
    1.75 +template<typename T>
    1.76 +class ThreadLocal
    1.77 +{
    1.78 +#if defined(XP_WIN)
    1.79 +    typedef unsigned long key_t;
    1.80 +#else
    1.81 +    typedef pthread_key_t key_t;
    1.82 +#endif
    1.83 +
    1.84 +    union Helper {
    1.85 +      void* ptr;
    1.86 +      T value;
    1.87 +    };
    1.88 +
    1.89 +  public:
    1.90 +    MOZ_WARN_UNUSED_RESULT inline bool init();
    1.91 +
    1.92 +    inline T get() const;
    1.93 +
    1.94 +    inline void set(const T value);
    1.95 +
    1.96 +    bool initialized() const {
    1.97 +      return inited;
    1.98 +    }
    1.99 +
   1.100 +  private:
   1.101 +    key_t key;
   1.102 +    bool inited;
   1.103 +};
   1.104 +
   1.105 +template<typename T>
   1.106 +inline bool
   1.107 +ThreadLocal<T>::init()
   1.108 +{
   1.109 +  static_assert(sizeof(T) <= sizeof(void*),
   1.110 +                "mozilla::ThreadLocal can't be used for types larger than "
   1.111 +                "a pointer");
   1.112 +  MOZ_ASSERT(!initialized());
   1.113 +#ifdef XP_WIN
   1.114 +  key = TlsAlloc();
   1.115 +  inited = key != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES
   1.116 +#else
   1.117 +  inited = !pthread_key_create(&key, nullptr);
   1.118 +#endif
   1.119 +  return inited;
   1.120 +}
   1.121 +
   1.122 +template<typename T>
   1.123 +inline T
   1.124 +ThreadLocal<T>::get() const
   1.125 +{
   1.126 +  MOZ_ASSERT(initialized());
   1.127 +  Helper h;
   1.128 +#ifdef XP_WIN
   1.129 +  h.ptr = TlsGetValue(key);
   1.130 +#else
   1.131 +  h.ptr = pthread_getspecific(key);
   1.132 +#endif
   1.133 +  return h.value;
   1.134 +}
   1.135 +
   1.136 +template<typename T>
   1.137 +inline void
   1.138 +ThreadLocal<T>::set(const T value)
   1.139 +{
   1.140 +  MOZ_ASSERT(initialized());
   1.141 +  Helper h;
   1.142 +  h.value = value;
   1.143 +  bool succeeded;
   1.144 +#ifdef XP_WIN
   1.145 +  succeeded = TlsSetValue(key, h.ptr);
   1.146 +#else
   1.147 +  succeeded = !pthread_setspecific(key, h.ptr);
   1.148 +#endif
   1.149 +  if (!succeeded)
   1.150 +    MOZ_CRASH();
   1.151 +}
   1.152 +
   1.153 +} // namespace mozilla
   1.154 +
   1.155 +#endif /* mozilla_ThreadLocal_h */

mercurial