]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/Utils/common/eCosThreadUtils.cpp
Initial revision
[karo-tx-redboot.git] / tools / src / tools / Utils / common / eCosThreadUtils.cpp
1 //####COPYRIGHTBEGIN####
2 //                                                                          
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it 
9 // under the terms of the GNU General Public License as published by the Free 
10 // Software Foundation; either version 2 of the License, or (at your option) 
11 // any later version.
12 // 
13 // This program is distributed in the hope that it will be useful, but WITHOUT 
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
16 // more details.
17 // 
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc., 
20 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //                                                                          
24 //####COPYRIGHTEND####
25 #include "eCosThreadUtils.h"
26 #include "eCosTrace.h"
27
28 CeCosThreadUtils::THREAD_ID CeCosThreadUtils::CS::nCSOwner=(CeCosThreadUtils::THREAD_ID)-1;
29 int  CeCosThreadUtils::CS::m_nCriticalSectionLock=0;
30 #ifdef _WIN32
31   CRITICAL_SECTION CeCosThreadUtils::CS::cs;
32   bool CeCosThreadUtils::CS::bCSInitialized=false;
33 #else // UNIX
34   // Static recursive mutex for unix critical section
35   #ifndef NO_THREADS
36     pthread_mutex_t CeCosThreadUtils::CS::cs = PTHREAD_MUTEX_INITIALIZER;
37   #endif
38 #endif
39
40
41 CeCosThreadUtils::THREAD_ID CeCosThreadUtils::GetThreadId()
42 {
43   return 
44   #ifdef _WIN32
45     GetCurrentThreadId();
46   #else // UNIX
47     #ifdef NO_THREADS
48     42;
49     #else
50     pthread_self();
51     #endif
52   #endif
53 }
54
55 // Wait for the specified Boolean to turn true or the timeout to occur
56 // The value of the Boolean is returned as result
57 bool CeCosThreadUtils::WaitFor (bool &b, Duration dTimeout)
58 {
59   Time t=Now();
60   do {
61     if(b){
62       break;
63     }
64     Sleep(250);
65   } while (Now()-t<dTimeout);
66   return b;
67 }
68
69 // This function spawns a thread and causes it to run asynchrously.
70 // The callback may be
71 //      A function, which is called when the thread completes
72 //      A boolean, which is set when the thread completes
73 //      Null, in which case no notification is received of thread completion
74 // pParam is passed to the thread function pThreadFunc on thread initiation.
75
76 bool CeCosThreadUtils::RunThread(CallbackProc *pThreadFunc, void *pParam, CallbackProc *pCompletionFunc, void *pCompletionParam, LPCTSTR pszName)
77 {
78   TRACE(_T("RunThread %s\n"),pszName);
79   // Do not spawn a thread while in possession of a mutex
80   //    ENTERCRITICAL;
81   //        VTRACE(_T("csl=%d\n"),CS::m_nCriticalSectionLock);
82   //        assert(1==CS::m_nCriticalSectionLock);
83   //    LEAVECRITICAL;
84   
85   ThreadInfo *pInfo=new ThreadInfo(pThreadFunc,pParam,pCompletionFunc,pCompletionParam,pszName); // SThreadFunc will delete
86   bool rc=false;
87
88 #ifdef _WIN32
89   // FIXME: CreateThread incompatible with C runtime calls?
90   DWORD dwID;
91   HANDLE hThread=CreateThread(NULL,0,SThreadFunc, pInfo, 0, &dwID);
92   if(hThread){
93     ::CloseHandle(hThread);
94     rc=true;
95   } else {
96     ERROR(_T("Failed to create thread\n"));
97   }
98 #else // UNIX
99   #ifdef NO_THREADS
100   assert(false);
101   #else
102   pthread_t hThread;
103   int n=pthread_create(&hThread, NULL, SThreadFunc, pInfo);
104   TRACE(  _T("RunThread: - non-blocking call (new thread=%x)\n"),hThread);
105   if (n != 0) {
106     ERROR(_T("RunThread(): pthread_create failed - %s\n"),strerror(errno));
107   } else {
108     
109     int n = pthread_detach(hThread);
110     
111     if (0==n) {
112       rc=true;
113     } else {
114       ERROR(_T("RunThread(): pthread_detach failed - %s\n"),strerror(errno));
115       hThread=0;
116     }
117   }
118   #endif
119 #endif
120   if(!rc){
121     delete pInfo;
122   }
123   return rc;
124   
125 }
126
127 #ifdef _WIN32
128 int CALLBACK CeCosThreadUtils::FilterFunction(EXCEPTION_POINTERS *p)
129 {
130   EXCEPTION_RECORD *pRec    =p->ExceptionRecord;
131   TRACE(_T("!!!Exception!!! address=%08x code=%08x\n"),pRec->ExceptionAddress,pRec->ExceptionCode);
132   /*
133   CONTEXT          *pContext=p->ContextRecord;
134   const unsigned char *ESP=(const unsigned char *)pContext->Esp;
135   for(int i=0;i<16;i++){
136   TRACE(_T("%08X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n"),ESP,
137   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]);
138   ESP+=16;
139   }
140   */
141   return EXCEPTION_EXECUTE_HANDLER;
142 }
143 #endif
144
145 CeCosThreadUtils::THREADFUNC CALLBACK CeCosThreadUtils::SThreadFunc (void *pParam)
146 {
147   THREAD_ID id=GetThreadId();
148   ThreadInfo *pInfo=(ThreadInfo*)pParam;
149   TRACE(_T("Thread %x [%s] created\n"),id,(LPCTSTR)pInfo->strName);
150 #if defined(_WIN32) && !defined(__CYGWIN__)
151   __try {
152     // Call what we are instructed to (e.g. LocalThreadFunc):
153     pInfo->pThreadFunc(pInfo->pThreadParam);
154   }
155     __except ( CeCosThreadUtils::FilterFunction(GetExceptionInformation() )) 
156   { 
157     TRACE(_T("Handling exception!!!...\n"));
158   }
159 #else // UNIX
160   try {
161     // Call what we are instructed to (e.g. LocalThreadFunc):
162     pInfo->pThreadFunc(pInfo->pThreadParam);
163   }
164   catch (...){
165     TRACE(_T("Exception caught in SThreadFunc!!!\n"));
166   }
167 #endif
168   
169   // Call the Callback:
170   if(pInfo->pCompletionFunc){
171     pInfo->pCompletionFunc (pInfo->pCompletionParam);
172   } else if (pInfo->pCompletionParam) {
173     // No function - just a flag:
174     *(bool *)pInfo->pCompletionParam=true;
175   }
176   // No more references to pInfo->pTest from now on...
177   TRACE(_T("Thread %x [%s] terminated\n"),id,(LPCTSTR)pInfo->strName);
178   delete pInfo;
179   return 0;
180 }
181
182 bool CeCosThreadUtils::CS::InCriticalSection()
183 {
184   return GetThreadId()==nCSOwner;
185 }
186
187 int CeCosThreadUtils::AtomicIncrement (int &n)
188 {
189   int rc;
190   ENTERCRITICAL;
191   rc=n++;
192   LEAVECRITICAL;
193   return rc;
194 }
195
196 int CeCosThreadUtils::AtomicDecrement (int &n)
197 {
198   int rc;
199   ENTERCRITICAL;
200   rc=n--;
201   LEAVECRITICAL;
202   return rc;
203 }
204
205 CeCosThreadUtils::CS::CS()
206 {
207   // Get mutex lock; block until available unless current
208   // thread already owns the mutex.
209   if(!InCriticalSection()){
210 #ifdef _WIN32
211     if(!bCSInitialized){
212                     InitializeCriticalSection(&cs);
213         bCSInitialized=true;
214     }
215     ::EnterCriticalSection(&cs);
216 #else // UNIX
217     #ifndef NO_THREADS
218       pthread_mutex_lock(&cs);
219     #endif
220 #endif
221     // As we now own the CS it is safe to perform the following assignment:
222     nCSOwner=GetThreadId();
223   }
224   // As we now own the CS it is safe to perform the following increment:
225   m_nCriticalSectionLock++;
226 }
227
228 CeCosThreadUtils::CS::~CS()
229 {
230   assert(InCriticalSection());
231   // As we own the CS we can safely manipulate variables:
232   m_nCriticalSectionLock--;
233   assert(m_nCriticalSectionLock>=0);
234   if(0==m_nCriticalSectionLock){
235     // Last lock is being released - let go of the mutex
236     nCSOwner=(THREAD_ID)-1;
237     
238     // Release mutex lock.  
239 #ifdef _WIN32
240     ::LeaveCriticalSection(&cs);
241 #else // UNIX
242     #ifndef NO_THREADS
243       pthread_mutex_unlock(&cs);
244     #endif
245 #endif
246   }
247 }
248
249 void CeCosThreadUtils::Sleep(int nMsec)
250 {
251 #ifdef _WIN32
252   ::Sleep(nMsec);
253 #else
254   sched_yield();
255   usleep((int)nMsec * 1000);
256 #endif
257 }