Skip to content

Commit d0e2a4d

Browse files
committed
add semaphore for win
1 parent 415be36 commit d0e2a4d

File tree

8 files changed

+382
-1
lines changed

8 files changed

+382
-1
lines changed

include/libipc/mutex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class IPC_EXPORT mutex {
2525

2626
bool open(char const *name) noexcept;
2727
void close() noexcept;
28+
2829
bool lock(std::uint64_t tm = ipc::invalid_value) noexcept;
2930
bool try_lock() noexcept(false); // std::system_error
3031
bool unlock() noexcept;

include/libipc/semaphore.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
#include <cstdint> // std::uint64_t
4+
5+
#include "libipc/export.h"
6+
#include "libipc/def.h"
7+
8+
namespace ipc {
9+
namespace sync {
10+
11+
class IPC_EXPORT semaphore {
12+
semaphore(semaphore const &) = delete;
13+
semaphore &operator=(semaphore const &) = delete;
14+
15+
public:
16+
semaphore();
17+
explicit semaphore(char const *name, std::uint32_t count = 0, std::uint32_t limit = ipc::invalid_value);
18+
~semaphore();
19+
20+
void const *native() const noexcept;
21+
void *native() noexcept;
22+
23+
bool valid() const noexcept;
24+
25+
bool open(char const *name, std::uint32_t count = 0, std::uint32_t limit = ipc::invalid_value) noexcept;
26+
void close() noexcept;
27+
28+
bool wait(std::uint64_t tm = ipc::invalid_value) noexcept;
29+
bool post(std::uint32_t count = 1) noexcept;
30+
31+
private:
32+
class semaphore_;
33+
semaphore_* p_;
34+
};
35+
36+
} // namespace sync
37+
} // namespace ipc

src/libipc/platform/condition_linux.h

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
#include <pthread.h>
6+
7+
#include "libipc/utility/log.h"
8+
#include "libipc/platform/get_wait_time.h"
9+
#include "libipc/mutex.h"
10+
11+
namespace ipc {
12+
namespace detail {
13+
namespace sync {
14+
15+
class condition {
16+
ipc::shm::handle shm_;
17+
pthread_cond_t *cond_ = nullptr;
18+
19+
pthread_cond_t *acquire_cond(char const *name) {
20+
if (!shm_.acquire(name, sizeof(pthread_cond_t))) {
21+
ipc::error("[acquire_cond] fail shm.acquire: %s\n", name);
22+
return nullptr;
23+
}
24+
return static_cast<pthread_cond_t *>(shm_.get());
25+
}
26+
27+
public:
28+
condition() = default;
29+
explicit condition(char const *name) noexcept {
30+
open(name);
31+
}
32+
33+
~condition() = default;
34+
35+
pthread_cond_t const *native() const noexcept {
36+
return cond_;
37+
}
38+
39+
pthread_cond_t *native() noexcept {
40+
return cond_;
41+
}
42+
43+
bool valid() const noexcept {
44+
static const char tmp[sizeof(pthread_cond_t)] {};
45+
return (cond_ != nullptr)
46+
&& (std::memcmp(tmp, cond_, sizeof(pthread_cond_t)) != 0);
47+
}
48+
49+
bool open(char const *name) noexcept {
50+
close();
51+
if ((cond_ = acquire_cond(name)) == nullptr) {
52+
return false;
53+
}
54+
if (shm_.ref() == 1) {
55+
::pthread_cond_destroy(cond_);
56+
auto finally = ipc::guard([this] { close(); }); // close when failed
57+
// init condition
58+
int eno;
59+
pthread_condattr_t cond_attr;
60+
if ((eno = ::pthread_condattr_init(&cond_attr)) != 0) {
61+
ipc::error("fail pthread_condattr_init[%d]\n", eno);
62+
return false;
63+
}
64+
IPC_UNUSED_ auto guard_cond_attr = unique_ptr(&cond_attr, ::pthread_condattr_destroy);
65+
if ((eno = ::pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) != 0) {
66+
ipc::error("fail pthread_condattr_setpshared[%d]\n", eno);
67+
return false;
68+
}
69+
*cond_ = PTHREAD_COND_INITIALIZER;
70+
if ((eno = ::pthread_cond_init(cond_, &cond_attr)) != 0) {
71+
ipc::error("fail pthread_cond_init[%d]\n", eno);
72+
return false;
73+
}
74+
finally.dismiss();
75+
}
76+
return valid();
77+
}
78+
79+
void close() noexcept {
80+
if (shm_.ref() == 1) {
81+
int eno;
82+
if ((eno = ::pthread_cond_destroy(cond_)) != 0) {
83+
ipc::error("fail pthread_cond_destroy[%d]\n", eno);
84+
}
85+
}
86+
shm_.release();
87+
cond_ = nullptr;
88+
}
89+
90+
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
91+
switch (tm) {
92+
case 0:
93+
return true;
94+
case invalid_value: {
95+
int eno;
96+
if ((eno = ::pthread_cond_wait(cond_, mtx.native())) != 0) {
97+
ipc::error("fail pthread_cond_wait[%d]\n", eno);
98+
return false;
99+
}
100+
}
101+
break;
102+
default: {
103+
auto ts = detail::make_timespec(tm);
104+
int eno;
105+
if ((eno = ::pthread_cond_timedwait(cond_, mtx.native(), &ts)) != 0) {
106+
if (eno != ETIMEDOUT) {
107+
ipc::error("fail pthread_cond_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
108+
eno, tm, ts.tv_sec, ts.tv_nsec);
109+
}
110+
return false;
111+
}
112+
}
113+
break;
114+
}
115+
return true;
116+
}
117+
118+
bool notify() noexcept {
119+
int eno;
120+
if ((eno = ::pthread_cond_signal(cond_)) != 0) {
121+
ipc::error("fail pthread_cond_signal[%d]\n", eno);
122+
return false;
123+
}
124+
return true;
125+
}
126+
127+
bool broadcast() noexcept {
128+
int eno;
129+
if ((eno = ::pthread_cond_broadcast(cond_)) != 0) {
130+
ipc::error("fail pthread_cond_broadcast[%d]\n", eno);
131+
return false;
132+
}
133+
return true;
134+
}
135+
};
136+
137+
} // namespace sync
138+
} // namespace detail
139+
} // namespace ipc

