DCL 4.0
Loading...
Searching...
No Matches
Thread.cpp
Go to the documentation of this file.
1
2#include <dcl/Config.h>
3
4#if __DCL_WINDOWS
5 #include <windows.h>
6 #include <VersionHelpers.h>
7#else
8 #include <sys/ioctl.h>
9 #include <sys/poll.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12#endif
13
14#if __DCL_PTHREAD
15 #include <pthread.h>
16 #include <sched.h> // sched_yield
17#endif
18
19#include <dcl/Thread.h>
20#include <dcl/Exception.h>
21
22#if __DCL_DEBUG
23#undef __THIS_FILE__
24static const char_t __THIS_FILE__[] = __T("dcl/Thread.cpp");
25#endif
26
27__DCL_BEGIN_NAMESPACE
28
30
31String Thread::toString() const
32{
33 StringBuilder r = className() + __T(":");
34 if (__name.isEmpty())
35 r += __T("(noname)");
36 return r;
37}
38
39Thread::Thread(const char_t* _name /*= NULL*/)
40{
41#if __DCL_WINDOWS
42 __hThread = NULL;
43#endif
44
45 __threadId = 0;
46 if (_name)
47 __name = _name;
48}
49
50#if __DCL_PTHREAD
51 #define __key_t pthread_key_t
52 #define __key_create(key) pthread_key_create(&key, NULL)
53 #define __key_delete(key) pthread_key_delete(key)
54 #define __key_get(key) pthread_getspecific(key)
55 #define __key_set(key, value) pthread_setspecific(key, value)
56 #define __key_set_success(key, value) pthread_setspecific(key, value) == 0
57#elif __DCL_WINDOWS
58 #define __key_t DWORD
59 #define __key_create(key) key = TlsAlloc()
60 #define __key_delete(key) TlsFree(key)
61 #define __key_get(key) TlsGetValue(key)
62 #define __key_set(key, value) TlsSetValue(key, value)
63 #define __key_set_success(key, value) TlsSetValue(key, value) == TRUE
64#endif
65
66static __key_t __keyCurrentThread = (__key_t) -1;
67
68void Thread::start()
70{
71 __DCL_ASSERT(__keyCurrentThread != (__key_t)-1);
72
73#if __DCL_PTHREAD
74 int n = pthread_create(
75 &__threadId,
76 (pthread_attr_t*)NULL,
77 Thread::startRoutine, (void*)this
78 );
79 if (n != 0)
80 throw new SysError(n);
81#elif __DCL_WINDOWS
82 DWORD id = 0;
83 __hThread = CreateThread(
84 NULL, // __in LPSECURITY_ATTRIBUTES lpThreadAttributes,
85 0, // default __in SIZE_T dwStackSize,
86 startRoutine, // __in LPTHREAD_START_ROUTINE lpStartAddress,
87 (LPVOID) this, // __in LPVOID lpParameter,
88 0, // run immediate __in DWORD dwCreationFlags,
89 &id // __out LPDWORD lpThreadId
90 );
91 __threadId = id;
92 if (__hThread == NULL)
93 throw new SysError(GetLastError());
94#endif
95}
96
98{
99 return __key_set_success(__keyCurrentThread, this);
100}
101
103{
104 __DCL_ASSERT(__keyCurrentThread != (__key_t)-1);
105 return (Thread*) __key_get(__keyCurrentThread);
106}
107
108#if __DCL_PTHREAD
109void*
110#elif __DCL_WINDOWS
111DWORD
112#endif
113Thread::startRoutine(void* _pThread)
114{
115 int r = -1;
116 Thread* pThread = (Thread*) _pThread;
117 try {
118 if (pThread->init())
119 r = pThread->run();
120 }
121 catch (Exception* cause) {
122 __DCL_TRACE2(__T("Thread execution fail! [%ls] %ls\n"),
123 pThread->toString().data(), cause->toStringAll().data());
124 cause->destroy();
125 }
126#if __DCL_PTHREAD
127 return (void*)(size_t)r;
128#elif __DCL_WINDOWS
129 return (DWORD)r;
130#endif
131}
132
133int Thread::join()
134{
135#if __DCL_PTHREAD
136 void* r;
137 pthread_join(__threadId, &r);
138#elif __DCL_WINDOWS
139 DWORD r = 0;
140 WaitForSingleObject(__hThread, INFINITE);
141 GetExitCodeThread(__hThread, &r);
142 CloseHandle(__hThread);
143 __hThread = NULL;
144#endif
145
146 __threadId = 0;
147 return (int)(size_t)r;
148}
149
150void Thread::sleep(unsigned int _mills)
151{
152#if __DCL_PTHREAD
153 /*
154 ::sleep(_milliseconds / 1000);
155 ::usleep((_milliseconds % 1000) * 1000);
156 */
157 poll(NULL, 0, _mills);
158#elif __DCL_WINDOWS
159 Sleep(_mills);
160#endif
161}
162
164{
165#if __DCL_PTHREAD
166 // pthread_yield(); deprecated
167 sched_yield();
168#elif __DCL_WINDOWS
169 SwitchToThread();
170#endif
171}
172
174{
175#if __DCL_PTHREAD
176 return pthread_self();
177#elif __DCL_WINDOWS
178 return GetCurrentThreadId();
179#endif
180}
181
182void Thread::once(OnceType& _onceControl, initRoutine _initRoutine)
183{
184 __DCL_ASSERT_PARAM(_initRoutine != NULL);
185#if __DCL_PTHREAD
186 pthread_once(&_onceControl, _initRoutine);
187#elif __DCL_WINDOWS
188 if (_onceControl != ONCE_INIT)
189 return;
190 if (incrementAndGet(_onceControl) == ONCE_INIT + 1)
191 _initRoutine();
192#endif
193}
194
195Thread::KeyType Thread::keyCreate() __DCL_THROWS1(SysError*)
196{
197#if __DCL_PTHREAD
198 KeyType rKey;
199 int failed = pthread_key_create(&rKey, NULL);
200 if (failed)
201 throw new SysError(failed);
202 return rKey;
203#elif __DCL_WINDOWS
204 KeyType rKey = TlsAlloc();
205 if (rKey == TLS_OUT_OF_INDEXES)
206 throw new SysError(GetLastError());
207 return rKey;
208#endif
209}
210
211void Thread::keyDelete(KeyType _key) __DCL_THROWS1(SysError*)
212{
213#if __DCL_PTHREAD
214 int failed = pthread_key_delete(_key);
215 if (failed)
216 throw new SysError(failed);
217#elif __DCL_WINDOWS
218 if (!TlsFree(_key))
219 throw new SysError(GetLastError());
220#endif
221}
222void Thread::keySetValue(KeyType _key, void* _value) __DCL_THROWS1(SysError*)
223{
224#if __DCL_PTHREAD
225 int failed = pthread_setspecific(_key, _value);
226 if (failed)
227 throw new SysError(failed);
228#elif __DCL_WINDOWS
229 if (!TlsSetValue(_key, _value))
230 throw new SysError(GetLastError());
231#endif
232}
233void* Thread::keyGetValue(KeyType _key) __DCL_THROWS1(SysError*)
234{
235#if __DCL_PTHREAD
236 return pthread_getspecific(_key);
237#elif __DCL_WINDOWS
238 void* p = TlsGetValue(_key);
239 if (p == NULL && GetLastError() != ERROR_SUCCESS)
240 throw new SysError(GetLastError());
241 return p;
242#endif
243}
244
245#if __DCL_PTHREAD
246 #define __lock_t pthread_spinlock_t
247 #define __init(lock) pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE)
248 #define __destroy(lock) pthread_spin_destroy(&lock)
249 #define __lock(lock) pthread_spin_lock(&lock)
250 #define __unlock(lock) pthread_spin_unlock(&lock)
251#elif __DCL_WINDOWS
252 #define __lock_t CRITICAL_SECTION
253 #define __init(lock) InitializeCriticalSectionAndSpinCount(&lock, INFINITE)
254 #define __destroy(lock) DeleteCriticalSection(&lock)
255 #define __lock(lock) EnterCriticalSection(&lock)
256 #define __unlock(lock) LeaveCriticalSection(&lock)
257#endif
258
259#define __LOCK_COUNT 7
260static __lock_t __lock[__LOCK_COUNT];
261
262void Thread::crtLock(const void* _p)
263{
264 __lock_t& lock = __lock[(size_t) _p % __LOCK_COUNT];
265 __lock(lock);
266}
267
268void Thread::crtUnlock(const void* _p)
269{
270 __lock_t& lock = __lock[(size_t) _p % __LOCK_COUNT];
271 __unlock(lock);
272}
273
274#if __DCL_PTHREAD
275long Thread::incrementAndGet(volatile long& _n)
276{
277 __lock_t& lock = __lock[((size_t)&_n) % __LOCK_COUNT];
278 __lock(lock);
279 long n = ++(_n);
280 __unlock(lock);
281 return n;
282}
283
284long Thread::decrementAndGet(volatile long& _n)
285{
286 __lock_t& lock = __lock[((size_t)&_n) % __LOCK_COUNT];
287 __lock(lock);
288 long n = --(_n);
289 __unlock(lock);
290 return n;
291}
292#endif
293
294#if __DCL_WINDOWS && _WIN32_WINNT < 0x0600
295
296long long Thread::incrementAndGet(volatile long long& _n)
297{
298 __lock_t& lock = __lock[((size_t)&_n) % __LOCK_COUNT];
299 __lock(lock);
300 long long n = ++(_n);
301 __unlock(lock);
302 return n;
303}
304
305long long Thread::decrementAndGet(volatile long long& _n)
306{
307 __lock_t& lock = __lock[((size_t)&_n) % __LOCK_COUNT];
308 __lock(lock);
309 long long n = --(_n);
310 __unlock(lock);
311 return n;
312}
313
314#endif // __DCL_WINDOWS && _WIN32_WINNT < 0x0600)
315
317{
318 __key_create(__keyCurrentThread);
319
320 for (int i = 0; i < __LOCK_COUNT; i++)
321 __init(__lock[i]);
322}
323
325{
326 __key_delete(__keyCurrentThread);
327
328 for (int i = 0; i < __LOCK_COUNT; i++)
329 __destroy(__lock[i]);
330}
331
332Thread::Event::Event()
333{
334 __bWaiting = false;
335
336#if __DCL_PTHREAD
337 __DCL_VERIFY(pipe(__fds) == 0);
338#elif __DCL_WINDOWS
339 __DCL_VERIFY(__hEvent = CreateEvent(
340 NULL, // lpEventAttributes
341 FALSE, // bManualReset
342 FALSE, // bInitialState
343 NULL // lpName
344 ));
345#endif
346}
347
348Thread::Event::~Event()
349{
350#if __DCL_PTHREAD
351 __DCL_VERIFY(close(__fds[0]) == 0);
352 __DCL_VERIFY(close(__fds[1]) == 0);
353#elif __DCL_WINDOWS
354 __DCL_VERIFY(CloseHandle(__hEvent) != FALSE);
355#endif
356}
357
358void Thread::Event::set()
359{
360#if __DCL_PTHREAD
361 char c = '1';
362 __DCL_VERIFY(write(__fds[1], &c, sizeof(c)) == sizeof(c));
363#elif __DCL_WINDOWS
364 __DCL_VERIFY(SetEvent(__hEvent) != FALSE);
365#endif
366}
367
368void Thread::Event::reset()
369{
370#if __DCL_PTHREAD
371 int nbytes = 0;
372 ioctl(__fds[READ_FD_INDEX], FIONREAD, &nbytes);
373 while (nbytes > 0) {
374 char buf[100];
375 int n = read(__fds[0], buf, nbytes < 100 ? nbytes : 100);
376 if (n > 0)
377 nbytes -= n;
378 else {
379 // 0: read all, -1:error
380 break;
381 }
382 }
383#elif __DCL_WINDOWS
384 __DCL_VERIFY(ResetEvent(__hEvent) != FALSE);
385#endif
386}
387
388bool Thread::Event::wait(unsigned int _milliseconds)
389{
390 bool r = true;
391 __bWaiting = true;
392#if __DCL_PTHREAD
393 struct pollfd pfd;
394 pfd.fd = __fds[READ_FD_INDEX];
395 pfd.events = POLLIN;
396 pfd.revents = 0;
397
398 int n = poll(&pfd, 1, _milliseconds);
399 if (n <= 0) {
400 r = false;
401 __DCL_ASSERT(n == 0);
402 errno = ETIMEDOUT;
403 }
404#elif __DCL_WINDOWS
405 switch(WaitForSingleObject(__hEvent, _milliseconds)) {
406 case WAIT_OBJECT_0:
407 break;
408 case WAIT_TIMEOUT:
409 r = false;
410 SetLastError(ERROR_TIMEOUT);
411 break;
412 default :
413 r = false;
414 __DCL_ASSERT(false);
415 }
416
417#endif
418 __bWaiting = false;
419 return r;
420}
421
422#if __DCL_WINDOWS
423Thread::Mutex::Mutex(DWORD _dwSpinCount)
424{
425 InitializeCriticalSectionAndSpinCount(&__cs, _dwSpinCount);
426}
427#endif
428
430{
431#if __DCL_PTHREAD
432 __DCL_VERIFY(pthread_mutex_init(&__mutex, NULL) == 0);
433#elif __DCL_WINDOWS
434 InitializeCriticalSection(&__cs);
435#endif
436}
437
439{
440#if __DCL_PTHREAD
441 __DCL_VERIFY(pthread_mutex_destroy(&__mutex) == 0);
442#elif __DCL_WINDOWS
443 DeleteCriticalSection(&__cs);
444#endif
445}
446
448{
449#if __DCL_PTHREAD
450 __DCL_VERIFY(pthread_mutex_lock(&__mutex) == 0);
451#elif __DCL_WINDOWS
452 EnterCriticalSection(&__cs);
453#endif
454}
455
457{
458#if __DCL_PTHREAD
459 int r = pthread_mutex_trylock(&__mutex);
460 __DCL_ASSERT(r != EINVAL);
461
462 __DCL_ASSERT(r == 0 || r == EBUSY);
463 return r == 0;
464#elif __DCL_WINDOWS
465 return TryEnterCriticalSection(&__cs) == TRUE;
466#endif
467}
468
470{
471#if __DCL_PTHREAD
472 __DCL_VERIFY(pthread_mutex_unlock(&__mutex) == 0);
473#elif __DCL_WINDOWS
474 LeaveCriticalSection(&__cs);
475#endif
476}
477
478#if __DCL_PTHREAD
479Thread::SpinLock::SpinLock(bool _pshared /* = false */)
480{
481 __DCL_VERIFY(pthread_spin_init(&__spinLock,
482 _pshared ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE
483 ) == 0);
484}
485
486Thread::SpinLock::~SpinLock()
487{
488 __DCL_VERIFY(pthread_spin_destroy(&__spinLock) == 0);
489}
490
491void Thread::SpinLock::lock()
492{
493 __DCL_VERIFY(pthread_spin_lock(&__spinLock) == 0);
494}
495
496bool Thread::SpinLock::tryLock()
497{
498 int r = pthread_spin_trylock(&__spinLock);
499 __DCL_ASSERT(r != EINVAL);
500
501 __DCL_ASSERT(r == 0 || r == EBUSY);
502 return r == 0;
503}
504
505void Thread::SpinLock::unlock()
506{
507 __DCL_VERIFY(pthread_spin_unlock(&__spinLock) == 0);
508}
509#endif // __DCL_PTHREAD
510
511#if __DCL_PTHREAD || (__DCL_WINDOWS && _WIN32_WINNT >= 0x0600)
512Thread::ReadWriteLock::ReadWriteLock()
513{
514#if __DCL_PTHREAD
515 __DCL_VERIFY(pthread_rwlock_init(&__rwlock, NULL) == 0);
516#else
517 InitializeSRWLock(&__srwlock);
518#endif
519}
520
521Thread::ReadWriteLock::~ReadWriteLock()
522{
523#if __DCL_PTHREAD
524 __DCL_VERIFY(pthread_rwlock_destroy(&__rwlock) == 0);
525#endif
526}
527
528void Thread::ReadWriteLock::readLock()
529{
530#if __DCL_PTHREAD
531 __DCL_VERIFY(pthread_rwlock_rdlock(&__rwlock) == 0);
532#else
533 AcquireSRWLockShared(&__srwlock);
534#endif
535}
536
537void Thread::ReadWriteLock::writeLock()
538{
539#if __DCL_PTHREAD
540 __DCL_VERIFY(pthread_rwlock_wrlock(&__rwlock) == 0);
541#else
542 AcquireSRWLockExclusive(&__srwlock);
543#endif
544}
545
546#if __DCL_PTHREAD
547bool Thread::ReadWriteLock::tryReadLock()
548{
549 int r = pthread_rwlock_tryrdlock(&__rwlock);
550 __DCL_ASSERT(r != EINVAL);
551 __DCL_ASSERT(r == 0 || r == EBUSY);
552 return r == 0;
553}
554
555bool Thread::ReadWriteLock::tryWriteLock()
556{
557 int r = pthread_rwlock_trywrlock(&__rwlock);
558 __DCL_ASSERT(r != EINVAL);
559 __DCL_ASSERT(r == 0 || r == EBUSY);
560 return r == 0;
561}
562
563void Thread::ReadWriteLock::unlock()
564{
565 __DCL_VERIFY(::pthread_rwlock_unlock(&__rwlock) == 0);
566}
567#else
568void Thread::ReadWriteLock::readUnlock()
569{
570 ReleaseSRWLockShared(&__srwlock);
571}
572void Thread::ReadWriteLock::writeUnlock()
573{
574 ReleaseSRWLockExclusive(&__srwlock);
575}
576#endif // __DCL_PTHREAD
577#endif // __DCL_PTHREAD || (__DCL_WINDOWS && _WIN32_WINNT >= 0x0600)
578
580{
581 __bWaiting = false;
582#if __DCL_PTHREAD
583 __DCL_VERIFY(pthread_cond_init(&__cond, NULL) == 0);
584#elif __DCL_WINDOWS && _WIN32_WINNT >= 0x0600
585 // Windows Vista, Windows Server 2008
586 __DCL_ASSERT(IsWindowsVistaOrGreater());
587 InitializeConditionVariable(&__cond);
588#endif
589
590}
591
593{
594#if __DCL_PTHREAD
595 __DCL_VERIFY(pthread_cond_destroy(&__cond) == 0);
596#endif
597}
598
600{
601#if __DCL_PTHREAD
602 __DCL_VERIFY(pthread_cond_signal(&__cond) == 0);
603#elif __DCL_WINDOWS
604 #if _WIN32_WINNT >= 0x0600
605 WakeConditionVariable(&__cond);
606 #else
607 __cond.set();
608 #endif
609#endif
610}
611
612#if __DCL_PTHREAD || (__DCL_WINDOWS && _WIN32_WINNT >= 0x0600)
613void Thread::CondVar::broadcast()
614{
615#if __DCL_PTHREAD
616 __DCL_VERIFY(pthread_cond_broadcast(&__cond) == 0);
617#elif __DCL_WINDOWS
618 WakeAllConditionVariable(&__cond);
619#endif
620}
621#endif
622
623bool Thread::CondVar::wait(Mutex& _mutex, unsigned int _milliseconds)
624{
625 bool r = true;
626 __bWaiting = true;
627#if __DCL_PTHREAD
628 // INFINITE == -1
629 if (_milliseconds == (unsigned int) INFINITE) {
630 __DCL_VERIFY(pthread_cond_wait(&__cond, (pthread_mutex_t*)&_mutex) == 0);
631 r = true;
632 }
633 else {
634 // millisoconds 1/1000
635 // microseconds 1/1000000
636 // nanoseconds 1/1000000000
637 struct timeval tv;
638 struct timezone tz;
639 struct timespec ts;
640 __DCL_VERIFY(gettimeofday(&tv, &tz) == 0);
641 ts.tv_sec = tv.tv_sec + (_milliseconds / 1000);
642 ts.tv_nsec = (tv.tv_usec * 1000) + ((_milliseconds % 1000) * 1000000);
643 int n = pthread_cond_timedwait(&__cond, (pthread_mutex_t*)&_mutex, &ts);
644 if (n != 0)
645 {
646 r = false;
647 __DCL_ASSERT(n == ETIMEDOUT);
648 errno = n;
649 }
650 }
651#elif __DCL_WINDOWS
652 #if _WIN32_WINNT >= 0x0600
653 if (!SleepConditionVariableCS(&__cond,
654 (CRITICAL_SECTION*)&_mutex, _milliseconds)) {
655 r = false;
656 __DCL_ASSERT(GetLastError() == ERROR_TIMEOUT);
657 }
658 #else
659 _mutex.unlock();
660 r = __cond.wait(INFINITE);
661 _mutex.lock();
662 if (r)
663 __cond.reset();
664 #endif
665#endif
666
667 __bWaiting = false;
668 return r;
669}
670
671#if __DCL_WINDOWS && _WIN32_WINNT >= 0x0600
672bool Thread::CondVar::wait(ReadWriteLock& _lock, bool _shared, unsigned int _milliseconds)
673{
674 bool r = true;
675 __bWaiting = true;
676 if (!SleepConditionVariableSRW(&__cond, (SRWLOCK *)&_lock,
677 _shared ? CONDITION_VARIABLE_LOCKMODE_SHARED : 0, _milliseconds)) {
678 r = false;
679 __DCL_ASSERT(GetLastError() == ERROR_TIMEOUT);
680 }
681 __bWaiting = false;
682 return r;
683}
684#endif
685
686#if __DCL_PTHREAD
687Thread::Barrier::Barrier(unsigned int _count)
688{
689 __DCL_VERIFY(pthread_barrier_init(&__barrier, NULL, _count) == 0);
690}
691
692Thread::Barrier::~Barrier()
693{
694 __DCL_VERIFY(pthread_barrier_destroy(&__barrier) == 0);
695}
696
697void Thread::Barrier::wait()
698{
699 __DCL_VERIFY(pthread_barrier_wait(&__barrier) == 0);
700}
701
702#endif
703
704__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
wchar_t char_t
Definition Config.h:275
#define __DCL_THROWS1(e)
Definition Config.h:167
#define TRUE
#define FALSE
#define __DCL_ASSERT_PARAM(expr)
Definition Object.h:384
#define __DCL_VERIFY(expr)
Definition Object.h:373
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
#define __DCL_TRACE2(fmt, arg1, arg2)
Definition Object.h:377
ByteString r
ByteBuffer * buf
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
void __cleanupThreadEnvironment()
Definition Thread.cpp:324
#define __LOCK_COUNT
Definition Thread.cpp:259
void __initializeThreadEnvironment()
Definition Thread.cpp:316
#define INFINITE
Definition Thread.h:17
virtual void destroy()
Definition Exception.cpp:74
String toStringAll() const
Definition Exception.cpp:45
virtual String toString() const
Definition Object.cpp:187
String className() const
Definition Object.cpp:163
bool wait(Mutex &_mutex, unsigned int _milliseconds=INFINITE)
Definition Thread.cpp:623
void unlock()
Definition Thread.cpp:469
void lock()
Definition Thread.cpp:447
bool tryLock()
Definition Thread.cpp:456
static void crtLock(const void *_p)
Definition Thread.cpp:262
static long incrementAndGet(volatile long &_n)
static void crtUnlock(const void *_p)
Definition Thread.cpp:268
static void yield()
Definition Thread.cpp:163
static void sleep(unsigned int _mills)
Definition Thread.cpp:150
virtual bool init()
Definition Thread.cpp:97
static unsigned long getCurrentThreadId()
Definition Thread.cpp:173
static Thread * getCurrentThread()
Definition Thread.cpp:102
static long decrementAndGet(volatile long &_n)
virtual int run()=0