Skip to content

Commit c995c31

Browse files
committed
Add IpcSharedSignal.
1 parent bcd1b7a commit c995c31

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed

src/common/ipc/IpcSharedSignal.h

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* The contents of this file are subject to the Initial
3+
* Developer's Public License Version 1.0 (the "License");
4+
* you may not use this file except in compliance with the
5+
* License. You may obtain a copy of the License at
6+
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
7+
*
8+
* Software distributed under the License is distributed AS IS,
9+
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing rights
11+
* and limitations under the License.
12+
*
13+
* The Original Code was created by Adriano dos Santos Fernandes
14+
* for the Firebird Open Source RDBMS project.
15+
*
16+
* Copyright (c) 2025 Adriano dos Santos Fernandes <[email protected]>
17+
* and all contributors signed below.
18+
*
19+
* All Rights Reserved.
20+
* Contributor(s): ______________________________________.
21+
*/
22+
23+
#ifndef COMMON_IPC_SHARED_SIGNAL_H
24+
#define COMMON_IPC_SHARED_SIGNAL_H
25+
26+
#include "firebird.h"
27+
28+
#ifdef WIN_NT
29+
#error This is not supported in Windows.
30+
#endif
31+
32+
#ifndef PTHREAD_PROCESS_SHARED
33+
#error Your system must support PTHREAD_PROCESS_SHARED to use firebird.
34+
#endif
35+
36+
#include "../StatusArg.h"
37+
#include "../common/os/mac_utils.h"
38+
#include "../utils_proto.h"
39+
#include <chrono>
40+
#include "fb_pthread.h"
41+
42+
namespace Firebird {
43+
44+
45+
class IpcSharedSignal
46+
{
47+
public:
48+
explicit IpcSharedSignal();
49+
~IpcSharedSignal();
50+
51+
IpcSharedSignal(const IpcSharedSignal&) = delete;
52+
IpcSharedSignal& operator=(const IpcSharedSignal&) = delete;
53+
54+
public:
55+
void reset();
56+
void signal();
57+
bool wait(std::chrono::microseconds timeout);
58+
59+
private:
60+
pthread_mutex_t mutex[1];
61+
pthread_cond_t cond[1];
62+
std::atomic_uint8_t flag = 0;
63+
};
64+
65+
66+
inline IpcSharedSignal::IpcSharedSignal()
67+
{
68+
pthread_mutexattr_t mattr;
69+
pthread_condattr_t cattr;
70+
71+
if (pthread_mutexattr_init(&mattr) != 0)
72+
system_error::raise("pthread_mutexattr_init");
73+
74+
if (pthread_condattr_init(&cattr) != 0)
75+
system_error::raise("pthread_condattr_init");
76+
77+
if (!isSandboxed())
78+
{
79+
if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED) != 0)
80+
system_error::raise("pthread_mutexattr_setpshared");
81+
82+
if (pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED) != 0)
83+
system_error::raise("pthread_condattr_setpshared");
84+
}
85+
86+
if (pthread_mutex_init(mutex, &mattr) != 0)
87+
system_error::raise("pthread_mutex_init");
88+
89+
if (pthread_cond_init(cond, &cattr) != 0)
90+
system_error::raise("pthread_cond_init");
91+
92+
if (pthread_mutexattr_destroy(&mattr) != 0)
93+
system_error::raise("pthread_mutexattr_destroy");
94+
95+
if (pthread_condattr_destroy(&cattr) != 0)
96+
system_error::raise("pthread_condattr_destroy");
97+
}
98+
99+
inline IpcSharedSignal::~IpcSharedSignal()
100+
{
101+
pthread_mutex_destroy(mutex);
102+
pthread_cond_destroy(cond);
103+
}
104+
105+
inline void IpcSharedSignal::reset()
106+
{
107+
flag.store(0, std::memory_order_release);
108+
}
109+
110+
inline void IpcSharedSignal::signal()
111+
{
112+
if (pthread_mutex_lock(mutex) != 0)
113+
system_error::raise("pthread_mutex_lock");
114+
115+
flag.store(1, std::memory_order_release);
116+
117+
const auto ret = pthread_cond_broadcast(cond);
118+
119+
if (pthread_mutex_unlock(mutex) != 0)
120+
system_error::raise("pthread_mutex_unlock");
121+
122+
if (ret != 0)
123+
system_error::raise("pthread_cond_broadcast");
124+
}
125+
126+
inline bool IpcSharedSignal::wait(std::chrono::microseconds timeout)
127+
{
128+
if (flag.load(std::memory_order_acquire) == 1)
129+
return true;
130+
131+
timespec timer;
132+
133+
#if defined(HAVE_CLOCK_GETTIME)
134+
clock_gettime(CLOCK_REALTIME, &timer);
135+
#elif defined(HAVE_GETTIMEOFDAY)
136+
struct timeval tp;
137+
GETTIMEOFDAY(&tp);
138+
timer.tv_sec = tp.tv_sec;
139+
timer.tv_nsec = tp.tv_usec * 1'000;
140+
#else
141+
struct timeb time_buffer;
142+
ftime(&time_buffer);
143+
timer.tv_sec = time_buffer.time;
144+
timer.tv_nsec = time_buffer.millitm * 1'000'000;
145+
#endif
146+
147+
bool ret = true;
148+
149+
if (pthread_mutex_lock(mutex) != 0)
150+
system_error::raise("pthread_mutex_lock");
151+
152+
do
153+
{
154+
if (flag.load(std::memory_order_acquire) == 1)
155+
{
156+
ret = true;
157+
break;
158+
}
159+
160+
// The Posix pthread_cond_wait & pthread_cond_timedwait calls
161+
// atomically release the mutex and start a wait.
162+
// The mutex is reacquired before the call returns.
163+
const auto wait = pthread_cond_timedwait(cond, mutex, &timer);
164+
165+
if (wait == ETIMEDOUT)
166+
{
167+
// The timer expired - see if the event occurred and return
168+
ret = flag.load(std::memory_order_acquire) == 1;
169+
break;
170+
}
171+
} while (true);
172+
173+
if (pthread_mutex_unlock(mutex) != 0)
174+
system_error::raise("pthread_mutex_unlock");
175+
176+
return ret;
177+
}
178+
179+
180+
} // namespace Firebird
181+
182+
#endif // COMMON_IPC_SHARED_SIGNAL_H

0 commit comments

Comments
 (0)