Skip to content

Commit 271c756

Browse files
updated
1 parent 5bd9061 commit 271c756

File tree

6 files changed

+186
-96
lines changed

6 files changed

+186
-96
lines changed

src/corelib.pro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ linux-* {
412412
SOURCES += tthreadapplicationserver_linux.cpp
413413
SOURCES += tredisdriver_linux.cpp
414414
SOURCES += tmemcacheddriver_linux.cpp
415+
SOURCES += tsharedmemory_linux.cpp
415416
}
416417

417418
# For Mac
@@ -420,6 +421,7 @@ macx {
420421
SOURCES += tthreadapplicationserver_qt.cpp
421422
SOURCES += tredisdriver_qt.cpp
422423
SOURCES += tmemcacheddriver_qt.cpp
424+
SOURCES += tsharedmemory_macx.cpp
423425
}
424426

425427
# For UNIX

src/tsharedmemory.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
#ifdef Q_OS_WIN
44
#include <QSharedMemory>
55
#endif
6+
#ifdef Q_OS_LINUX
7+
#include <pthread.h>
8+
#endif
9+
610

711
class T_CORE_EXPORT TSharedMemory
812
#ifdef Q_OS_WIN
@@ -27,6 +31,15 @@ class T_CORE_EXPORT TSharedMemory
2731
bool unlock();
2832

2933
private:
34+
struct header_t {
35+
#ifdef Q_OS_LINUX
36+
pthread_rwlock_t rwlock;
37+
uint lockcounter {0};
38+
#endif
39+
};
40+
41+
void initRwlock(header_t *header) const;
42+
3043
#ifndef Q_OS_WIN
3144
QString _name;
3245
size_t _size {0};

src/tsharedmemory_linux.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* Copyright (c) 2022, AOYAMA Kazuharu
2+
* All rights reserved.
3+
*
4+
* This software may be used and distributed according to the terms of
5+
* the New BSD License, which is incorporated herein by reference.
6+
*/
7+
8+
#include "tsharedmemory.h"
9+
#include <pthread.h>
10+
11+
12+
void TSharedMemory::initRwlock(header_t *header) const
13+
{
14+
pthread_rwlockattr_t attr;
15+
16+
int res = pthread_rwlockattr_init(&attr);
17+
Q_ASSERT(!res);
18+
res = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); // Linux only
19+
Q_ASSERT(!res);
20+
res = pthread_rwlock_init(&header->rwlock, &attr);
21+
Q_ASSERT(!res);
22+
}
23+
24+
25+
bool TSharedMemory::lockForRead()
26+
{
27+
struct timespec timeout;
28+
header_t *header = (header_t *)_ptr;
29+
30+
while (pthread_rwlock_tryrdlock(&header->rwlock) == EBUSY) {
31+
uint cnt = header->lockcounter;
32+
timespec_get(&timeout, TIME_UTC);
33+
timeout.tv_sec += 1; // 1sec
34+
35+
int res = pthread_rwlock_timedrdlock(&header->rwlock, &timeout);
36+
if (!res) {
37+
// success
38+
break;
39+
} else {
40+
if (res == ETIMEDOUT && header->lockcounter == cnt) {
41+
// resets rwlock object
42+
initRwlock(header);
43+
}
44+
}
45+
}
46+
header->lockcounter++;
47+
return true;
48+
}
49+
50+
51+
bool TSharedMemory::lockForWrite()
52+
{
53+
struct timespec timeout;
54+
header_t *header = (header_t *)_ptr;
55+
56+
while (pthread_rwlock_trywrlock(&header->rwlock) == EBUSY) {
57+
uint cnt = header->lockcounter;
58+
timespec_get(&timeout, TIME_UTC);
59+
timeout.tv_sec += 1; // 1sec
60+
61+
int res = pthread_rwlock_timedwrlock(&header->rwlock, &timeout);
62+
if (!res) {
63+
// success
64+
break;
65+
} else {
66+
if (res == ETIMEDOUT && header->lockcounter == cnt) {
67+
// resets rwlock object
68+
initRwlock(header);
69+
}
70+
}
71+
}
72+
header->lockcounter++;
73+
return true;
74+
}
75+
76+
77+
bool TSharedMemory::unlock()
78+
{
79+
header_t *header = (header_t *)_ptr;
80+
pthread_rwlock_unlock(&header->rwlock);
81+
return true;
82+
}

src/tsharedmemory_macx.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* Copyright (c) 2025, AOYAMA Kazuharu
2+
* All rights reserved.
3+
*
4+
* This software may be used and distributed according to the terms of
5+
* the New BSD License, which is incorporated herein by reference.
6+
*/
7+
8+
#include "tsharedmemory.h"
9+
#include <semaphore.h>
10+
#include <fcntl.h> // O_CREAT, O_EXCL
11+
#include <sys/stat.h> // mode constants
12+
#include <errno.h>
13+
14+
15+
void TSharedMemory::initRwlock(header_t *) const
16+
{
17+
const QByteArray SEM_NAME = _name + "_global_lock";
18+
19+
sem_t* sem = sem_open(SEM_NAME.data(), O_CREAT | O_EXCL, 0644, 1);
20+
if (sem == SEM_FAILED) {
21+
if (errno == EEXIST) {
22+
return true;
23+
} else {
24+
tSystemError("sem_open (init) failed: {}", strerror(errno));
25+
return false;
26+
}
27+
}
28+
29+
tSystemDebug("Semaphore initialized");
30+
sem_close(sem);
31+
return true;
32+
}
33+
34+
35+
bool TSharedMemory::lockForRead()
36+
{
37+
const QByteArray SEM_NAME = _name + "_global_lock";
38+
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;
43+
}
44+
45+
if (sem_wait(sem) < 0) {
46+
tSystemError("sem_wait failed: {}", strerror(errno));
47+
sem_close(sem);
48+
return false;
49+
}
50+
51+
sem_close(sem);
52+
return true;
53+
}
54+
55+
56+
bool TSharedMemory::lockForWrite()
57+
{
58+
// Same as lockForRead()
59+
return lockForRead();
60+
}
61+
62+
63+
bool TSharedMemory::unlock()
64+
{
65+
const QByteArray SEM_NAME = _name + "_global_lock";
66+
67+
sem_t* sem = sem_open(SEM_NAME.data(), 0); // 既存を開く
68+
if (sem == SEM_FAILED) {
69+
tSystemError("sem_open (unlock) failed: {}", strerror(errno));
70+
return false;
71+
}
72+
73+
if (sem_post(sem) < 0) {
74+
tSystemError("sem_post failed: {}", strerror(errno));
75+
sem_close(sem);
76+
return false;
77+
}
78+
79+
sem_close(sem);
80+
return true;
81+
}

