Add portability support for PThread's TLS API
authorChristopher Dykes <cdykes@fb.com>
Sat, 15 Apr 2017 00:05:09 +0000 (17:05 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Sat, 15 Apr 2017 00:24:22 +0000 (17:24 -0700)
Summary:
This is the last piece needed to get Folly working on Windows without PThreads.
Updating Folly's test suite to support compiling without PThreads will come next.

Reviewed By: yfeldblum

Differential Revision: D4894048

fbshipit-source-id: 6076317e1364aef82a5d3cb306bea7c2226b3cdc

folly/Makefile.am
folly/portability/PThread.cpp [new file with mode: 0644]
folly/portability/PThread.h

index b2dbcfaf45f029db312b834a643bbcc1f58d49b2..4bde2ae3ee190ef3bc6e023f105bde10f13c29c2 100644 (file)
@@ -489,6 +489,7 @@ libfolly_la_SOURCES = \
        portability/Malloc.cpp \
        portability/Memory.cpp \
        portability/OpenSSL.cpp \
+       portability/PThread.cpp \
        portability/Sockets.cpp \
        portability/Stdio.cpp \
        portability/Stdlib.cpp \
diff --git a/folly/portability/PThread.cpp b/folly/portability/PThread.cpp
new file mode 100644 (file)
index 0000000..aba122a
--- /dev/null
@@ -0,0 +1,89 @@
+/*\r
+ * Copyright 2017 Facebook, Inc.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *   http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include <folly/portability/PThread.h>\r
+\r
+#if !FOLLY_HAVE_PTHREAD && _WIN32\r
+#include <unordered_map>\r
+#include <utility>\r
+\r
+namespace folly {\r
+namespace portability {\r
+namespace pthread {\r
+static thread_local struct PThreadLocalMap {\r
+  PThreadLocalMap() = default;\r
+  ~PThreadLocalMap() {\r
+    for (auto kv : keyMap) {\r
+      // Call destruction callbacks if they exist.\r
+      if (kv.second.second != nullptr) {\r
+        kv.second.second(kv.second.first);\r
+      }\r
+    }\r
+  }\r
+\r
+  int createKey(pthread_key_t* key, void (*destructor)(void*)) {\r
+    auto ret = TlsAlloc();\r
+    if (ret == TLS_OUT_OF_INDEXES) {\r
+      return -1;\r
+    }\r
+    *key = ret;\r
+    keyMap.emplace(*key, std::make_pair(nullptr, destructor));\r
+    return 0;\r
+  }\r
+\r
+  int deleteKey(pthread_key_t key) {\r
+    if (!TlsFree(key)) {\r
+      return -1;\r
+    }\r
+    keyMap.erase(key);\r
+    return 0;\r
+  }\r
+\r
+  void* getKey(pthread_key_t key) {\r
+    return TlsGetValue(key);\r
+  }\r
+\r
+  int setKey(pthread_key_t key, void* value) {\r
+    if (!TlsSetValue(key, value)) {\r
+      return -1;\r
+    }\r
+    keyMap[key].first = value;\r
+    return 0;\r
+  }\r
+\r
+  std::unordered_map<pthread_key_t, std::pair<void*, void (*)(void*)>> keyMap{};\r
+} s_tls_key_map;\r
+\r
+int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) {\r
+  return s_tls_key_map.createKey(key, destructor);\r
+}\r
+\r
+int pthread_key_delete(pthread_key_t key) {\r
+  return s_tls_key_map.deleteKey(key);\r
+}\r
+\r
+void* pthread_getspecific(pthread_key_t key) {\r
+  return s_tls_key_map.getKey(key);\r
+}\r
+\r
+int pthread_setspecific(pthread_key_t key, const void* value) {\r
+  // Yes, the PThread API really is this bad -_-...\r
+  return s_tls_key_map.setKey(key, const_cast<void*>(value));\r
+}\r
+}\r
+}\r
+}\r
+#endif\r
index 2ddf98052f67dc4abde54baf53364590f50a3331..e632458189aa30a6e6d748717abf0e26281483f9 100755 (executable)
 
 #pragma once
 
+#include <folly/portability/Config.h>
+
+#if !FOLLY_HAVE_PTHREAD
+
+#ifndef _WIN32
+#error Building Folly without pthreads is only supported on Windows.
+#endif
+
+#include <folly/portability/Windows.h>
+#include <cstdint>
+
+namespace folly {
+namespace portability {
+namespace pthread {
+using pthread_key_t = DWORD;
+
+int pthread_key_create(pthread_key_t* key, void (*destructor)(void*));
+int pthread_key_delete(pthread_key_t key);
+void* pthread_getspecific(pthread_key_t key);
+int pthread_setspecific(pthread_key_t key, const void* value);
+}
+}
+}
+
+/* using override */ using namespace folly::portability::pthread;
+
+#else
+
 #include <pthread.h>
 
 #ifdef _WIN32
@@ -95,3 +123,4 @@ struct hash<pthread_t> {
 };
 }
 #endif
+#endif