00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __SYNC_H__
00012 #define __SYNC_H__
00013
00014
00015 BEGIN_GIGABASE_NAMESPACE
00016
00017 #if defined(_WIN32)
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 typedef void (thread_proc* thread_proc_t)(void*);
00060
00061 void create(thread_proc_t f, void* arg) {
00062 DWORD threadid;
00063 h = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(f), arg, 0, &threadid);
00064 }
00065 void join() {
00066 WaitForSingleObject(h, INFINITE);
00067 CloseHandle(h);
00068 h = NULL;
00069 }
00070 void detach() {
00071 if (h != NULL) {
00072 CloseHandle(h);
00073 h = NULL;
00074 }
00075 }
00076 dbThread() {
00077 h = NULL;
00078 }
00079 ~dbThread() {
00080 if (h != NULL) {
00081 CloseHandle(h);
00082 }
00083 }
00084 static int numberOfProcessors() {
00085 SYSTEM_INFO sysinfo;
00086 GetSystemInfo(&sysinfo);
00087 return sysinfo.dwNumberOfProcessors;
00088 }
00089 };
00090
00091 const int dbMaxSemValue = 1000000;
00092
00093
00094 class GIGABASE_DLL_ENTRY dbSemaphore {
00095 HANDLE s;
00096 public:
00097 void wait(dbMutex& mutex, time_t timeout = INFINITE) {
00098 mutex.unlock();
00099 int rc = WaitForSingleObject(s, timeout == (time_t)INFINITE ? timeout : timeout*1000);
00100 assert(rc == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT);
00101 mutex.lock();
00102 }
00103 void signal(unsigned inc = 1) {
00104 if (inc != 0) {
00105 ReleaseSemaphore(s, inc, NULL);
00106 }
00107 }
00108 void open(unsigned initValue = 0) {
00109 s = CreateSemaphore(NULL, initValue, dbMaxSemValue, NULL);
00110 assert(s != NULL);
00111 }
00112 void close() {
00113 CloseHandle(s);
00114 }
00115 dbSemaphore() {
00116 s = NULL;
00117 }
00118 };
00119
00120 class GIGABASE_DLL_ENTRY dbEvent {
00121 HANDLE e;
00122 int nWaitingThreads;
00123 int nPulses;
00124 public:
00125 void wait(dbMutex& mutex, time_t timeout = INFINITE) {
00126 nWaitingThreads += 1;
00127 mutex.unlock();
00128 int rc = WaitForSingleObject(e, timeout == (time_t)INFINITE ? timeout : timeout*1000);
00129 assert(rc == WAIT_OBJECT_0 || rc == WAIT_TIMEOUT);
00130 mutex.lock();
00131 nWaitingThreads -= 1;
00132 if (nPulses > 0) {
00133 nPulses -= 1;
00134 ResetEvent(e);
00135 }
00136 }
00137 void signal() {
00138 SetEvent(e);
00139 }
00140 void reset() {
00141 ResetEvent(e);
00142 }
00143 void pulse() {
00144 if (nWaitingThreads > 0) {
00145 nPulses += 1;
00146 SetEvent(e);
00147 }
00148 }
00149 void open(bool initValue = false) {
00150 e = CreateEvent(NULL, true, initValue, NULL);
00151 nWaitingThreads = 0;
00152 nPulses = 0;
00153 }
00154 void close() {
00155 CloseHandle(e);
00156 }
00157 dbEvent() {
00158 e = NULL;
00159 }
00160 };
00161
00162 template<class T>
00163 class dbThreadContext {
00164 int index;
00165 public:
00166 T* get() {
00167 return (T*)TlsGetValue(index);
00168 }
00169 void set(T* value) {
00170 TlsSetValue(index, value);
00171 }
00172 dbThreadContext() {
00173 index = TlsAlloc();
00174 assert(index != (int)TLS_OUT_OF_INDEXES);
00175 }
00176 ~dbThreadContext() {
00177 TlsFree(index);
00178 }
00179 };
00180
00181 #else // Unix
00182
00183 #define thread_proc
00184
00185 #ifndef NO_PTHREADS
00186
00187 END_GIGABASE_NAMESPACE
00188
00189 #include <unistd.h>
00190 #include <sys/time.h>
00191 #include <pthread.h>
00192
00193 BEGIN_GIGABASE_NAMESPACE
00194
00195 class dbMutex {
00196 friend class dbEvent;
00197 friend class dbSemaphore;
00198 pthread_mutex_t cs;
00199 bool initialized;
00200 public:
00201 dbMutex() {
00202 pthread_mutex_init(&cs, NULL);
00203 initialized = true;
00204 }
00205 ~dbMutex() {
00206 pthread_mutex_destroy(&cs);
00207 initialized = false;
00208 }
00209 bool isInitialized() {
00210 return initialized;
00211 }
00212 void lock() {
00213 if (initialized) {
00214 pthread_mutex_lock(&cs);
00215 }
00216 }
00217 void unlock() {
00218 if (initialized) {
00219 pthread_mutex_unlock(&cs);
00220 }
00221 }
00222 };
00223
00224
00225 const size_t dbThreadStackSize = 1024*1024;
00226
00227 class dbThread {
00228 pthread_t thread;
00229 public:
00230 typedef void (thread_proc* thread_proc_t)(void*);
00231
00232 void create(thread_proc_t f, void* arg) {
00233 pthread_attr_t attr;
00234 pthread_attr_init(&attr);
00235 #if !defined(__linux__)
00236 pthread_attr_setstacksize(&attr, dbThreadStackSize);
00237 #endif
00238 #if defined(_AIX41)
00239
00240 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
00241 #endif
00242 pthread_create(&thread, &attr, (void*(*)(void*))f, arg);
00243 pthread_attr_destroy(&attr);
00244 }
00245
00246 enum ThreadPriority {
00247 THR_PRI_LOW,
00248 THR_PRI_HIGH
00249 };
00250 #if defined(PRI_OTHER_MIN) && defined(PRI_OTHER_MAX)
00251 void setPriority(ThreadPriority pri) {
00252 struct sched_param sp;
00253 sp.sched_priority = pri == THR_PRI_LOW ? IPRI_OTHER_MIN : PRI_OTHER_MAX;
00254 pthread_setschedparam(thread, SCHED_OTHER, &sp);
00255 }
00256 #else
00257 void setPriority(ThreadPriority) {}
00258 #endif
00259
00260
00261
00262 void join() {
00263 void* result;
00264 pthread_join(thread, &result);
00265 }
00266 void detach() {
00267 pthread_detach(thread);
00268 }
00269 static int numberOfProcessors();
00270 };
00271
00272 #if defined(_SC_NPROCESSORS_ONLN)
00273 inline int dbThread::numberOfProcessors() {
00274 return sysconf(_SC_NPROCESSORS_ONLN);
00275 }
00276 #elif defined(__linux__)
00277 END_GIGABASE_NAMESPACE
00278 #include <linux/smp.h>
00279 BEGIN_GIGABASE_NAMESPACE
00280 inline int dbThread::numberOfProcessors() { return smp_num_cpus; }
00281 #elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__OpenBSD__)
00282 #if defined(__bsdi__) || defined(__OpenBSD__)
00283 END_GIGABASE_NAMESPACE
00284 #include <sys/param.h>
00285 BEGIN_GIGABASE_NAMESPACE
00286 #endif
00287 END_GIGABASE_NAMESPACE
00288 #include <sys/sysctl.h>
00289 BEGIN_GIGABASE_NAMESPACE
00290 inline int dbThread::numberOfProcessors() {
00291 int mib[2],ncpus=0;
00292 size_t len=sizeof(ncpus);
00293 mib[0]= CTL_HW;
00294 mib[1]= HW_NCPU;
00295 sysctl(mib,2,&ncpus,&len,NULL,0);
00296 return ncpus;
00297 }
00298 #else
00299 #warning Do not know how to detect number of processors: assuming 1
00300 inline int dbThread::numberOfProcessors() { return 1; }
00301 #endif
00302
00303 class dbEvent {
00304 pthread_cond_t cond;
00305 int signaled;
00306 long n_signals;
00307
00308 public:
00309 void wait(dbMutex& mutex) {
00310 long before_n_signals = n_signals;
00311 while (!signaled && n_signals == before_n_signals) {
00312 pthread_cond_wait(&cond, &mutex.cs);
00313 }
00314 }
00315
00316 void wait(dbMutex& mutex, time_t timeout) {
00317 long before_n_signals = n_signals;
00318 while (!signaled && n_signals == before_n_signals) {
00319 struct timespec abs_ts;
00320 #ifdef PTHREAD_GET_EXPIRATION_NP
00321 struct timespec rel_ts;
00322 rel_ts.tv_sec = timeout;
00323 rel_ts.tv_nsec = 0;
00324 pthread_get_expiration_np(&rel_ts, &abs_ts);
00325 #else
00326 struct timeval cur_tv;
00327 gettimeofday(&cur_tv, NULL);
00328 abs_ts.tv_sec = cur_tv.tv_sec + timeout;
00329 abs_ts.tv_nsec = cur_tv.tv_usec*1000;
00330 #endif
00331 pthread_cond_timedwait(&cond, &mutex.cs, &abs_ts);
00332 }
00333 }
00334
00335 void signal() {
00336 signaled = true;
00337 n_signals += 1;
00338 pthread_cond_broadcast(&cond);
00339 }
00340
00341 void pulse() {
00342 n_signals += 1;
00343 pthread_cond_broadcast(&cond);
00344 }
00345
00346 void reset() {
00347 signaled = false;
00348 }
00349 void open(bool initValue = false) {
00350 signaled = initValue;
00351 n_signals = 0;
00352 pthread_cond_init(&cond, NULL);
00353 }
00354 void close() {
00355 pthread_cond_destroy(&cond);
00356 }
00357 };
00358
00359 class dbSemaphore {
00360 pthread_cond_t cond;
00361 int count;
00362 public:
00363 void wait(dbMutex& mutex) {
00364 while (count == 0) {
00365 pthread_cond_wait(&cond, &mutex.cs);
00366 }
00367 count -= 1;
00368 }
00369
00370 void wait(dbMutex& mutex, time_t timeout) {
00371 while (count == 0) {
00372 struct timespec abs_ts;
00373 #ifdef PTHREAD_GET_EXPIRATION_NP
00374 struct timespec rel_ts;
00375 rel_ts.tv_sec = timeout;
00376 rel_ts.tv_nsec = 0;
00377 pthread_get_expiration_np(&rel_ts, &abs_ts);
00378 #else
00379 struct timeval cur_tv;
00380 gettimeofday(&cur_tv, NULL);
00381 abs_ts.tv_sec = cur_tv.tv_sec + timeout;
00382 abs_ts.tv_nsec = cur_tv.tv_usec*1000;
00383 #endif
00384 pthread_cond_timedwait(&cond, &mutex.cs, &abs_ts);
00385 }
00386 count -= 1;
00387 }
00388
00389 void signal(unsigned inc = 1) {
00390 count += inc;
00391 if (inc > 1) {
00392 pthread_cond_broadcast(&cond);
00393 } else if (inc == 1) {
00394 pthread_cond_signal(&cond);
00395 }
00396 }
00397 void open(unsigned initValue = 0) {
00398 pthread_cond_init(&cond, NULL);
00399 count = initValue;
00400 }
00401 void close() {
00402 pthread_cond_destroy(&cond);
00403 }
00404 };
00405
00406 template<class T>
00407 class dbThreadContext {
00408 pthread_key_t key;
00409 public:
00410 T* get() {
00411 return (T*)pthread_getspecific(key);
00412 }
00413 void set(T* value) {
00414 pthread_setspecific(key, value);
00415 }
00416 dbThreadContext() {
00417 pthread_key_create(&key, NULL);
00418 }
00419 ~dbThreadContext() {
00420 pthread_key_delete(key);
00421 }
00422 };
00423
00424 #else
00425
00426 class dbMutex {
00427 bool initialized;
00428
00429 public:
00430 dbMutex() {
00431 initialized = true;
00432 }
00433
00434 ~dbMutex() {
00435 initialized = false;
00436 }
00437
00438 bool isInitialized() {
00439 return initialized;
00440 }
00441
00442 void lock() {}
00443 void unlock() {}
00444 };
00445
00446 class dbThread {
00447 public:
00448 typedef void (thread_proc* thread_proc_t)(void*);
00449 void create(thread_proc_t f, void* arg) { f(arg); }
00450 void join() {}
00451 void detach() {}
00452
00453 enum ThreadPriority {
00454 THR_PRI_LOW,
00455 THR_PRI_HIGH
00456 };
00457 void setPriority(ThreadPriority) {}
00458
00459 static int numberOfProcessors() { return 1; }
00460 };
00461
00462 class dbSemaphore {
00463 int count;
00464 public:
00465 void wait(dbMutex&, time_t=0) {
00466 assert (count > 0);
00467 count -= 1;
00468 }
00469 void signal(unsigned inc = 1) {
00470 count += inc;
00471 }
00472 void open(unsigned initValue = 0) {
00473 count = initValue;
00474 }
00475 void close() {}
00476 };
00477
00478 class dbEvent {
00479 bool signaled;
00480 public:
00481 void wait(dbMutex&, time_t=0) {
00482 assert(signaled);
00483 }
00484 void signal() {
00485 signaled = true;
00486 }
00487 void reset() {
00488 signaled = false;
00489 }
00490 void open(bool initValue = false) {
00491 signaled = initValue;
00492 }
00493 void pulse() {}
00494 void close() {}
00495 };
00496
00497 template<class T>
00498 class dbThreadContext {
00499 T* value;
00500 public:
00501 T* get() {
00502 return value;
00503 }
00504 void set(T* value) {
00505 this->value = value;
00506 }
00507 dbThreadContext() { value = NULL; }
00508 };
00509
00510
00511 #endif
00512
00513 #endif
00514
00515 class GIGABASE_DLL_ENTRY dbCriticalSection {
00516 private:
00517 dbMutex& mutex;
00518 public:
00519 dbCriticalSection(dbMutex& guard) : mutex(guard) {
00520 mutex.lock();
00521 }
00522 ~dbCriticalSection() {
00523 mutex.unlock();
00524 }
00525 };
00526
00527 #define SMALL_BUF_SIZE 512
00528
00529 template<class T>
00530 class dbSmallBuffer {
00531 protected:
00532 T smallBuf[SMALL_BUF_SIZE];
00533 T* buf;
00534 size_t used;
00535
00536 public:
00537 dbSmallBuffer(size_t size) {
00538 if (size > SMALL_BUF_SIZE) {
00539 buf = new T[size];
00540 } else {
00541 buf = smallBuf;
00542 }
00543 used = size;
00544 }
00545
00546 dbSmallBuffer() {
00547 used = 0;
00548 buf = smallBuf;
00549 }
00550
00551 void put(size_t size) {
00552 if (size > SMALL_BUF_SIZE && size > used) {
00553 if (buf != smallBuf) {
00554 delete[] buf;
00555 }
00556 buf = new T[size];
00557 used = size;
00558 }
00559 }
00560
00561 operator T*() { return buf; }
00562 T* base() { return buf; }
00563
00564 ~dbSmallBuffer() {
00565 if (buf != smallBuf) {
00566 delete[] buf;
00567 }
00568 }
00569 };
00570
00571
00572 class GIGABASE_DLL_ENTRY dbPooledThread {
00573 private:
00574 friend class dbThreadPool;
00575
00576 dbThread thread;
00577 dbThreadPool* pool;
00578 dbPooledThread* next;
00579 dbThread::thread_proc_t f;
00580 void* arg;
00581 bool running;
00582 dbSemaphore startSem;
00583 dbSemaphore readySem;
00584
00585 static void thread_proc pooledThreadFunc(void* arg);
00586
00587 void run();
00588 void stop();
00589
00590 dbPooledThread(dbThreadPool* threadPool);
00591 ~dbPooledThread();
00592 };
00593
00594 class GIGABASE_DLL_ENTRY dbThreadPool {
00595 friend class dbPooledThread;
00596 dbPooledThread* freeThreads;
00597 dbMutex mutex;
00598
00599 public:
00600 dbPooledThread* create(dbThread::thread_proc_t f, void* arg);
00601 void join(dbPooledThread* thr);
00602 dbThreadPool();
00603 ~dbThreadPool();
00604 };
00605
00606 END_GIGABASE_NAMESPACE
00607
00608 #endif