Create the pthread.h portability header
authorChristopher Dykes <cdykes@fb.com>
Fri, 1 Apr 2016 18:16:57 +0000 (11:16 -0700)
committerFacebook Github Bot 8 <facebook-github-bot-8-bot@fb.com>
Fri, 1 Apr 2016 18:20:30 +0000 (11:20 -0700)
Summary: The primary issue is that the pthread implementation we use for Windows defines `pthread_t` as a struct (yes, it is allowed to do this), which breaks a lot of things.

Reviewed By: yfeldblum

Differential Revision: D2862671

fb-gh-sync-id: 551569b6a9e2e374cf77e186e148b6b397f8f25f
fbshipit-source-id: 551569b6a9e2e374cf77e186e148b6b397f8f25f

folly/Conv.h
folly/Makefile.am
folly/io/async/EventBase.cpp
folly/io/async/NotificationQueue.h
folly/io/async/SSLContext.cpp
folly/portability/PThread.h [new file with mode: 0755]

index eeeb3847996cb3b76e7f477f39858a30d82c9075..b730857bf68f9dcd5c04e2b2b439fa180856a2a3 100644 (file)
@@ -792,6 +792,17 @@ toAppend(const Ts&... vs) {
   ::folly::detail::toAppendStrImpl(vs...);
 }
 
+#ifdef _MSC_VER
+// Special case pid_t on MSVC, because it's a void* rather than an
+// integral type. We can't do a global special case because this is already
+// dangerous enough (as most pointers will implicitly convert to a void*)
+// just doing it for MSVC.
+template <class Tgt>
+void toAppend(const pid_t a, Tgt* res) {
+  toAppend(uint64_t(a), res);
+}
+#endif
+
 /**
  * Special version of the call that preallocates exaclty as much memory
  * as need for arguments to be stored in target. This means we are
index 44d109c33ab57196aae753b2a8acc54ab0899ca5..3ea8c30ab3291fde15c76404960987aae0ac6312 100644 (file)
@@ -275,6 +275,7 @@ nobase_follyinclude_HEADERS = \
        portability/IOVec.h \
        portability/Malloc.h \
        portability/Memory.h \
+       portability/PThread.h \
        portability/String.h \
        portability/Strings.h \
        portability/SysFile.h \
index 5dcc99673d070fa188fc39cbdfcded097083b21c..1e0c808d28eb3da084e2e4eff29ee78be372e819 100644 (file)
@@ -132,7 +132,7 @@ static std::mutex libevent_mutex_;
 EventBase::EventBase(bool enableTimeMeasurement)
   : runOnceCallbacks_(nullptr)
   , stop_(false)
-  , loopThread_(0)
+  , loopThread_()
   , queue_(nullptr)
   , fnRunner_(nullptr)
   , maxLatency_(0)
@@ -177,7 +177,7 @@ EventBase::EventBase(bool enableTimeMeasurement)
 EventBase::EventBase(event_base* evb, bool enableTimeMeasurement)
   : runOnceCallbacks_(nullptr)
   , stop_(false)
-  , loopThread_(0)
+  , loopThread_()
   , evb_(evb)
   , queue_(nullptr)
   , fnRunner_(nullptr)
@@ -426,7 +426,7 @@ bool EventBase::loopBody(int flags) {
     return false;
   }
 
-  loopThread_.store(0, std::memory_order_release);
+  loopThread_.store({}, std::memory_order_release);
 
   VLOG(5) << "EventBase(): Done with loop.";
   return true;
index 5afba0473f1efbba69bab07f4153ba3ea2cc7614..58a3a82150adfbf6c584d8a4b6fbddf25965fdce 100644 (file)
@@ -240,11 +240,11 @@ class NotificationQueue {
 #else
                              FdType fdType = FdType::PIPE)
 #endif
-    : eventfd_(-1),
-      pipeFds_{-1, -1},
-      advisoryMaxQueueSize_(maxSize),
-      pid_(getpid()),
-      queue_() {
+      : eventfd_(-1),
+        pipeFds_{-1, -1},
+        advisoryMaxQueueSize_(maxSize),
+        pid_(pid_t(getpid())),
+        queue_() {
 
     RequestContext::saveContext();
 
@@ -438,9 +438,7 @@ class NotificationQueue {
    * check ensures that we catch the problem in the misbehaving child process
    * code, and crash before signalling the parent process.
    */
-  void checkPid() const {
-    CHECK_EQ(pid_, getpid());
-  }
+  void checkPid() const { CHECK_EQ(pid_, pid_t(getpid())); }
 
  private:
   // Forbidden copy constructor and assignment operator
index ac032da294158c5125164062e034b39c03bf3c31..c4f052b8112d57f0a3a66945188d44be8940fffc 100644 (file)
@@ -696,6 +696,8 @@ static unsigned long callbackThreadID() {
   return static_cast<unsigned long>(
 #ifdef __APPLE__
     pthread_mach_thread_np(pthread_self())
+#elif _MSC_VER
+    pthread_getw32threadid_np(pthread_self())
 #else
     pthread_self()
 #endif
diff --git a/folly/portability/PThread.h b/folly/portability/PThread.h
new file mode 100755 (executable)
index 0000000..4bfecef
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#ifdef _WIN32
+// We implement a sane comparison operand for
+// pthread_t and an integer so that it may be
+// compared against 0.
+
+inline bool operator==(pthread_t ptA, unsigned int b) {
+  if (ptA.p == nullptr) {
+    return b == 0;
+  }
+  return pthread_getw32threadid_np(ptA) == b;
+}
+
+inline bool operator!=(pthread_t ptA, unsigned int b) {
+  if (ptA.p == nullptr) {
+    return b != 0;
+  }
+  return pthread_getw32threadid_np(ptA) != b;
+}
+
+inline bool operator==(pthread_t ptA, pthread_t ptB) {
+  return pthread_equal(ptA, ptB) != 0;
+}
+
+inline bool operator!=(pthread_t ptA, pthread_t ptB) {
+  return pthread_equal(ptA, ptB) == 0;
+}
+
+inline bool operator<(pthread_t ptA, pthread_t ptB) {
+  return ptA.p < ptB.p;
+}
+
+inline bool operator!(pthread_t ptA) {
+  return ptA == 0;
+}
+
+inline int pthread_attr_getstack(
+    pthread_attr_t* attr,
+    void** stackaddr,
+    size_t* stacksize) {
+  if (pthread_attr_getstackaddr(attr, stackaddr) != 0) {
+    return -1;
+  }
+  if (pthread_attr_getstacksize(attr, stacksize) != 0) {
+    return -1;
+  }
+  return 0;
+}
+
+inline int
+pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize) {
+  if (pthread_attr_setstackaddr(attr, stackaddr) != 0) {
+    return -1;
+  }
+  if (pthread_attr_setstacksize(attr, stacksize) != 0) {
+    return -1;
+  }
+  return 0;
+}
+
+inline int pthread_attr_getguardsize(pthread_attr_t* attr, size_t* guardsize) {
+  *guardsize = 0;
+  return 0;
+}
+
+#include <xstddef>
+namespace std {
+template <>
+struct hash<pthread_t> {
+  std::size_t operator()(const pthread_t& k) const {
+    return 0 ^ std::hash<decltype(k.p)>(k.p) ^ std::hash<decltype(k.x)>(k.x);
+  }
+};
+}
+#endif