src/tsharedmemory_qt.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,7 @@ bool TSharedMemory::unlock()
103103
{
104104
return QSharedMemory::unlock();
105105
}
106+
107+
108+
void TSharedMemory::initRwlock(header_t *) const
109+
{}

src/tsharedmemory_unix.cpp

Lines changed: 4 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,8 @@
1212
#include <sys/mman.h>
1313
#include <sys/stat.h>
1414
#include <fcntl.h>
15-
#include <pthread.h>
1615
#include <time.h>
1716

18-
struct header_t {
19-
pthread_rwlock_t rwlock;
20-
uint lockcounter {0};
21-
};
22-
23-
24-
static void rwlock_init(pthread_rwlock_t *rwlock)
25-
{
26-
pthread_rwlockattr_t attr;
27-
28-
int res = pthread_rwlockattr_init(&attr);
29-
Q_ASSERT(!res);
30-
res = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
31-
Q_ASSERT(!res);
32-
res = pthread_rwlock_init(rwlock, &attr);
33-
Q_ASSERT(!res);
34-
}
35-
3617

3718
TSharedMemory::TSharedMemory(const QString &name) :
3819
_name(name)
@@ -52,17 +33,12 @@ TSharedMemory::~TSharedMemory()
5233

5334
bool TSharedMemory::create(size_t size)
5435
{
55-
static const header_t INIT_HEADER = []() {
56-
static header_t header;
57-
rwlock_init(&header.rwlock);
58-
return header;
59-
}();
60-
6136
if (_ptr || size == 0 || _name.isEmpty()) {
6237
return false;
6338
}
6439

6540
struct stat st;
41+
header_t *header = nullptr;
6642

6743
// Creates shared memory
6844
_fd = shm_open(qUtf8Printable(_name), O_CREAT | O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR);
@@ -90,7 +66,9 @@ bool TSharedMemory::create(size_t size)
9066
goto error;
9167
}
9268

93-
std::memcpy(_ptr, &INIT_HEADER, sizeof(INIT_HEADER));
69+
header = new (_ptr) header_t{};
70+
initRwlock(header);
71+
9472
_size = size;
9573
tSystemDebug("SharedMemory created. name:{} size:{}", qUtf8Printable(_name), (qulonglong)_size);
9674
return true;
@@ -202,73 +180,3 @@ size_t TSharedMemory::size() const
202180
{
203181
return _size;
204182
}
205-
206-
207-
bool TSharedMemory::lockForRead()
208-
{
209-
#ifdef Q_OS_LINUX
210-
struct timespec timeout;
211-
header_t *header = (header_t *)_ptr;
212-
213-
while (pthread_rwlock_tryrdlock(&header->rwlock) == EBUSY) {
214-
uint cnt = header->lockcounter;
215-
timespec_get(&timeout, TIME_UTC);
216-
timeout.tv_sec += 1; // 1sec
217-
218-
int res = pthread_rwlock_timedrdlock(&header->rwlock, &timeout);
219-
if (!res) {
220-
// success
221-
break;
222-
} else {
223-
if (res == ETIMEDOUT && header->lockcounter == cnt) {
224-
// resets rwlock object
225-
rwlock_init(&header->rwlock);
226-
}
227-
}
228-
}
229-
header->lockcounter++;
230-
return true;
231-
#else
232-
header_t *header = (header_t *)_ptr;
233-
return pthread_rwlock_rdlock(&header->rwlock) == 0;
234-
#endif
235-
}
236-
237-
238-
bool TSharedMemory::lockForWrite()
239-
{
240-
#ifdef Q_OS_LINUX
241-
struct timespec timeout;
242-
header_t *header = (header_t *)_ptr;
243-
244-
while (pthread_rwlock_trywrlock(&header->rwlock) == EBUSY) {
245-
uint cnt = header->lockcounter;
246-
timespec_get(&timeout, TIME_UTC);
247-
timeout.tv_sec += 1; // 1sec
248-
249-
int res = pthread_rwlock_timedwrlock(&header->rwlock, &timeout);
250-
if (!res) {
251-
// success
252-
break;
253-
} else {
254-
if (res == ETIMEDOUT && header->lockcounter == cnt) {
255-
// resets rwlock object
256-
rwlock_init(&header->rwlock);
257-
}
258-
}
259-
}
260-
header->lockcounter++;
261-
return true;
262-
#else
263-
header_t *header = (header_t *)_ptr;
264-
return pthread_rwlock_wrlock(&header->rwlock) == 0;
265-
#endif
266-
}
267-
268-
269-
bool TSharedMemory::unlock()
270-
{
271-
header_t *header = (header_t *)_ptr;
272-
pthread_rwlock_unlock(&header->rwlock);
273-
return true;
274-
}

0 commit comments

Comments
 (0)