PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
condition_variable.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2021, Intel Corporation */
3 
9 #ifndef LIBPMEMOBJ_CPP_CONDVARIABLE_HPP
10 #define LIBPMEMOBJ_CPP_CONDVARIABLE_HPP
11 
12 #include <chrono>
13 #include <condition_variable>
14 
16 #include <libpmemobj++/mutex.hpp>
17 #include <libpmemobj/thread.h>
18 
19 namespace pmem
20 {
21 
22 namespace obj
23 {
24 
36  typedef std::chrono::system_clock clock_type;
37 
38 public:
40  typedef PMEMcond *native_handle_type;
41 
49  {
50  PMEMobjpool *pop;
51  if ((pop = pmemobj_pool_by_ptr(&pcond)) == nullptr)
52  throw pmem::lock_error(
53  1, std::generic_category(),
54  "Persistent condition variable not from persistent memory.");
55 
56  pmemobj_cond_zero(pop, &pcond);
57  }
58 
62  ~condition_variable() = default;
63 
72  void
74  {
75  PMEMobjpool *pop = pmemobj_pool_by_ptr(this);
76  if (int ret = pmemobj_cond_signal(pop, &this->pcond))
77  throw detail::exception_with_errormsg<lock_error>(
78  ret, std::system_category(),
79  "Error notifying one on a condition variable.");
80  }
81 
87  void
89  {
90  PMEMobjpool *pop = pmemobj_pool_by_ptr(this);
91  if (int ret = pmemobj_cond_broadcast(pop, &this->pcond))
92  throw detail::exception_with_errormsg<lock_error>(
93  ret, std::system_category(),
94  "Error notifying all on a condition variable.");
95  }
96 
112  void
113  wait(mutex &lock)
114  {
115  this->wait_impl(lock);
116  }
117 
135  template <typename Lock>
136  void
137  wait(Lock &lock)
138  {
139  this->wait_impl(*lock.mutex());
140  }
141 
161  template <typename Predicate>
162  void
163  wait(mutex &lock, Predicate pred)
164  {
165  this->wait_impl(lock, std::move(pred));
166  }
167 
189  template <typename Lock, typename Predicate>
190  void
191  wait(Lock &lock, Predicate pred)
192  {
193  this->wait_impl(*lock.mutex(), std::move(pred));
194  }
195 
217  template <typename Clock, typename Duration>
218  std::cv_status
220  const std::chrono::time_point<Clock, Duration> &timeout)
221  {
222  return this->wait_until_impl(lock, timeout);
223  }
224 
248  template <typename Lock, typename Clock, typename Duration>
249  std::cv_status
250  wait_until(Lock &lock,
251  const std::chrono::time_point<Clock, Duration> &timeout)
252  {
253  return this->wait_until_impl(*lock.mutex(), timeout);
254  }
255 
278  template <typename Clock, typename Duration, typename Predicate>
279  bool
281  const std::chrono::time_point<Clock, Duration> &timeout,
282  Predicate pred)
283  {
284  return this->wait_until_impl(lock, timeout, std::move(pred));
285  }
286 
311  template <typename Lock, typename Clock, typename Duration,
312  typename Predicate>
313  bool
314  wait_until(Lock &lock,
315  const std::chrono::time_point<Clock, Duration> &timeout,
316  Predicate pred)
317  {
318  return this->wait_until_impl(*lock.mutex(), timeout,
319  std::move(pred));
320  }
321 
345  template <typename Lock, typename Rep, typename Period>
346  std::cv_status
347  wait_for(Lock &lock, const std::chrono::duration<Rep, Period> &rel_time)
348  {
349  return this->wait_until_impl(*lock.mutex(),
350  clock_type::now() + rel_time);
351  }
352 
377  template <typename Lock, typename Rep, typename Period,
378  typename Predicate>
379  bool
380  wait_for(Lock &lock, const std::chrono::duration<Rep, Period> &rel_time,
381  Predicate pred)
382  {
383  return this->wait_until_impl(*lock.mutex(),
384  clock_type::now() + rel_time,
385  std::move(pred));
386  }
387 
409  template <typename Rep, typename Period>
410  std::cv_status
412  const std::chrono::duration<Rep, Period> &rel_time)
413  {
414  return this->wait_until_impl(lock,
415  clock_type::now() + rel_time);
416  }
417 
440  template <typename Rep, typename Period, typename Predicate>
441  bool
443  const std::chrono::duration<Rep, Period> &rel_time,
444  Predicate pred)
445  {
446  return this->wait_until_impl(lock, clock_type::now() + rel_time,
447  std::move(pred));
448  }
449 
456  native_handle() noexcept
457  {
458  return &this->pcond;
459  }
460 
465 
470 
471 private:
475  void
476  wait_impl(mutex &lock)
477  {
478  PMEMobjpool *pop = pmemobj_pool_by_ptr(this);
479  if (int ret = pmemobj_cond_wait(pop, &this->pcond,
480  lock.native_handle()))
481  throw detail::exception_with_errormsg<lock_error>(
482  ret, std::system_category(),
483  "Error waiting on a condition variable.");
484  }
485 
489  template <typename Predicate>
490  void
491  wait_impl(mutex &lock, Predicate pred)
492  {
493  while (!pred())
494  this->wait(lock);
495  }
496 
500  template <typename Clock, typename Duration>
501  std::cv_status
502  wait_until_impl(
503  mutex &lock,
504  const std::chrono::time_point<Clock, Duration> &abs_timeout)
505  {
506  PMEMobjpool *pop = pmemobj_pool_by_ptr(this);
507 
508  /* convert to my clock */
509  const typename Clock::time_point their_now = Clock::now();
510  const clock_type::time_point my_now = clock_type::now();
511  const auto delta = abs_timeout - their_now;
512  const auto my_rel = my_now + delta;
513 
514  struct timespec ts = detail::timepoint_to_timespec(my_rel);
515 
516  auto ret = pmemobj_cond_timedwait(pop, &this->pcond,
517  lock.native_handle(), &ts);
518 
519  if (ret == 0)
520  return std::cv_status::no_timeout;
521  else if (ret == ETIMEDOUT)
522  return std::cv_status::timeout;
523  else
524  throw detail::exception_with_errormsg<lock_error>(
525  ret, std::system_category(),
526  "Error waiting on a condition variable.");
527  }
528 
532  template <typename Clock, typename Duration, typename Predicate>
533  bool
534  wait_until_impl(
535  mutex &lock,
536  const std::chrono::time_point<Clock, Duration> &abs_timeout,
537  Predicate pred)
538  {
539  while (!pred())
540  if (this->wait_until_impl(lock, abs_timeout) ==
541  std::cv_status::timeout)
542  return pred();
543  return true;
544  }
545 
547  PMEMcond pcond;
548 };
549 
550 } /* namespace obj */
551 
552 } /* namespace pmem */
553 
554 #endif /* LIBPMEMOBJ_CPP_CONDVARIABLE_HPP */
Custom lock error class.
Definition: pexceptions.hpp:121
Persistent memory resident condition variable.
Definition: condition_variable.hpp:35
~condition_variable()=default
Defaulted destructor.
void wait(Lock &lock, Predicate pred)
Makes the current thread block until the condition variable is notified.
Definition: condition_variable.hpp:191
condition_variable & operator=(const condition_variable &)=delete
Deleted assignment operator.
condition_variable(const condition_variable &)=delete
Deleted copy constructor.
condition_variable()
Default constructor.
Definition: condition_variable.hpp:48
native_handle_type native_handle() noexcept
Access a native handle to this condition variable.
Definition: condition_variable.hpp:456
PMEMcond * native_handle_type
The handle typedef to the underlying basic type.
Definition: condition_variable.hpp:40
bool wait_for(Lock &lock, const std::chrono::duration< Rep, Period > &rel_time, Predicate pred)
Makes the current thread block until the condition variable is notified or the specified amount of ti...
Definition: condition_variable.hpp:380
std::cv_status wait_for(Lock &lock, const std::chrono::duration< Rep, Period > &rel_time)
Makes the current thread block until the condition variable is notified, the specified amount of time...
Definition: condition_variable.hpp:347
bool wait_for(mutex &lock, const std::chrono::duration< Rep, Period > &rel_time, Predicate pred)
Makes the current thread block until the condition variable is notified or the specified amount of ti...
Definition: condition_variable.hpp:442
void notify_all()
Notify and unblock all threads waiting on *this condition.
Definition: condition_variable.hpp:88
std::cv_status wait_until(Lock &lock, const std::chrono::time_point< Clock, Duration > &timeout)
Makes the current thread block until the condition variable is notified, a specific time is reached o...
Definition: condition_variable.hpp:250
bool wait_until(mutex &lock, const std::chrono::time_point< Clock, Duration > &timeout, Predicate pred)
Makes the current thread block until the condition variable is notified or a specific time is reached...
Definition: condition_variable.hpp:280
void wait(mutex &lock, Predicate pred)
Makes the current thread block until the condition variable is notified.
Definition: condition_variable.hpp:163
std::cv_status wait_for(mutex &lock, const std::chrono::duration< Rep, Period > &rel_time)
Makes the current thread block until the condition variable is notified, the specified amount of time...
Definition: condition_variable.hpp:411
void notify_one()
Notify and unblock one thread waiting on *this condition.
Definition: condition_variable.hpp:73
void wait(Lock &lock)
Makes the current thread block until the condition variable is notified or it is woken up by some oth...
Definition: condition_variable.hpp:137
void wait(mutex &lock)
Makes the current thread block until the condition variable is notified or it is woken up by some oth...
Definition: condition_variable.hpp:113
bool wait_until(Lock &lock, const std::chrono::time_point< Clock, Duration > &timeout, Predicate pred)
Makes the current thread block until the condition variable is notified or a specific time is reached...
Definition: condition_variable.hpp:314
std::cv_status wait_until(mutex &lock, const std::chrono::time_point< Clock, Duration > &timeout)
Makes the current thread block until the condition variable is notified, a specific time is reached o...
Definition: condition_variable.hpp:219
Persistent memory resident mutex implementation.
Definition: mutex.hpp:33
native_handle_type native_handle() noexcept
Access a native handle to this condition variable.
Definition: mutex.hpp:134
Commonly used conversions.
Pmem-resident mutex.
timespec timepoint_to_timespec(const std::chrono::time_point< Clock, Duration > &timepoint)
Convert std::chrono::time_point to posix timespec.
Definition: conversions.hpp:30
Persistent memory namespace.
Definition: allocation_flag.hpp:15