From 3f7333b9ed377f5baf3d9e798eee57ac41cba5fb Mon Sep 17 00:00:00 2001
From: David Capello <davidcapello@gmail.com>
Date: Sat, 2 Oct 2010 20:20:59 -0300
Subject: [PATCH] Fix pthread implementation of base::thread class (problems
 joining threads, initializing m_id field, etc.).

---
 src/base/thread.cpp          | 43 ++++++++++++++++++++++--------------
 src/base/thread.h            | 12 +++-------
 src/base/thread_unittest.cpp | 28 +++++++++++++++++------
 3 files changed, 51 insertions(+), 32 deletions(-)

diff --git a/src/base/thread.cpp b/src/base/thread.cpp
index be49d3e32..d015248d5 100644
--- a/src/base/thread.cpp
+++ b/src/base/thread.cpp
@@ -39,7 +39,7 @@ namespace {
 
 base::thread::thread()
   : m_native_handle(NULL)
-  , m_id()
+  , m_id(this_thread::get_id())
 {
 }
 
@@ -47,15 +47,11 @@ base::thread::~thread()
 {
   if (joinable())
     detach();
-
-#ifdef USE_PTHREADS
-  delete (pthread_t*)m_native_handle;
-#endif
 }
 
 bool base::thread::joinable() const
 {
-  return (m_id != this_thread::get_id());
+  return (m_id != 0 && m_id != this_thread::get_id());
 }
 
 void base::thread::join()
@@ -64,7 +60,7 @@ void base::thread::join()
 #ifdef WIN32
     ::WaitForSingleObject(m_native_handle, INFINITE);
 #else
-    ::pthread_join(*(pthread_t*)m_native_handle, NULL);
+    ::pthread_join(m_id.m_native_id, NULL);
 #endif
     detach();
   }
@@ -75,32 +71,47 @@ void base::thread::detach()
   if (joinable()) {
 #ifdef WIN32
     ::CloseHandle(m_native_handle);
-#else
-    ::pthread_detach(*(pthread_t*)m_native_handle);
-    delete (pthread_t*)m_native_handle;
-#endif
     m_native_handle = NULL;
+#else
+    ::pthread_detach(m_id.m_native_id);
+#endif
     m_id = id();
   }
 }
 
+base::thread::id base::thread::get_id() const
+{
+  return m_id;
+}
+
+base::thread::native_handle_type base::thread::native_handle()
+{
+#ifdef WIN32
+  return (native_handle_type)m_native_handle;
+#else
+  return (native_handle_type)m_id.m_native_id;
+#endif
+}
+
 void base::thread::launch_thread(func_wrapper* f)
 {
+  m_native_handle = NULL;
+  m_id = id();
+
 #ifdef WIN32
 
   DWORD native_id;
   m_native_handle = ::CreateThread(NULL, 0, win32_thread_proxy, (LPVOID)f,
 				   CREATE_SUSPENDED, &native_id);
-  m_id.m_native_id = native_id;
+  m_id = id((unsigned int)native_id);
+
   ResumeThread(m_native_handle);
 
 #else
 
   pthread_t thread;
-  if (::pthread_create(&thread, NULL, pthread_thread_proxy, f))
-    m_native_handle = new pthread_t(thread);
-  else
-    m_native_handle = NULL;
+  if (::pthread_create(&thread, NULL, pthread_thread_proxy, f) == 0)
+    m_id = id((unsigned int)thread);
 
 #endif
 }
diff --git a/src/base/thread.h b/src/base/thread.h
index b3a3c49cb..555b8cf25 100644
--- a/src/base/thread.h
+++ b/src/base/thread.h
@@ -28,8 +28,7 @@ namespace base {		// Based on C++0x threads lib
       bool operator> (const id& y) const { return m_native_id >  y.m_native_id; }
       bool operator>=(const id& y) const { return m_native_id >= y.m_native_id; }
 
-      // TODO should we replace this with support for iostreams?
-      //unsigned get_native_id() { return m_native_id; }
+      id& operator=(const id& y) { m_native_id = y.m_native_id; }
     };
 
     typedef void* native_handle_type;
@@ -63,13 +62,8 @@ namespace base {		// Based on C++0x threads lib
     void join();
     void detach();
 
-    id get_id() const {
-      return m_id;
-    }
-
-    native_handle_type native_handle() {
-      return m_native_handle;
-    }
+    id get_id() const;
+    native_handle_type native_handle();
 
     class details {
     public:
diff --git a/src/base/thread_unittest.cpp b/src/base/thread_unittest.cpp
index 5282d4c1c..2e23bb065 100644
--- a/src/base/thread_unittest.cpp
+++ b/src/base/thread_unittest.cpp
@@ -8,23 +8,37 @@
 
 #include "base/thread.h"
 
-#include <iostream>
-
-using std::cout;
 using namespace base;
 
-static bool flag = false;
+void nothing() { }
 
-static void func0() {
+TEST(Thread, NotJoinable)
+{
+  thread t;
+  EXPECT_FALSE(t.joinable());
+}
+
+TEST(Thread, Joinable)
+{
+  thread t(&nothing);
+  EXPECT_TRUE(t.joinable());
+  t.join();
+}
+
+//////////////////////////////////////////////////////////////////////
+
+bool flag = false;
+
+void func0() {
   flag = true;
 }
 
-static void func1(int x) {
+void func1(int x) {
   flag = true;
   EXPECT_EQ(2, x);
 }
 
-static void func2(int x, int y) {
+void func2(int x, int y) {
   flag = true;
   EXPECT_EQ(2, x);
   EXPECT_EQ(4, y);