| 1 | #pragma once
|
|---|
| 2 | #include "Mil.h"
|
|---|
| 3 | #include "Serial.h"
|
|---|
| 4 | #include "Atomic.h"
|
|---|
| 5 | #include "FilterException.h"
|
|---|
| 6 |
|
|---|
| 7 | #ifndef MIL_MAX_THREADS
|
|---|
| 8 | #define MIL_MAX_THREADS 25
|
|---|
| 9 | #endif
|
|---|
| 10 |
|
|---|
| 11 | namespace mil {
|
|---|
| 12 | namespace thread {
|
|---|
| 13 | typedef intptr_t id_t;
|
|---|
| 14 | extern Serial id_serial;
|
|---|
| 15 | extern void* get(id_t thread_id);
|
|---|
| 16 | extern void set(id_t thread_id, void* object);
|
|---|
| 17 | extern bool is_valid_id(id_t thread_id);
|
|---|
| 18 | }
|
|---|
| 19 | }
|
|---|
| 20 |
|
|---|
| 21 | #if defined(MIL_OS_WINDOWS)
|
|---|
| 22 | #include "os-windows/Thread.h"
|
|---|
| 23 | #define MIL_DEFAULT_THREAD mil::thread::Windows
|
|---|
| 24 | //#elif defined(__CYGWIN__)
|
|---|
| 25 | //#include "os-windows/Thread.h"
|
|---|
| 26 | #elif defined(MIL_OS_UNIX)
|
|---|
| 27 | #include "os-unix/Thread.h"
|
|---|
| 28 | #define MIL_DEFAULT_THREAD mil::thread::Posix
|
|---|
| 29 | #else
|
|---|
| 30 | #error
|
|---|
| 31 | #endif
|
|---|
| 32 |
|
|---|
| 33 | #ifdef __OBJC__
|
|---|
| 34 | #include "gui-cocoa/CocoaThread.h"
|
|---|
| 35 | namespace mil {
|
|---|
| 36 | namespace thread {
|
|---|
| 37 | template <typename Child>
|
|---|
| 38 | class Cocoa : public boost::noncopyable {
|
|---|
| 39 | MIL_CRTP_CLASS_MEMBERS;
|
|---|
| 40 |
|
|---|
| 41 | WorkerThread* thread;
|
|---|
| 42 |
|
|---|
| 43 | public:
|
|---|
| 44 | Cocoa() {
|
|---|
| 45 | thread = [[WorkerThread alloc] init];
|
|---|
| 46 | }
|
|---|
| 47 |
|
|---|
| 48 | ~Cocoa() {
|
|---|
| 49 | [thread release];
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | void start() {
|
|---|
| 53 | struct foo {
|
|---|
| 54 | static void* thread_routine(void* object) {
|
|---|
| 55 | Child::thread_routine(object);
|
|---|
| 56 | return NULL;
|
|---|
| 57 | }
|
|---|
| 58 | };
|
|---|
| 59 |
|
|---|
| 60 | void* (*routine_)(void*) = foo::thread_routine;
|
|---|
| 61 | void* arg_ = (void*)this;
|
|---|
| 62 |
|
|---|
| 63 | [thread setData:routine_ arg:arg_];
|
|---|
| 64 | [NSThread detachNewThreadSelector:@selector(start) toTarget:thread withObject:nil];
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | void join() {
|
|---|
| 68 | for (int retry = 50; !getChild().is_exited.load(); retry--) {
|
|---|
| 69 | if (retry == 0) {
|
|---|
| 70 | halt << "thread can't exit";
|
|---|
| 71 | }
|
|---|
| 72 | sleep(1);
|
|---|
| 73 | }
|
|---|
| 74 | }
|
|---|
| 75 | };
|
|---|
| 76 | }
|
|---|
| 77 | }
|
|---|
| 78 | #endif
|
|---|
| 79 |
|
|---|
| 80 | #ifdef MIL_OS_UNIX
|
|---|
| 81 |
|
|---|
| 82 | namespace mil {
|
|---|
| 83 | namespace thread {
|
|---|
| 84 |
|
|---|
| 85 | typedef pid_t native_id_t;
|
|---|
| 86 | static inline native_id_t get_native_id() {
|
|---|
| 87 | return gettid();
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | template <typename Child>
|
|---|
| 91 | class Posix : public boost::noncopyable {
|
|---|
| 92 | pthread_t t;
|
|---|
| 93 | pthread_attr_t a;
|
|---|
| 94 |
|
|---|
| 95 | MIL_CRTP_CLASS_MEMBERS;
|
|---|
| 96 |
|
|---|
| 97 | public:
|
|---|
| 98 | void start() {
|
|---|
| 99 | struct foo {
|
|---|
| 100 | static void* thread(void* object) {
|
|---|
| 101 | Child::thread_routine(object);
|
|---|
| 102 | return NULL;
|
|---|
| 103 | }
|
|---|
| 104 | };
|
|---|
| 105 |
|
|---|
| 106 | pthread_attr_init(&a);
|
|---|
| 107 | pthread_attr_setdetachstate(&a,PTHREAD_CREATE_DETACHED);
|
|---|
| 108 | pthread_create(&t, &a, foo::thread,
|
|---|
| 109 | static_cast<void*>(this));
|
|---|
| 110 | }
|
|---|
| 111 |
|
|---|
| 112 | void join() {
|
|---|
| 113 | for (int retry = 50; !getChild().is_exited.load(); retry--) {
|
|---|
| 114 | if (retry == 0) {
|
|---|
| 115 | halt << "thread can't exit";
|
|---|
| 116 | }
|
|---|
| 117 | sleep(1);
|
|---|
| 118 | }
|
|---|
| 119 | }
|
|---|
| 120 | };
|
|---|
| 121 | }
|
|---|
| 122 | }
|
|---|
| 123 | #endif
|
|---|
| 124 |
|
|---|
| 125 | #ifdef MIL_OS_WINDOWS
|
|---|
| 126 | namespace mil {
|
|---|
| 127 | namespace thread {
|
|---|
| 128 |
|
|---|
| 129 | typedef DWORD native_id_t;
|
|---|
| 130 | static inline native_id_t get_native_id() {
|
|---|
| 131 | return GetCurrentThreadId();
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | template <typename Child>
|
|---|
| 135 | class Windows : public boost::noncopyable {
|
|---|
| 136 | public:
|
|---|
| 137 | MIL_CRTP_CLASS_MEMBERS;
|
|---|
| 138 |
|
|---|
| 139 | protected:
|
|---|
| 140 | atomic<HANDLE> hThread;
|
|---|
| 141 |
|
|---|
| 142 | public:
|
|---|
| 143 | void start() {
|
|---|
| 144 | struct foo {
|
|---|
| 145 | static DWORD WINAPI thread(LPVOID object) {
|
|---|
| 146 | Child::thread_routine(object);
|
|---|
| 147 | return 0;
|
|---|
| 148 | }
|
|---|
| 149 | };
|
|---|
| 150 |
|
|---|
| 151 | DWORD threadId;
|
|---|
| 152 | LPVOID obj = reinterpret_cast<LPVOID>(this);
|
|---|
| 153 | HANDLE t = CreateThread(NULL, 0, foo::thread, obj, 0, &threadId);
|
|---|
| 154 | if (t == NULL) {
|
|---|
| 155 | halt << "CreateThread(): failed";
|
|---|
| 156 | }
|
|---|
| 157 | hThread.store(t);
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 | void join() {
|
|---|
| 161 | HANDLE t = hThread.exchange(0);
|
|---|
| 162 | if (!t) {
|
|---|
| 163 | return;
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | for (int retry = 50; !getChild().is_exited.load(); retry--) {
|
|---|
| 167 | if (retry == 0) {
|
|---|
| 168 | MessageBox(NULL, _T("terminate thread"), _T(""), MB_OK);
|
|---|
| 169 | //ExitProcess(1); // XXX
|
|---|
| 170 | TerminateThread(t, 1);
|
|---|
| 171 | break;
|
|---|
| 172 | }
|
|---|
| 173 | sleep(1);
|
|---|
| 174 | }
|
|---|
| 175 | CloseHandle(t);
|
|---|
| 176 | }
|
|---|
| 177 |
|
|---|
| 178 | Windows() : hThread(NULL) {
|
|---|
| 179 | }
|
|---|
| 180 | };
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 | #endif
|
|---|
| 184 |
|
|---|
| 185 | namespace mil {
|
|---|
| 186 | template <class Child, template<class> class ThreadType = MIL_DEFAULT_THREAD>
|
|---|
| 187 | class Thread : public ThreadType<Thread<Child, ThreadType> > {
|
|---|
| 188 | public:
|
|---|
| 189 | MIL_CRTP_CLASS_MEMBERS;
|
|---|
| 190 |
|
|---|
| 191 | const thread::id_t thread_id;
|
|---|
| 192 | atomic<bool> is_exited;
|
|---|
| 193 |
|
|---|
| 194 | static int thread_routine_filtered(int, char** argv) {
|
|---|
| 195 | Thread<Child, ThreadType>* obj = (Thread<Child, ThreadType>*)argv;
|
|---|
| 196 | typedef Thread<Child, ThreadType> Type;
|
|---|
| 197 |
|
|---|
| 198 | MIL_MODULE_SUPER_CHILD_TYPE(Type)& o =
|
|---|
| 199 | MIL_MODULE_GET_SUPER_CHILD(*obj);
|
|---|
| 200 |
|
|---|
| 201 | o.run();
|
|---|
| 202 | o.is_exited.store(true);
|
|---|
| 203 | //std::cout << "X" << std::flush;
|
|---|
| 204 | return 0;
|
|---|
| 205 | }
|
|---|
| 206 |
|
|---|
| 207 | static void thread_routine(void* object) {
|
|---|
| 208 | char** argv = reinterpret_cast<char**>(object);
|
|---|
| 209 | filter_exception_and_start(0, argv, thread_routine_filtered);
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | void run() {
|
|---|
| 213 | }
|
|---|
| 214 |
|
|---|
| 215 | void start() {
|
|---|
| 216 | if (!this->is_exited.load()) {
|
|---|
| 217 | return;
|
|---|
| 218 | }
|
|---|
| 219 | this->is_exited.store(false);
|
|---|
| 220 | //ThreadPlatform<Thread<Child> >::start();
|
|---|
| 221 | ThreadType<Thread<Child, ThreadType> >::start();
|
|---|
| 222 | }
|
|---|
| 223 |
|
|---|
| 224 | Thread() : thread_id(thread::id_serial.retain()), is_exited(true) {
|
|---|
| 225 | if (!thread::is_valid_id(thread_id)) {
|
|---|
| 226 | halt << "can't retain thread id";
|
|---|
| 227 | return;
|
|---|
| 228 | }
|
|---|
| 229 | //threads[thread_id].store(reinterpret_cast<void*>(this));
|
|---|
| 230 | thread::set(thread_id, reinterpret_cast<void*>(this));
|
|---|
| 231 | }
|
|---|
| 232 |
|
|---|
| 233 | ~Thread() {
|
|---|
| 234 | this->join();
|
|---|
| 235 | thread::set(thread_id, NULL);
|
|---|
| 236 | //threads[thread_id].store(NULL);
|
|---|
| 237 | if (!thread::id_serial.release(thread_id)) {
|
|---|
| 238 | halt << "can't release thread id";
|
|---|
| 239 | }
|
|---|
| 240 | }
|
|---|
| 241 | };
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|