6
6
*/
7
7
8
8
#include " tsharedmemory.h"
9
+ #include < TSystemGlobal>
9
10
#include < semaphore.h>
10
11
#include < fcntl.h> // O_CREAT, O_EXCL
11
- #include < sys/stat.h> // mode constants
12
+ #include < sys/stat.h>
13
+ #include < time.h>
12
14
#include < errno.h>
13
15
14
16
15
- void TSharedMemory::initRwlock ( header_t *) const
17
+ static inline QByteArray semaphoreName ( const QString &name)
16
18
{
17
- const QByteArray SEM_NAME = _name + " _global_lock" ;
19
+ return (name.startsWith (" /" ) ? " " : " /" ) + name.toLatin1 () + " _global_lock" ;
20
+ }
21
+
18
22
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 );
20
26
if (sem == SEM_FAILED) {
21
27
if (errno == EEXIST) {
28
+ tSystemError (" sem_open semaphore already exists: {}" , semaphoreName (_name));
22
29
return true ;
23
30
} else {
24
- tSystemError (" sem_open (init) failed: {}" , strerror (errno));
31
+ tSystemError (" sem_open (init) failed: {}" , ( const char *) strerror (errno));
25
32
return false ;
26
33
}
27
34
}
@@ -32,24 +39,58 @@ void TSharedMemory::initRwlock(header_t *) const
32
39
}
33
40
34
41
42
+ void TSharedMemory::releaseRwlock (header_t *) const
43
+ {
44
+ sem_unlink (semaphoreName (_name).data ());
45
+ }
46
+
47
+
35
48
bool TSharedMemory::lockForRead ()
36
49
{
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
+ }
38
63
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
+ }
43
88
}
44
89
45
- if (sem_wait (sem) < 0 ) {
46
- tSystemError (" sem_wait failed: {}" , strerror (errno));
90
+ if (sem != SEM_FAILED) {
47
91
sem_close (sem);
48
- return false ;
49
92
}
50
-
51
- sem_close (sem);
52
- return true ;
93
+ return !res;
53
94
}
54
95
55
96
@@ -62,16 +103,14 @@ bool TSharedMemory::lockForWrite()
62
103
63
104
bool TSharedMemory::unlock ()
64
105
{
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 );
68
107
if (sem == SEM_FAILED) {
69
- tSystemError (" sem_open (unlock) failed: {}" , strerror (errno));
108
+ tSystemError (" sem_open (unlock) failed: {}" , ( const char *) strerror (errno));
70
109
return false ;
71
110
}
72
111
73
112
if (sem_post (sem) < 0 ) {
74
- tSystemError (" sem_post failed: {}" , strerror (errno));
113
+ tSystemError (" sem_post failed: {}" , ( const char *) strerror (errno));
75
114
sem_close (sem);
76
115
return false ;
77
116
}
0 commit comments