Refactored the Event object. Becasue the Event is used in filesystem/FileCache.cpp...
authorJim Carroll <thecarrolls@jiminger.com>
Sat, 18 Jun 2011 17:21:41 +0000 (13:21 -0400)
committerJim Carroll <thecarrolls@jiminger.com>
Thu, 23 Jun 2011 14:15:26 +0000 (10:15 -0400)
xbmc/filesystem/FileCache.cpp
xbmc/threads/Event.cpp
xbmc/threads/Event.h
xbmc/threads/Interruptible.cpp [new file with mode: 0644]
xbmc/threads/Interruptible.h [new file with mode: 0644]
xbmc/threads/Makefile
xbmc/threads/Thread.cpp
xbmc/threads/Thread.h
xbmc/threads/ThreadLocal.cpp [new file with mode: 0644]
xbmc/threads/ThreadLocal.h [new file with mode: 0644]

index 8c47a7b..0047f0c 100644 (file)
@@ -78,7 +78,7 @@ private:
 };
 
 
-CFileCache::CFileCache()
+CFileCache::CFileCache() : m_seekEvent(false,true)
 {
    m_bDeleteCache = true;
    m_nSeekResult = 0;
@@ -243,11 +243,8 @@ void CFileCache::Process()
       CLog::Log(LOGINFO, "CFileCache::Process - Hit eof.");
       m_pCache->EndOfInput();
 
-      // since there is no more to read - wait either for seek or close
-      // WaitForSingleObject is CThread::WaitForSingleObject that will also listen to the
-      // end thread event.
-      int nRet = CThread::WaitForSingleObject(m_seekEvent.GetHandle(), INFINITE);
-      if (nRet == WAIT_OBJECT_0)
+      // The thread event will now also cause the wait of an event to return a false.
+      if (m_seekEvent.Wait())
       {
         m_pCache->ClearEndOfInput();
         m_seekEvent.Set(); // hack so that later we realize seek is needed
index 5cc23c5..6b9b3ec 100644 (file)
 */
 
 #include "Event.h"
-#include "utils/log.h"
+#include "utils/TimeUtils.h"
+#include "PlatformDefs.h"
 
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-CEvent::CEvent(bool manual)
-{
-  if(manual)
-    m_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-  else
-    m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+void CEvent::Interrupt() 
+{ 
+  CSingleLock lock(mutex);
+  interrupted = true;
+  condVar.notifyAll(); 
 }
 
-CEvent::CEvent(const CEvent& src)
+bool CEvent::Wait()
 {
-  if(DuplicateHandle( GetCurrentProcess()
-                    , src.m_hEvent
-                    , GetCurrentProcess()
-                    , &m_hEvent
-                    , 0
-                    , TRUE
-                    , DUPLICATE_SAME_ACCESS ))
-  {
-    CLog::Log(LOGERROR, "CEvent - failed to duplicate handle");
-    m_hEvent = INVALID_HANDLE_VALUE;
-  }
-}
+  CSingleLock lock(mutex);
+  interrupted = false;
+  Guard g(interruptible ? this : NULL);
 
-CEvent::~CEvent()
-{
-  CloseHandle(m_hEvent);
-}
+  while (!setState && !interrupted)
+    condVar.wait(mutex);
 
-CEvent& CEvent::operator=(const CEvent& src)
-{
-  CloseHandle(m_hEvent);
-
-  if(DuplicateHandle( GetCurrentProcess()
-                    , src.m_hEvent
-                    , GetCurrentProcess()
-                    , &m_hEvent
-                    , 0
-                    , TRUE
-                    , DUPLICATE_SAME_ACCESS ))
-  {
-    CLog::Log(LOGERROR, "CEvent - failed to duplicate handle");
-    m_hEvent = INVALID_HANDLE_VALUE;
-  }
-  return *this;
-}
+  bool ret = setState;
+  if (!manualReset)
+    setState = false;
 
-
-void CEvent::Wait()
-{
-  if (m_hEvent)
-  {
-    WaitForSingleObject(m_hEvent, INFINITE);
-  }
+  return ret;
 }
 
-void CEvent::Set()
+bool CEvent::WaitMSec(unsigned int milliSeconds)
 {
-  if (m_hEvent) SetEvent(m_hEvent);
-}
+  CSingleLock lock(mutex);
+  interrupted = false;
+  Guard g(interruptible ? this : NULL);
 
-void CEvent::Reset()
-{
+  unsigned int startTime = CTimeUtils::GetTimeMS();
+  unsigned int remainingTime = milliSeconds;
+  while(!setState && !interrupted)
+  {
+    XbmcThreads::ConditionVariable::TimedWaitResponse resp = condVar.wait(mutex,remainingTime);
 
-  if (m_hEvent) ResetEvent(m_hEvent);
-}
+    if (setState)
+      return true;
 
-HANDLE CEvent::GetHandle()
-{
-  return m_hEvent;
-}
+    if (resp == XbmcThreads::ConditionVariable::TIMEDOUT)
+      return false;
 
-bool CEvent::WaitMSec(unsigned int milliSeconds)
-{
+    unsigned int elapsedTimeMillis = CTimeUtils::GetTimeMS() - startTime;
+    if (elapsedTimeMillis > milliSeconds)
+      return false;
 
-  if (m_hEvent)
-  {
-    DWORD dwResult = WaitForSingleObject(m_hEvent, milliSeconds);
-    if (dwResult == WAIT_OBJECT_0) return true;
+    remainingTime = milliSeconds - elapsedTimeMillis;
   }
-  return false;
+
+  bool ret = setState;
+  if (!manualReset)
+    setState = false;
+
+  return ret;
 }
 
index 622a3d7..310a734 100644 (file)
@@ -1,57 +1,76 @@
-// Event.h: interface for the CEvent class.
-//
-//////////////////////////////////////////////////////////////////////
-
-#if !defined(AFX_EVENT_H__724ADE14_0F5C_4836_B995_08FFAA97D6B9__INCLUDED_)
-#define AFX_EVENT_H__724ADE14_0F5C_4836_B995_08FFAA97D6B9__INCLUDED_
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
 
-#if _MSC_VER > 1000
 #pragma once
-#endif // _MSC_VER > 1000
 
+#include "threads/Condition.h"
+#include "threads/Interruptible.h"
 
-/*
-* XBMC Media Center
-* Copyright (c) 2002 Frodo
-* Portions Copyright (c) by the authors of ffmpeg and xvid
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#if defined(_WIN32)
-#include <windows.h>
-#else
-#include "PlatformInclude.h"
-#endif
-
-class CEvent
+/**
+ * This is an Event class built from a ConditionVariable. The Event adds the state
+ * that the condition is gating as well as the mutex/lock.
+ *
+ * This Event can be 'interruptible' (even though there is only a single place
+ * in the code that uses this behavior).
+ *
+ * This class manages 'spurious returns' from the condition variable.
+ */
+class CEvent : public XbmcThreads::IInterruptible
 {
+  bool manualReset;
+  bool setState;
+  bool interrupted;
+  bool interruptible;
+  XbmcThreads::ConditionVariable condVar;
+  CCriticalSection mutex;
+
+  // block the ability to copy
+  inline CEvent& operator=(const CEvent& src) { return *this; }
+  inline CEvent(const CEvent& other) {}
 public:
+
+  inline CEvent(bool manual = false, bool interruptible_ = false) : 
+    manualReset(manual), setState(false), interrupted(false), interruptible(interruptible_) {}
+  inline void Reset() { CSingleLock lock(mutex); setState = false; }
+  inline void Set() { CSingleLock lock(mutex); setState = true; condVar.notifyAll(); }
+
+  virtual void Interrupt();
+  inline bool wasInterrupted() { CSingleLock lock(mutex); return interrupted; }
+
+  /**
+   * This will wait up to 'milliSeconds' milliseconds for the Event
+   *  to be triggered. The method will return 'true' if the Event
+   *  was triggered. If it was either interrupted, or it timed out
+   *  it will return false. To determine if it was interrupted you can
+   *  use 'wasInterrupted()' call prior to any further call to a 
+   *  Wait* method.
+   */
   bool WaitMSec(unsigned int milliSeconds);
-  HANDLE GetHandle();
-  void Reset();
-  void Set();
-  void Wait();
-  CEvent(bool manual = false);
-  CEvent(const CEvent& event);
-  CEvent& operator=(const CEvent& src);
-
-  virtual ~CEvent();
-
-protected:
-  HANDLE m_hEvent;
+
+  /**
+   * This will wait for the Event to be triggered. The method will return 
+   * 'true' if the Event was triggered. If it was either interrupted
+   * it will return false. To determine if it was interrupted you can
+   * use 'wasInterrupted()' call prior to any further call to a Wait* method.
+   */
+  bool Wait();
 };
 
-#endif // !defined(AFX_EVENT_H__724ADE14_0F5C_4836_B995_08FFAA97D6B9__INCLUDED_)
diff --git a/xbmc/threads/Interruptible.cpp b/xbmc/threads/Interruptible.cpp
new file mode 100644 (file)
index 0000000..f0a9f88
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+
+#include <vector>
+
+#include "threads/Interruptible.h"
+#include "threads/ThreadLocal.h"
+#include "threads/SingleLock.h"
+
+namespace XbmcThreads
+{
+  static CCriticalSection staticMutexForLockingTheListOfIInterruptiblesForCallingInterrupt;
+  static ThreadLocal<std::vector<IInterruptible*> > threadSpecificInterruptibles;
+  static std::vector<IInterruptible*> allInterruptibles;
+
+  static void callInterrupt(std::vector<IInterruptible*> * interruptibles)
+  {
+    if (interruptibles != NULL)
+    {
+      // copy the list in case the Interrupt call modifies it.
+      std::vector<IInterruptible*> list(interruptibles->size());
+      std::vector<IInterruptible*>::iterator iter;
+
+      {
+        CSingleLock lock(staticMutexForLockingTheListOfIInterruptiblesForCallingInterrupt);
+        for (iter=interruptibles->begin(); iter != interruptibles->end(); iter++)
+          list.push_back(*(iter));
+      }
+
+      for (iter=list.begin(); iter != list.end(); iter++)
+        (*iter)->Interrupt();
+    }
+  }
+
+  void IInterruptible::InterruptAll()
+  {
+    callInterrupt(&allInterruptibles);
+  }
+
+  void IInterruptible::InterruptThreadSpecific()
+  {
+    callInterrupt(threadSpecificInterruptibles.get());
+  }
+
+  void IInterruptible::enteringWaitState()
+  {
+    std::vector<IInterruptible*> * cur = threadSpecificInterruptibles.get();
+    if (cur == NULL)
+    {
+      cur = new std::vector<IInterruptible*>();
+      threadSpecificInterruptibles.set(cur);
+    }
+    cur->push_back(this);
+
+    CSingleLock lock(staticMutexForLockingTheListOfIInterruptiblesForCallingInterrupt);
+    allInterruptibles.push_back(this);
+  }
+
+  void static removeIt(std::vector<IInterruptible*> * list, IInterruptible* val)
+  {
+    std::vector<IInterruptible*>::iterator iter;
+    for (iter = list->begin(); iter != list->end(); iter++)
+    {
+      if ((*iter) == val)
+      {
+        list->erase(iter);
+        break;
+      }
+    }
+  }
+
+  void IInterruptible::leavingWaitState()
+  {
+    std::vector<IInterruptible*> * cur = threadSpecificInterruptibles.get();
+    if (cur != NULL)
+      removeIt(cur,this);
+    CSingleLock lock(staticMutexForLockingTheListOfIInterruptiblesForCallingInterrupt);
+    removeIt(&allInterruptibles,this);
+  }
+
+}
diff --git a/xbmc/threads/Interruptible.h b/xbmc/threads/Interruptible.h
new file mode 100644 (file)
index 0000000..fb1036a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#pragma once
+
+namespace XbmcThreads
+{
+  /**
+   * This interface is meant to be implemented by operations that
+   *  block and can be interrupted.
+   *
+   * The implementer of an IInterruptible must not only handle the Interrupt
+   *  callback but also register and unregister the Interruptable before entering
+   *  and after leaving a wait state. The Guard class is a helper for the 
+   *  implementers to do this. As an example:
+   *
+   *  class MyInterruptible : public IInterruptible
+   *  {
+   *  public:
+   *     virtual void Interrupt();
+   *
+   *     void blockingMethodCall() { XbmcThreads::IInterruptible::Guard g(*this); ... do blocking; }
+   *  };
+   *
+   * See CEvent as an example
+   */
+  class IInterruptible
+  {
+  public:
+    virtual void Interrupt() = 0;
+
+    /**
+     * Calling InterruptAll will invoke interrup on all IInterruptibles
+     *  currently in a wait state
+     */
+    static void InterruptAll();
+
+    /**
+     * Calling InterruptThreadSpecific will invoke interrup on all IInterruptibles
+     *  currently in a wait state in this thread only.
+     */
+    static void InterruptThreadSpecific();
+
+  protected:
+
+    void enteringWaitState();
+    void leavingWaitState();
+
+    class Guard
+    {
+      IInterruptible* interruptible;
+    public:
+      inline Guard(IInterruptible* pinterruptible) : interruptible(pinterruptible) { if (pinterruptible) pinterruptible->enteringWaitState(); }
+      inline ~Guard() { if (interruptible) interruptible->leavingWaitState(); }
+    };
+  };
+}
+
index 370bf71..ef8354a 100644 (file)
@@ -1,9 +1,11 @@
 SRCS=Atomics.cpp \
      Condition.cpp \
      Event.cpp \
+     Interruptible.cpp \
      LockFree.cpp \
      Semaphore.cpp \
      Thread.cpp \
+     ThreadLocal.cpp \
 
 LIB=threads.a
 
index c51b19e..e9ce717 100644 (file)
@@ -40,29 +40,16 @@ using namespace __cxxabiv1;
 
 #include "utils/log.h"
 #include "utils/TimeUtils.h"
+#include "threads/ThreadLocal.h"
+#include "threads/Interruptible.h"
 
-#if defined(__APPLE__) || defined(__FreeBSD__)
-//
-// Use pthread's built-in support for TLS, it's more portable.
-//
-static pthread_once_t keyOnce = PTHREAD_ONCE_INIT;
-static pthread_key_t  tlsLocalThread = 0;
-
-//
-// Called once and only once.
-//
-static void MakeTlsKeys()
-{
-  pthread_key_create(&tlsLocalThread, NULL);
-}
-
-#endif
+static XbmcThreads::ThreadLocal<CThread> currentThread;
 
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-CThread::CThread(const char* ThreadName)
+CThread::CThread(const char* ThreadName) : m_StopEvent(true)
 {
 #if defined(__APPLE__) || defined(__FreeBSD__)
   // Initialize thread local storage and local thread pointer.
@@ -77,7 +64,6 @@ CThread::CThread(const char* ThreadName)
   m_iLastTime = 0;
   m_iLastUsage = 0;
   m_fLastUsage = 0.0f;
-  m_StopEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
 
   m_pRunnable=NULL;
 
@@ -85,7 +71,7 @@ CThread::CThread(const char* ThreadName)
     m_ThreadName = ThreadName;
 }
 
-CThread::CThread(IRunnable* pRunnable, const char* ThreadName)
+CThread::CThread(IRunnable* pRunnable, const char* ThreadName) : m_StopEvent(true)
 {
 #if defined(__APPLE__) || defined(__FreeBSD__)
   // Initialize thread local storage and local thread pointer.
@@ -100,7 +86,6 @@ CThread::CThread(IRunnable* pRunnable, const char* ThreadName)
   m_iLastTime = 0;
   m_iLastUsage = 0;
   m_fLastUsage = 0.0f;
-  m_StopEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
 
   m_pRunnable=pRunnable;
 
@@ -116,35 +101,28 @@ CThread::~CThread()
   }
   m_ThreadHandle = NULL;
 
-  if (m_StopEvent)
-    CloseHandle(m_StopEvent);
 }
 
-#ifdef _LINUX
-#if defined(__APPLE__) || defined(__FreeBSD__)
-// Use pthread-based TLS.
-#define LOCAL_THREAD ((CThread* )pthread_getspecific(tlsLocalThread))
-#else
-// Use compiler-based TLS.
-__thread CThread* pLocalThread = NULL;
-#define LOCAL_THREAD pLocalThread
-#endif
+#ifndef _WIN32
 void CThread::term_handler (int signum)
 {
   CLog::Log(LOGERROR,"thread 0x%lx (%lu) got signal %d. calling OnException and terminating thread abnormally.", (long unsigned int)pthread_self(), (long unsigned int)pthread_self(), signum);
-  if (LOCAL_THREAD)
+
+  CThread* curThread = currentThread.get();
+  if (curThread)
   {
-    LOCAL_THREAD->m_bStop = TRUE;
-    if (LOCAL_THREAD->m_StopEvent)
-      SetEvent(LOCAL_THREAD->m_StopEvent);
+    curThread->m_bStop = TRUE;
+    curThread->m_StopEvent.Set();
+    XbmcThreads::IInterruptible::InterruptThreadSpecific();
 
-    LOCAL_THREAD->OnException();
-    if( LOCAL_THREAD->IsAutoDelete() )
-      delete LOCAL_THREAD;
+    curThread->OnException();
+    if( curThread->IsAutoDelete() )
+      delete curThread;
   }
 
   pthread_exit(NULL);
 }
+
 int CThread::staticThread(void* data)
 #else
 DWORD WINAPI CThread::staticThread(LPVOID* data)
@@ -161,13 +139,11 @@ DWORD WINAPI CThread::staticThread(LPVOID* data)
 
   CLog::Log(LOGDEBUG,"Thread %s start, auto delete: %d", pThread->m_ThreadName.c_str(), pThread->IsAutoDelete());
 
+  currentThread.set(pThread);
 #ifndef _LINUX
   /* install win32 exception translator */
   win32_exception::install_handler();
 #else
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
-  pLocalThread = pThread;
-#endif
   struct sigaction action;
   action.sa_handler = term_handler;
   sigemptyset (&action.sa_mask);
@@ -177,11 +153,6 @@ DWORD WINAPI CThread::staticThread(LPVOID* data)
 #endif
 
 
-#if defined(__APPLE__) || defined(__FreeBSD__)
-  // Set the TLS.
-  pthread_setspecific(tlsLocalThread, (void*)pThread);
-#endif
-
   try
   {
     pThread->OnStartup();
@@ -278,7 +249,7 @@ void CThread::Create(bool bAutoDelete, unsigned stacksize)
   m_fLastUsage = 0.0f;
   m_bAutoDelete = bAutoDelete;
   m_bStop = false;
-  ::ResetEvent(m_StopEvent);
+  m_StopEvent.Reset();
 
   m_ThreadHandle = (HANDLE)_beginthreadex(NULL, stacksize, (PBEGINTHREADEX_THREADFUNC)staticThread, (void*)this, 0, &m_ThreadId);
 
@@ -297,7 +268,8 @@ bool CThread::IsAutoDelete() const
 void CThread::StopThread(bool bWait /*= true*/)
 {
   m_bStop = true;
-  SetEvent(m_StopEvent);
+  m_StopEvent.Set();
+  XbmcThreads::IInterruptible::InterruptThreadSpecific();
   if (m_ThreadHandle && bWait)
   {
     WaitForThreadExit(INFINITE);
@@ -565,36 +537,12 @@ bool CThread::IsCurrentThread(const ThreadIdentifier tid)
 #endif
 }
 
-
-DWORD CThread::WaitForSingleObject(HANDLE hHandle, unsigned int milliseconds)
-{
-  if(milliseconds > 10 && IsCurrentThread())
-  {
-    HANDLE handles[2] = {hHandle, m_StopEvent};
-    DWORD result = ::WaitForMultipleObjects(2, handles, false, milliseconds);
-
-    if(result == WAIT_TIMEOUT || result == WAIT_OBJECT_0)
-      return result;
-
-    if( milliseconds == INFINITE )
-      return WAIT_ABANDONED;
-    else
-      return WAIT_TIMEOUT;
-  }
-  else
-    return ::WaitForSingleObject(hHandle, milliseconds);
-}
-
-DWORD CThread::WaitForMultipleObjects(DWORD nCount, HANDLE *lpHandles, BOOL bWaitAll, unsigned int milliseconds)
-{
-  // for now not implemented
-  return ::WaitForMultipleObjects(nCount, lpHandles, bWaitAll, milliseconds);
-}
-
 void CThread::Sleep(unsigned int milliseconds)
 {
   if(milliseconds > 10 && IsCurrentThread())
-    ::WaitForSingleObject(m_StopEvent, milliseconds);
+    m_StopEvent.WaitMSec(milliseconds);
   else
     ::Sleep(milliseconds);
 }
+
+
index 803b92a..f33d253 100644 (file)
@@ -59,8 +59,6 @@ public:
   virtual ~CThread();
   void Create(bool bAutoDelete = false, unsigned stacksize = 0);
   bool WaitForThreadExit(unsigned int milliseconds);
-  DWORD WaitForSingleObject(HANDLE hHandle, unsigned int milliseconds);
-  DWORD WaitForMultipleObjects(DWORD nCount, HANDLE *lpHandles, BOOL bWaitAll, unsigned int milliseconds);
   void Sleep(unsigned int milliseconds);
   bool SetPriority(const int iPriority);
   void SetPrioritySched_RR(void);
@@ -84,10 +82,6 @@ protected:
   virtual void OnException(){} // signal termination handler
   virtual void Process();
 
-#ifdef _LINUX
-  static void term_handler (int signum);
-#endif
-
   volatile bool m_bStop;
   HANDLE m_ThreadHandle;
 
@@ -97,7 +91,7 @@ private:
 private:
   ThreadIdentifier ThreadId() const;
   bool m_bAutoDelete;
-  HANDLE m_StopEvent;
+  CEvent m_StopEvent;
   unsigned m_ThreadId; // This value is unreliable on platforms using pthreads
                        // Use m_ThreadHandle->m_hThread instead
   IRunnable* m_pRunnable;
@@ -108,12 +102,17 @@ private:
 
   CStdString m_ThreadName;
 
-private:
+#ifdef _LINUX
+  static void term_handler (int signum);
+#endif
+
 #ifndef _WIN32
   static int staticThread(void* data);
 #else
   static DWORD WINAPI staticThread(LPVOID* data);
 #endif
+
+private:
 };
 
 #endif // !defined(AFX_THREAD_H__ACFB7357_B961_4AC1_9FB2_779526219817__INCLUDED_)
diff --git a/xbmc/threads/ThreadLocal.cpp b/xbmc/threads/ThreadLocal.cpp
new file mode 100644 (file)
index 0000000..c28ba05
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+* Copyright (C) 2005-2011 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#include "threads/ThreadLocal.h"
+
+namespace XbmcThreads
+{
+  void ThreadLocalNoCleanup(void*) {}
+}
diff --git a/xbmc/threads/ThreadLocal.h b/xbmc/threads/ThreadLocal.h
new file mode 100644 (file)
index 0000000..a0e9129
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+* Copyright (C) 2005-2011 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#pragma once
+
+#include <boost/thread/tss.hpp>
+
+namespace XbmcThreads
+{
+  extern void ThreadLocalNoCleanup(void*);
+
+  /**
+   * A thin wrapper around boost::thread_specific_ptr
+   */
+  template <typename T> class ThreadLocal
+  {
+    boost::thread_specific_ptr<T> value;
+
+    typedef void (*cleanupFunction)(T*);
+  public:
+    inline ThreadLocal() : value((cleanupFunction)ThreadLocalNoCleanup) {}
+    inline T* replace(T* val) { void* ret = value.get(); value.reset(val); return (T*)ret; }
+    inline void set(T* val) { value.reset(val); }
+    inline T* get() { return value.get(); }
+  };
+}
+