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