src/libipc/platform/condition_win.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
#include <Windows.h>
6+
7+
#include "libipc/utility/log.h"
8+
#include "libipc/mutex.h"
9+
10+
namespace ipc {
11+
namespace detail {
12+
namespace sync {
13+
14+
class condition {
15+
HANDLE h_ = NULL;
16+
17+
public:
18+
condition() noexcept = default;
19+
explicit condition(char const *name) noexcept {
20+
open(name);
21+
}
22+
23+
~condition() noexcept = default;
24+
25+
HANDLE native() const noexcept {
26+
return h_;
27+
}
28+
29+
bool valid() const noexcept {
30+
return h_ != NULL;
31+
}
32+
33+
bool open(char const *name) noexcept {
34+
close();
35+
return valid();
36+
}
37+
38+
void close() noexcept {
39+
if (!valid()) return;
40+
::CloseHandle(h_);
41+
h_ = NULL;
42+
}
43+
44+
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
45+
return true;
46+
}
47+
48+
bool notify() noexcept {
49+
return true;
50+
}
51+
52+
bool broadcast() noexcept {
53+
return true;
54+
}
55+
};
56+
57+
} // namespace sync
58+
} // namespace detail
59+
} // namespace ipc

src/libipc/platform/mutex_linux.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class mutex {
2424

2525
pthread_mutex_t *acquire_mutex(char const *name) {
2626
if (!shm_.acquire(name, sizeof(pthread_mutex_t))) {
27-
ipc::error("fail shm.acquire: %s\n", name);
27+
ipc::error("[acquire_mutex] fail shm.acquire: %s\n", name);
2828
return nullptr;
2929
}
3030
return static_cast<pthread_mutex_t *>(shm_.get());

src/libipc/platform/semaphore_linux.h

Whitespace-only changes.

src/libipc/platform/semaphore_win.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
#include <Windows.h>
6+
7+
#include "libipc/utility/log.h"
8+
9+
#include "libipc/platform/to_tchar.h"
10+
#include "libipc/platform/get_sa.h"
11+
12+
namespace ipc {
13+
namespace detail {
14+
namespace sync {
15+
16+
class semaphore {
17+
HANDLE h_ = NULL;
18+
19+
public:
20+
semaphore() noexcept = default;
21+
explicit semaphore(char const *name, std::uint32_t count, std::uint32_t limit) noexcept {
22+
open(name, count, limit);
23+
}
24+
25+
~semaphore() noexcept = default;
26+
27+
HANDLE native() const noexcept {
28+
return h_;
29+
}
30+
31+
bool valid() const noexcept {
32+
return h_ != NULL;
33+
}
34+
35+
bool open(char const *name, std::uint32_t count, std::uint32_t limit) noexcept {
36+
close();
37+
h_ = ::CreateSemaphore(detail::get_sa(),
38+
static_cast<LONG>(count),
39+
(limit == invalid_value) ? LONG_MAX : static_cast<LONG>(limit),
40+
ipc::detail::to_tchar(name).c_str());
41+
if (h_ == NULL) {
42+
ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name);
43+
return false;
44+
}
45+
return true;
46+
}
47+
48+
void close() noexcept {
49+
if (!valid()) return;
50+
::CloseHandle(h_);
51+
h_ = NULL;
52+
}
53+
54+
bool wait(std::uint64_t tm) noexcept {
55+
DWORD ret, ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm);
56+
switch ((ret = ::WaitForSingleObject(h_, ms))) {
57+
case WAIT_OBJECT_0:
58+
return true;
59+
case WAIT_TIMEOUT:
60+
return false;
61+
case WAIT_ABANDONED:
62+
default:
63+
ipc::error("fail WaitForSingleObject[%lu]: 0x%08X\n", ::GetLastError(), ret);
64+
return false;
65+
}
66+
}
67+
68+
bool post(std::uint32_t count) noexcept {
69+
if (!::ReleaseSemaphore(h_, static_cast<LONG>(count), NULL)) {
70+
ipc::error("fail ReleaseSemaphore[%lu]\n", ::GetLastError());
71+
return false;
72+
}
73+
return true;
74+
}
75+
};
76+
77+
} // namespace sync
78+
} // namespace detail
79+
} // namespace ipc

0 commit comments

Comments
 (0)