66 */
77
88#include " tsharedmemory.h"
9+ #include < TSystemGlobal>
910#include < semaphore.h>
1011#include < fcntl.h> // O_CREAT, O_EXCL
11- #include < sys/stat.h> // mode constants
12+ #include < sys/stat.h>
13+ #include < time.h>
1214#include < errno.h>
1315
1416
15- void TSharedMemory::initRwlock ( header_t *) const
17+ static inline QByteArray semaphoreName ( const QString &name)
1618{
17- const QByteArray SEM_NAME = _name + " _global_lock" ;
19+ return (name.startsWith (" /" ) ? " " : " /" ) + name.toLatin1 () + " _global_lock" ;
20+ }
21+
1822
19- sem_t * sem = sem_open (SEM_NAME.data (), O_CREAT | O_EXCL, 0644 , 1 );
23+ bool TSharedMemory::initRwlock (header_t *) const
24+ {
25+ sem_t *sem = sem_open (semaphoreName (_name).data (), O_CREAT | O_EXCL, 0644 , 1 );
2026 if (sem == SEM_FAILED) {
2127 if (errno == EEXIST) {
28+ tSystemError (" sem_open semaphore already exists: {}" , semaphoreName (_name));
2229 return true ;
2330 } else {
24- tSystemError (" sem_open (init) failed: {}" , strerror (errno));
31+ tSystemError (" sem_open (init) failed: {}" , ( const char *) strerror (errno));
2532 return false ;
2633 }
2734 }
@@ -32,24 +39,58 @@ void TSharedMemory::initRwlock(header_t *) const
3239}
3340
3441
42+ void TSharedMemory::releaseRwlock (header_t *) const
43+ {
44+ sem_unlink (semaphoreName (_name).data ());
45+ }
46+
47+
3548bool TSharedMemory::lockForRead ()
3649{
37- const QByteArray SEM_NAME = _name + " _global_lock" ;
50+ // Use semaphore as a lock mechanism between processes.
51+ // PTHREAD_PROCESS_SHARED attribute is not supported on macos.
52+
53+ sem_t *sem = SEM_FAILED;
54+ header_t *header = (header_t *)_ptr;
55+ uint cnt = header->lockcounter ;
56+
57+ auto sem_timedwait = [&](int msecs) {
58+ sem = sem_open (semaphoreName (_name).data (), 0 );
59+ if (sem == SEM_FAILED) {
60+ tSystemError (" sem_open (lock) failed: {}" , (const char *)strerror (errno));
61+ return -1 ;
62+ }
3863
39- sem_t * sem = sem_open (SEM_NAME.data (), 0 );
40- if (sem == SEM_FAILED) {
41- tSystemError (" sem_open (lock) failed: {}" , strerror (errno));
42- return false ;
64+ auto deadline = std::chrono::steady_clock::now () + std::chrono::milliseconds (msecs);
65+ while (std::chrono::steady_clock::now () < deadline) {
66+ if (sem_trywait (sem) < 0 ) {
67+ if (errno == EAGAIN) {
68+ std::this_thread::sleep_for (std::chrono::milliseconds (20 ));
69+ continue ;
70+ } else {
71+ return -1 ; // error
72+ }
73+ } else {
74+ header->lockcounter ++;
75+ return 0 ; // lock success
76+ }
77+ }
78+ tSystemError (" sem_wait (lock) timed out: {}" , semaphoreName (_name));
79+ return 1 ; // timeout
80+ };
81+
82+ int res;
83+ while ((res = sem_timedwait (1000 )) == 1 ) {
84+ if (header->lockcounter == cnt) { // timeout and same counter
85+ releaseRwlock (header);
86+ initRwlock (header);
87+ }
4388 }
4489
45- if (sem_wait (sem) < 0 ) {
46- tSystemError (" sem_wait failed: {}" , strerror (errno));
90+ if (sem != SEM_FAILED) {
4791 sem_close (sem);
48- return false ;
4992 }
50-
51- sem_close (sem);
52- return true ;
93+ return !res;
5394}
5495
5596
@@ -62,16 +103,14 @@ bool TSharedMemory::lockForWrite()
62103
63104bool TSharedMemory::unlock ()
64105{
65- const QByteArray SEM_NAME = _name + " _global_lock" ;
66-
67- sem_t * sem = sem_open (SEM_NAME.data (), 0 ); // 既存を開く
106+ sem_t *sem = sem_open (semaphoreName (_name).data (), 0 );
68107 if (sem == SEM_FAILED) {
69- tSystemError (" sem_open (unlock) failed: {}" , strerror (errno));
108+ tSystemError (" sem_open (unlock) failed: {}" , ( const char *) strerror (errno));
70109 return false ;
71110 }
72111
73112 if (sem_post (sem) < 0 ) {
74- tSystemError (" sem_post failed: {}" , strerror (errno));
113+ tSystemError (" sem_post failed: {}" , ( const char *) strerror (errno));
75114 sem_close (sem);
76115 return false ;
77116 }
0 commit comments