Skip to content

Commit bcd1b7a

Browse files
committed
Add IpcNamedSignal.
1 parent 4554c09 commit bcd1b7a

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed

builds/win32/msvc15/common.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
<ClInclude Include="..\..\..\src\common\IntlUtil.h" />
200200
<ClInclude Include="..\..\..\src\common\ipc\IpcChat.h" />
201201
<ClInclude Include="..\..\..\src\common\ipc\IpcMessage.h" />
202+
<ClInclude Include="..\..\..\src\common\ipc\IpcNamedSignal.h" />
202203
<ClInclude Include="..\..\..\src\common\isc_f_proto.h" />
203204
<ClInclude Include="..\..\..\src\common\isc_proto.h" />
204205
<ClInclude Include="..\..\..\src\common\isc_s_proto.h" />

builds/win32/msvc15/common.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,5 +632,8 @@
632632
<ClInclude Include="..\..\..\src\common\ipc\IpcMessage.h">
633633
<Filter>headers</Filter>
634634
</ClInclude>
635+
<ClInclude Include="..\..\..\src\common\ipc\IpcNamedSignal.h">
636+
<Filter>headers</Filter>
637+
</ClInclude>
635638
</ItemGroup>
636639
</Project>

src/common/ipc/IpcNamedSignal.h

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
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_NAMED_SIGNAL_H
24+
#define COMMON_IPC_NAMED_SIGNAL_H
25+
26+
#include "firebird.h"
27+
#include "../classes/fb_string.h"
28+
#include "../StatusArg.h"
29+
#include "../utils_proto.h"
30+
#include <chrono>
31+
#ifdef WIN_NT
32+
#include <windows.h>
33+
#else
34+
#include "fb_pthread.h"
35+
#include <errno.h>
36+
#include <fcntl.h>
37+
#include <semaphore.h>
38+
#endif
39+
40+
#ifdef ANDROID
41+
#error This is not supported in Android.
42+
#endif
43+
44+
namespace Firebird {
45+
46+
47+
// An event in Windows, a semaphore in POSIX.
48+
class IpcNamedSignal
49+
{
50+
public:
51+
explicit IpcNamedSignal(const string& name);
52+
~IpcNamedSignal();
53+
54+
IpcNamedSignal(const IpcNamedSignal&) = delete;
55+
IpcNamedSignal& operator=(const IpcNamedSignal&) = delete;
56+
57+
private:
58+
static string fixName(const string& name);
59+
60+
#ifndef WIN_NT
61+
public:
62+
static void remove(const string& name)
63+
{
64+
if (sem_unlink(fixName(name).c_str()) != 0)
65+
fb_assert(false);
66+
}
67+
#endif
68+
69+
public:
70+
void reset();
71+
void signal();
72+
bool wait(std::chrono::microseconds timeout);
73+
74+
private:
75+
#ifdef WIN_NT
76+
HANDLE handle = INVALID_HANDLE_VALUE;
77+
#else
78+
sem_t* handle = nullptr;
79+
#endif
80+
};
81+
82+
83+
#ifdef WIN_NT
84+
85+
86+
inline IpcNamedSignal::IpcNamedSignal(const string& name)
87+
{
88+
TEXT objectName[BUFFER_TINY];
89+
strncpy(objectName, name.c_str(), sizeof(objectName));
90+
91+
if (!fb_utils::private_kernel_object_name(objectName, sizeof(objectName)))
92+
(Arg::Gds(isc_random) << "private_kernel_object_name failed").raise();
93+
94+
handle = CreateEvent(nullptr, TRUE, FALSE, objectName);
95+
96+
if (!handle)
97+
system_error::raise("CreateEvent");
98+
99+
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
100+
}
101+
102+
inline IpcNamedSignal::~IpcNamedSignal()
103+
{
104+
if (handle)
105+
CloseHandle(handle);
106+
}
107+
108+
inline string IpcNamedSignal::fixName(const string& name)
109+
{
110+
return name;
111+
}
112+
113+
inline void IpcNamedSignal::reset()
114+
{
115+
ResetEvent(handle);
116+
}
117+
118+
inline void IpcNamedSignal::signal()
119+
{
120+
if (!SetEvent(handle))
121+
system_error::raise("SetEvent");
122+
}
123+
124+
inline bool IpcNamedSignal::wait(std::chrono::microseconds timeout)
125+
{
126+
const auto wait = WaitForSingleObject(handle, timeout.count() / 1'000);
127+
128+
if (wait == WAIT_OBJECT_0)
129+
return true;
130+
else if (wait == WAIT_TIMEOUT)
131+
return false;
132+
else
133+
system_error::raise("WaitForSingleObject");
134+
}
135+
136+
137+
#else
138+
139+
140+
inline IpcNamedSignal::IpcNamedSignal(const string& name)
141+
{
142+
handle = sem_open(fixName(name).c_str(), O_CREAT, S_IRUSR | S_IWUSR, 0);
143+
144+
if (handle == SEM_FAILED)
145+
system_error::raise("sem_open");
146+
}
147+
148+
inline IpcNamedSignal::~IpcNamedSignal()
149+
{
150+
if (handle)
151+
sem_close(handle);
152+
}
153+
154+
inline string IpcNamedSignal::fixName(const string& name)
155+
{
156+
if (name[0] == '/')
157+
return name;
158+
159+
return "/" + name;
160+
}
161+
162+
inline void IpcNamedSignal::reset()
163+
{
164+
int semVal;
165+
166+
while (sem_getvalue(handle, &semVal) == 0 && semVal > 0)
167+
sem_trywait(handle);
168+
}
169+
170+
inline void IpcNamedSignal::signal()
171+
{
172+
if (sem_post(handle) != 0)
173+
system_error::raise("sem_post");
174+
}
175+
176+
inline bool IpcNamedSignal::wait(std::chrono::microseconds timeout)
177+
{
178+
timespec timer;
179+
180+
#if defined(HAVE_CLOCK_GETTIME)
181+
clock_gettime(CLOCK_REALTIME, &timer);
182+
#elif defined(HAVE_GETTIMEOFDAY)
183+
struct timeval tp;
184+
GETTIMEOFDAY(&tp);
185+
timer.tv_sec = tp.tv_sec;
186+
timer.tv_nsec = tp.tv_usec * 1'000;
187+
#else
188+
struct timeb time_buffer;
189+
ftime(&time_buffer);
190+
timer.tv_sec = time_buffer.time;
191+
timer.tv_nsec = time_buffer.millitm * 1'000'000;
192+
#endif
193+
194+
constexpr SINT64 BILLION = 1'000'000'000;
195+
const SINT64 nanos =
196+
std::chrono::seconds(timer.tv_sec).count() + timer.tv_nsec + std::chrono::nanoseconds(timeout).count();
197+
timer.tv_sec = nanos / BILLION;
198+
timer.tv_nsec = nanos % BILLION;
199+
200+
#ifdef HAVE_SEM_TIMEDWAIT
201+
const auto wait = sem_timedwait(handle, &timer);
202+
#else
203+
const auto wait = sem_timedwait_fallback(handle, &timer);
204+
#endif
205+
206+
if (wait == 0)
207+
return true;
208+
else if (errno == ETIMEDOUT)
209+
return false;
210+
else
211+
system_error::raise("sem_timedwait");
212+
}
213+
214+
215+
#endif
216+
217+
218+
} // namespace Firebird
219+
220+
#endif // COMMON_IPC_NAMED_SIGNAL_H

0 commit comments

Comments
 (0)