]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/log/src/windows/ipc_sync_wrappers.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / log / src / windows / ipc_sync_wrappers.hpp
CommitLineData
7c673cae
FG
1/*
2 * Copyright Andrey Semashev 2016.
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
6 */
7/*!
8 * \file windows/ipc_sync_wrappers.hpp
9 * \author Andrey Semashev
10 * \date 23.01.2016
11 *
12 * \brief This header is the Boost.Log library implementation, see the library documentation
13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14 */
15
16#ifndef BOOST_LOG_WINDOWS_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
17#define BOOST_LOG_WINDOWS_IPC_SYNC_WRAPPERS_HPP_INCLUDED_
18
19#include <boost/log/detail/config.hpp>
b32b8144
FG
20#include <boost/winapi/access_rights.hpp>
21#include <boost/winapi/handles.hpp>
22#include <boost/winapi/event.hpp>
23#include <boost/winapi/semaphore.hpp>
24#include <boost/winapi/wait.hpp>
25#include <boost/winapi/dll.hpp>
26#include <boost/winapi/time.hpp>
27#include <boost/winapi/get_last_error.hpp>
7c673cae
FG
28#include <cstddef>
29#include <limits>
30#include <string>
31#include <utility>
32#include <boost/assert.hpp>
33#include <boost/throw_exception.hpp>
34#include <boost/checked_delete.hpp>
35#include <boost/memory_order.hpp>
36#include <boost/atomic/atomic.hpp>
37#include <boost/intrusive/options.hpp>
38#include <boost/intrusive/set.hpp>
39#include <boost/intrusive/set_hook.hpp>
40#include <boost/intrusive/list.hpp>
41#include <boost/intrusive/list_hook.hpp>
42#include <boost/log/exceptions.hpp>
43#include <boost/log/utility/permissions.hpp>
44#include "windows/auto_handle.hpp"
45#include <boost/log/detail/header.hpp>
46
47namespace boost {
48
49BOOST_LOG_OPEN_NAMESPACE
50
51namespace ipc {
52
53namespace aux {
54
55// TODO: Port to Boost.Atomic when it supports extended atomic ops
56#if defined(BOOST_MSVC) && (_MSC_VER >= 1400) && !defined(UNDER_CE)
57
58#if _MSC_VER == 1400
59extern "C" unsigned char _interlockedbittestandset(long *a, long b);
60extern "C" unsigned char _interlockedbittestandreset(long *a, long b);
61#else
62extern "C" unsigned char _interlockedbittestandset(volatile long *a, long b);
63extern "C" unsigned char _interlockedbittestandreset(volatile long *a, long b);
64#endif
65
66#pragma intrinsic(_interlockedbittestandset)
67#pragma intrinsic(_interlockedbittestandreset)
68
69BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
70{
71 return _interlockedbittestandset(reinterpret_cast< long* >(&x.storage()), static_cast< long >(bit)) != 0;
72}
73
74BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
75{
76 return _interlockedbittestandreset(reinterpret_cast< long* >(&x.storage()), static_cast< long >(bit)) != 0;
77}
78
79#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
80
81BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
82{
83 boost::atomic< uint32_t >::storage_type* p = &x.storage();
84 bool ret;
85 __asm
86 {
87 mov eax, bit
88 mov edx, p
89 lock bts [edx], eax
90 setc ret
91 };
92 return ret;
93}
94
95BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
96{
97 boost::atomic< uint32_t >::storage_type* p = &x.storage();
98 bool ret;
99 __asm
100 {
101 mov eax, bit
102 mov edx, p
103 lock btr [edx], eax
104 setc ret
105 };
106 return ret;
107}
108
109#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
110
111#if !defined(__CUDACC__)
112#define BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA "cc",
113#else
114#define BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA
115#endif
116
117BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
118{
119 bool res;
120 __asm__ __volatile__
121 (
122 "lock; bts %[bit_number], %[storage]\n\t"
123 "setc %[result]\n\t"
124 : [storage] "+m" (x.storage()), [result] "=q" (res)
125 : [bit_number] "Kq" (bit)
126 : BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
127 );
128 return res;
129}
130
131BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
132{
133 bool res;
134 __asm__ __volatile__
135 (
136 "lock; btr %[bit_number], %[storage]\n\t"
137 "setc %[result]\n\t"
138 : [storage] "+m" (x.storage()), [result] "=q" (res)
139 : [bit_number] "Kq" (bit)
140 : BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA "memory"
141 );
142 return res;
143}
144
145#else
146
147BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
148{
149 const uint32_t mask = uint32_t(1u) << bit;
150 uint32_t old_val = x.fetch_or(mask, boost::memory_order_acq_rel);
151 return (old_val & mask) != 0u;
152}
153
154BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT
155{
156 const uint32_t mask = uint32_t(1u) << bit;
157 uint32_t old_val = x.fetch_and(~mask, boost::memory_order_acq_rel);
158 return (old_val & mask) != 0u;
159}
160
161#endif
162
163//! Interprocess event object
164class interprocess_event
165{
166private:
167 auto_handle m_event;
168
169public:
170 void create(const wchar_t* name, bool manual_reset, permissions const& perms = permissions());
171 void create_or_open(const wchar_t* name, bool manual_reset, permissions const& perms = permissions());
172 void open(const wchar_t* name);
173
b32b8144 174 boost::winapi::HANDLE_ get_handle() const BOOST_NOEXCEPT { return m_event.get(); }
7c673cae
FG
175
176 void set()
177 {
b32b8144 178 if (BOOST_UNLIKELY(!boost::winapi::SetEvent(m_event.get())))
7c673cae 179 {
b32b8144 180 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
181 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to set an interprocess event object", (err));
182 }
183 }
184
185 void set_noexcept() BOOST_NOEXCEPT
186 {
b32b8144 187 BOOST_VERIFY(!!boost::winapi::SetEvent(m_event.get()));
7c673cae
FG
188 }
189
190 void reset()
191 {
b32b8144 192 if (BOOST_UNLIKELY(!boost::winapi::ResetEvent(m_event.get())))
7c673cae 193 {
b32b8144 194 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
195 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to reset an interprocess event object", (err));
196 }
197 }
198
199 void wait()
200 {
b32b8144
FG
201 const boost::winapi::DWORD_ retval = boost::winapi::WaitForSingleObject(m_event.get(), boost::winapi::infinite);
202 if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
7c673cae 203 {
b32b8144 204 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
205 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess event object", (err));
206 }
207 }
208
b32b8144 209 bool wait(boost::winapi::HANDLE_ abort_handle)
7c673cae 210 {
b32b8144
FG
211 boost::winapi::HANDLE_ handles[2u] = { m_event.get(), abort_handle };
212 const boost::winapi::DWORD_ retval = boost::winapi::WaitForMultipleObjects(2u, handles, false, boost::winapi::infinite);
213 if (retval == (boost::winapi::wait_object_0 + 1u))
7c673cae
FG
214 {
215 // Wait was interrupted
216 return false;
217 }
b32b8144 218 else if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
7c673cae 219 {
b32b8144 220 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
221 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess event object", (err));
222 }
223
224 return true;
225 }
226
227 void swap(interprocess_event& that) BOOST_NOEXCEPT
228 {
229 m_event.swap(that.m_event);
230 }
231};
232
233//! Interprocess semaphore object
234class interprocess_semaphore
235{
236private:
b32b8144 237 typedef boost::winapi::DWORD_ NTSTATUS_;
7c673cae
FG
238 struct semaphore_basic_information
239 {
b32b8144
FG
240 boost::winapi::ULONG_ current_count; // current semaphore count
241 boost::winapi::ULONG_ maximum_count; // max semaphore count
7c673cae 242 };
b32b8144
FG
243 typedef NTSTATUS_ (__stdcall *nt_query_semaphore_t)(boost::winapi::HANDLE_ h, unsigned int info_class, semaphore_basic_information* pinfo, boost::winapi::ULONG_ info_size, boost::winapi::ULONG_* ret_len);
244 typedef bool (*is_semaphore_zero_count_t)(boost::winapi::HANDLE_ h);
7c673cae
FG
245
246private:
247 auto_handle m_sem;
248
249 static boost::atomic< is_semaphore_zero_count_t > is_semaphore_zero_count;
250 static nt_query_semaphore_t nt_query_semaphore;
251
252public:
253 void create_or_open(const wchar_t* name, permissions const& perms = permissions());
254 void open(const wchar_t* name);
255
b32b8144 256 boost::winapi::HANDLE_ get_handle() const BOOST_NOEXCEPT { return m_sem.get(); }
7c673cae
FG
257
258 void post(uint32_t count)
259 {
b32b8144 260 BOOST_ASSERT(count <= static_cast< uint32_t >((std::numeric_limits< boost::winapi::LONG_ >::max)()));
7c673cae 261
b32b8144 262 if (BOOST_UNLIKELY(!boost::winapi::ReleaseSemaphore(m_sem.get(), static_cast< boost::winapi::LONG_ >(count), NULL)))
7c673cae 263 {
b32b8144 264 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
265 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to post on an interprocess semaphore object", (err));
266 }
267 }
268
269 bool is_zero_count() const
270 {
271 return is_semaphore_zero_count.load(boost::memory_order_acquire)(m_sem.get());
272 }
273
274 void wait()
275 {
b32b8144
FG
276 const boost::winapi::DWORD_ retval = boost::winapi::WaitForSingleObject(m_sem.get(), boost::winapi::infinite);
277 if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
7c673cae 278 {
b32b8144 279 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
280 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess semaphore object", (err));
281 }
282 }
283
b32b8144 284 bool wait(boost::winapi::HANDLE_ abort_handle)
7c673cae 285 {
b32b8144
FG
286 boost::winapi::HANDLE_ handles[2u] = { m_sem.get(), abort_handle };
287 const boost::winapi::DWORD_ retval = boost::winapi::WaitForMultipleObjects(2u, handles, false, boost::winapi::infinite);
288 if (retval == (boost::winapi::wait_object_0 + 1u))
7c673cae
FG
289 {
290 // Wait was interrupted
291 return false;
292 }
b32b8144 293 else if (BOOST_UNLIKELY(retval != boost::winapi::wait_object_0))
7c673cae 294 {
b32b8144 295 const boost::winapi::DWORD_ err = boost::winapi::GetLastError();
7c673cae
FG
296 BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to block on an interprocess semaphore object", (err));
297 }
298
299 return true;
300 }
301
302 void swap(interprocess_semaphore& that) BOOST_NOEXCEPT
303 {
304 m_sem.swap(that.m_sem);
305 }
306
307private:
b32b8144
FG
308 static bool is_semaphore_zero_count_init(boost::winapi::HANDLE_ h);
309 static bool is_semaphore_zero_count_nt_query_semaphore(boost::winapi::HANDLE_ h);
310 static bool is_semaphore_zero_count_emulated(boost::winapi::HANDLE_ h);
7c673cae
FG
311};
312
313//! Interprocess mutex. Implementation adopted from Boost.Sync.
314class interprocess_mutex
315{
316public:
317 //! Shared state that should be visible to all processes using the mutex
318 struct shared_state
319 {
320 boost::atomic< uint32_t > m_lock_state;
321
322 shared_state() BOOST_NOEXCEPT : m_lock_state(0u)
323 {
324 }
325 };
326
327 struct auto_unlock
328 {
329 explicit auto_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(mutex) {}
330 ~auto_unlock() { m_mutex.unlock(); }
331
332 BOOST_DELETED_FUNCTION(auto_unlock(auto_unlock const&))
333 BOOST_DELETED_FUNCTION(auto_unlock& operator=(auto_unlock const&))
334
335 private:
336 interprocess_mutex& m_mutex;
337 };
338
339 struct optional_unlock
340 {
341 optional_unlock() BOOST_NOEXCEPT : m_mutex(NULL) {}
342 explicit optional_unlock(interprocess_mutex& mutex) BOOST_NOEXCEPT : m_mutex(&mutex) {}
343 ~optional_unlock() { if (m_mutex) m_mutex->unlock(); }
344
345 interprocess_mutex* disengage() BOOST_NOEXCEPT
346 {
347 interprocess_mutex* p = m_mutex;
348 m_mutex = NULL;
349 return p;
350 }
351
352 void engage(interprocess_mutex& mutex) BOOST_NOEXCEPT
353 {
354 BOOST_ASSERT(!m_mutex);
355 m_mutex = &mutex;
356 }
357
358 BOOST_DELETED_FUNCTION(optional_unlock(optional_unlock const&))
359 BOOST_DELETED_FUNCTION(optional_unlock& operator=(optional_unlock const&))
360
361 private:
362 interprocess_mutex* m_mutex;
363 };
364
365private:
366 interprocess_event m_event;
367 shared_state* m_shared_state;
368
369#if !defined(BOOST_MSVC) || _MSC_VER >= 1800
370 static BOOST_CONSTEXPR_OR_CONST uint32_t lock_flag_bit = 31u;
371 static BOOST_CONSTEXPR_OR_CONST uint32_t event_set_flag_bit = 30u;
372 static BOOST_CONSTEXPR_OR_CONST uint32_t lock_flag_value = 1u << lock_flag_bit;
373 static BOOST_CONSTEXPR_OR_CONST uint32_t event_set_flag_value = 1u << event_set_flag_bit;
374 static BOOST_CONSTEXPR_OR_CONST uint32_t waiter_count_mask = event_set_flag_value - 1u;
375#else
376 // MSVC 8-11, inclusively, fail to link if these constants are declared as static constants instead of an enum
377 enum
378 {
379 lock_flag_bit = 31u,
380 event_set_flag_bit = 30u,
381 lock_flag_value = 1u << lock_flag_bit,
382 event_set_flag_value = 1u << event_set_flag_bit,
383 waiter_count_mask = event_set_flag_value - 1u
384 };
385#endif
386
387public:
388 interprocess_mutex() BOOST_NOEXCEPT : m_shared_state(NULL)
389 {
390 }
391
392 void create(const wchar_t* name, shared_state* shared, permissions const& perms = permissions())
393 {
394 m_event.create(name, false, perms);
395 m_shared_state = shared;
396 }
397
398 void open(const wchar_t* name, shared_state* shared)
399 {
400 m_event.open(name);
401 m_shared_state = shared;
402 }
403
404 bool try_lock()
405 {
406 return !bit_test_and_set(m_shared_state->m_lock_state, lock_flag_bit);
407 }
408
409 void lock()
410 {
411 if (BOOST_UNLIKELY(!try_lock()))
412 lock_slow();
413 }
414
b32b8144 415 bool lock(boost::winapi::HANDLE_ abort_handle)
7c673cae
FG
416 {
417 if (BOOST_LIKELY(try_lock()))
418 return true;
419 return lock_slow(abort_handle);
420 }
421
422 void unlock() BOOST_NOEXCEPT
423 {
424 const uint32_t old_count = m_shared_state->m_lock_state.fetch_add(lock_flag_value, boost::memory_order_release);
425 if ((old_count & event_set_flag_value) == 0u && (old_count > lock_flag_value))
426 {
427 if (!bit_test_and_set(m_shared_state->m_lock_state, event_set_flag_bit))
428 {
429 m_event.set_noexcept();
430 }
431 }
432 }
433
434 BOOST_DELETED_FUNCTION(interprocess_mutex(interprocess_mutex const&))
435 BOOST_DELETED_FUNCTION(interprocess_mutex& operator=(interprocess_mutex const&))
436
437private:
438 void lock_slow();
b32b8144 439 bool lock_slow(boost::winapi::HANDLE_ abort_handle);
7c673cae
FG
440 void mark_waiting_and_try_lock(uint32_t& old_state);
441 void clear_waiting_and_try_lock(uint32_t& old_state);
442};
443
444//! A simple clock that corresponds to GetTickCount/GetTickCount64 timeline
445struct tick_count_clock
446{
447#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
b32b8144 448 typedef boost::winapi::ULONGLONG_ time_point;
7c673cae 449#else
b32b8144 450 typedef boost::winapi::DWORD_ time_point;
7c673cae
FG
451#endif
452
453 static time_point now() BOOST_NOEXCEPT
454 {
455#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
b32b8144 456 return boost::winapi::GetTickCount64();
7c673cae 457#else
b32b8144 458 return boost::winapi::GetTickCount();
7c673cae
FG
459#endif
460 }
461};
462
463//! Interprocess condition variable
464class interprocess_condition_variable
465{
466private:
467 typedef boost::intrusive::list_base_hook<
468 boost::intrusive::tag< struct for_sem_order_by_usage >,
469 boost::intrusive::link_mode< boost::intrusive::safe_link >
470 > semaphore_info_list_hook_t;
471
472 typedef boost::intrusive::set_base_hook<
473 boost::intrusive::tag< struct for_sem_lookup_by_id >,
474 boost::intrusive::link_mode< boost::intrusive::safe_link >,
475 boost::intrusive::optimize_size< true >
476 > semaphore_info_set_hook_t;
477
478 //! Information about a semaphore object
479 struct semaphore_info :
480 public semaphore_info_list_hook_t,
481 public semaphore_info_set_hook_t
482 {
483 struct order_by_id
484 {
485 typedef bool result_type;
486
487 result_type operator() (semaphore_info const& left, semaphore_info const& right) const BOOST_NOEXCEPT
488 {
489 return left.m_id < right.m_id;
490 }
491 result_type operator() (semaphore_info const& left, uint32_t right) const BOOST_NOEXCEPT
492 {
493 return left.m_id < right;
494 }
495 result_type operator() (uint32_t left, semaphore_info const& right) const BOOST_NOEXCEPT
496 {
497 return left < right.m_id;
498 }
499 };
500
501 //! The semaphore
502 interprocess_semaphore m_semaphore;
503 //! Timestamp of the moment when the semaphore was checked for zero count and it was not zero. In milliseconds since epoch.
504 tick_count_clock::time_point m_last_check_for_zero;
505 //! The flag indicates that the semaphore has been checked for zero count and it was not zero
506 bool m_checked_for_zero;
507 //! The semaphore id
508 const uint32_t m_id;
509
510 explicit semaphore_info(uint32_t id) BOOST_NOEXCEPT : m_last_check_for_zero(0u), m_id(id)
511 {
512 }
513
514 //! Checks if the semaphore is in 'non-zero' state for too long
515 bool check_non_zero_timeout(tick_count_clock::time_point now) BOOST_NOEXCEPT
516 {
517 if (!m_checked_for_zero)
518 {
519 m_last_check_for_zero = now;
520 m_checked_for_zero = true;
521 return false;
522 }
523
524 return (now - m_last_check_for_zero) >= 2000u;
525 }
526
527 BOOST_DELETED_FUNCTION(semaphore_info(semaphore_info const&))
528 BOOST_DELETED_FUNCTION(semaphore_info& operator=(semaphore_info const&))
529 };
530
531 typedef boost::intrusive::list<
532 semaphore_info,
533 boost::intrusive::base_hook< semaphore_info_list_hook_t >,
534 boost::intrusive::constant_time_size< false >
535 > semaphore_info_list;
536
537 typedef boost::intrusive::set<
538 semaphore_info,
539 boost::intrusive::base_hook< semaphore_info_set_hook_t >,
540 boost::intrusive::compare< semaphore_info::order_by_id >,
541 boost::intrusive::constant_time_size< false >
542 > semaphore_info_set;
543
544public:
545 struct shared_state
546 {
547 //! Number of waiters blocked on the semaphore if >0, 0 if no threads are blocked, <0 when the blocked threads were signalled
548 int32_t m_waiters;
549 //! The semaphore generation
550 uint32_t m_generation;
551 //! Id of the semaphore which is used to block threads on
552 uint32_t m_semaphore_id;
553
554 shared_state() BOOST_NOEXCEPT :
555 m_waiters(0),
556 m_generation(0u),
557 m_semaphore_id(0u)
558 {
559 }
560 };
561
562private:
563 //! The list of semaphores used for blocking. The list is in the order at which the semaphores are considered to be picked for being used.
564 semaphore_info_list m_semaphore_info_list;
565 //! The list of semaphores used for blocking. Used for searching for a particular semaphore by id.
566 semaphore_info_set m_semaphore_info_set;
567 //! The semaphore that is currently being used for blocking
568 semaphore_info* m_current_semaphore;
569 //! A string storage for formatting a semaphore name
570 std::wstring m_semaphore_name;
571 //! Permissions used to create new semaphores
572 permissions m_perms;
573 //! Process-shared state
574 shared_state* m_shared_state;
575 //! The next id for creating a new semaphore
576 uint32_t m_next_semaphore_id;
577
578public:
579 interprocess_condition_variable() BOOST_NOEXCEPT :
580 m_current_semaphore(NULL),
581 m_shared_state(NULL),
582 m_next_semaphore_id(0u)
583 {
584 }
585
586 ~interprocess_condition_variable()
587 {
588 m_semaphore_info_set.clear();
589 m_semaphore_info_list.clear_and_dispose(boost::checked_deleter< semaphore_info >());
590 }
591
592 void init(const wchar_t* name, shared_state* shared, permissions const& perms = permissions())
593 {
594 m_perms = perms;
595 m_shared_state = shared;
596
597 m_semaphore_name = name;
598 // Reserve space for generate_semaphore_name()
599 m_semaphore_name.append(L".sem00000000");
600
601 m_current_semaphore = get_semaphore(m_shared_state->m_semaphore_id);
602 }
603
604 void notify_all()
605 {
606 const int32_t waiters = m_shared_state->m_waiters;
607 if (waiters > 0)
608 {
609 const uint32_t id = m_shared_state->m_semaphore_id;
610 if (m_current_semaphore->m_id != id)
611 m_current_semaphore = get_semaphore(id);
612
613 m_current_semaphore->m_semaphore.post(waiters);
614 m_shared_state->m_waiters = -waiters;
615 }
616 }
617
b32b8144 618 bool wait(interprocess_mutex::optional_unlock& lock, boost::winapi::HANDLE_ abort_handle);
7c673cae
FG
619
620 BOOST_DELETED_FUNCTION(interprocess_condition_variable(interprocess_condition_variable const&))
621 BOOST_DELETED_FUNCTION(interprocess_condition_variable& operator=(interprocess_condition_variable const&))
622
623private:
624 //! Finds or opens a semaphore with the specified id
625 semaphore_info* get_semaphore(uint32_t id);
626 //! Finds or creates a semaphore with zero counter
627 semaphore_info* get_unused_semaphore();
628
629 //! Marks the semaphore info as unused and moves to the end of list
630 void mark_unused(semaphore_info& info) BOOST_NOEXCEPT;
631
632 //! Generates semaphore name according to id
633 void generate_semaphore_name(uint32_t id) BOOST_NOEXCEPT;
634
635 //! Returns \c true if \a left is less than \a right considering possible integer overflow
636 static bool is_overflow_less(uint32_t left, uint32_t right) BOOST_NOEXCEPT
637 {
638 return ((left - right) & 0x80000000u) != 0u;
639 }
640};
641
642} // namespace aux
643
644} // namespace ipc
645
646BOOST_LOG_CLOSE_NAMESPACE // namespace log
647
648} // namespace boost
649
650#include <boost/log/detail/footer.hpp>
651
652#endif // BOOST_LOG_WINDOWS_IPC_SYNC_WRAPPERS_HPP_INCLUDED_