Alexandria 2.31.0
SDC-CH common library for the Euclid project
Loading...
Searching...
No Matches
SemaphoreMach.icpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2012-2021 Euclid Science Ground Segment
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 3.0 of the License, or (at your option)
7 * any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <cerrno>
20#include <mach/mach_init.h>
21#include <mach/mach_traps.h>
22#include <mach/semaphore.h>
23#include <mach/task.h>
24#include <system_error>
25
26namespace Euclid {
27class Semaphore::SemaphoreImpl {
28public:
29 explicit SemaphoreImpl(unsigned int i) {
30 auto ret = semaphore_create(mach_task_self(), &m_semaphore, SYNC_POLICY_FIFO, i);
31 if (ret != KERN_SUCCESS) {
32 throw std::system_error(errno, std::system_category());
33 }
34 }
35
36 ~SemaphoreImpl() {
37 semaphore_destroy(mach_task_self(), m_semaphore);
38 }
39
40 void post() {
41 if (semaphore_signal(m_semaphore) != KERN_SUCCESS) {
42 throw std::system_error(EINVAL, std::system_category());
43 }
44 }
45
46 void wait() {
47 for (;;) {
48 auto ret = semaphore_wait(m_semaphore);
49 if (ret == KERN_SUCCESS) {
50 return;
51 }
52 if (ret == KERN_ABORTED) {
53 continue;
54 }
55 throw std::system_error(EINVAL, std::system_category());
56 }
57 }
58
59 bool try_acquire() {
60 const mach_timespec_t wait{0, 0};
61 return timed_wait(wait);
62 }
63
64 bool try_acquire_until(std::chrono::system_clock::time_point abs_time) {
65 using std::chrono::duration_cast;
66
67 auto now = std::chrono::system_clock::now();
68 auto left = abs_time - now;
69
70 auto seconds = duration_cast<std::chrono::seconds>(left);
71 auto nseconds = duration_cast<std::chrono::nanoseconds>(left) - duration_cast<std::chrono::nanoseconds>(seconds);
72
73 const mach_timespec_t wait{static_cast<unsigned int>(seconds.count()), static_cast<int>(nseconds.count())};
74 return timed_wait(wait);
75 }
76
77private:
78 semaphore_t m_semaphore;
79
80 bool timed_wait(const mach_timespec_t& wait) {
81 auto ret = semaphore_timedwait(m_semaphore, wait);
82 if (ret == KERN_SUCCESS) {
83 return true;
84 }
85 if (ret == KERN_OPERATION_TIMED_OUT) {
86 return false;
87 }
88 throw std::system_error(EINVAL, std::system_category());
89 }
90};
91} // namespace Euclid