1 /*************************************************************************************************
2 * Threading devices
3 * Copyright (C) 2009-2012 Mikio Hirabayashi
4 * This file is part of Kyoto Cabinet.
5 * This program is free software: you can redistribute it and/or modify it under the terms of
6 * the GNU General Public License as published by the Free Software Foundation, either version
7 * 3 of the License, or any later version.
8 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License along with this program.
12 * If not, see <http://www.gnu.org/licenses/>.
13 *************************************************************************************************/
14
15
16 #include "kcthread.h"
17 #include "myconf.h"
18
19 namespace kyotocabinet { // common namespace
20
21
22 /**
23 * Constants for implementation.
24 */
25 namespace {
26 const uint32_t LOCKBUSYLOOP = 8192; ///< threshold of busy loop and sleep for locking
27 const size_t LOCKSEMNUM = 256; ///< number of semaphores for locking
28 }
29
30
31 /**
32 * Thread internal.
33 */
34 struct ThreadCore {
35 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
36 ::HANDLE th; ///< handle
37 #else
38 ::pthread_t th; ///< identifier
39 bool alive; ///< alive flag
40 #endif
41 };
42
43
44 /**
45 * CondVar internal.
46 */
47 struct CondVarCore {
48 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
49 ::CRITICAL_SECTION mutex; ///< mutex
50 uint32_t wait; ///< wait count
51 uint32_t wake; ///< wake count
52 ::HANDLE sev; ///< signal event handle
53 ::HANDLE fev; ///< finish event handle
54 #else
55 ::pthread_cond_t cond; ///< condition
56 #endif
57 };
58
59
60 /**
61 * Call the running thread.
62 * @param arg the thread.
63 * @return always NULL.
64 */
65 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
66 static ::DWORD threadrun(::LPVOID arg);
67 #else
68 static void* threadrun(void* arg);
69 #endif
70
71
72 /**
73 * Default constructor.
74 */
Thread()75 Thread::Thread() : opq_(NULL) {
76 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
77 _assert_(true);
78 ThreadCore* core = new ThreadCore;
79 core->th = NULL;
80 opq_ = (void*)core;
81 #else
82 _assert_(true);
83 ThreadCore* core = new ThreadCore;
84 core->alive = false;
85 opq_ = (void*)core;
86 #endif
87 }
88
89
90 /**
91 * Destructor.
92 */
~Thread()93 Thread::~Thread() {
94 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
95 _assert_(true);
96 ThreadCore* core = (ThreadCore*)opq_;
97 if (core->th) join();
98 delete core;
99 #else
100 _assert_(true);
101 ThreadCore* core = (ThreadCore*)opq_;
102 if (core->alive) join();
103 delete core;
104 #endif
105 }
106
107
108 /**
109 * Start the thread.
110 */
start()111 void Thread::start() {
112 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
113 _assert_(true);
114 ThreadCore* core = (ThreadCore*)opq_;
115 if (core->th) throw std::invalid_argument("already started");
116 ::DWORD id;
117 core->th = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadrun, this, 0, &id);
118 if (!core->th) throw std::runtime_error("CreateThread");
119 #else
120 _assert_(true);
121 ThreadCore* core = (ThreadCore*)opq_;
122 if (core->alive) throw std::invalid_argument("already started");
123 if (::pthread_create(&core->th, NULL, threadrun, this) != 0)
124 throw std::runtime_error("pthread_create");
125 core->alive = true;
126 #endif
127 }
128
129
130 /**
131 * Wait for the thread to finish.
132 */
join()133 void Thread::join() {
134 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
135 _assert_(true);
136 ThreadCore* core = (ThreadCore*)opq_;
137 if (!core->th) throw std::invalid_argument("not alive");
138 if (::WaitForSingleObject(core->th, INFINITE) == WAIT_FAILED)
139 throw std::runtime_error("WaitForSingleObject");
140 ::CloseHandle(core->th);
141 core->th = NULL;
142 #else
143 _assert_(true);
144 ThreadCore* core = (ThreadCore*)opq_;
145 if (!core->alive) throw std::invalid_argument("not alive");
146 core->alive = false;
147 if (::pthread_join(core->th, NULL) != 0) throw std::runtime_error("pthread_join");
148 #endif
149 }
150
151
152 /**
153 * Put the thread in the detached state.
154 */
detach()155 void Thread::detach() {
156 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
157 _assert_(true);
158 #else
159 _assert_(true);
160 ThreadCore* core = (ThreadCore*)opq_;
161 if (!core->alive) throw std::invalid_argument("not alive");
162 core->alive = false;
163 if (::pthread_detach(core->th) != 0) throw std::runtime_error("pthread_detach");
164 #endif
165 }
166
167
168 /**
169 * Terminate the running thread.
170 */
exit()171 void Thread::exit() {
172 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
173 _assert_(true);
174 ::ExitThread(0);
175 #else
176 _assert_(true);
177 ::pthread_exit(NULL);
178 #endif
179 }
180
181
182 /**
183 * Yield the processor from the current thread.
184 */
yield()185 void Thread::yield() {
186 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
187 _assert_(true);
188 ::Sleep(0);
189 #else
190 _assert_(true);
191 ::sched_yield();
192 #endif
193 }
194
195
196 /**
197 * Chill the processor by suspending execution for a quick moment.
198 */
chill()199 void Thread::chill() {
200 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
201 _assert_(true);
202 ::Sleep(21);
203 #else
204 _assert_(true);
205 struct ::timespec req;
206 req.tv_sec = 0;
207 req.tv_nsec = 21 * 1000 * 1000;
208 ::nanosleep(&req, NULL);
209 #endif
210 }
211
212
213
214 /**
215 * Suspend execution of the current thread.
216 */
sleep(double sec)217 bool Thread::sleep(double sec) {
218 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
219 _assert_(sec >= 0.0);
220 if (sec <= 0.0) {
221 yield();
222 return true;
223 }
224 if (sec > INT32MAX) sec = INT32MAX;
225 ::Sleep(sec * 1000);
226 return true;
227 #else
228 _assert_(sec >= 0.0);
229 if (sec <= 0.0) {
230 yield();
231 return true;
232 }
233 if (sec > INT32MAX) sec = INT32MAX;
234 double integ, fract;
235 fract = std::modf(sec, &integ);
236 struct ::timespec req, rem;
237 req.tv_sec = (time_t)integ;
238 req.tv_nsec = (long)(fract * 999999000);
239 while (::nanosleep(&req, &rem) != 0) {
240 if (errno != EINTR) return false;
241 req = rem;
242 }
243 return true;
244 #endif
245 }
246
247
248 /**
249 * Get the hash value of the current thread.
250 */
hash()251 int64_t Thread::hash() {
252 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
253 _assert_(true);
254 return ::GetCurrentThreadId();
255 #else
256 _assert_(true);
257 pthread_t tid = pthread_self();
258 int64_t num;
259 if (sizeof(tid) == sizeof(num)) {
260 std::memcpy(&num, &tid, sizeof(num));
261 } else if (sizeof(tid) == sizeof(int32_t)) {
262 uint32_t inum;
263 std::memcpy(&inum, &tid, sizeof(inum));
264 num = inum;
265 } else {
266 num = hashmurmur(&tid, sizeof(tid));
267 }
268 return num & INT64MAX;
269 #endif
270 }
271
272
273 /**
274 * Call the running thread.
275 */
276 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
threadrun(::LPVOID arg)277 static ::DWORD threadrun(::LPVOID arg) {
278 _assert_(true);
279 Thread* thread = (Thread*)arg;
280 thread->run();
281 return NULL;
282 }
283 #else
threadrun(void * arg)284 static void* threadrun(void* arg) {
285 _assert_(true);
286 Thread* thread = (Thread*)arg;
287 thread->run();
288 return NULL;
289 }
290 #endif
291
292
293 /**
294 * Default constructor.
295 */
Mutex()296 Mutex::Mutex() : opq_(NULL) {
297 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
298 _assert_(true);
299 ::CRITICAL_SECTION* mutex = new ::CRITICAL_SECTION;
300 ::InitializeCriticalSection(mutex);
301 opq_ = (void*)mutex;
302 #else
303 _assert_(true);
304 ::pthread_mutex_t* mutex = new ::pthread_mutex_t;
305 if (::pthread_mutex_init(mutex, NULL) != 0) throw std::runtime_error("pthread_mutex_init");
306 opq_ = (void*)mutex;
307 #endif
308 }
309
310
311 /**
312 * Constructor with the specifications.
313 */
Mutex(Type type)314 Mutex::Mutex(Type type) {
315 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
316 _assert_(true);
317 ::CRITICAL_SECTION* mutex = new ::CRITICAL_SECTION;
318 ::InitializeCriticalSection(mutex);
319 opq_ = (void*)mutex;
320 #else
321 _assert_(true);
322 ::pthread_mutexattr_t attr;
323 if (::pthread_mutexattr_init(&attr) != 0) throw std::runtime_error("pthread_mutexattr_init");
324 switch (type) {
325 case FAST: {
326 break;
327 }
328 case ERRORCHECK: {
329 if (::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
330 throw std::runtime_error("pthread_mutexattr_settype");
331 break;
332 }
333 case RECURSIVE: {
334 if (::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
335 throw std::runtime_error("pthread_mutexattr_settype");
336 break;
337 }
338 }
339 ::pthread_mutex_t* mutex = new ::pthread_mutex_t;
340 if (::pthread_mutex_init(mutex, &attr) != 0) throw std::runtime_error("pthread_mutex_init");
341 ::pthread_mutexattr_destroy(&attr);
342 opq_ = (void*)mutex;
343 #endif
344 }
345
346
347 /**
348 * Destructor.
349 */
~Mutex()350 Mutex::~Mutex() {
351 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
352 _assert_(true);
353 ::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
354 ::DeleteCriticalSection(mutex);
355 delete mutex;
356 #else
357 _assert_(true);
358 ::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
359 ::pthread_mutex_destroy(mutex);
360 delete mutex;
361 #endif
362 }
363
364
365 /**
366 * Get the lock.
367 */
lock()368 void Mutex::lock() {
369 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
370 _assert_(true);
371 ::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
372 ::EnterCriticalSection(mutex);
373 #else
374 _assert_(true);
375 ::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
376 if (::pthread_mutex_lock(mutex) != 0) throw std::runtime_error("pthread_mutex_lock");
377 #endif
378 }
379
380
381 /**
382 * Try to get the lock.
383 */
lock_try()384 bool Mutex::lock_try() {
385 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
386 _assert_(true);
387 ::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
388 if (!::TryEnterCriticalSection(mutex)) return false;
389 return true;
390 #else
391 _assert_(true);
392 ::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
393 int32_t ecode = ::pthread_mutex_trylock(mutex);
394 if (ecode == 0) return true;
395 if (ecode != EBUSY) throw std::runtime_error("pthread_mutex_trylock");
396 return false;
397 #endif
398 }
399
400
401 /**
402 * Try to get the lock.
403 */
lock_try(double sec)404 bool Mutex::lock_try(double sec) {
405 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || defined(_SYS_CYGWIN_) || defined(_SYS_MACOSX_)
406 _assert_(sec >= 0.0);
407 if (lock_try()) return true;
408 double end = time() + sec;
409 Thread::yield();
410 uint32_t wcnt = 0;
411 while (!lock_try()) {
412 if (time() > end) return false;
413 if (wcnt >= LOCKBUSYLOOP) {
414 Thread::chill();
415 } else {
416 Thread::yield();
417 wcnt++;
418 }
419 }
420 return true;
421 #else
422 _assert_(sec >= 0.0);
423 ::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
424 struct ::timeval tv;
425 struct ::timespec ts;
426 if (::gettimeofday(&tv, NULL) == 0) {
427 double integ;
428 double fract = std::modf(sec, &integ);
429 ts.tv_sec = tv.tv_sec + (time_t)integ;
430 ts.tv_nsec = (long)(tv.tv_usec * 1000.0 + fract * 999999000);
431 if (ts.tv_nsec >= 1000000000) {
432 ts.tv_nsec -= 1000000000;
433 ts.tv_sec++;
434 }
435 } else {
436 ts.tv_sec = std::time(NULL) + 1;
437 ts.tv_nsec = 0;
438 }
439 int32_t ecode = ::pthread_mutex_timedlock(mutex, &ts);
440 if (ecode == 0) return true;
441 if (ecode != ETIMEDOUT) throw std::runtime_error("pthread_mutex_timedlock");
442 return false;
443 #endif
444 }
445
446
447 /**
448 * Release the lock.
449 */
unlock()450 void Mutex::unlock() {
451 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
452 _assert_(true);
453 ::CRITICAL_SECTION* mutex = (::CRITICAL_SECTION*)opq_;
454 ::LeaveCriticalSection(mutex);
455 #else
456 _assert_(true);
457 ::pthread_mutex_t* mutex = (::pthread_mutex_t*)opq_;
458 if (::pthread_mutex_unlock(mutex) != 0) throw std::runtime_error("pthread_mutex_unlock");
459 #endif
460 }
461
462
463 /**
464 * SlottedMutex internal.
465 */
466 struct SlottedMutexCore {
467 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
468 ::CRITICAL_SECTION* mutexes; ///< primitives
469 size_t slotnum; ///< number of slots
470 #else
471 ::pthread_mutex_t* mutexes; ///< primitives
472 size_t slotnum; ///< number of slots
473 #endif
474 };
475
476
477 /**
478 * Constructor.
479 */
SlottedMutex(size_t slotnum)480 SlottedMutex::SlottedMutex(size_t slotnum) : opq_(NULL) {
481 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
482 _assert_(true);
483 SlottedMutexCore* core = new SlottedMutexCore;
484 ::CRITICAL_SECTION* mutexes = new ::CRITICAL_SECTION[slotnum];
485 for (size_t i = 0; i < slotnum; i++) {
486 ::InitializeCriticalSection(mutexes + i);
487 }
488 core->mutexes = mutexes;
489 core->slotnum = slotnum;
490 opq_ = (void*)core;
491 #else
492 _assert_(true);
493 SlottedMutexCore* core = new SlottedMutexCore;
494 ::pthread_mutex_t* mutexes = new ::pthread_mutex_t[slotnum];
495 for (size_t i = 0; i < slotnum; i++) {
496 if (::pthread_mutex_init(mutexes + i, NULL) != 0)
497 throw std::runtime_error("pthread_mutex_init");
498 }
499 core->mutexes = mutexes;
500 core->slotnum = slotnum;
501 opq_ = (void*)core;
502 #endif
503 }
504
505
506 /**
507 * Destructor.
508 */
~SlottedMutex()509 SlottedMutex::~SlottedMutex() {
510 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
511 _assert_(true);
512 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
513 ::CRITICAL_SECTION* mutexes = core->mutexes;
514 size_t slotnum = core->slotnum;
515 for (size_t i = 0; i < slotnum; i++) {
516 ::DeleteCriticalSection(mutexes + i);
517 }
518 delete[] mutexes;
519 delete core;
520 #else
521 _assert_(true);
522 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
523 ::pthread_mutex_t* mutexes = core->mutexes;
524 size_t slotnum = core->slotnum;
525 for (size_t i = 0; i < slotnum; i++) {
526 ::pthread_mutex_destroy(mutexes + i);
527 }
528 delete[] mutexes;
529 delete core;
530 #endif
531 }
532
533
534 /**
535 * Get the lock of a slot.
536 */
lock(size_t idx)537 void SlottedMutex::lock(size_t idx) {
538 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
539 _assert_(true);
540 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
541 ::EnterCriticalSection(core->mutexes + idx);
542 #else
543 _assert_(true);
544 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
545 if (::pthread_mutex_lock(core->mutexes + idx) != 0)
546 throw std::runtime_error("pthread_mutex_lock");
547 #endif
548 }
549
550
551 /**
552 * Release the lock of a slot.
553 */
unlock(size_t idx)554 void SlottedMutex::unlock(size_t idx) {
555 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
556 _assert_(true);
557 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
558 ::LeaveCriticalSection(core->mutexes + idx);
559 #else
560 _assert_(true);
561 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
562 if (::pthread_mutex_unlock(core->mutexes + idx) != 0)
563 throw std::runtime_error("pthread_mutex_unlock");
564 #endif
565 }
566
567
568 /**
569 * Get the locks of all slots.
570 */
lock_all()571 void SlottedMutex::lock_all() {
572 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
573 _assert_(true);
574 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
575 ::CRITICAL_SECTION* mutexes = core->mutexes;
576 size_t slotnum = core->slotnum;
577 for (size_t i = 0; i < slotnum; i++) {
578 ::EnterCriticalSection(core->mutexes + i);
579 }
580 #else
581 _assert_(true);
582 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
583 ::pthread_mutex_t* mutexes = core->mutexes;
584 size_t slotnum = core->slotnum;
585 for (size_t i = 0; i < slotnum; i++) {
586 if (::pthread_mutex_lock(mutexes + i) != 0)
587 throw std::runtime_error("pthread_mutex_lock");
588 }
589 #endif
590 }
591
592
593 /**
594 * Release the locks of all slots.
595 */
unlock_all()596 void SlottedMutex::unlock_all() {
597 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
598 _assert_(true);
599 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
600 ::CRITICAL_SECTION* mutexes = core->mutexes;
601 size_t slotnum = core->slotnum;
602 for (size_t i = 0; i < slotnum; i++) {
603 ::LeaveCriticalSection(mutexes + i);
604 }
605 #else
606 _assert_(true);
607 SlottedMutexCore* core = (SlottedMutexCore*)opq_;
608 ::pthread_mutex_t* mutexes = core->mutexes;
609 size_t slotnum = core->slotnum;
610 for (size_t i = 0; i < slotnum; i++) {
611 if (::pthread_mutex_unlock(mutexes + i) != 0)
612 throw std::runtime_error("pthread_mutex_unlock");
613 }
614 #endif
615 }
616
617
618 /**
619 * Default constructor.
620 */
SpinLock()621 SpinLock::SpinLock() : opq_(NULL) {
622 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
623 _assert_(true);
624 #elif _KC_GCCATOMIC
625 _assert_(true);
626 #else
627 _assert_(true);
628 ::pthread_spinlock_t* spin = new ::pthread_spinlock_t;
629 if (::pthread_spin_init(spin, PTHREAD_PROCESS_PRIVATE) != 0)
630 throw std::runtime_error("pthread_spin_init");
631 opq_ = (void*)spin;
632 #endif
633 }
634
635
636 /**
637 * Destructor.
638 */
~SpinLock()639 SpinLock::~SpinLock() {
640 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
641 _assert_(true);
642 #elif _KC_GCCATOMIC
643 _assert_(true);
644 #else
645 _assert_(true);
646 ::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
647 ::pthread_spin_destroy(spin);
648 delete spin;
649 #endif
650 }
651
652
653 /**
654 * Get the lock.
655 */
lock()656 void SpinLock::lock() {
657 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
658 _assert_(true);
659 uint32_t wcnt = 0;
660 while (::InterlockedCompareExchange((LONG*)&opq_, 1, 0) != 0) {
661 if (wcnt >= LOCKBUSYLOOP) {
662 Thread::chill();
663 } else {
664 Thread::yield();
665 wcnt++;
666 }
667 }
668 #elif _KC_GCCATOMIC
669 _assert_(true);
670 uint32_t wcnt = 0;
671 while (!__sync_bool_compare_and_swap(&opq_, 0, 1)) {
672 if (wcnt >= LOCKBUSYLOOP) {
673 Thread::chill();
674 } else {
675 Thread::yield();
676 wcnt++;
677 }
678 }
679 #else
680 _assert_(true);
681 ::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
682 if (::pthread_spin_lock(spin) != 0) throw std::runtime_error("pthread_spin_lock");
683 #endif
684 }
685
686
687 /**
688 * Try to get the lock.
689 */
lock_try()690 bool SpinLock::lock_try() {
691 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
692 _assert_(true);
693 return ::InterlockedCompareExchange((LONG*)&opq_, 1, 0) == 0;
694 #elif _KC_GCCATOMIC
695 _assert_(true);
696 return __sync_bool_compare_and_swap(&opq_, 0, 1);
697 #else
698 _assert_(true);
699 ::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
700 int32_t ecode = ::pthread_spin_trylock(spin);
701 if (ecode == 0) return true;
702 if (ecode != EBUSY) throw std::runtime_error("pthread_spin_trylock");
703 return false;
704 #endif
705 }
706
707
708 /**
709 * Release the lock.
710 */
unlock()711 void SpinLock::unlock() {
712 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
713 _assert_(true);
714 ::InterlockedExchange((LONG*)&opq_, 0);
715 #elif _KC_GCCATOMIC
716 _assert_(true);
717 __sync_lock_release(&opq_);
718 #else
719 _assert_(true);
720 ::pthread_spinlock_t* spin = (::pthread_spinlock_t*)opq_;
721 if (::pthread_spin_unlock(spin) != 0) throw std::runtime_error("pthread_spin_unlock");
722 #endif
723 }
724
725
726 /**
727 * SlottedSpinLock internal.
728 */
729 struct SlottedSpinLockCore {
730 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
731 uint32_t* locks; ///< primitives
732 size_t slotnum; ///< number of slots
733 #else
734 ::pthread_spinlock_t* spins; ///< primitives
735 size_t slotnum; ///< number of slots
736 #endif
737 };
738
739
740 /**
741 * Constructor.
742 */
SlottedSpinLock(size_t slotnum)743 SlottedSpinLock::SlottedSpinLock(size_t slotnum) : opq_(NULL) {
744 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
745 _assert_(true);
746 SlottedSpinLockCore* core = new SlottedSpinLockCore;
747 uint32_t* locks = new uint32_t[slotnum];
748 for (size_t i = 0; i < slotnum; i++) {
749 locks[i] = 0;
750 }
751 core->locks = locks;
752 core->slotnum = slotnum;
753 opq_ = (void*)core;
754 #else
755 _assert_(true);
756 SlottedSpinLockCore* core = new SlottedSpinLockCore;
757 ::pthread_spinlock_t* spins = new ::pthread_spinlock_t[slotnum];
758 for (size_t i = 0; i < slotnum; i++) {
759 if (::pthread_spin_init(spins + i, PTHREAD_PROCESS_PRIVATE) != 0)
760 throw std::runtime_error("pthread_spin_init");
761 }
762 core->spins = spins;
763 core->slotnum = slotnum;
764 opq_ = (void*)core;
765 #endif
766 }
767
768
769 /**
770 * Destructor.
771 */
~SlottedSpinLock()772 SlottedSpinLock::~SlottedSpinLock() {
773 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
774 _assert_(true);
775 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
776 delete[] core->locks;
777 delete core;
778 #else
779 _assert_(true);
780 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
781 ::pthread_spinlock_t* spins = core->spins;
782 size_t slotnum = core->slotnum;
783 for (size_t i = 0; i < slotnum; i++) {
784 ::pthread_spin_destroy(spins + i);
785 }
786 delete[] spins;
787 delete core;
788 #endif
789 }
790
791
792 /**
793 * Get the lock of a slot.
794 */
lock(size_t idx)795 void SlottedSpinLock::lock(size_t idx) {
796 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
797 _assert_(true);
798 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
799 uint32_t* lock = core->locks + idx;
800 uint32_t wcnt = 0;
801 while (::InterlockedCompareExchange((LONG*)lock, 1, 0) != 0) {
802 if (wcnt >= LOCKBUSYLOOP) {
803 Thread::chill();
804 } else {
805 Thread::yield();
806 wcnt++;
807 }
808 }
809 #elif _KC_GCCATOMIC
810 _assert_(true);
811 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
812 uint32_t* lock = core->locks + idx;
813 uint32_t wcnt = 0;
814 while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
815 if (wcnt >= LOCKBUSYLOOP) {
816 Thread::chill();
817 } else {
818 Thread::yield();
819 wcnt++;
820 }
821 }
822 #else
823 _assert_(true);
824 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
825 if (::pthread_spin_lock(core->spins + idx) != 0)
826 throw std::runtime_error("pthread_spin_lock");
827 #endif
828 }
829
830
831 /**
832 * Release the lock of a slot.
833 */
unlock(size_t idx)834 void SlottedSpinLock::unlock(size_t idx) {
835 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
836 _assert_(true);
837 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
838 uint32_t* lock = core->locks + idx;
839 ::InterlockedExchange((LONG*)lock, 0);
840 #elif _KC_GCCATOMIC
841 _assert_(true);
842 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
843 uint32_t* lock = core->locks + idx;
844 __sync_lock_release(lock);
845 #else
846 _assert_(true);
847 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
848 if (::pthread_spin_unlock(core->spins + idx) != 0)
849 throw std::runtime_error("pthread_spin_unlock");
850 #endif
851 }
852
853
854 /**
855 * Get the locks of all slots.
856 */
lock_all()857 void SlottedSpinLock::lock_all() {
858 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
859 _assert_(true);
860 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
861 uint32_t* locks = core->locks;
862 size_t slotnum = core->slotnum;
863 for (size_t i = 0; i < slotnum; i++) {
864 uint32_t* lock = locks + i;
865 uint32_t wcnt = 0;
866 while (::InterlockedCompareExchange((LONG*)lock, 1, 0) != 0) {
867 if (wcnt >= LOCKBUSYLOOP) {
868 Thread::chill();
869 } else {
870 Thread::yield();
871 wcnt++;
872 }
873 }
874 }
875 #elif _KC_GCCATOMIC
876 _assert_(true);
877 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
878 uint32_t* locks = core->locks;
879 size_t slotnum = core->slotnum;
880 for (size_t i = 0; i < slotnum; i++) {
881 uint32_t* lock = locks + i;
882 uint32_t wcnt = 0;
883 while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
884 if (wcnt >= LOCKBUSYLOOP) {
885 Thread::chill();
886 } else {
887 Thread::yield();
888 wcnt++;
889 }
890 }
891 }
892 #else
893 _assert_(true);
894 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
895 ::pthread_spinlock_t* spins = core->spins;
896 size_t slotnum = core->slotnum;
897 for (size_t i = 0; i < slotnum; i++) {
898 if (::pthread_spin_lock(spins + i) != 0)
899 throw std::runtime_error("pthread_spin_lock");
900 }
901 #endif
902 }
903
904
905 /**
906 * Release the locks of all slots.
907 */
unlock_all()908 void SlottedSpinLock::unlock_all() {
909 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
910 _assert_(true);
911 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
912 uint32_t* locks = core->locks;
913 size_t slotnum = core->slotnum;
914 for (size_t i = 0; i < slotnum; i++) {
915 uint32_t* lock = locks + i;
916 ::InterlockedExchange((LONG*)lock, 0);
917 }
918 #elif _KC_GCCATOMIC
919 _assert_(true);
920 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
921 uint32_t* locks = core->locks;
922 size_t slotnum = core->slotnum;
923 for (size_t i = 0; i < slotnum; i++) {
924 uint32_t* lock = locks + i;
925 __sync_lock_release(lock);
926 }
927 #else
928 _assert_(true);
929 SlottedSpinLockCore* core = (SlottedSpinLockCore*)opq_;
930 ::pthread_spinlock_t* spins = core->spins;
931 size_t slotnum = core->slotnum;
932 for (size_t i = 0; i < slotnum; i++) {
933 if (::pthread_spin_unlock(spins + i) != 0)
934 throw std::runtime_error("pthread_spin_unlock");
935 }
936 #endif
937 }
938
939
940 /**
941 * Default constructor.
942 */
RWLock()943 RWLock::RWLock() : opq_(NULL) {
944 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
945 _assert_(true);
946 SpinRWLock* rwlock = new SpinRWLock;
947 opq_ = (void*)rwlock;
948 #else
949 _assert_(true);
950 ::pthread_rwlock_t* rwlock = new ::pthread_rwlock_t;
951 if (::pthread_rwlock_init(rwlock, NULL) != 0) throw std::runtime_error("pthread_rwlock_init");
952 opq_ = (void*)rwlock;
953 #endif
954 }
955
956
957 /**
958 * Destructor.
959 */
~RWLock()960 RWLock::~RWLock() {
961 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
962 _assert_(true);
963 SpinRWLock* rwlock = (SpinRWLock*)opq_;
964 delete rwlock;
965 #else
966 _assert_(true);
967 ::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
968 ::pthread_rwlock_destroy(rwlock);
969 delete rwlock;
970 #endif
971 }
972
973
974 /**
975 * Get the writer lock.
976 */
lock_writer()977 void RWLock::lock_writer() {
978 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
979 _assert_(true);
980 SpinRWLock* rwlock = (SpinRWLock*)opq_;
981 rwlock->lock_writer();
982 #else
983 _assert_(true);
984 ::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
985 if (::pthread_rwlock_wrlock(rwlock) != 0) throw std::runtime_error("pthread_rwlock_lock");
986 #endif
987 }
988
989
990 /**
991 * Try to get the writer lock.
992 */
lock_writer_try()993 bool RWLock::lock_writer_try() {
994 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
995 _assert_(true);
996 SpinRWLock* rwlock = (SpinRWLock*)opq_;
997 return rwlock->lock_writer_try();
998 #else
999 _assert_(true);
1000 ::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
1001 int32_t ecode = ::pthread_rwlock_trywrlock(rwlock);
1002 if (ecode == 0) return true;
1003 if (ecode != EBUSY) throw std::runtime_error("pthread_rwlock_trylock");
1004 return false;
1005 #endif
1006 }
1007
1008
1009 /**
1010 * Get a reader lock.
1011 */
lock_reader()1012 void RWLock::lock_reader() {
1013 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1014 _assert_(true);
1015 SpinRWLock* rwlock = (SpinRWLock*)opq_;
1016 rwlock->lock_reader();
1017 #else
1018 _assert_(true);
1019 ::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
1020 if (::pthread_rwlock_rdlock(rwlock) != 0) throw std::runtime_error("pthread_rwlock_lock");
1021 #endif
1022 }
1023
1024
1025 /**
1026 * Try to get a reader lock.
1027 */
lock_reader_try()1028 bool RWLock::lock_reader_try() {
1029 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1030 _assert_(true);
1031 SpinRWLock* rwlock = (SpinRWLock*)opq_;
1032 return rwlock->lock_reader_try();
1033 #else
1034 _assert_(true);
1035 ::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
1036 int32_t ecode = ::pthread_rwlock_tryrdlock(rwlock);
1037 if (ecode == 0) return true;
1038 if (ecode != EBUSY) throw std::runtime_error("pthread_rwlock_trylock");
1039 return false;
1040 #endif
1041 }
1042
1043
1044 /**
1045 * Release the lock.
1046 */
unlock()1047 void RWLock::unlock() {
1048 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1049 _assert_(true);
1050 SpinRWLock* rwlock = (SpinRWLock*)opq_;
1051 rwlock->unlock();
1052 #else
1053 _assert_(true);
1054 ::pthread_rwlock_t* rwlock = (::pthread_rwlock_t*)opq_;
1055 if (::pthread_rwlock_unlock(rwlock) != 0) throw std::runtime_error("pthread_rwlock_unlock");
1056 #endif
1057 }
1058
1059
1060 /**
1061 * SlottedRWLock internal.
1062 */
1063 struct SlottedRWLockCore {
1064 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1065 RWLock* rwlocks; ///< primitives
1066 size_t slotnum; ///< number of slots
1067 #else
1068 ::pthread_rwlock_t* rwlocks; ///< primitives
1069 size_t slotnum; ///< number of slots
1070 #endif
1071 };
1072
1073
1074 /**
1075 * Constructor.
1076 */
SlottedRWLock(size_t slotnum)1077 SlottedRWLock::SlottedRWLock(size_t slotnum) : opq_(NULL) {
1078 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1079 _assert_(true);
1080 SlottedRWLockCore* core = new SlottedRWLockCore;
1081 RWLock* rwlocks = new RWLock[slotnum];
1082 core->rwlocks = rwlocks;
1083 core->slotnum = slotnum;
1084 opq_ = (void*)core;
1085 #else
1086 _assert_(true);
1087 SlottedRWLockCore* core = new SlottedRWLockCore;
1088 ::pthread_rwlock_t* rwlocks = new ::pthread_rwlock_t[slotnum];
1089 for (size_t i = 0; i < slotnum; i++) {
1090 if (::pthread_rwlock_init(rwlocks + i, NULL) != 0)
1091 throw std::runtime_error("pthread_rwlock_init");
1092 }
1093 core->rwlocks = rwlocks;
1094 core->slotnum = slotnum;
1095 opq_ = (void*)core;
1096 #endif
1097 }
1098
1099
1100 /**
1101 * Destructor.
1102 */
~SlottedRWLock()1103 SlottedRWLock::~SlottedRWLock() {
1104 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1105 _assert_(true);
1106 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1107 delete[] core->rwlocks;
1108 delete core;
1109 #else
1110 _assert_(true);
1111 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1112 ::pthread_rwlock_t* rwlocks = core->rwlocks;
1113 size_t slotnum = core->slotnum;
1114 for (size_t i = 0; i < slotnum; i++) {
1115 ::pthread_rwlock_destroy(rwlocks + i);
1116 }
1117 delete[] rwlocks;
1118 delete core;
1119 #endif
1120 }
1121
1122
1123 /**
1124 * Get the writer lock of a slot.
1125 */
lock_writer(size_t idx)1126 void SlottedRWLock::lock_writer(size_t idx) {
1127 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1128 _assert_(true);
1129 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1130 core->rwlocks[idx].lock_writer();
1131 #else
1132 _assert_(true);
1133 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1134 if (::pthread_rwlock_wrlock(core->rwlocks + idx) != 0)
1135 throw std::runtime_error("pthread_rwlock_wrlock");
1136 #endif
1137 }
1138
1139
1140 /**
1141 * Get the reader lock of a slot.
1142 */
lock_reader(size_t idx)1143 void SlottedRWLock::lock_reader(size_t idx) {
1144 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1145 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1146 core->rwlocks[idx].lock_reader();
1147 #else
1148 _assert_(true);
1149 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1150 if (::pthread_rwlock_rdlock(core->rwlocks + idx) != 0)
1151 throw std::runtime_error("pthread_rwlock_rdlock");
1152 #endif
1153 }
1154
1155
1156 /**
1157 * Release the lock of a slot.
1158 */
unlock(size_t idx)1159 void SlottedRWLock::unlock(size_t idx) {
1160 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1161 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1162 core->rwlocks[idx].unlock();
1163 #else
1164 _assert_(true);
1165 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1166 if (::pthread_rwlock_unlock(core->rwlocks + idx) != 0)
1167 throw std::runtime_error("pthread_rwlock_unlock");
1168 #endif
1169 }
1170
1171
1172 /**
1173 * Get the writer locks of all slots.
1174 */
lock_writer_all()1175 void SlottedRWLock::lock_writer_all() {
1176 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1177 _assert_(true);
1178 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1179 RWLock* rwlocks = core->rwlocks;
1180 size_t slotnum = core->slotnum;
1181 for (size_t i = 0; i < slotnum; i++) {
1182 rwlocks[i].lock_writer();
1183 }
1184 #else
1185 _assert_(true);
1186 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1187 ::pthread_rwlock_t* rwlocks = core->rwlocks;
1188 size_t slotnum = core->slotnum;
1189 for (size_t i = 0; i < slotnum; i++) {
1190 if (::pthread_rwlock_wrlock(rwlocks + i) != 0)
1191 throw std::runtime_error("pthread_rwlock_wrlock");
1192 }
1193 #endif
1194 }
1195
1196
1197 /**
1198 * Get the reader locks of all slots.
1199 */
lock_reader_all()1200 void SlottedRWLock::lock_reader_all() {
1201 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1202 _assert_(true);
1203 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1204 RWLock* rwlocks = core->rwlocks;
1205 size_t slotnum = core->slotnum;
1206 for (size_t i = 0; i < slotnum; i++) {
1207 rwlocks[i].lock_reader();
1208 }
1209 #else
1210 _assert_(true);
1211 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1212 ::pthread_rwlock_t* rwlocks = core->rwlocks;
1213 size_t slotnum = core->slotnum;
1214 for (size_t i = 0; i < slotnum; i++) {
1215 if (::pthread_rwlock_rdlock(rwlocks + i) != 0)
1216 throw std::runtime_error("pthread_rwlock_rdlock");
1217 }
1218 #endif
1219 }
1220
1221
1222 /**
1223 * Release the locks of all slots.
1224 */
unlock_all()1225 void SlottedRWLock::unlock_all() {
1226 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1227 _assert_(true);
1228 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1229 RWLock* rwlocks = core->rwlocks;
1230 size_t slotnum = core->slotnum;
1231 for (size_t i = 0; i < slotnum; i++) {
1232 rwlocks[i].unlock();
1233 }
1234 #else
1235 _assert_(true);
1236 SlottedRWLockCore* core = (SlottedRWLockCore*)opq_;
1237 ::pthread_rwlock_t* rwlocks = core->rwlocks;
1238 size_t slotnum = core->slotnum;
1239 for (size_t i = 0; i < slotnum; i++) {
1240 if (::pthread_rwlock_unlock(rwlocks + i) != 0)
1241 throw std::runtime_error("pthread_rwlock_unlock");
1242 }
1243 #endif
1244 }
1245
1246
1247 /**
1248 * SpinRWLock internal.
1249 */
1250 struct SpinRWLockCore {
1251 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1252 LONG sem; ///< semaphore
1253 uint32_t cnt; ///< count of threads
1254 #elif _KC_GCCATOMIC
1255 int32_t sem; ///< semaphore
1256 uint32_t cnt; ///< count of threads
1257 #else
1258 ::pthread_spinlock_t sem; ///< semaphore
1259 uint32_t cnt; ///< count of threads
1260 #endif
1261 };
1262
1263
1264 /**
1265 * Lock the semephore of SpinRWLock.
1266 * @param core the internal fields.
1267 */
1268 static void spinrwlocklock(SpinRWLockCore* core);
1269
1270
1271 /**
1272 * Unlock the semephore of SpinRWLock.
1273 * @param core the internal fields.
1274 */
1275 static void spinrwlockunlock(SpinRWLockCore* core);
1276
1277
1278 /**
1279 * Default constructor.
1280 */
SpinRWLock()1281 SpinRWLock::SpinRWLock() : opq_(NULL) {
1282 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
1283 _assert_(true);
1284 SpinRWLockCore* core = new SpinRWLockCore;
1285 core->sem = 0;
1286 core->cnt = 0;
1287 opq_ = (void*)core;
1288 #else
1289 _assert_(true);
1290 SpinRWLockCore* core = new SpinRWLockCore;
1291 if (::pthread_spin_init(&core->sem, PTHREAD_PROCESS_PRIVATE) != 0)
1292 throw std::runtime_error("pthread_spin_init");
1293 core->cnt = 0;
1294 opq_ = (void*)core;
1295 #endif
1296 }
1297
1298
1299 /**
1300 * Destructor.
1301 */
~SpinRWLock()1302 SpinRWLock::~SpinRWLock() {
1303 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
1304 _assert_(true);
1305 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1306 delete core;
1307 #else
1308 _assert_(true);
1309 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1310 ::pthread_spin_destroy(&core->sem);
1311 delete core;
1312 #endif
1313 }
1314
1315
1316 /**
1317 * Get the writer lock.
1318 */
lock_writer()1319 void SpinRWLock::lock_writer() {
1320 _assert_(true);
1321 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1322 spinrwlocklock(core);
1323 uint32_t wcnt = 0;
1324 while (core->cnt > 0) {
1325 spinrwlockunlock(core);
1326 if (wcnt >= LOCKBUSYLOOP) {
1327 Thread::chill();
1328 } else {
1329 Thread::yield();
1330 wcnt++;
1331 }
1332 spinrwlocklock(core);
1333 }
1334 core->cnt = INT32MAX;
1335 spinrwlockunlock(core);
1336 }
1337
1338
1339 /**
1340 * Try to get the writer lock.
1341 */
lock_writer_try()1342 bool SpinRWLock::lock_writer_try() {
1343 _assert_(true);
1344 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1345 spinrwlocklock(core);
1346 if (core->cnt > 0) {
1347 spinrwlockunlock(core);
1348 return false;
1349 }
1350 core->cnt = INT32MAX;
1351 spinrwlockunlock(core);
1352 return true;
1353 }
1354
1355
1356 /**
1357 * Get a reader lock.
1358 */
lock_reader()1359 void SpinRWLock::lock_reader() {
1360 _assert_(true);
1361 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1362 spinrwlocklock(core);
1363 uint32_t wcnt = 0;
1364 while (core->cnt >= (uint32_t)INT32MAX) {
1365 spinrwlockunlock(core);
1366 if (wcnt >= LOCKBUSYLOOP) {
1367 Thread::chill();
1368 } else {
1369 Thread::yield();
1370 wcnt++;
1371 }
1372 spinrwlocklock(core);
1373 }
1374 core->cnt++;
1375 spinrwlockunlock(core);
1376 }
1377
1378
1379 /**
1380 * Try to get a reader lock.
1381 */
lock_reader_try()1382 bool SpinRWLock::lock_reader_try() {
1383 _assert_(true);
1384 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1385 spinrwlocklock(core);
1386 if (core->cnt >= (uint32_t)INT32MAX) {
1387 spinrwlockunlock(core);
1388 return false;
1389 }
1390 core->cnt++;
1391 spinrwlockunlock(core);
1392 return true;
1393 }
1394
1395
1396 /**
1397 * Release the lock.
1398 */
unlock()1399 void SpinRWLock::unlock() {
1400 _assert_(true);
1401 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1402 spinrwlocklock(core);
1403 if (core->cnt >= (uint32_t)INT32MAX) {
1404 core->cnt = 0;
1405 } else {
1406 core->cnt--;
1407 }
1408 spinrwlockunlock(core);
1409 }
1410
1411
1412 /**
1413 * Promote a reader lock to the writer lock.
1414 */
promote()1415 bool SpinRWLock::promote() {
1416 _assert_(true);
1417 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1418 spinrwlocklock(core);
1419 if (core->cnt > 1) {
1420 spinrwlockunlock(core);
1421 return false;
1422 }
1423 core->cnt = INT32MAX;
1424 spinrwlockunlock(core);
1425 return true;
1426 }
1427
1428
1429 /**
1430 * Demote the writer lock to a reader lock.
1431 */
demote()1432 void SpinRWLock::demote() {
1433 _assert_(true);
1434 SpinRWLockCore* core = (SpinRWLockCore*)opq_;
1435 spinrwlocklock(core);
1436 core->cnt = 1;
1437 spinrwlockunlock(core);
1438 }
1439
1440
1441 /**
1442 * Lock the semephore of SpinRWLock.
1443 */
spinrwlocklock(SpinRWLockCore * core)1444 static void spinrwlocklock(SpinRWLockCore* core) {
1445 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1446 _assert_(core);
1447 while (::InterlockedCompareExchange(&core->sem, 1, 0) != 0) {
1448 ::Sleep(0);
1449 }
1450 #elif _KC_GCCATOMIC
1451 _assert_(core);
1452 while (!__sync_bool_compare_and_swap(&core->sem, 0, 1)) {
1453 ::sched_yield();
1454 }
1455 #else
1456 _assert_(core);
1457 if (::pthread_spin_lock(&core->sem) != 0) throw std::runtime_error("pthread_spin_lock");
1458 #endif
1459 }
1460
1461
1462 /**
1463 * Unlock the semephore of SpinRWLock.
1464 */
spinrwlockunlock(SpinRWLockCore * core)1465 static void spinrwlockunlock(SpinRWLockCore* core) {
1466 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1467 _assert_(core);
1468 ::InterlockedExchange(&core->sem, 0);
1469 #elif _KC_GCCATOMIC
1470 _assert_(core);
1471 __sync_lock_release(&core->sem);
1472 #else
1473 _assert_(core);
1474 if (::pthread_spin_unlock(&core->sem) != 0) throw std::runtime_error("pthread_spin_unlock");
1475 #endif
1476 }
1477
1478
1479 /**
1480 * SlottedRWLock internal.
1481 */
1482 struct SlottedSpinRWLockCore {
1483 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1484 LONG sems[LOCKSEMNUM]; ///< semaphores
1485 #elif _KC_GCCATOMIC
1486 int32_t sems[LOCKSEMNUM]; ///< semaphores
1487 #else
1488 ::pthread_spinlock_t sems[LOCKSEMNUM]; ///< semaphores
1489 #endif
1490 uint32_t* cnts; ///< counts of threads
1491 size_t slotnum; ///< number of slots
1492 };
1493
1494
1495 /**
1496 * Lock the semephore of SlottedSpinRWLock.
1497 * @param core the internal fields.
1498 * @param idx the index of the semaphoe.
1499 */
1500 static void slottedspinrwlocklock(SlottedSpinRWLockCore* core, size_t idx);
1501
1502
1503 /**
1504 * Unlock the semephore of SlottedSpinRWLock.
1505 * @param core the internal fields.
1506 * @param idx the index of the semaphoe.
1507 */
1508 static void slottedspinrwlockunlock(SlottedSpinRWLockCore* core, size_t idx);
1509
1510
1511 /**
1512 * Constructor.
1513 */
SlottedSpinRWLock(size_t slotnum)1514 SlottedSpinRWLock::SlottedSpinRWLock(size_t slotnum) : opq_(NULL) {
1515 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1516 SlottedSpinRWLockCore* core = new SlottedSpinRWLockCore;
1517 LONG* sems = core->sems;
1518 uint32_t* cnts = new uint32_t[slotnum];
1519 for (size_t i = 0; i < LOCKSEMNUM; i++) {
1520 sems[i] = 0;
1521 }
1522 for (size_t i = 0; i < slotnum; i++) {
1523 cnts[i] = 0;
1524 }
1525 core->cnts = cnts;
1526 core->slotnum = slotnum;
1527 opq_ = (void*)core;
1528 #elif _KC_GCCATOMIC
1529 SlottedSpinRWLockCore* core = new SlottedSpinRWLockCore;
1530 int32_t* sems = core->sems;
1531 uint32_t* cnts = new uint32_t[slotnum];
1532 for (size_t i = 0; i < LOCKSEMNUM; i++) {
1533 sems[i] = 0;
1534 }
1535 for (size_t i = 0; i < slotnum; i++) {
1536 cnts[i] = 0;
1537 }
1538 core->cnts = cnts;
1539 core->slotnum = slotnum;
1540 opq_ = (void*)core;
1541 #else
1542 _assert_(true);
1543 SlottedSpinRWLockCore* core = new SlottedSpinRWLockCore;
1544 ::pthread_spinlock_t* sems = core->sems;
1545 uint32_t* cnts = new uint32_t[slotnum];
1546 for (size_t i = 0; i < LOCKSEMNUM; i++) {
1547 if (::pthread_spin_init(sems + i, PTHREAD_PROCESS_PRIVATE) != 0)
1548 throw std::runtime_error("pthread_spin_init");
1549 }
1550 for (size_t i = 0; i < slotnum; i++) {
1551 cnts[i] = 0;
1552 }
1553 core->cnts = cnts;
1554 core->slotnum = slotnum;
1555 opq_ = (void*)core;
1556 #endif
1557 }
1558
1559
1560 /**
1561 * Destructor.
1562 */
~SlottedSpinRWLock()1563 SlottedSpinRWLock::~SlottedSpinRWLock() {
1564 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) || _KC_GCCATOMIC
1565 _assert_(true);
1566 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1567 delete[] core->cnts;
1568 delete core;
1569 #else
1570 _assert_(true);
1571 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1572 ::pthread_spinlock_t* sems = core->sems;
1573 for (size_t i = 0; i < LOCKSEMNUM; i++) {
1574 ::pthread_spin_destroy(sems + i);
1575 }
1576 delete[] core->cnts;
1577 delete core;
1578 #endif
1579 }
1580
1581
1582 /**
1583 * Get the writer lock of a slot.
1584 */
lock_writer(size_t idx)1585 void SlottedSpinRWLock::lock_writer(size_t idx) {
1586 _assert_(true);
1587 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1588 size_t semidx = idx % LOCKSEMNUM;
1589 slottedspinrwlocklock(core, semidx);
1590 uint32_t wcnt = 0;
1591 while (core->cnts[idx] > 0) {
1592 slottedspinrwlockunlock(core, semidx);
1593 if (wcnt >= LOCKBUSYLOOP) {
1594 Thread::chill();
1595 } else {
1596 Thread::yield();
1597 wcnt++;
1598 }
1599 slottedspinrwlocklock(core, semidx);
1600 }
1601 core->cnts[idx] = INT32MAX;
1602 slottedspinrwlockunlock(core, semidx);
1603 }
1604
1605
1606 /**
1607 * Get the reader lock of a slot.
1608 */
lock_reader(size_t idx)1609 void SlottedSpinRWLock::lock_reader(size_t idx) {
1610 _assert_(true);
1611 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1612 size_t semidx = idx % LOCKSEMNUM;
1613 slottedspinrwlocklock(core, semidx);
1614 uint32_t wcnt = 0;
1615 while (core->cnts[idx] >= (uint32_t)INT32MAX) {
1616 slottedspinrwlockunlock(core, semidx);
1617 if (wcnt >= LOCKBUSYLOOP) {
1618 Thread::chill();
1619 } else {
1620 Thread::yield();
1621 wcnt++;
1622 }
1623 slottedspinrwlocklock(core, semidx);
1624 }
1625 core->cnts[idx]++;
1626 slottedspinrwlockunlock(core, semidx);
1627 }
1628
1629
1630 /**
1631 * Release the lock of a slot.
1632 */
unlock(size_t idx)1633 void SlottedSpinRWLock::unlock(size_t idx) {
1634 _assert_(true);
1635 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1636 size_t semidx = idx % LOCKSEMNUM;
1637 slottedspinrwlocklock(core, semidx);
1638 if (core->cnts[idx] >= (uint32_t)INT32MAX) {
1639 core->cnts[idx] = 0;
1640 } else {
1641 core->cnts[idx]--;
1642 }
1643 slottedspinrwlockunlock(core, semidx);
1644 }
1645
1646
1647 /**
1648 * Get the writer locks of all slots.
1649 */
lock_writer_all()1650 void SlottedSpinRWLock::lock_writer_all() {
1651 _assert_(true);
1652 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1653 uint32_t* cnts = core->cnts;
1654 size_t slotnum = core->slotnum;
1655 for (size_t i = 0; i < slotnum; i++) {
1656 size_t semidx = i % LOCKSEMNUM;
1657 slottedspinrwlocklock(core, semidx);
1658 uint32_t wcnt = 0;
1659 while (cnts[i] > 0) {
1660 slottedspinrwlockunlock(core, semidx);
1661 if (wcnt >= LOCKBUSYLOOP) {
1662 Thread::chill();
1663 } else {
1664 Thread::yield();
1665 wcnt++;
1666 }
1667 slottedspinrwlocklock(core, semidx);
1668 }
1669 cnts[i] = INT32MAX;
1670 slottedspinrwlockunlock(core, semidx);
1671 }
1672 }
1673
1674
1675 /**
1676 * Get the reader locks of all slots.
1677 */
lock_reader_all()1678 void SlottedSpinRWLock::lock_reader_all() {
1679 _assert_(true);
1680 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1681 uint32_t* cnts = core->cnts;
1682 size_t slotnum = core->slotnum;
1683 for (size_t i = 0; i < slotnum; i++) {
1684 size_t semidx = i % LOCKSEMNUM;
1685 slottedspinrwlocklock(core, semidx);
1686 uint32_t wcnt = 0;
1687 while (cnts[i] >= (uint32_t)INT32MAX) {
1688 slottedspinrwlockunlock(core, semidx);
1689 if (wcnt >= LOCKBUSYLOOP) {
1690 Thread::chill();
1691 } else {
1692 Thread::yield();
1693 wcnt++;
1694 }
1695 slottedspinrwlocklock(core, semidx);
1696 }
1697 cnts[i]++;
1698 slottedspinrwlockunlock(core, semidx);
1699 }
1700 }
1701
1702
1703 /**
1704 * Release the locks of all slots.
1705 */
unlock_all()1706 void SlottedSpinRWLock::unlock_all() {
1707 _assert_(true);
1708 SlottedSpinRWLockCore* core = (SlottedSpinRWLockCore*)opq_;
1709 uint32_t* cnts = core->cnts;
1710 size_t slotnum = core->slotnum;
1711 for (size_t i = 0; i < slotnum; i++) {
1712 size_t semidx = i % LOCKSEMNUM;
1713 slottedspinrwlocklock(core, semidx);
1714 if (cnts[i] >= (uint32_t)INT32MAX) {
1715 cnts[i] = 0;
1716 } else {
1717 cnts[i]--;
1718 }
1719 slottedspinrwlockunlock(core, semidx);
1720 }
1721 }
1722
1723
1724 /**
1725 * Lock the semephore of SlottedSpinRWLock.
1726 */
slottedspinrwlocklock(SlottedSpinRWLockCore * core,size_t idx)1727 static void slottedspinrwlocklock(SlottedSpinRWLockCore* core, size_t idx) {
1728 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1729 _assert_(core);
1730 while (::InterlockedCompareExchange(core->sems + idx, 1, 0) != 0) {
1731 ::Sleep(0);
1732 }
1733 #elif _KC_GCCATOMIC
1734 _assert_(core);
1735 while (!__sync_bool_compare_and_swap(core->sems + idx, 0, 1)) {
1736 ::sched_yield();
1737 }
1738 #else
1739 _assert_(core);
1740 if (::pthread_spin_lock(core->sems + idx) != 0) throw std::runtime_error("pthread_spin_lock");
1741 #endif
1742 }
1743
1744
1745 /**
1746 * Unlock the semephore of SlottedSpinRWLock.
1747 */
slottedspinrwlockunlock(SlottedSpinRWLockCore * core,size_t idx)1748 static void slottedspinrwlockunlock(SlottedSpinRWLockCore* core, size_t idx) {
1749 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1750 _assert_(core);
1751 ::InterlockedExchange(core->sems + idx, 0);
1752 #elif _KC_GCCATOMIC
1753 _assert_(core);
1754 __sync_lock_release(core->sems + idx);
1755 #else
1756 _assert_(core);
1757 if (::pthread_spin_unlock(core->sems + idx) != 0)
1758 throw std::runtime_error("pthread_spin_unlock");
1759 #endif
1760 }
1761
1762
1763 /**
1764 * Default constructor.
1765 */
CondVar()1766 CondVar::CondVar() : opq_(NULL) {
1767 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1768 _assert_(true);
1769 CondVarCore* core = new CondVarCore;
1770 ::InitializeCriticalSection(&core->mutex);
1771 core->wait = 0;
1772 core->wake = 0;
1773 core->sev = ::CreateEvent(NULL, true, false, NULL);
1774 if (!core->sev) throw std::runtime_error("CreateEvent");
1775 core->fev = ::CreateEvent(NULL, false, false, NULL);
1776 if (!core->fev) throw std::runtime_error("CreateEvent");
1777 opq_ = (void*)core;
1778 #else
1779 _assert_(true);
1780 CondVarCore* core = new CondVarCore;
1781 if (::pthread_cond_init(&core->cond, NULL) != 0)
1782 throw std::runtime_error("pthread_cond_init");
1783 opq_ = (void*)core;
1784 #endif
1785 }
1786
1787
1788 /**
1789 * Destructor.
1790 */
~CondVar()1791 CondVar::~CondVar() {
1792 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1793 _assert_(true);
1794 CondVarCore* core = (CondVarCore*)opq_;
1795 ::CloseHandle(core->fev);
1796 ::CloseHandle(core->sev);
1797 ::DeleteCriticalSection(&core->mutex);
1798 #else
1799 _assert_(true);
1800 CondVarCore* core = (CondVarCore*)opq_;
1801 ::pthread_cond_destroy(&core->cond);
1802 delete core;
1803 #endif
1804 }
1805
1806
1807 /**
1808 * Wait for the signal.
1809 */
wait(Mutex * mutex)1810 void CondVar::wait(Mutex* mutex) {
1811 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1812 _assert_(mutex);
1813 CondVarCore* core = (CondVarCore*)opq_;
1814 ::CRITICAL_SECTION* mymutex = (::CRITICAL_SECTION*)mutex->opq_;
1815 ::EnterCriticalSection(&core->mutex);
1816 core->wait++;
1817 ::LeaveCriticalSection(&core->mutex);
1818 ::LeaveCriticalSection(mymutex);
1819 while (true) {
1820 ::WaitForSingleObject(core->sev, INFINITE);
1821 ::EnterCriticalSection(&core->mutex);
1822 if (core->wake > 0) {
1823 core->wait--;
1824 core->wake--;
1825 if (core->wake < 1) {
1826 ::ResetEvent(core->sev);
1827 ::SetEvent(core->fev);
1828 }
1829 ::LeaveCriticalSection(&core->mutex);
1830 break;
1831 }
1832 ::LeaveCriticalSection(&core->mutex);
1833 }
1834 ::EnterCriticalSection(mymutex);
1835 #else
1836 _assert_(mutex);
1837 CondVarCore* core = (CondVarCore*)opq_;
1838 ::pthread_mutex_t* mymutex = (::pthread_mutex_t*)mutex->opq_;
1839 if (::pthread_cond_wait(&core->cond, mymutex) != 0)
1840 throw std::runtime_error("pthread_cond_wait");
1841 #endif
1842 }
1843
1844
1845 /**
1846 * Wait for the signal.
1847 */
wait(Mutex * mutex,double sec)1848 bool CondVar::wait(Mutex* mutex, double sec) {
1849 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1850 _assert_(mutex && sec >= 0);
1851 if (sec <= 0) return false;
1852 CondVarCore* core = (CondVarCore*)opq_;
1853 ::CRITICAL_SECTION* mymutex = (::CRITICAL_SECTION*)mutex->opq_;
1854 ::EnterCriticalSection(&core->mutex);
1855 core->wait++;
1856 ::LeaveCriticalSection(&core->mutex);
1857 ::LeaveCriticalSection(mymutex);
1858 while (true) {
1859 if (::WaitForSingleObject(core->sev, sec * 1000) == WAIT_TIMEOUT) {
1860 ::EnterCriticalSection(&core->mutex);
1861 if (::WaitForSingleObject(core->sev, 0) == WAIT_TIMEOUT) {
1862 core->wait--;
1863 ::SetEvent(core->fev);
1864 ::LeaveCriticalSection(&core->mutex);
1865 ::EnterCriticalSection(mymutex);
1866 return false;
1867 }
1868 ::LeaveCriticalSection(&core->mutex);
1869 }
1870 ::EnterCriticalSection(&core->mutex);
1871 if (core->wake > 0) {
1872 core->wait--;
1873 core->wake--;
1874 if (core->wake < 1) {
1875 ::ResetEvent(core->sev);
1876 ::SetEvent(core->fev);
1877 }
1878 ::LeaveCriticalSection(&core->mutex);
1879 break;
1880 }
1881 ::LeaveCriticalSection(&core->mutex);
1882 }
1883 ::EnterCriticalSection(mymutex);
1884 return true;
1885 #else
1886 _assert_(mutex && sec >= 0);
1887 if (sec <= 0) return false;
1888 CondVarCore* core = (CondVarCore*)opq_;
1889 ::pthread_mutex_t* mymutex = (::pthread_mutex_t*)mutex->opq_;
1890 struct ::timeval tv;
1891 struct ::timespec ts;
1892 if (::gettimeofday(&tv, NULL) == 0) {
1893 double integ;
1894 double fract = std::modf(sec, &integ);
1895 ts.tv_sec = tv.tv_sec + (time_t)integ;
1896 ts.tv_nsec = (long)(tv.tv_usec * 1000.0 + fract * 999999000);
1897 if (ts.tv_nsec >= 1000000000) {
1898 ts.tv_nsec -= 1000000000;
1899 ts.tv_sec++;
1900 }
1901 } else {
1902 ts.tv_sec = std::time(NULL) + 1;
1903 ts.tv_nsec = 0;
1904 }
1905 int32_t ecode = ::pthread_cond_timedwait(&core->cond, mymutex, &ts);
1906 if (ecode == 0) return true;
1907 if (ecode != ETIMEDOUT && ecode != EINTR)
1908 throw std::runtime_error("pthread_cond_timedwait");
1909 return false;
1910 #endif
1911 }
1912
1913
1914 /**
1915 * Send the wake-up signal to another waiting thread.
1916 */
signal()1917 void CondVar::signal() {
1918 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1919 _assert_(true);
1920 CondVarCore* core = (CondVarCore*)opq_;
1921 ::EnterCriticalSection(&core->mutex);
1922 if (core->wait > 0) {
1923 core->wake = 1;
1924 ::SetEvent(core->sev);
1925 ::LeaveCriticalSection(&core->mutex);
1926 ::WaitForSingleObject(core->fev, INFINITE);
1927 } else {
1928 ::LeaveCriticalSection(&core->mutex);
1929 }
1930 #else
1931 _assert_(true);
1932 CondVarCore* core = (CondVarCore*)opq_;
1933 if (::pthread_cond_signal(&core->cond) != 0)
1934 throw std::runtime_error("pthread_cond_signal");
1935 #endif
1936 }
1937
1938
1939 /**
1940 * Send the wake-up signals to all waiting threads.
1941 */
broadcast()1942 void CondVar::broadcast() {
1943 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1944 _assert_(true);
1945 CondVarCore* core = (CondVarCore*)opq_;
1946 ::EnterCriticalSection(&core->mutex);
1947 if (core->wait > 0) {
1948 core->wake = core->wait;
1949 ::SetEvent(core->sev);
1950 ::LeaveCriticalSection(&core->mutex);
1951 ::WaitForSingleObject(core->fev, INFINITE);
1952 } else {
1953 ::LeaveCriticalSection(&core->mutex);
1954 }
1955 #else
1956 _assert_(true);
1957 CondVarCore* core = (CondVarCore*)opq_;
1958 if (::pthread_cond_broadcast(&core->cond) != 0)
1959 throw std::runtime_error("pthread_cond_broadcast");
1960 #endif
1961 }
1962
1963
1964 /**
1965 * Default constructor.
1966 */
TSDKey()1967 TSDKey::TSDKey() : opq_(NULL) {
1968 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1969 _assert_(true);
1970 ::DWORD key = ::TlsAlloc();
1971 if (key == 0xFFFFFFFF) throw std::runtime_error("TlsAlloc");
1972 opq_ = (void*)key;
1973 #else
1974 _assert_(true);
1975 ::pthread_key_t* key = new ::pthread_key_t;
1976 if (::pthread_key_create(key, NULL) != 0)
1977 throw std::runtime_error("pthread_key_create");
1978 opq_ = (void*)key;
1979 #endif
1980 }
1981
1982
1983 /**
1984 * Constructor with the specifications.
1985 */
TSDKey(void (* dstr)(void *))1986 TSDKey::TSDKey(void (*dstr)(void*)) : opq_(NULL) {
1987 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
1988 _assert_(true);
1989 ::DWORD key = ::TlsAlloc();
1990 if (key == 0xFFFFFFFF) throw std::runtime_error("TlsAlloc");
1991 opq_ = (void*)key;
1992 #else
1993 _assert_(true);
1994 ::pthread_key_t* key = new ::pthread_key_t;
1995 if (::pthread_key_create(key, dstr) != 0)
1996 throw std::runtime_error("pthread_key_create");
1997 opq_ = (void*)key;
1998 #endif
1999 }
2000
2001
2002 /**
2003 * Destructor.
2004 */
~TSDKey()2005 TSDKey::~TSDKey() {
2006 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2007 _assert_(true);
2008 ::DWORD key = (::DWORD)opq_;
2009 ::TlsFree(key);
2010 #else
2011 _assert_(true);
2012 ::pthread_key_t* key = (::pthread_key_t*)opq_;
2013 ::pthread_key_delete(*key);
2014 delete key;
2015 #endif
2016 }
2017
2018
2019 /**
2020 * Set the value.
2021 */
set(void * ptr)2022 void TSDKey::set(void* ptr) {
2023 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2024 _assert_(true);
2025 ::DWORD key = (::DWORD)opq_;
2026 if (!::TlsSetValue(key, ptr)) std::runtime_error("TlsSetValue");
2027 #else
2028 _assert_(true);
2029 ::pthread_key_t* key = (::pthread_key_t*)opq_;
2030 if (::pthread_setspecific(*key, ptr) != 0)
2031 throw std::runtime_error("pthread_setspecific");
2032 #endif
2033 }
2034
2035
2036 /**
2037 * Get the value.
2038 */
get() const2039 void* TSDKey::get() const {
2040 #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_)
2041 _assert_(true);
2042 ::DWORD key = (::DWORD)opq_;
2043 return ::TlsGetValue(key);
2044 #else
2045 _assert_(true);
2046 ::pthread_key_t* key = (::pthread_key_t*)opq_;
2047 return ::pthread_getspecific(*key);
2048 #endif
2049 }
2050
2051
2052 /**
2053 * Set the new value.
2054 */
set(int64_t val)2055 int64_t AtomicInt64::set(int64_t val) {
2056 #if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
2057 _assert_(true);
2058 return ::InterlockedExchange((uint64_t*)&value_, val);
2059 #elif _KC_GCCATOMIC
2060 _assert_(true);
2061 int64_t oval = __sync_lock_test_and_set(&value_, val);
2062 __sync_synchronize();
2063 return oval;
2064 #else
2065 _assert_(true);
2066 lock_.lock();
2067 int64_t oval = value_;
2068 value_ = val;
2069 lock_.unlock();
2070 return oval;
2071 #endif
2072 }
2073
2074
2075 /**
2076 * Add a value.
2077 */
add(int64_t val)2078 int64_t AtomicInt64::add(int64_t val) {
2079 #if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
2080 _assert_(true);
2081 return ::InterlockedExchangeAdd((uint64_t*)&value_, val);
2082 #elif _KC_GCCATOMIC
2083 _assert_(true);
2084 int64_t oval = __sync_fetch_and_add(&value_, val);
2085 __sync_synchronize();
2086 return oval;
2087 #else
2088 _assert_(true);
2089 lock_.lock();
2090 int64_t oval = value_;
2091 value_ += val;
2092 lock_.unlock();
2093 return oval;
2094 #endif
2095 }
2096
2097
2098 /**
2099 * Perform compare-and-swap.
2100 */
cas(int64_t oval,int64_t nval)2101 bool AtomicInt64::cas(int64_t oval, int64_t nval) {
2102 #if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
2103 _assert_(true);
2104 return ::InterlockedCompareExchange((uint64_t*)&value_, nval, oval) == oval;
2105 #elif _KC_GCCATOMIC
2106 _assert_(true);
2107 bool rv = __sync_bool_compare_and_swap(&value_, oval, nval);
2108 __sync_synchronize();
2109 return rv;
2110 #else
2111 _assert_(true);
2112 bool rv = false;
2113 lock_.lock();
2114 if (value_ == oval) {
2115 value_ = nval;
2116 rv = true;
2117 }
2118 lock_.unlock();
2119 return rv;
2120 #endif
2121 }
2122
2123
2124 /**
2125 * Get the current value.
2126 */
get() const2127 int64_t AtomicInt64::get() const {
2128 #if (defined(_SYS_MSVC_) || defined(_SYS_MINGW_)) && defined(_SYS_WIN64_)
2129 _assert_(true);
2130 return ::InterlockedExchangeAdd((uint64_t*)&value_, 0);
2131 #elif _KC_GCCATOMIC
2132 _assert_(true);
2133 return __sync_fetch_and_add((int64_t*)&value_, 0);
2134 #else
2135 _assert_(true);
2136 lock_.lock();
2137 int64_t oval = value_;
2138 lock_.unlock();
2139 return oval;
2140 #endif
2141 }
2142
2143
2144 } // common namespace
2145
2146 // END OF FILE
2147