core+main: switch to std::thread and thread_local

Change-Id: I892eb7d87639c2b0d24a8ed457b9d32635269216
diff --git a/core/global-io.cpp b/core/global-io.cpp
index f03d13c..e906999 100644
--- a/core/global-io.cpp
+++ b/core/global-io.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,35 +24,35 @@
  */
 
 #include "global-io.hpp"
-#include <boost/thread/tss.hpp>
 
 namespace nfd {
 
-namespace scheduler {
-// defined in scheduler.cpp
-void
-resetGlobalScheduler();
-} // namespace scheduler
-
-static boost::thread_specific_ptr<boost::asio::io_service> g_ioService;
+static thread_local unique_ptr<boost::asio::io_service> g_ioService;
 static boost::asio::io_service* g_mainIoService = nullptr;
 static boost::asio::io_service* g_ribIoService = nullptr;
 
 boost::asio::io_service&
 getGlobalIoService()
 {
-  if (g_ioService.get() == nullptr) {
-    g_ioService.reset(new boost::asio::io_service());
+  if (g_ioService == nullptr) {
+    g_ioService = make_unique<boost::asio::io_service>();
   }
   return *g_ioService;
 }
 
+#ifdef WITH_TESTS
+namespace scheduler {
+void
+resetGlobalScheduler(); // defined in scheduler.cpp
+} // namespace scheduler
+
 void
 resetGlobalIoService()
 {
   scheduler::resetGlobalScheduler();
   g_ioService.reset();
 }
+#endif
 
 void
 setMainIoService(boost::asio::io_service* mainIo)
diff --git a/core/scheduler.cpp b/core/scheduler.cpp
index 094c188..68f7c75 100644
--- a/core/scheduler.cpp
+++ b/core/scheduler.cpp
@@ -26,20 +26,17 @@
 #include "scheduler.hpp"
 #include "global-io.hpp"
 
-#include <boost/thread/tss.hpp>
-
 namespace nfd {
 namespace scheduler {
 
-static boost::thread_specific_ptr<Scheduler> g_scheduler;
+static thread_local unique_ptr<Scheduler> g_scheduler;
 
 Scheduler&
 getGlobalScheduler()
 {
-  if (g_scheduler.get() == nullptr) {
-    g_scheduler.reset(new Scheduler(getGlobalIoService()));
+  if (g_scheduler == nullptr) {
+    g_scheduler = make_unique<Scheduler>(getGlobalIoService());
   }
-
   return *g_scheduler;
 }
 
@@ -49,11 +46,13 @@
   return getGlobalScheduler().scheduleEvent(after, event);
 }
 
+#ifdef WITH_TESTS
 void
 resetGlobalScheduler()
 {
   g_scheduler.reset();
 }
+#endif
 
 } // namespace scheduler
 } // namespace nfd
diff --git a/daemon/main.cpp b/daemon/main.cpp
index f237a09..37f34b5 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -39,14 +39,12 @@
 #include <boost/program_options/options_description.hpp>
 #include <boost/program_options/parsers.hpp>
 #include <boost/program_options/variables_map.hpp>
-// boost::thread is used instead of std::thread to guarantee proper cleanup of thread local storage,
-// see https://www.boost.org/doc/libs/1_58_0/doc/html/thread/thread_local_storage.html
-#include <boost/thread.hpp>
 #include <boost/version.hpp>
 
 #include <atomic>
 #include <condition_variable>
 #include <iostream>
+#include <thread>
 
 #include <ndn-cxx/util/logging.hpp>
 #include <ndn-cxx/version.hpp>
@@ -118,33 +116,32 @@
     std::mutex m;
     std::condition_variable cv;
 
-    std::string configFile = this->m_configFile; // c++11 lambda cannot capture member variables
-    boost::thread ribThread([configFile, &retval, &ribIo, mainIo, &cv, &m] {
-        {
-          std::lock_guard<std::mutex> lock(m);
-          ribIo = &getGlobalIoService();
-          BOOST_ASSERT(ribIo != mainIo);
-          setRibIoService(ribIo);
-        }
-        cv.notify_all(); // notify that ribIo has been assigned
+    std::thread ribThread([configFile = m_configFile, &retval, &ribIo, mainIo, &cv, &m] {
+      {
+        std::lock_guard<std::mutex> lock(m);
+        ribIo = &getGlobalIoService();
+        BOOST_ASSERT(ribIo != mainIo);
+        setRibIoService(ribIo);
+      }
+      cv.notify_all(); // notify that ribIo has been assigned
 
-        try {
-          ndn::KeyChain ribKeyChain;
-          // must be created inside a separate thread
-          rib::Service ribService(configFile, ribKeyChain);
-          getGlobalIoService().run(); // ribIo is not thread-safe to use here
-        }
-        catch (const std::exception& e) {
-          NFD_LOG_FATAL(boost::diagnostic_information(e));
-          retval = 1;
-          mainIo->stop();
-        }
+      try {
+        ndn::KeyChain ribKeyChain;
+        // must be created inside a separate thread
+        rib::Service ribService(configFile, ribKeyChain);
+        getGlobalIoService().run(); // ribIo is not thread-safe to use here
+      }
+      catch (const std::exception& e) {
+        NFD_LOG_FATAL(boost::diagnostic_information(e));
+        retval = 1;
+        mainIo->stop();
+      }
 
-        {
-          std::lock_guard<std::mutex> lock(m);
-          ribIo = nullptr;
-        }
-      });
+      {
+        std::lock_guard<std::mutex> lock(m);
+        ribIo = nullptr;
+      }
+    });
 
     {
       // Wait to guarantee that ribIo is properly initialized, so it can be used to terminate
diff --git a/tests/core/global-io.t.cpp b/tests/core/global-io.t.cpp
index 5aa3bc6..02f5c4c 100644
--- a/tests/core/global-io.t.cpp
+++ b/tests/core/global-io.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -29,7 +29,7 @@
 #include "tests/rib-io-fixture.hpp"
 #include "tests/test-common.hpp"
 
-#include <boost/thread.hpp>
+#include <thread>
 
 namespace nfd {
 namespace tests {
@@ -40,9 +40,9 @@
 {
   boost::asio::io_service* s1 = &getGlobalIoService();
   boost::asio::io_service* s2 = nullptr;
-  boost::thread t([&s2] {
-      s2 = &getGlobalIoService();
-    });
+  std::thread t([&s2] {
+    s2 = &getGlobalIoService();
+  });
 
   t.join();
 
@@ -60,10 +60,10 @@
   BOOST_CHECK(&getGlobalIoService() == mainIo);
   BOOST_CHECK(&getMainIoService() == mainIo);
   BOOST_CHECK(&getRibIoService() == ribIo);
-  auto mainThreadId = boost::this_thread::get_id();
+  auto mainThreadId = std::this_thread::get_id();
 
   runOnRibIoService([&] {
-    BOOST_CHECK(mainThreadId != boost::this_thread::get_id());
+    BOOST_CHECK(mainThreadId != std::this_thread::get_id());
     BOOST_CHECK(&getGlobalIoService() == ribIo);
     BOOST_CHECK(&getMainIoService() == mainIo);
     BOOST_CHECK(&getRibIoService() == ribIo);
@@ -71,7 +71,7 @@
 
   runOnRibIoService([&] {
     runOnMainIoService([&] {
-      BOOST_CHECK(mainThreadId == boost::this_thread::get_id());
+      BOOST_CHECK(mainThreadId == std::this_thread::get_id());
       BOOST_CHECK(&getGlobalIoService() == mainIo);
       BOOST_CHECK(&getMainIoService() == mainIo);
       BOOST_CHECK(&getRibIoService() == ribIo);
@@ -83,7 +83,7 @@
 {
   bool hasRibRun = false;
   runOnRibIoService([&] { hasRibRun = true; });
-  boost::this_thread::sleep_for(1_s);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
   BOOST_CHECK_EQUAL(hasRibRun, false);
 
   poll();
@@ -107,7 +107,7 @@
 {
   bool hasRibRun = false;
   runOnRibIoService([&] { hasRibRun = true; });
-  boost::this_thread::sleep_for(1_s);
+  std::this_thread::sleep_for(std::chrono::seconds(1));
   BOOST_CHECK_EQUAL(hasRibRun, false);
 
   advanceClocks(1_ns, 1);
diff --git a/tests/core/scheduler.t.cpp b/tests/core/scheduler.t.cpp
index 88adb03..8e319e0 100644
--- a/tests/core/scheduler.t.cpp
+++ b/tests/core/scheduler.t.cpp
@@ -27,7 +27,7 @@
 
 #include "tests/test-common.hpp"
 
-#include <boost/thread.hpp>
+#include <thread>
 
 namespace nfd {
 namespace scheduler {
@@ -72,7 +72,7 @@
 {
   scheduler::Scheduler* s1 = &scheduler::getGlobalScheduler();
   scheduler::Scheduler* s2 = nullptr;
-  boost::thread t([&s2] { s2 = &scheduler::getGlobalScheduler(); });
+  std::thread t([&s2] { s2 = &scheduler::getGlobalScheduler(); });
   t.join();
 
   BOOST_CHECK(s1 != nullptr);
diff --git a/tests/rib-io-fixture.cpp b/tests/rib-io-fixture.cpp
index 91fc979..8702994 100644
--- a/tests/rib-io-fixture.cpp
+++ b/tests/rib-io-fixture.cpp
@@ -38,7 +38,7 @@
   g_mainIo = &getGlobalIoService();
   setMainIoService(g_mainIo);
 
-  g_ribThread = boost::thread([&] {
+  g_ribThread = std::thread([&] {
     {
       std::lock_guard<std::mutex> lock(m);
       g_ribIo = &getGlobalIoService();
diff --git a/tests/rib-io-fixture.hpp b/tests/rib-io-fixture.hpp
index fa43af5..f2bb892 100644
--- a/tests/rib-io-fixture.hpp
+++ b/tests/rib-io-fixture.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -27,9 +27,10 @@
 #define NFD_TESTS_RIB_IO_FIXTURE_HPP
 
 #include "tests/test-common.hpp"
-#include <boost/thread.hpp>
+
 #include <condition_variable>
 #include <mutex>
+#include <thread>
 
 namespace nfd {
 namespace tests {
@@ -66,7 +67,7 @@
 
   /** \brief global RIB thread
    */
-  boost::thread g_ribThread;
+  std::thread g_ribThread;
 
 private:
   bool m_shouldStopRibIo = false;
diff --git a/wscript b/wscript
index 4722ece..6b7c556 100644
--- a/wscript
+++ b/wscript
@@ -109,7 +109,7 @@
 
     conf.check_cxx(header_name='valgrind/valgrind.h', define_name='HAVE_VALGRIND', mandatory=False)
 
-    boost_libs = ['system', 'program_options', 'filesystem', 'thread']
+    boost_libs = ['system', 'program_options', 'filesystem']
     if conf.env.WITH_TESTS or conf.env.WITH_OTHER_TESTS:
         boost_libs.append('unit_test_framework')