00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __SYNC_UNIX_H__
00012 #define __SYNC_UNIX_H__
00013
00014
00015 #include <unistd.h>
00016 #include <string.h>
00017 #include <fcntl.h>
00018 #include <sys/time.h>
00019 #include <sys/types.h>
00020 #include <errno.h>
00021
00022 #if !defined(USE_POSIX_SEMAPHORES) || !defined(USE_POSIX_MMAP) || !USE_POSIX_MMAP
00023 #include <sys/ipc.h>
00024 extern char const* keyFileDir;
00025 #endif
00026
00027 #if defined(USE_POSIX_SEMAPHORES)
00028 #include <semaphore.h>
00029 #else
00030 #include <sys/sem.h>
00031 #endif
00032
00033 #if defined(USE_POSIX_MMAP) && USE_POSIX_MMAP
00034 #include <sys/mman.h>
00035 #else
00036 #include <sys/shm.h>
00037 #include <sys/mman.h>
00038 #endif
00039
00040
00041 #define thread_proc
00042
00044
00045
00046
00047 #ifndef NO_PTHREADS
00048
00049
00050 #include <pthread.h>
00051
00052 class dbMutex {
00053 friend class dbLocalEvent;
00054 friend class dbLocalSemaphore;
00055 pthread_mutex_t cs;
00056 bool initialized;
00057 public:
00058 dbMutex() {
00059 pthread_mutex_init(&cs, NULL);
00060 initialized = true;
00061 }
00062 ~dbMutex() {
00063 pthread_mutex_destroy(&cs);
00064 initialized = false;
00065 }
00066 bool isInitialized() {
00067 return initialized;
00068 }
00069 void lock() {
00070 if (initialized) {
00071 pthread_mutex_lock(&cs);
00072 }
00073 }
00074 void unlock() {
00075 if (initialized) {
00076 pthread_mutex_unlock(&cs);
00077 }
00078 }
00079 };
00080
00081 const size_t dbThreadStackSize = 1024*1024;
00082
00083 class dbThread {
00084 pthread_t thread;
00085 public:
00086 typedef void (thread_proc* thread_proc_t)(void*);
00087 void create(thread_proc_t f, void* arg) {
00088 pthread_attr_t attr;
00089 pthread_attr_init(&attr);
00090 #if !defined(__linux__)
00091 pthread_attr_setstacksize(&attr, dbThreadStackSize);
00092 #endif
00093 #if defined(_AIX41)
00094
00095 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_UNDETACHED);
00096 #endif
00097 pthread_create(&thread, &attr, (void*(*)(void*))f, arg);
00098 pthread_attr_destroy(&attr);
00099 }
00100
00101 void join() {
00102 void* result;
00103 pthread_join(thread, &result);
00104 }
00105 void detach() {
00106 pthread_detach(thread);
00107 }
00108
00109 enum ThreadPriority {
00110 THR_PRI_LOW,
00111 THR_PRI_HIGH
00112 };
00113 void setPriority(ThreadPriority pri) {
00114 #if defined(PRI_OTHER_MIN) && defined(PRI_OTHER_MAX)
00115 struct sched_param sp;
00116 sp.sched_priority = pri == THR_PRI_LOW ? PRI_OTHER_MIN : PRI_OTHER_MAX;
00117 pthread_setschedparam(thread, SCHED_OTHER, &sp);
00118 #endif
00119 }
00120
00121 static int numberOfProcessors();
00122 };
00123
00124
00125 class dbLocalEvent {
00126 pthread_cond_t cond;
00127 int signaled;
00128 public:
00129 void wait(dbMutex& mutex) {
00130 while (!signaled) {
00131 pthread_cond_wait(&cond, &mutex.cs);
00132 }
00133 }
00134 bool wait(dbMutex& mutex, time_t timeout) {
00135 while (!signaled) {
00136 struct timespec abs_ts;
00137 #ifdef PTHREAD_GET_EXPIRATION_NP
00138 struct timespec rel_ts;
00139 rel_ts.tv_sec = timeout/1000;
00140 rel_ts.tv_nsec = timeout%1000*1000000;
00141 pthread_get_expiration_np(&rel_ts, &abs_ts);
00142 #else
00143 struct timeval cur_tv;
00144 gettimeofday(&cur_tv, NULL);
00145 abs_ts.tv_sec = cur_tv.tv_sec + timeout/1000;
00146 abs_ts.tv_nsec = cur_tv.tv_usec*1000 + timeout%1000*1000000;
00147 if (abs_ts.tv_nsec > 1000000000) {
00148 abs_ts.tv_nsec -= 1000000000;
00149 abs_ts.tv_sec += 1;
00150 }
00151 #endif
00152 int rc = pthread_cond_timedwait(&cond, &mutex.cs, &abs_ts);
00153 if (rc == ETIMEDOUT) {
00154 return false;
00155 }
00156 }
00157 return true;
00158 }
00159 void signal() {
00160 signaled = true;
00161 pthread_cond_broadcast(&cond);
00162 }
00163 void reset() {
00164 signaled = false;
00165 }
00166 void open(bool initValue = false) {
00167 signaled = initValue;
00168 pthread_cond_init(&cond, NULL);
00169 }
00170 void close() {
00171 pthread_cond_destroy(&cond);
00172 }
00173 };
00174
00175 class dbLocalSemaphore {
00176 pthread_cond_t cond;
00177 int count;
00178 public:
00179 void wait(dbMutex& mutex) {
00180 while (count == 0) {
00181 pthread_cond_wait(&cond, &mutex.cs);
00182 }
00183 count -= 1;
00184 }
00185 void wait(dbMutex& mutex, time_t timeout) {
00186 while (count == 0) {
00187 struct timespec abs_ts;
00188 #ifdef PTHREAD_GET_EXPIRATION_NP
00189 struct timespec rel_ts;
00190 rel_ts.tv_sec = timeout/1000;
00191 rel_ts.tv_nsec = timeout%1000*1000000;
00192 pthread_get_expiration_np(&rel_ts, &abs_ts);
00193 #else
00194 struct timeval cur_tv;
00195 gettimeofday(&cur_tv, NULL);
00196 abs_ts.tv_sec = cur_tv.tv_sec + timeout/1000;
00197 abs_ts.tv_nsec = cur_tv.tv_usec*1000 + timeout%1000*1000000;
00198 if (abs_ts.tv_nsec > 1000000000) {
00199 abs_ts.tv_nsec -= 1000000000;
00200 abs_ts.tv_sec += 1;
00201 }
00202 #endif
00203 pthread_cond_timedwait(&cond, &mutex.cs, &abs_ts);
00204 }
00205 count -= 1;
00206 }
00207 void signal(unsigned inc = 1) {
00208 count += inc;
00209 if (inc > 1) {
00210 pthread_cond_broadcast(&cond);
00211 } else if (inc == 1) {
00212 pthread_cond_signal(&cond);
00213 }
00214 }
00215 void open(unsigned initValue = 0) {
00216 pthread_cond_init(&cond, NULL);
00217 count = initValue;
00218 }
00219 void close() {
00220 pthread_cond_destroy(&cond);
00221 }
00222 };
00223
00224 template<class T>
00225 class dbThreadContext {
00226 pthread_key_t key;
00227 public:
00228 T* get() {
00229 return (T*)pthread_getspecific(key);
00230 }
00231 void set(T* value) {
00232 pthread_setspecific(key, value);
00233 }
00234 dbThreadContext() {
00235 pthread_key_create(&key, NULL);
00236 }
00237 ~dbThreadContext() {
00238 pthread_key_delete(key);
00239 }
00240 };
00241
00242 class dbProcessId {
00243 int pid;
00244 pthread_t tid;
00245 public:
00246 bool operator != (dbProcessId const& other) const {
00247 return pid != other.pid || tid != other.tid;
00248 }
00249
00250 void clear() {
00251 pid = 0;
00252 tid = 0;
00253 }
00254
00255 static dbProcessId getCurrent() {
00256 dbProcessId curr;
00257 curr.pid = getpid();
00258 curr.tid = pthread_self();
00259 return curr;
00260 }
00261 };
00262
00263 #else // NO_PTHREAD
00264
00265
00266
00267
00268 class dbMutex {
00269 bool initialized;
00270
00271 public:
00272 dbMutex() {
00273 initialized = true;
00274 }
00275
00276 ~dbMutex() {
00277 initialized = false;
00278 }
00279
00280 bool isInitialized() {
00281 return initialized;
00282 }
00283
00284 void lock() {}
00285 void unlock() {}
00286 };
00287
00288 class dbThread {
00289 public:
00290 typedef void (thread_proc* thread_proc_t)(void*);
00291 void create(thread_proc_t f, void* arg) { f(arg); }
00292 void join() {}
00293 void detach() {}
00294 enum ThreadPriority {
00295 THR_PRI_LOW,
00296 THR_PRI_HIGH
00297 };
00298 void setPriority(ThreadPriority pri) { }
00299 static int numberOfProcessors() { return 1; }
00300 };
00301
00302 class dbLocalSemaphore {
00303 int count;
00304 public:
00305 void wait(dbMutex&) {
00306 assert (count > 0);
00307 count -= 1;
00308 }
00309 void signal(unsigned inc = 1) {
00310 count += inc;
00311 }
00312 void open(unsigned initValue = 0) {
00313 count = initValue;
00314 }
00315 void close() {}
00316 };
00317
00318 class dbLocalEvent {
00319 bool signaled;
00320 public:
00321 void wait(dbMutex&) {
00322 assert(signaled);
00323 }
00324 bool wait(dbMutex& mutex, time_t timeout) {
00325 return true;
00326 }
00327 void signal() {
00328 signaled = true;
00329 }
00330 void reset() {
00331 signaled = false;
00332 }
00333 void open(bool initValue = false) {
00334 signaled = initValue;
00335 }
00336 void close() {}
00337 };
00338
00339 template<class T>
00340 class dbThreadContext {
00341 T* value;
00342 public:
00343 T* get() {
00344 return value;
00345 }
00346 void set(T* value) {
00347 this->value = value;
00348 }
00349 dbThreadContext() { value = NULL; }
00350 };
00351
00352
00353 class dbProcessId {
00354 int pid;
00355 public:
00356 bool operator != (dbProcessId const& other) const {
00357 return pid != other.pid;
00358 }
00359
00360 void clear() {
00361 pid = 0;
00362 }
00363
00364 static dbProcessId getCurrent() {
00365 dbProcessId curr;
00366 curr.pid = getpid();
00367 return curr;
00368 }
00369 };
00370
00371 #endif // NO_PTHREAD
00372
00373
00374 #define INFINITE (~0U)
00375
00376
00377 #ifdef USE_POSIX_SEMAPHORES
00378
00379 class dbInitializationMutex {
00380 sem_t* sem;
00381 public:
00382 enum initializationStatus {
00383 InitializationError,
00384 AlreadyInitialized,
00385 NotYetInitialized
00386 };
00387 initializationStatus initialize(char const* name) {
00388 initializationStatus status;
00389 char* tmp = NULL;
00390 if (*name != '/') {
00391 tmp = new char[strlen(name)+2];
00392 strcpy(tmp+1, name);
00393 *tmp = '/';
00394 name = tmp;
00395 }
00396 while (true) {
00397 sem = sem_open(name, 0);
00398 if (sem == SEM_FAILED) {
00399 if (errno == ENOENT) {
00400 sem = sem_open(name, O_CREAT|O_EXCL, 0777, 0);
00401 if (sem != SEM_FAILED) {
00402 status = NotYetInitialized;
00403 break;
00404 } else if (errno != EEXIST) {
00405 status = InitializationError;
00406 break;
00407 }
00408 } else {
00409 status = InitializationError;
00410 break;
00411 }
00412 } else {
00413 status = (sem_wait(sem) == 0 && sem_post(sem) == 0)
00414 ? AlreadyInitialized : InitializationError;
00415 break;
00416 }
00417 }
00418 delete[] tmp;
00419 return status;
00420 }
00421
00422 void done() {
00423 sem_post(sem);
00424 }
00425 bool close() {
00426 sem_close(sem);
00427 return false;
00428 }
00429 void erase() {
00430 close();
00431 }
00432 };
00433
00434 class dbSemaphore {
00435 protected:
00436 sem_t* sem;
00437 public:
00438 void wait() {
00439 int rc = sem_wait(sem);
00440 assert(rc == 0);
00441 }
00442
00443 bool wait(unsigned msec) {
00444 #ifdef POSIX_1003_1d
00445 struct timespec abs_ts;
00446 struct timeval cur_tv;
00447 clock_gettime(CLOCK_REALTIME, &cur_tv);
00448 abs_ts.tv_sec = cur_tv.tv_sec + (msec + cur_tv.tv_usec / 1000) / 1000000;
00449 abs_ts.tv_nsec = (msec + cur_tv.tv_usec / 1000) % 1000000 * 1000;
00450 int rc = sem_timedwait(sem, &abs_ts);
00451 if (rc < 0) {
00452 assert(errno == ETIMEDOUT);
00453 return false;
00454 }
00455 return true;
00456 #else
00457 int rc = sem_wait(sem);
00458 assert(rc == 0);
00459 return true;
00460 #endif
00461 }
00462
00463 void signal(unsigned inc = 1) {
00464 while (--inc > 0) {
00465 sem_post(sem);
00466 }
00467 }
00468 void reset() {
00469 while (sem_trywait(sem) == 0);
00470 }
00471 bool open(char const* name, unsigned initValue = 0) {
00472 char* tmp = NULL;
00473 if (*name != '/') {
00474 tmp = new char[strlen(name)+2];
00475 strcpy(tmp+1, name);
00476 *tmp = '/';
00477 name = tmp;
00478 }
00479 sem = sem_open(name, O_CREAT, 0777, initValue);
00480 delete[] tmp;
00481 return sem != NULL;
00482 }
00483 void close() {
00484 sem_close(sem);
00485 }
00486 void erase() {
00487 close();
00488 }
00489 };
00490
00491 class dbEvent : public dbSemaphore {
00492 public:
00493 void wait() {
00494 dbSemaphore::wait();
00495 sem_post(sem);
00496 }
00497 bool wait(unsigned msec) {
00498 if (dbSemaphore::wait(msec)) {
00499 sem_post(sem);
00500 return true;
00501 }
00502 return false;
00503 }
00504 void signal() {
00505 while (sem_trywait(sem) == 0);
00506 sem_post(sem);
00507 }
00508 void reset() {
00509 while (sem_trywait(sem) == 0);
00510 }
00511 bool open(char const* name, bool signaled = false) {
00512 return dbSemaphore::open(name, (int)signaled);
00513 }
00514 };
00515 #else // USE_POSIX_SEMAPHORES
00516
00517
00518 class dbInitializationMutex {
00519 int semid;
00520 public:
00521 enum initializationStatus {
00522 InitializationError,
00523 AlreadyInitialized,
00524 NotYetInitialized
00525 };
00526 initializationStatus initialize(char const* name);
00527 void done();
00528 bool close();
00529 void erase();
00530 };
00531
00532
00533 class dbSemaphore {
00534 int s;
00535 public:
00536 bool wait(unsigned msec = INFINITE);
00537 void signal(unsigned inc = 1);
00538 bool open(char const* name, unsigned initValue = 0);
00539 void reset();
00540 void close();
00541 void erase();
00542 };
00543
00544 class dbEvent {
00545 int e;
00546 public:
00547 bool wait(unsigned msec = INFINITE);
00548 void signal();
00549 void reset();
00550 bool open(char const* name, bool signaled = false);
00551 void close();
00552 void erase();
00553 };
00554 #endif // USE_POSIX_SEMAPHORES
00555
00556
00557
00558 #if defined(USE_POSIX_MMAP) && USE_POSIX_MMAP
00559
00560
00561 template<class T>
00562 class dbSharedObject {
00563 char* name;
00564 T* ptr;
00565 int fd;
00566 public:
00567
00568 dbSharedObject() {
00569 name = NULL;
00570 ptr = NULL;
00571 fd = -1;
00572 }
00573
00574 bool open(char* fileName) {
00575 delete[] name;
00576 name = new char[strlen(fileName) + 1];
00577 strcpy(name, fileName);
00578 fd = ::open(fileName, O_RDWR|O_CREAT, 0777);
00579 if (fd < 0) {
00580 return false;
00581 }
00582 if (ftruncate(fd, sizeof(T)) < 0) {
00583 ::close(fd);
00584 return false;
00585 }
00586 ptr = (T*)mmap(NULL,
00587 DOALIGN(sizeof(T), 4096),
00588 PROT_READ|PROT_WRITE,
00589 MAP_SHARED,
00590 fd,
00591 0);
00592 if (ptr == MAP_FAILED) {
00593 ptr = NULL;
00594 ::close(fd);
00595 return false;
00596 }
00597 return true;
00598 }
00599
00600 T* get() { return ptr; }
00601
00602 void close() {
00603 if (ptr != NULL) {
00604 munmap(ptr, DOALIGN(sizeof(T), 4096));
00605 }
00606 if (fd > 0) {
00607 ::close(fd);
00608 }
00609 }
00610 void erase() {
00611 close();
00612 unlink(name);
00613 }
00614
00615 ~dbSharedObject() {
00616 delete[] name;
00617 }
00618 };
00619
00620 #else // USE_POSIX_MMAP
00621
00622
00623 extern char const* keyFileDir;
00624 class dbSharedMemory {
00625 protected:
00626 char* ptr;
00627 int shm;
00628
00629 public:
00630 bool open(char const* name, size_t size);
00631 void close();
00632 void erase();
00633 char* get_base() {
00634 return ptr;
00635 }
00636 };
00637
00638 template<class T>
00639 class dbSharedObject : public dbSharedMemory {
00640 public:
00641 bool open(char* name) {
00642 return dbSharedMemory::open(name, sizeof(T));
00643 }
00644 T* get() { return (T*)ptr; }
00645 };
00646
00647 #endif
00648
00650
00651
00652
00653
00654 #if defined(__QNX__) && !defined(NO_PTHREADS)
00655 typedef pthread_mutex_t sharedsem_t;
00656
00657 class dbGlobalCriticalSection {
00658 pthread_mutexattr_t attr;
00659 sharedsem_t* sem;
00660 public:
00661 void enter() {
00662 int rc = pthread_mutex_lock(sem);
00663 assert(rc == 0);
00664 }
00665 void leave() {
00666 int rc = pthread_mutex_unlock(sem);
00667 assert(rc == 0);
00668 }
00669 bool open(char const*, sharedsem_t* shr) {
00670 sem = shr;
00671 return true;
00672 }
00673 bool create(char const*, sharedsem_t* shr) {
00674 sem = shr;
00675 pthread_mutexattr_init(&attr);
00676 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
00677 pthread_mutexattr_setrecursive(&attr, PTHREAD_RECURSIVE_ENABLE);
00678 pthread_mutex_init(sem, &attr);
00679 return true;
00680 }
00681 void close() {}
00682 void erase() {
00683 pthread_mutex_destroy(sem);
00684 }
00685 };
00686
00687
00688 #elif defined(__osf__)
00689
00690
00691 #include <errno.h>
00692 typedef msemaphore sharedsem_t;
00693
00694 class dbGlobalCriticalSection {
00695 sharedsem_t* sem;
00696 public:
00697 void enter() {
00698 int rc;
00699 while ((rc = msem_lock(sem, 0)) < 0 && errno == EINTR);
00700 assert(rc == 0);
00701 }
00702 void leave() {
00703 int rc = msem_unlock(sem, 0);
00704 assert(rc == 0);
00705 }
00706 bool open(char const*, sharedsem_t* shr) {
00707 sem = shr;
00708 return true;
00709 }
00710 bool create(char const*, sharedsem_t* shr) {
00711 sem = shr;
00712 msem_init(shr, MSEM_UNLOCKED);
00713 return true;
00714 }
00715 void close() {}
00716 void erase() {
00717 msem_remove(sem);
00718 }
00719 };
00720
00721
00722 #elif defined(__sun)
00723
00724 #include <synch.h>
00725 #include <errno.h>
00726 typedef sema_t sharedsem_t;
00727
00728 class dbGlobalCriticalSection {
00729 sharedsem_t* sem;
00730 public:
00731 void enter() {
00732 int rc;
00733 while ((rc = sema_wait(sem)) < 0 && errno == EINTR);
00734 assert(rc == 0);
00735 }
00736 void leave() {
00737 int rc = sema_post(sem);
00738 assert(rc == 0);
00739 }
00740 bool open(char const*, sharedsem_t* shr) {
00741 sem = shr;
00742 return true;
00743 }
00744 bool create(char const*, sharedsem_t* shr) {
00745 sem = shr;
00746 return sema_init(shr, 1, USYNC_PROCESS, NULL) == 0;
00747 }
00748 void close() {}
00749 void erase() {
00750 sema_destroy(sem);
00751 }
00752 };
00753
00754 #elif defined(USE_POSIX_SEMAPHORES)
00755
00756 typedef sem_t sharedsem_t;
00757
00758 class dbGlobalCriticalSection {
00759 sharedsem_t* sem;
00760
00761 public:
00762 void enter() {
00763 int rc = sem_wait(sem);
00764 assert(rc == 0);
00765 }
00766 void leave() {
00767 int rc = sem_post(sem);
00768 assert(rc == 0);
00769 }
00770 bool open(char const* name, sharedsem_t* shr) {
00771 sem = shr;
00772 return true;
00773 }
00774
00775
00776 bool create(char const* name, sharedsem_t* shr) {
00777 sem = shr;
00778 return sem_init(sem, 1, 1) == 0;
00779 }
00780 void close() {}
00781 void erase() {
00782 sem_destroy(sem);
00783 }
00784 };
00785
00786 #else
00787
00788 #define USE_LOCAL_CS_IMPL
00789
00790
00791 typedef long sharedsem_t;
00792
00793 class dbGlobalCriticalSection {
00794 int semid;
00795 sharedsem_t* count;
00796
00797 public:
00798 void enter();
00799 void leave();
00800 bool open(char const* name, sharedsem_t* shr);
00801 bool create(char const* name, sharedsem_t* shr);
00802 void close() {}
00803 void erase();
00804 };
00805 #endif //dbGLobalCriticalSection switch
00806
00807 #endif //__SYNC_UNIX_H__