From 54a987e1f16c90a0c6164145df6ef19a3764e120 Mon Sep 17 00:00:00 2001
From: Asiri Rathnayake <asiri.rathnayake@arm.com>
Date: Thu, 9 Feb 2017 09:31:41 +0000
Subject: [PATCH] Threading support: externalize sleep_for() function.

Different platforms implement the wait/sleep functions in difrerent ways.
It makes sense to externalize this into the threading API.

Differential revision: https://reviews.llvm.org/D29630

Reviewers: EricWF, joerg
llvm-svn: 294573
---
 libcxx/include/__threading_support | 37 ++++++++++++++++++++++++++++--
 libcxx/src/thread.cpp              | 28 ++--------------------
 2 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support
index 53a956ed9809..ac0544dfb368 100644
--- a/libcxx/include/__threading_support
+++ b/libcxx/include/__threading_support
@@ -12,6 +12,8 @@
 #define _LIBCPP_THREADING_SUPPORT
 
 #include <__config>
+#include <chrono>
+#include <errno.h>
 
 #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
 #pragma GCC system_header
@@ -28,8 +30,6 @@
 #include <Windows.h>
 #include <process.h>
 #include <fibersapi.h>
-
-#include <chrono>
 #endif
 
 #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
@@ -183,6 +183,9 @@ int __libcpp_thread_detach(__libcpp_thread_t *__t);
 _LIBCPP_THREAD_ABI_VISIBILITY
 void __libcpp_thread_yield();
 
+_LIBCPP_THREAD_ABI_VISIBILITY
+void __libcpp_thread_sleep_for(const chrono::nanoseconds& ns);
+
 // Thread local storage
 _LIBCPP_THREAD_ABI_VISIBILITY
 int __libcpp_tls_create(__libcpp_tls_key* __key,
@@ -345,6 +348,28 @@ void __libcpp_thread_yield()
   sched_yield();
 }
 
+void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
+{
+   using namespace chrono;
+   seconds __s = duration_cast<seconds>(__ns);
+   timespec __ts;
+   typedef decltype(__ts.tv_sec) ts_sec;
+   _LIBCPP_CONSTEXPR ts_sec __ts_sec_max = numeric_limits<ts_sec>::max();
+
+   if (__s.count() < __ts_sec_max)
+   {
+     __ts.tv_sec = static_cast<ts_sec>(__s.count());
+     __ts.tv_nsec = static_cast<decltype(__ts.tv_nsec)>((__ns - __s).count());
+   }
+   else
+   {
+     __ts.tv_sec = __ts_sec_max;
+     __ts.tv_nsec = 999999999; // (10^9 - 1)
+   }
+
+   while (nanosleep(&__ts, &__ts) == -1 && errno == EINTR);
+}
+
 // Thread local storage
 int __libcpp_tls_create(__libcpp_tls_key *__key, void (*__at_exit)(void *))
 {
@@ -562,6 +587,14 @@ void __libcpp_thread_yield()
   SwitchToThread();
 }
 
+void __libcpp_thread_sleep_for(const chrono::nanoseconds& __ns)
+{
+  using namespace chrono;
+  // round-up to the nearest milisecond
+  milliseconds __ms = duration_cast<milliseconds>(__ns + 999999);
+  Sleep(__ms.count());
+}
+
 // Thread Local Storage
 int __libcpp_tls_create(__libcpp_tls_key* __key,
                         void(_LIBCPP_TLS_DESTRUCTOR_CC* __at_exit)(void*))
diff --git a/libcxx/src/thread.cpp b/libcxx/src/thread.cpp
index afa8e163bec9..6fa549d9b599 100644
--- a/libcxx/src/thread.cpp
+++ b/libcxx/src/thread.cpp
@@ -114,33 +114,9 @@ namespace this_thread
 void
 sleep_for(const chrono::nanoseconds& ns)
 {
-    using namespace chrono;
-    if (ns > nanoseconds::zero())
+    if (ns > chrono::nanoseconds::zero())
     {
-#if defined(_LIBCPP_WIN32API)
-        milliseconds ms = duration_cast<milliseconds>(ns);
-        if (ms.count() == 0 || ns > duration_cast<nanoseconds>(ms))
-          ++ms;
-        Sleep(ms.count());
-#else
-        seconds s = duration_cast<seconds>(ns);
-        timespec ts;
-        typedef decltype(ts.tv_sec) ts_sec;
-        _LIBCPP_CONSTEXPR ts_sec ts_sec_max = numeric_limits<ts_sec>::max();
-        if (s.count() < ts_sec_max)
-        {
-            ts.tv_sec = static_cast<ts_sec>(s.count());
-            ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count());
-        }
-        else
-        {
-            ts.tv_sec = ts_sec_max;
-            ts.tv_nsec = giga::num - 1;
-        }
-
-        while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
-            ;
-#endif
+        __libcpp_thread_sleep_for(ns);
     }
 }