00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "Common/Lock.h"
00026 #include "include/error.h"
00027
00028
00029 #include <iostream>
00030
00031
00032 #include "Common/Thread.h"
00033 #include "Common/ThreadGroup.h"
00034
00035 #ifdef _WIN32
00036 # include <process.h>
00037 #else
00038 # include <unistd.h>
00039 #endif
00040
00041 using namespace std;
00042
00043 namespace IXE {
00044
00045 Thread::Thread(char const* name) :
00046 runnable(this),
00047 name(name),
00048 state(Created),
00049 group(ThreadGroup::Root())
00050 {
00051 if (group)
00052 group->add(this);
00053 }
00054
00055 Thread::Thread(Runnable* target, char const* name) :
00056 runnable(target),
00057 name(name),
00058 state(Created),
00059 group(ThreadGroup::Root())
00060 {
00061 if (!target)
00062 runnable = this;
00063 group->add(this);
00064 }
00065
00066
00067 Thread::Thread(ThreadGroup* group, Runnable* target, char const* name) :
00068 runnable(target),
00069 name(name),
00070 state(Created),
00071 group(group)
00072 {
00073 if (!target)
00074 runnable = this;
00075 if (group)
00076 group->add(this);
00077 }
00078
00079 bool
00080 Thread::inCurrentThread()
00081 {
00082 return thread == GetCurrentThread();
00083 }
00084
00085 Thread::~Thread()
00086 {
00087 # ifndef _WIN32
00088
00089
00090 pthread_detach(thread);
00091 # endif
00092 if (state == Terminated)
00093 return;
00094 if (group) {
00095 Locking(group->destroying,
00096 {
00097 if (group->destroying) {
00098 LeaveCriticalSection(&group->destroying._lock);
00099
00100
00101
00102
00103
00104 if (state != Terminated) {
00105 state = Terminated;
00106 TerminateThread(thread, 0);
00107 }
00108 return;
00109 }
00110 });
00111 }
00112
00113
00114
00115 if (group)
00116 group->remove(this);
00117
00118 LockUp our(_lock);
00119 if (state == Created)
00120 return;
00121 if (state != Terminated) {
00122 if (inCurrentThread())
00123
00124 ExitThread(0);
00125 else
00126 TerminateThread(thread, 0);
00127 }
00128 }
00129
00130 int Thread::ActiveCount()
00131 {
00132 return (group) ? group->ActiveCount() : 1;
00133 }
00134
00135 void Thread::Join(int millis, int nanos)
00136
00137 {
00138 LockUp our(_lock);
00139 if (millis != -1 && millis < 0)
00140 throw InvalidArgumentError("timeout value is negative");
00141 if (nanos < 0 || nanos > 999999)
00142 throw InvalidArgumentError("nanosecond timeout value out of range");
00143 if (inCurrentThread())
00144 throw InvalidThreadStateError(string("self wait"));
00145 if (state != Running && state != Created)
00146 return;
00147
00148 # ifdef _WIN32
00149 if (millis == -1)
00150 millis = INFINITE;
00151 DWORD ret;
00152 ConditionWaitInterval(termination, &_lock, millis, nanos, ret);
00153 if (ret == 0xFFFFFFFF)
00154 throw SystemError("WaitForSingleObjectEx() failed");
00155 # else // !_WIN32
00156 if (millis == -1) {
00157 ConditionWait(termination, &_lock);
00158 } else {
00159 int ret;
00160 ConditionWaitInterval(termination, &_lock, millis, nanos, ret);
00161 if (ret == ETIMEDOUT) {
00162 SYS_CALL(::pthread_join, (thread, 0));
00163 state = Detached;
00164 }
00165 }
00166 # endif // _WIN32
00167 }
00168
00169
00170 void
00171 Thread::Run()
00172 {
00173 cerr << "*** Thread::Run() called!. Should be overwritten!" << endl;
00174 }
00175
00176
00177 TRESULT
00178 Thread::Main(void* arg)
00179 {
00180 Thread& th = *(Thread*)arg;
00181 # ifndef _WIN32
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 # endif
00192 th.state = Running;
00193 th.runnable->Run();
00194 th.state = Terminated;
00195 try {
00196 if (th.group) {
00197 th.group->remove(&th);
00198 th.group = 0;
00199 }
00200 } catch (...) {
00201 }
00202 # ifdef _MSC_VER
00203 _endthreadex(0);
00204 # else
00205 th.termination.notify();
00206
00207 # endif
00208 delete &th;
00209 return 0;
00210 }
00211
00212 void
00213 Thread::Start()
00214 {
00215 LockUp our(_lock);
00216 if (state != Created)
00217 return;
00218
00219 # ifdef _WIN32
00220 unsigned int id;
00221 # ifdef _MSC_VER
00222 thread = (HANDLE)_beginthreadex(0, 0, Main, this, CREATE_SUSPENDED, &id);
00223 # else
00224 thread = CreateThread(NULL, 0, (DWORD (__stdcall*)(void *))Main, this, CREATE_SUSPENDED, &id);
00225 # endif
00226 if (thread == NULL)
00227 throw SystemError("CreateThread() failed");
00228 ResumeThread(thread);
00229 # else // !_WIN32
00230 starting.In();
00231 int ret = ::pthread_create(&thread, NULL, Main, this);
00232 starting.Out();
00233 if (ret != 0) {
00234 throw SystemError(string("pthread_create() failed: ") + ret);
00235 }
00236 # endif
00237 }
00238
00239
00240 void
00241 Thread::Sleep(int millis, int nanos)
00242 {
00243 # ifdef _WIN32
00244 ::Sleep(millis);
00245 # else
00246 struct timespec delay;
00247 long seconds = (millis / 1000);
00248 delay.tv_sec = seconds;
00249 long restmillis = millis % 1000;
00250 delay.tv_nsec = (restmillis) * 1000 + nanos;
00251 unsigned nsecs = delay.tv_sec * 1000000;
00252 nsecs += delay.tv_nsec / 1000;
00253 usleep(nsecs);
00254 # endif
00255 }
00256
00257
00258 void
00259 Thread::Yield()
00260 {
00261 # ifdef _WIN32
00262 ::Sleep(0);
00263 # else
00264 sched_yield();
00265 # endif
00266 }
00267
00268
00269 # ifdef _WIN32
00270 HANDLE
00271 # else
00272 pthread_t
00273 # endif
00274 Thread::CurrentThreadId()
00275 {
00276 return GetCurrentThread();
00277 }
00278
00279 static
00280 int threadPriorityTable[] =
00281 {
00282 # ifdef _WIN32
00283 THREAD_PRIORITY_HIGHEST,
00284 THREAD_PRIORITY_ABOVE_NORMAL,
00285 THREAD_PRIORITY_NORMAL,
00286 THREAD_PRIORITY_BELOW_NORMAL,
00287 THREAD_PRIORITY_LOWEST
00288 # else
00289 1,
00290 2,
00291 3,
00292 4,
00293 5
00294 # endif
00295 };
00296
00297
00298 int
00299 Thread::Priority()
00300 {
00301 # ifdef _WIN32
00302 DWORD erg = GetThreadPriority(thread);
00303 for (int i = 0; i < sizeof(threadPriorityTable) / sizeof(threadPriorityTable[0]); i++)
00304 if (threadPriorityTable[i] == erg)
00305 return i;
00306 return 2;
00307 # else
00308 sched_param param;
00309 int policy;
00310 SYS_CALL(::pthread_getschedparam, (thread, &policy, ¶m));
00311 int prio = param.sched_priority;
00312 for (int i = 0; i < int(sizeof(threadPriorityTable) / sizeof(threadPriorityTable[0])); i++)
00313 if (threadPriorityTable[i] == prio)
00314 return i;
00315 return 2;
00316 # endif
00317 }
00318
00319
00320 void
00321 Thread::Priority(int newPriority)
00322 {
00323 # ifdef _WIN32
00324 SetThreadPriority(thread, threadPriorityTable[newPriority]);
00325 # else
00326 sched_param param;
00327 int policy = 0;
00328 SYS_CALL(::pthread_getschedparam, (thread, &policy, ¶m));
00329 param.sched_priority = threadPriorityTable[newPriority];
00330 SYS_CALL(::pthread_setschedparam, (thread, policy, ¶m));
00331 # endif
00332 }
00333
00334 bool
00335 Thread::IsAlive()
00336 {
00337 return state == Running;
00338 }
00339
00340 }