Jack2  1.9.10
JackWinThread.cpp
00001 /*
00002  Copyright (C) 2004-2008 Grame
00003 
00004  This program is free software; you can redistribute it and/or modify
00005  it under the terms of the GNU Lesser General Public License as published by
00006  the Free Software Foundation; either version 2.1 of the License, or
00007  (at your option) any later version.
00008 
00009  This program is distributed in the hope that it will be useful,
00010  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  GNU Lesser General Public License for more details.
00013 
00014  You should have received a copy of the GNU Lesser General Public License
00015  along with this program; if not, write to the Free Software
00016  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018  */
00019 
00020 #include "JackWinThread.h"
00021 #include "JackError.h"
00022 #include "JackTime.h"
00023 #include <assert.h>
00024 #include <stdio.h>
00025 
00026 namespace Jack
00027 {
00028 
00029 DWORD WINAPI JackWinThread::ThreadHandler(void* arg)
00030 {
00031     JackWinThread* obj = (JackWinThread*)arg;
00032     JackRunnableInterface* runnable = obj->fRunnable;
00033 
00034     // Signal creation thread when started with StartSync
00035     jack_log("JackWinThread::ThreadHandler : start");
00036     obj->fStatus = kIniting;
00037 
00038     // Call Init method
00039     if (!runnable->Init()) {
00040         jack_error("Thread init fails: thread quits");
00041         return 0;
00042     }
00043 
00044     obj->fStatus = kRunning;
00045 
00046     // If Init succeed, start the thread loop
00047     bool res = true;
00048     while (obj->fStatus == kRunning && res) {
00049         res = runnable->Execute();
00050     }
00051 
00052     SetEvent(obj->fEvent);
00053     jack_log("JackWinThread::ThreadHandler : exit");
00054     return 0;
00055 }
00056 
00057 JackWinThread::JackWinThread(JackRunnableInterface* runnable)
00058         : JackMMCSS(), JackThreadInterface(runnable, 0, false, 0)
00059 {
00060     fEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
00061     fThread = (HANDLE)NULL;
00062     assert(fEvent);
00063 }
00064 
00065 JackWinThread::~JackWinThread()
00066 {
00067     CloseHandle(fEvent);
00068     CloseHandle(fThread);
00069 }
00070 
00071 int JackWinThread::Start()
00072 {
00073     fStatus = kStarting;
00074 
00075     // Check if the thread was correctly started
00076     if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) {
00077         fStatus = kIdle;
00078         return -1;
00079     } else {
00080         return 0;
00081     }
00082 }
00083 
00084 int JackWinThread::StartSync()
00085 {
00086     fStatus = kStarting;
00087 
00088     if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) {
00089         fStatus = kIdle;
00090         return -1;
00091     } else {
00092         int count = 0;
00093         while (fStatus == kStarting && ++count < 1000) {
00094             JackSleep(1000);
00095         }
00096         return (count == 1000) ? -1 : 0;
00097     }
00098 }
00099 
00100 int JackWinThread::StartImp(jack_native_thread_t* thread, int priority, int realtime, ThreadCallback start_routine, void* arg)
00101 {
00102     DWORD id;
00103     *thread = CreateThread(NULL, 0, start_routine, arg, 0, &id);
00104 
00105     if (*thread == NULL) {
00106         jack_error("Cannot create thread error = %d", GetLastError());
00107         return -1;
00108     }
00109 
00110     if (realtime) {
00111 
00112         jack_log("JackWinThread::StartImp : create RT thread");
00113         if (!SetThreadPriority(*thread, THREAD_PRIORITY_TIME_CRITICAL)) {
00114             jack_error("Cannot set priority class = %d", GetLastError());
00115             return -1;
00116         }
00117 
00118     } else {
00119         jack_log("JackWinThread::StartImp : create non RT thread");
00120     }
00121 
00122     return 0;
00123 }
00124 
00125 // voir http://www.microsoft.com/belux/msdn/nl/community/columns/ldoc/multithread1.mspx
00126 
00127 int JackWinThread::Kill()
00128 {
00129     if (fThread != (HANDLE)NULL) { // If thread has been started
00130         TerminateThread(fThread, 0);
00131         WaitForSingleObject(fThread, INFINITE);
00132         CloseHandle(fThread);
00133         jack_log("JackWinThread::Kill");
00134         fThread = (HANDLE)NULL;
00135         fStatus = kIdle;
00136         return 0;
00137     } else {
00138         return -1;
00139     }
00140 }
00141 
00142 int JackWinThread::Stop()
00143 {
00144     if (fThread != (HANDLE)NULL) { // If thread has been started
00145         jack_log("JackWinThread::Stop");
00146         fStatus = kIdle; // Request for the thread to stop
00147         WaitForSingleObject(fEvent, INFINITE);
00148         CloseHandle(fThread);
00149         fThread = (HANDLE)NULL;
00150         return 0;
00151     } else {
00152         return -1;
00153     }
00154 }
00155 
00156 int JackWinThread::KillImp(jack_native_thread_t thread)
00157 {
00158     if (thread != (HANDLE)NULL) { // If thread has been started
00159         TerminateThread(thread, 0);
00160         WaitForSingleObject(thread, INFINITE);
00161         CloseHandle(thread);
00162         return 0;
00163     } else {
00164         return -1;
00165     }
00166 }
00167 
00168 int JackWinThread::StopImp(jack_native_thread_t thread)
00169 {
00170     if (thread) { // If thread has been started
00171         WaitForSingleObject(thread, INFINITE);
00172         CloseHandle(thread);
00173         return 0;
00174     } else {
00175         return -1;
00176     }
00177 }
00178 
00179 int JackWinThread::AcquireRealTime()
00180 {
00181     return (fThread != (HANDLE)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1;
00182 }
00183 
00184 int JackWinThread::AcquireSelfRealTime()
00185 {
00186     return AcquireRealTimeImp(GetCurrentThread(), fPriority);
00187 }
00188 
00189 int JackWinThread::AcquireRealTime(int priority)
00190 {
00191     fPriority = priority;
00192     return AcquireRealTime();
00193 }
00194 
00195 int JackWinThread::AcquireSelfRealTime(int priority)
00196 {
00197     fPriority = priority;
00198     return AcquireSelfRealTime();
00199 }
00200 
00201 int JackWinThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority)
00202 {
00203     jack_log("JackWinThread::AcquireRealTimeImp priority = %d", priority);
00204 
00205     if (priority >= 90 && MMCSSAcquireRealTime(thread) == 0) {
00206         jack_info("MMCSS API used to acquire RT for thread");
00207         return 0;
00208     } else {
00209         jack_info("MMCSS API not used...");
00210         if (SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL)) {
00211             return 0;
00212         } else {
00213             jack_error("Cannot set thread priority = %d", GetLastError());
00214             return -1;
00215         }
00216     }
00217 }
00218 
00219 int JackWinThread::DropRealTime()
00220 {
00221     return (fThread != (HANDLE)NULL) ? DropRealTimeImp(fThread) : -1;
00222 }
00223 
00224 int JackWinThread::DropSelfRealTime()
00225 {
00226     return DropRealTimeImp(GetCurrentThread());
00227 }
00228 
00229 int JackWinThread::DropRealTimeImp(jack_native_thread_t thread)
00230 {
00231     if (MMCSSDropRealTime(thread) == 0 ) {
00232         jack_info("MMCSS API used to drop RT for thread");
00233         return 0;
00234     } else if (SetThreadPriority(thread, THREAD_PRIORITY_NORMAL)) {
00235         return 0;
00236     } else {
00237         jack_error("Cannot set thread priority = %d", GetLastError());
00238         return -1;
00239     }
00240 }
00241 
00242 jack_native_thread_t JackWinThread::GetThreadID()
00243 {
00244     return fThread;
00245 }
00246 
00247 bool JackWinThread::IsThread()
00248 {
00249     return GetCurrentThread() == fThread;
00250 }
00251 
00252 void JackWinThread::Terminate()
00253 {
00254     jack_log("JackWinThread::Terminate");
00255     ExitThread(0);
00256 }
00257 
00258 SERVER_EXPORT void ThreadExit()
00259 {
00260     jack_log("ThreadExit");
00261     ExitThread(0);
00262 }
00263 
00264 } // end of namespace
00265 
00266 bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr)
00267 {
00268     return false;
00269 }
00270 
00271 bool jack_tls_allocate_key(jack_tls_key *key_ptr)
00272 {
00273     DWORD key;
00274 
00275     key = TlsAlloc();
00276     if (key == TLS_OUT_OF_INDEXES)
00277     {
00278         jack_error("TlsAlloc() failed. Error is %d", (unsigned int)GetLastError());
00279         return false;
00280     }
00281 
00282     *key_ptr = key;
00283     return true;
00284 }
00285 
00286 bool jack_tls_free_key(jack_tls_key key)
00287 {
00288     if (!TlsFree(key))
00289     {
00290         jack_error("TlsFree() failed. Error is %d", (unsigned int)GetLastError());
00291         return false;
00292     }
00293 
00294     return true;
00295 }
00296 
00297 bool jack_tls_set(jack_tls_key key, void *data_ptr)
00298 {
00299     if (!TlsSetValue(key, data_ptr))
00300     {
00301         jack_error("TlsSetValue() failed. Error is %d", (unsigned int)GetLastError());
00302         return false;
00303     }
00304 
00305     return true;
00306 }
00307 
00308 void *jack_tls_get(jack_tls_key key)
00309 {
00310     return TlsGetValue(key);
00311 }