]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - tools/src/tools/Utils/common/eCosThreadUtils.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / Utils / common / eCosThreadUtils.cpp
diff --git a/tools/src/tools/Utils/common/eCosThreadUtils.cpp b/tools/src/tools/Utils/common/eCosThreadUtils.cpp
new file mode 100644 (file)
index 0000000..0737fd4
--- /dev/null
@@ -0,0 +1,257 @@
+//####COPYRIGHTBEGIN####
+//                                                                          
+// ----------------------------------------------------------------------------
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+//
+// This program is part of the eCos host tools.
+//
+// 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., 
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+//
+// ----------------------------------------------------------------------------
+//                                                                          
+//####COPYRIGHTEND####
+#include "eCosThreadUtils.h"
+#include "eCosTrace.h"
+
+CeCosThreadUtils::THREAD_ID CeCosThreadUtils::CS::nCSOwner=(CeCosThreadUtils::THREAD_ID)-1;
+int  CeCosThreadUtils::CS::m_nCriticalSectionLock=0;
+#ifdef _WIN32
+  CRITICAL_SECTION CeCosThreadUtils::CS::cs;
+  bool CeCosThreadUtils::CS::bCSInitialized=false;
+#else // UNIX
+  // Static recursive mutex for unix critical section
+  #ifndef NO_THREADS
+    pthread_mutex_t CeCosThreadUtils::CS::cs = PTHREAD_MUTEX_INITIALIZER;
+  #endif
+#endif
+
+
+CeCosThreadUtils::THREAD_ID CeCosThreadUtils::GetThreadId()
+{
+  return 
+  #ifdef _WIN32
+    GetCurrentThreadId();
+  #else // UNIX
+    #ifdef NO_THREADS
+    42;
+    #else
+    pthread_self();
+    #endif
+  #endif
+}
+
+// Wait for the specified Boolean to turn true or the timeout to occur
+// The value of the Boolean is returned as result
+bool CeCosThreadUtils::WaitFor (bool &b, Duration dTimeout)
+{
+  Time t=Now();
+  do {
+    if(b){
+      break;
+    }
+    Sleep(250);
+  } while (Now()-t<dTimeout);
+  return b;
+}
+
+// This function spawns a thread and causes it to run asynchrously.
+// The callback may be
+//      A function, which is called when the thread completes
+//      A boolean, which is set when the thread completes
+//      Null, in which case no notification is received of thread completion
+// pParam is passed to the thread function pThreadFunc on thread initiation.
+
+bool CeCosThreadUtils::RunThread(CallbackProc *pThreadFunc, void *pParam, CallbackProc *pCompletionFunc, void *pCompletionParam, LPCTSTR pszName)
+{
+  TRACE(_T("RunThread %s\n"),pszName);
+  // Do not spawn a thread while in possession of a mutex
+  //    ENTERCRITICAL;
+  //        VTRACE(_T("csl=%d\n"),CS::m_nCriticalSectionLock);
+  //        assert(1==CS::m_nCriticalSectionLock);
+  //    LEAVECRITICAL;
+  
+  ThreadInfo *pInfo=new ThreadInfo(pThreadFunc,pParam,pCompletionFunc,pCompletionParam,pszName); // SThreadFunc will delete
+  bool rc=false;
+
+#ifdef _WIN32
+  // FIXME: CreateThread incompatible with C runtime calls?
+  DWORD dwID;
+  HANDLE hThread=CreateThread(NULL,0,SThreadFunc, pInfo, 0, &dwID);
+  if(hThread){
+    ::CloseHandle(hThread);
+    rc=true;
+  } else {
+    ERROR(_T("Failed to create thread\n"));
+  }
+#else // UNIX
+  #ifdef NO_THREADS
+  assert(false);
+  #else
+  pthread_t hThread;
+  int n=pthread_create(&hThread, NULL, SThreadFunc, pInfo);
+  TRACE(  _T("RunThread: - non-blocking call (new thread=%x)\n"),hThread);
+  if (n != 0) {
+    ERROR(_T("RunThread(): pthread_create failed - %s\n"),strerror(errno));
+  } else {
+    
+    int n = pthread_detach(hThread);
+    
+    if (0==n) {
+      rc=true;
+    } else {
+      ERROR(_T("RunThread(): pthread_detach failed - %s\n"),strerror(errno));
+      hThread=0;
+    }
+  }
+  #endif
+#endif
+  if(!rc){
+    delete pInfo;
+  }
+  return rc;
+  
+}
+
+#ifdef _WIN32
+int CALLBACK CeCosThreadUtils::FilterFunction(EXCEPTION_POINTERS *p)
+{
+  EXCEPTION_RECORD *pRec    =p->ExceptionRecord;
+  TRACE(_T("!!!Exception!!! address=%08x code=%08x\n"),pRec->ExceptionAddress,pRec->ExceptionCode);
+  /*
+  CONTEXT          *pContext=p->ContextRecord;
+  const unsigned char *ESP=(const unsigned char *)pContext->Esp;
+  for(int i=0;i<16;i++){
+  TRACE(_T("%08X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n"),ESP,
+  ESP[0],ESP[1],ESP[2],ESP[3],ESP[4],ESP[5],ESP[6],ESP[7],ESP[8],ESP[9],ESP[10],ESP[11],ESP[12],ESP[13],ESP[14],ESP[15]);
+  ESP+=16;
+  }
+  */
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+#endif
+
+CeCosThreadUtils::THREADFUNC CALLBACK CeCosThreadUtils::SThreadFunc (void *pParam)
+{
+  THREAD_ID id=GetThreadId();
+  ThreadInfo *pInfo=(ThreadInfo*)pParam;
+  TRACE(_T("Thread %x [%s] created\n"),id,(LPCTSTR)pInfo->strName);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  __try {
+    // Call what we are instructed to (e.g. LocalThreadFunc):
+    pInfo->pThreadFunc(pInfo->pThreadParam);
+  }
+    __except ( CeCosThreadUtils::FilterFunction(GetExceptionInformation() )) 
+  { 
+    TRACE(_T("Handling exception!!!...\n"));
+  }
+#else // UNIX
+  try {
+    // Call what we are instructed to (e.g. LocalThreadFunc):
+    pInfo->pThreadFunc(pInfo->pThreadParam);
+  }
+  catch (...){
+    TRACE(_T("Exception caught in SThreadFunc!!!\n"));
+  }
+#endif
+  
+  // Call the Callback:
+  if(pInfo->pCompletionFunc){
+    pInfo->pCompletionFunc (pInfo->pCompletionParam);
+  } else if (pInfo->pCompletionParam) {
+    // No function - just a flag:
+    *(bool *)pInfo->pCompletionParam=true;
+  }
+  // No more references to pInfo->pTest from now on...
+  TRACE(_T("Thread %x [%s] terminated\n"),id,(LPCTSTR)pInfo->strName);
+  delete pInfo;
+  return 0;
+}
+
+bool CeCosThreadUtils::CS::InCriticalSection()
+{
+  return GetThreadId()==nCSOwner;
+}
+
+int CeCosThreadUtils::AtomicIncrement (int &n)
+{
+  int rc;
+  ENTERCRITICAL;
+  rc=n++;
+  LEAVECRITICAL;
+  return rc;
+}
+
+int CeCosThreadUtils::AtomicDecrement (int &n)
+{
+  int rc;
+  ENTERCRITICAL;
+  rc=n--;
+  LEAVECRITICAL;
+  return rc;
+}
+
+CeCosThreadUtils::CS::CS()
+{
+  // Get mutex lock; block until available unless current
+  // thread already owns the mutex.
+  if(!InCriticalSection()){
+#ifdef _WIN32
+    if(!bCSInitialized){
+                   InitializeCriticalSection(&cs);
+        bCSInitialized=true;
+    }
+    ::EnterCriticalSection(&cs);
+#else // UNIX
+    #ifndef NO_THREADS
+      pthread_mutex_lock(&cs);
+    #endif
+#endif
+    // As we now own the CS it is safe to perform the following assignment:
+    nCSOwner=GetThreadId();
+  }
+  // As we now own the CS it is safe to perform the following increment:
+  m_nCriticalSectionLock++;
+}
+
+CeCosThreadUtils::CS::~CS()
+{
+  assert(InCriticalSection());
+  // As we own the CS we can safely manipulate variables:
+  m_nCriticalSectionLock--;
+  assert(m_nCriticalSectionLock>=0);
+  if(0==m_nCriticalSectionLock){
+    // Last lock is being released - let go of the mutex
+    nCSOwner=(THREAD_ID)-1;
+    
+    // Release mutex lock.  
+#ifdef _WIN32
+    ::LeaveCriticalSection(&cs);
+#else // UNIX
+    #ifndef NO_THREADS
+      pthread_mutex_unlock(&cs);
+    #endif
+#endif
+  }
+}
+
+void CeCosThreadUtils::Sleep(int nMsec)
+{
+#ifdef _WIN32
+  ::Sleep(nMsec);
+#else
+  sched_yield();
+  usleep((int)nMsec * 1000);
+#endif
+}