00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __SYNC_H__
00012 #define __SYNC_H__
00013
00014 BEGIN_GIGABASE_NAMESPACE
00015
00016 #if defined(_WIN32) && !defined(__SYMBIAN32__)
00017
00018 class GIGABASE_DLL_ENTRY dbMutex {
00019 CRITICAL_SECTION cs;
00020 bool initialized;
00021 public:
00022 dbMutex() {
00023 InitializeCriticalSection(&cs);
00024 initialized = true;
00025 }
00026 ~dbMutex() {
00027 DeleteCriticalSection(&cs);
00028 initialized = false;
00029 }
00030 bool isInitialized() {
00031 return initialized;
00032 }
00033 void lock() {
00034 if (initialized) {
00035 EnterCriticalSection(&cs);
00036 }
00037 }
00038 void unlock() {
00039 if (initialized) {
00040 LeaveCriticalSection(&cs);
00041 }
00042 }
00043 };
00044
00045 #define thread_proc WINAPI
00046
00047 class GIGABASE_DLL_ENTRY dbThread {
00048 HANDLE h;
00049 public:
00050 enum ThreadPriority {
00051 THR_PRI_LOW,
00052 THR_PRI_HIGH
00053 };
00054
00055 void setPriority(ThreadPriority pri) {
00056 SetThreadPriority(h, pri == THR_PRI_LOW ? THREAD_PRIORITY_IDLE : THREAD_PRIORITY_HIGHEST);
00057 }
00058
00059 static void sleep(time_t sec) {
00060 Sleep((DWORD)(sec*1000));
00061 }
00062
00063 typedef void (thread_proc* thread_proc_t)(void*);
00064
00065 void create(thread_proc_t f, void* arg) {
00066 DWORD threadid;
00067 h = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(f), arg, 0, &threadid);
00068 }
00069 void join() {
00070 WaitForSingleObject(h, INFINITE);
00071 CloseHandle(h);
00072 h = NULL;
00073 }
00074 void detach() {
00075 if (h != NULL) {
00076 CloseHandle(h);
00077 h = NULL;
00078 }
00079 }
00080 dbThread() {
00081 h = NULL;
00082 }
00083 ~dbThread() {
00084 if (h != NULL) {
00085 CloseHandle(h);
00086 }
00087 }
00088 static int numberOfProcessors() {
00089 SYSTEM_INFO sysinfo;
00090 GetSystemInfo(&sysinfo);
00091 return sysinfo.dwNumberOfProcessors;
00092 }
00093 };
00094
00095 const int dbMaxSemValue = 1000000;
00096
00097
00098 class GIGABASE_DLL_ENTRY dbSemaphore {
00099 HANDLE s;
00100 public:
00101 void wait(dbMutex& mutex, time_t timeout = INFINITE) {
00102 mutex.unlock();
00103 int rc = WaitForSingleObject(s, (DWORD)(timeout == (time_t)INFINITE ? timeout : timeout*1000));
00104 assert(rc == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT);
00105 mutex.lock();
00106 }
00107 void signal(unsigned inc = 1) {
00108 if (inc != 0) {
00109 ReleaseSemaphore(s, inc, NULL);
00110 }
00111 }
00112 void open(unsigned initValue = 0) {
00113 s = CreateSemaphore(NULL, initValue, dbMaxSemValue, NULL);
00114 assert(s != NULL);
00115 }
00116 void close() {
00117 CloseHandle(s);
00118 }
00119 dbSemaphore() {
00120 s = NULL;
00121 }
00122 };
00123
00124 class GIGABASE_DLL_ENTRY dbEvent {
00125 HANDLE e;
00126 int nWaitingThreads;
00127 int nPulses;
00128 public:
00129 void wait(dbMutex& mutex, time_t timeout = INFINITE) {
00130 nWaitingThreads += 1;
00131 mutex.unlock();
00132 int rc = WaitForSingleObject(e, (DWORD)(timeout == (time_t)INFINITE ? timeout : timeout*1000));
00133 assert(rc == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT);
00134 mutex.lock();
00135 nWaitingThreads -= 1;
00136 if (nPulses > 0) {
00137 nPulses -= 1;
00138 ResetEvent(e);
00139 }
00140 }
00141 void signal() {
00142 SetEvent(e);
00143 }
00144 void reset() {
00145 ResetEvent(e);
00146 }
00147 void pulse() {
00148 if (nWaitingThreads > 0) {
00149 nPulses += 1;
00150 SetEvent(e);
00151 }
00152 }
00153 void open(bool initValue = false) {
00154 e = CreateEvent(NULL, true, initValue, NULL);
00155 nWaitingThreads = 0;
00156 nPulses = 0;
00157 }
00158 void close() {
00159 CloseHandle(e);
00160 }
00161 dbEvent() {
00162 e = NULL;
00163 }
00164 };
00165
00166 template<class T>
00167 class dbThreadContext {
00168 int index;
00169 public:
00170 T* get() {
00171 return (T*)TlsGetValue(index);
00172 }
00173 void set(T* value) {
00174 TlsSetValue(index, value);
00175 }
00176 dbThreadContext() {
00177 index = TlsAlloc();
00178 assert(index != (int)TLS_OUT_OF_INDEXES);
00179 }
00180 ~dbThreadContext() {
00181 TlsFree(index);
00182 }
00183 };
00184
00185 #else // Unix
00186
00187 #define thread_proc
00188
00189 #if defined(NO_PTHREADS)
00190
00191 class dbMutex {
00192 bool initialized;
00193
00194 public:
00195 dbMutex() {
00196 initialized = true;
00197 }
00198
00199 ~dbMutex() {
00200 initialized = false;
00201 }
00202
00203 bool isInitialized() {
00204 return initialized;
00205 }
00206
00207 void lock() {}
00208 void unlock() {}
00209 };
00210
00211 class dbThread {
00212 public:
00213 typedef void (thread_proc* thread_proc_t)(void*);
00214 void create(thread_proc_t f, void* arg) { f(arg); }
00215 void join() {}
00216 void detach() {}
00217
00218 enum ThreadPriority {
00219 THR_PRI_LOW,
00220 THR_PRI_HIGH
00221 };
00222 void setPriority(ThreadPriority) {}
00223
00224 static int numberOfProcessors() { return 1; }
00225 };
00226
00227 class dbSemaphore {
00228 int count;
00229 public:
00230 void wait(dbMutex&, time_t=0) {
00231 assert (count > 0);
00232 count -= 1;
00233 }
00234 void signal(unsigned inc = 1) {
00235 count += inc;
00236 }
00237 void open(unsigned initValue = 0) {
00238 count = initValue;
00239 }
00240 void close() {}
00241 };
00242
00243 class dbEvent {
00244 bool signaled;
00245 public:
00246 void wait(dbMutex&, time_t=0) {
00247 assert(signaled);
00248 }
00249 void signal() {
00250 signaled = true;
00251 }
00252 void reset() {
00253 signaled = false;
00254 }
00255 void open(bool initValue = false) {
00256 signaled = initValue;
00257 }
00258 void pulse() {}
00259 void close() {}
00260 };
00261
00262 template<class T>
00263 class dbThreadContext {
00264 T* value;
00265 public:
00266 T* get() {
00267 return value;
00268 }
00269 void set(T* value) {
00270 this->value = value;
00271 }
00272 dbThreadContext() { value = NULL; }
00273 };
00274
00275 #elif defined(__SYMBIAN32__)
00276
00277 class dbMutex
00278 {
00279 friend class dbEvent;
00280 friend class dbSemaphore;
00281 RMutex cs;
00282 bool initialized;
00283 public:
00284 dbMutex() {
00285 int rc = cs.CreateLocal();
00286 assert(rc == KErrNone);
00287 initialized = true;
00288 }
00289 ~dbMutex() {
00290 cs.Close();
00291 initialized = false;
00292 }
00293 bool isInitialized() {
00294 return initialized;
00295 }
00296 void lock() {
00297 if (initialized) {
00298 cs.Wait();
00299 }
00300 }
00301 void unlock() {
00302 if (initialized) {
00303 cs.Signal();
00304 }
00305 }
00306 };
00307
00308 class dbThread
00309 {
00310 RThread thread;
00311 static TInt count;
00312 public:
00313 static size_t heapMinSize;
00314 static size_t heapMaxSize;
00315 static size_t stackSize;
00316
00317 typedef void (thread_proc* thread_proc_t)(void*);
00318 void create(thread_proc_t f, void* arg) {
00319 TBuf<16> name;
00320 name.Format(_L("%d"), User::LockedInc(count));
00321 int rc = thread.Create(name, (TThreadFunction)f, stackSize, heapMinSize, heapMaxSize, arg);
00322 assert(rc == KErrNone);
00323 }
00324
00325 void join() {
00326 TRequestStatus status;
00327 thread.Rendezvous(status);
00328 status.Int();
00329 }
00330 void detach() {}
00331
00332 enum ThreadPriority {
00333 THR_PRI_LOW,
00334 THR_PRI_HIGH
00335 };
00336
00337 void setPriority(ThreadPriority pri) {
00338 thread.SetPriority(pri == THR_PRI_LOW ? EPriorityLess : EPriorityMore);
00339 }
00340
00341 static int numberOfProcessors() { return 1; }
00342 };
00343
00344 class dbEvent
00345 {
00346 RCondVar cond;
00347 int signaled;
00348 long n_signals;
00349
00350 public:
00351 void wait(dbMutex& mutex) {
00352 long before_n_signals = n_signals;
00353 while (!signaled && n_signals == before_n_signals) {
00354 int rc = cond.Wait(mutex.cs);
00355 assert(rc == KErrNone);
00356 }
00357 }
00358
00359 bool wait(dbMutex& mutex, time_t timeout) {
00360 if (!signaled) {
00361 long before_n_signals = n_signals;
00362 do {
00363 int rc = cond.TimedWait(mutex.cs, timeout*1000000);
00364 if (rc == KErrTimedOut) {
00365 return false;
00366 }
00367 assert(rc == KErrNone);
00368 } while (!signaled && n_signals == before_n_signals);
00369 }
00370 return true;
00371 }
00372
00373 void signal() {
00374 signaled = true;
00375 n_signals += 1;
00376 cond.Broadcast();
00377 }
00378
00379 void pulse() {
00380 n_signals += 1;
00381 cond.Broadcast();
00382 }
00383
00384 void reset() {
00385 signaled = false;
00386 }
00387 void open(bool initValue = false) {
00388 signaled = initValue;
00389 n_signals = 0;
00390 int rc = cond.CreateLocal();
00391 assert(rc == KErrNone);
00392 }
00393 void close() {
00394 cond.Close();
00395 }
00396 };
00397
00398 class dbSemaphore {
00399 RCondVar cond;
00400 int count;
00401 public:
00402 void wait(dbMutex& mutex) {
00403 while (count == 0) {
00404 int rc = cond.Wait(mutex.cs);
00405 assert(rc == KErrNone);
00406 }
00407 count -= 1;
00408 }
00409
00410 bool wait(dbMutex& mutex, time_t timeout) {
00411 if (count == 0) {
00412 do {
00413 int rc = cond.TimedWait(mutex.cs, timeout*1000000);
00414 if (rc == KErrTimedOut) {
00415 return false;
00416 }
00417 assert(rc == KErrNone);
00418 } while (count == 0);
00419 }
00420 count -= 1;
00421 return true;
00422 }
00423
00424 void signal(unsigned inc = 1) {
00425 count += inc;
00426 if (inc > 1) {
00427 cond.Broadcast();
00428 } else if (inc == 1) {
00429 cond.Signal();
00430 }
00431 }
00432 void open(unsigned initValue = 0) {
00433 int rc = cond.CreateLocal();
00434 assert(rc == KErrNone);
00435 count = initValue;
00436 }
00437 void close() {
00438 cond.Close();
00439 }
00440 };
00441
00442 extern int dbTlsIndex;
00443
00444 template<class T>
00445 class dbThreadContext {
00446 int index;
00447 public:
00448 T* get() {
00449 return (T*)UserSvr::DllTls(index);
00450 }
00451 void set(T* value) {
00452 UserSvr::DllSetTls(index, value);
00453 }
00454 dbThreadContext() {
00455 index = ++dbTlsIndex;
00456 }
00457 ~dbThreadContext() {
00458 UserSvr::DllFreeTls(index);
00459 }
00460 };
00461
00462 #else // Posix threads
00463
00464 END_GIGABASE_NAMESPACE
00465
00466 #include <unistd.h>
00467 #include <sys/time.h>
00468 #include <pthread.h>
00469
00470 BEGIN_GIGABASE_NAMESPACE
00471
00472 class dbMutex {
00473 friend class dbEvent;
00474 friend class dbSemaphore;
00475 pthread_mutex_t cs;
00476 bool initialized;
00477 public:
00478 dbMutex() {
00479 pthread_mutex_init(&cs, NULL);
00480 initialized = true;
00481 }
00482 ~dbMutex() {
00483 pthread_mutex_destroy(&cs);
00484 initialized = false;
00485 }
00486 bool isInitialized() {
00487 return initialized;
00488 }
00489 void lock() {
00490 if (initialized) {
00491 pthread_mutex_lock(&cs);
00492 }
00493 }
00494 void unlock() {
00495 if (initialized) {
00496 pthread_mutex_unlock(&cs);
00497 }
00498 }
00499 };
00500
00501
00502 const size_t dbThreadStackSize = 1024*1024;
00503
00504 class dbThread {
00505 pthread_t thread;
00506 public:
00507 typedef void (thread_proc* thread_proc_t)(void*);
00508
00509 void create(thread_proc_t f, void* arg) {
00510 pthread_attr_t attr;
00511 pthread_attr_init(&attr);
00512 #if !defined(__linux__)
00513 pthread_attr_setstacksize(&attr, dbThreadStackSize);
00514 #endif
00515 #if defined(_AIX41)
00516
00517 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
00518 #endif
00519 pthread_create(&thread, &attr, (void*(*)(void*))f, arg);
00520 pthread_attr_destroy(&attr);
00521 }
00522
00523 enum ThreadPriority {
00524 THR_PRI_LOW,
00525 THR_PRI_HIGH
00526 };
00527 #if defined(PRI_OTHER_MIN) && defined(PRI_OTHER_MAX)
00528 void setPriority(ThreadPriority pri) {
00529 struct sched_param sp;
00530 sp.sched_priority = pri == THR_PRI_LOW ? PRI_OTHER_MIN : PRI_OTHER_MAX;
00531 pthread_setschedparam(thread, SCHED_OTHER, &sp);
00532 }
00533 #else
00534 void setPriority(ThreadPriority) {}
00535 #endif
00536
00537 static void sleep(time_t sec) {
00538 ::sleep(sec);
00539 }
00540
00541 void join() {
00542 void* result;
00543 pthread_join(thread, &result);
00544 }
00545 void detach() {
00546 pthread_detach(thread);
00547 }
00548 static int numberOfProcessors();
00549 };
00550
00551 #if defined(_SC_NPROCESSORS_ONLN)
00552 inline int dbThread::numberOfProcessors() {
00553 return sysconf(_SC_NPROCESSORS_ONLN);
00554 }
00555 #elif defined(__linux__)
00556 END_GIGABASE_NAMESPACE
00557 #include <linux/smp.h>
00558 BEGIN_GIGABASE_NAMESPACE
00559 inline int dbThread::numberOfProcessors() { return smp_num_cpus; }
00560 #elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__OpenBSD__) || defined(__NetBSD__)
00561 #if defined(__bsdi__) || defined(__OpenBSD__)
00562 END_GIGABASE_NAMESPACE
00563 #include <sys/param.h>
00564 BEGIN_GIGABASE_NAMESPACE
00565 #endif
00566 END_GIGABASE_NAMESPACE
00567 #include <sys/sysctl.h>
00568 BEGIN_GIGABASE_NAMESPACE
00569 inline int dbThread::numberOfProcessors() {
00570 int mib[2],ncpus=0;
00571 size_t len=sizeof(ncpus);
00572 mib[0]= CTL_HW;
00573 mib[1]= HW_NCPU;
00574 sysctl(mib,2,&ncpus,&len,NULL,0);
00575 return ncpus;
00576 }
00577 #else
00578 #warning Do not know how to detect number of processors: assuming 1
00579 inline int dbThread::numberOfProcessors() { return 1; }
00580 #endif
00581
00582 class dbEvent {
00583 pthread_cond_t cond;
00584 int signaled;
00585 long n_signals;
00586
00587 public:
00588 void wait(dbMutex& mutex) {
00589 long before_n_signals = n_signals;
00590 while (!signaled && n_signals == before_n_signals) {
00591 pthread_cond_wait(&cond, &mutex.cs);
00592 }
00593 }
00594
00595 bool wait(dbMutex& mutex, time_t timeout) {
00596 if (!signaled) {
00597 struct timespec abs_ts;
00598 #ifdef PTHREAD_GET_EXPIRATION_NP
00599 struct timespec rel_ts;
00600 rel_ts.tv_sec = timeout;
00601 rel_ts.tv_nsec = 0;
00602 pthread_get_expiration_np(&rel_ts, &abs_ts);
00603 #else
00604 struct timeval cur_tv;
00605 gettimeofday(&cur_tv, NULL);
00606 abs_ts.tv_sec = cur_tv.tv_sec + timeout;
00607 abs_ts.tv_nsec = cur_tv.tv_usec*1000;
00608 #endif
00609 long before_n_signals = n_signals;
00610 do {
00611 int rc = pthread_cond_timedwait(&cond, &mutex.cs, &abs_ts);
00612 if (rc != 0) {
00613 return false;
00614 }
00615 } while (!signaled && n_signals == before_n_signals);
00616 }
00617 return true;
00618 }
00619
00620 void signal() {
00621 signaled = true;
00622 n_signals += 1;
00623 pthread_cond_broadcast(&cond);
00624 }
00625
00626 void pulse() {
00627 n_signals += 1;
00628 pthread_cond_broadcast(&cond);
00629 }
00630
00631 void reset() {
00632 signaled = false;
00633 }
00634 void open(bool initValue = false) {
00635 signaled = initValue;
00636 n_signals = 0;
00637 pthread_cond_init(&cond, NULL);
00638 }
00639 void close() {
00640 pthread_cond_destroy(&cond);
00641 }
00642 };
00643
00644 class dbSemaphore {
00645 pthread_cond_t cond;
00646 int count;
00647 public:
00648 void wait(dbMutex& mutex) {
00649 while (count == 0) {
00650 pthread_cond_wait(&cond, &mutex.cs);
00651 }
00652 count -= 1;
00653 }
00654
00655 bool wait(dbMutex& mutex, time_t timeout) {
00656 if (count == 0) {
00657 struct timespec abs_ts;
00658 #ifdef PTHREAD_GET_EXPIRATION_NP
00659 struct timespec rel_ts;
00660 rel_ts.tv_sec = timeout;
00661 rel_ts.tv_nsec = 0;
00662 pthread_get_expiration_np(&rel_ts, &abs_ts);
00663 #else
00664 struct timeval cur_tv;
00665 gettimeofday(&cur_tv, NULL);
00666 abs_ts.tv_sec = cur_tv.tv_sec + timeout;
00667 abs_ts.tv_nsec = cur_tv.tv_usec*1000;
00668 #endif
00669 do {
00670 int rc = pthread_cond_timedwait(&cond, &mutex.cs, &abs_ts);
00671 if (rc != 0) {
00672 return false;
00673 }
00674 } while (count == 0);
00675 }
00676 count -= 1;
00677 return true;
00678 }
00679
00680 void signal(unsigned inc = 1) {
00681 count += inc;
00682 if (inc > 1) {
00683 pthread_cond_broadcast(&cond);
00684 } else if (inc == 1) {
00685 pthread_cond_signal(&cond);
00686 }
00687 }
00688 void open(unsigned initValue = 0) {
00689 pthread_cond_init(&cond, NULL);
00690 count = initValue;
00691 }
00692 void close() {
00693 pthread_cond_destroy(&cond);
00694 }
00695 };
00696
00697 template<class T>
00698 class dbThreadContext {
00699 pthread_key_t key;
00700 public:
00701 T* get() {
00702 return (T*)pthread_getspecific(key);
00703 }
00704 void set(T* value) {
00705 pthread_setspecific(key, value);
00706 }
00707 dbThreadContext() {
00708 pthread_key_create(&key, NULL);
00709 }
00710 ~dbThreadContext() {
00711 pthread_key_delete(key);
00712 }
00713 };
00714
00715 #endif
00716
00717 #endif
00718
00719 class GIGABASE_DLL_ENTRY dbCriticalSection {
00720 private:
00721 dbMutex& mutex;
00722 public:
00723 dbCriticalSection(dbMutex& guard) : mutex(guard) {
00724 mutex.lock();
00725 }
00726 ~dbCriticalSection() {
00727 mutex.unlock();
00728 }
00729 };
00730
00731 #define SMALL_BUF_SIZE 512
00732
00733 template<class T>
00734 class dbSmallBuffer {
00735 protected:
00736 T smallBuf[SMALL_BUF_SIZE];
00737 T* buf;
00738 size_t used;
00739
00740 public:
00741 dbSmallBuffer(size_t size) {
00742 if (size > SMALL_BUF_SIZE) {
00743 buf = new T[size];
00744 } else {
00745 buf = smallBuf;
00746 }
00747 used = size;
00748 }
00749
00750 dbSmallBuffer() {
00751 used = 0;
00752 buf = smallBuf;
00753 }
00754
00755 void put(size_t size) {
00756 if (size > SMALL_BUF_SIZE && size > used) {
00757 if (buf != smallBuf) {
00758 delete[] buf;
00759 }
00760 buf = new T[size];
00761 used = size;
00762 }
00763 }
00764
00765 operator T*() { return buf; }
00766 T* base() { return buf; }
00767
00768 ~dbSmallBuffer() {
00769 if (buf != smallBuf) {
00770 delete[] buf;
00771 }
00772 }
00773 };
00774
00775 class dbThreadPool;
00776
00777 class GIGABASE_DLL_ENTRY dbPooledThread {
00778 private:
00779 friend class dbThreadPool;
00780
00781 dbThread thread;
00782 dbThreadPool* pool;
00783 dbPooledThread* next;
00784 dbThread::thread_proc_t f;
00785 void* arg;
00786 bool running;
00787 dbSemaphore startSem;
00788 dbSemaphore readySem;
00789
00790 static void thread_proc pooledThreadFunc(void* arg);
00791
00792 void run();
00793 void stop();
00794
00795 dbPooledThread(dbThreadPool* threadPool);
00796 ~dbPooledThread();
00797 };
00798
00799 class GIGABASE_DLL_ENTRY dbThreadPool {
00800 friend class dbPooledThread;
00801 dbPooledThread* freeThreads;
00802 dbMutex mutex;
00803
00804 public:
00805 dbPooledThread* create(dbThread::thread_proc_t f, void* arg);
00806 void join(dbPooledThread* thr);
00807 dbThreadPool();
00808 ~dbThreadPool();
00809 };
00810
00811 END_GIGABASE_NAMESPACE
00812
00813 #endif