summaryrefslogtreecommitdiff
path: root/indra/llcommon/llcond.h
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-07-17 15:51:59 +0200
committerNat Goodspeed <nat@lindenlab.com>2020-03-25 18:44:04 -0400
commita3de18996f0c4aee37266c1a3d72c5cc9cadd6c1 (patch)
tree57a00153c306f72bdb0e53c90660e9bf8ee056d9 /indra/llcommon/llcond.h
parentd8e08ecde97362f6b3117cbb68395fdd299027e2 (diff)
DRTVWR-476: Review response: support LLDate and llunits.h durations.
Also introduce value_type typedef.
Diffstat (limited to 'indra/llcommon/llcond.h')
-rw-r--r--indra/llcommon/llcond.h168
1 files changed, 141 insertions, 27 deletions
diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h
index adfeb27f82..5ed9f10123 100644
--- a/indra/llcommon/llcond.h
+++ b/indra/llcommon/llcond.h
@@ -14,6 +14,8 @@
#if ! defined(LL_LLCOND_H)
#define LL_LLCOND_H
+#include "llunits.h"
+#include "lldate.h"
#include <boost/fiber/condition_variable.hpp>
#include <mutex>
#include <chrono>
@@ -37,9 +39,12 @@
template <typename DATA>
class LLCond
{
+public:
+ typedef value_type DATA;
+
private:
// This is the DATA controlled by the condition_variable.
- DATA mData;
+ value_type mData;
// condition_variable must be used in conjunction with a mutex. Use
// boost::fibers::mutex instead of std::mutex because the latter blocks
// the entire calling thread, whereas the former blocks only the current
@@ -52,7 +57,7 @@ private:
public:
/// LLCond can be explicitly initialized with a specific value for mData if
/// desired.
- LLCond(DATA&& init=DATA()):
+ LLCond(value_type&& init=value_type()):
mData(init)
{}
@@ -63,7 +68,7 @@ public:
/// get() returns a const reference to the stored DATA. The only way to
/// get a non-const reference -- to modify the stored DATA -- is via
/// update_one() or update_all().
- const DATA& get() const { return mData; }
+ const value_type& get() const { return mData; }
/**
* Pass update_one() an invocable accepting non-const (DATA&). The
@@ -122,7 +127,7 @@ public:
// But what if they instead pass a predicate accepting non-const
// (DATA&)? Such a predicate could modify mData, which would be Bad.
// Forbid that.
- while (! pred(const_cast<const DATA&>(mData)))
+ while (! pred(const_cast<const value_type&>(mData)))
{
mCond.wait(lk);
}
@@ -143,20 +148,30 @@ public:
{
std::unique_lock<boost::fibers::mutex> lk(mMutex);
// see wait() for comments about this const_cast
- while (! pred(const_cast<const DATA&>(mData)))
+ while (! pred(const_cast<const value_type&>(mData)))
{
if (boost::fibers::cv_status::timeout == mCond.wait_until(lk, timeout_time))
{
// It's possible that wait_until() timed out AND the predicate
// became true more or less simultaneously. Even though
// wait_until() timed out, check the predicate one more time.
- return pred(const_cast<const DATA&>(mData));
+ return pred(const_cast<const value_type&>(mData));
}
}
return true;
}
/**
+ * This wait_until() overload accepts LLDate as the time_point. Its
+ * semantics are the same as the generic wait_until() method.
+ */
+ template <typename Pred>
+ bool wait_until(const LLDate& timeout_time, Pred pred)
+ {
+ return wait_until(convert(timeout_time), pred);
+ }
+
+ /**
* Pass wait_for() a chrono::duration, indicating how long we're willing
* to wait, and a predicate accepting (const DATA&), returning bool. The
* predicate returns true when the condition for which it is waiting has
@@ -178,6 +193,24 @@ public:
// stick to it.
return wait_until(std::chrono::steady_clock::now() + timeout_duration, pred);
}
+
+ /**
+ * This wait_for() overload accepts F32Milliseconds as the duration. Any
+ * duration unit defined in llunits.h is implicitly convertible to
+ * F32Milliseconds. The semantics of this method are the same as the
+ * generic wait_for() method.
+ */
+ template <typename Pred>
+ bool wait_for(F32Milliseconds timeout_duration, Pred pred)
+ {
+ return wait_for(convert(timeout_duration), pred);
+ }
+
+protected:
+ // convert LLDate to a chrono::time_point
+ std::chrono::system_clock::time_point convert(const LLDate&);
+ // convert F32Milliseconds to a chrono::duration
+ std::chrono::milliseconds convert(F32Milliseconds);
};
template <typename DATA>
@@ -186,26 +219,32 @@ class LLScalarCond: public LLCond<DATA>
using super = LLCond<DATA>;
public:
+ using super::value_type;
+ using super::get;
+ using super::wait;
+ using super::wait_until;
+ using super::wait_for;
+
/// LLScalarCond can be explicitly initialized with a specific value for
/// mData if desired.
- LLCond(DATA&& init=DATA()):
+ LLCond(value_type&& init=value_type()):
super(init)
{}
/// Pass set_one() a new value to which to update mData. set_one() will
/// lock the mutex, update mData and then call notify_one() on the
/// condition_variable.
- void set_one(DATA&& value)
+ void set_one(value_type&& value)
{
- super::update_one([](DATA& data){ data = value; });
+ super::update_one([](value_type& data){ data = value; });
}
/// Pass set_all() a new value to which to update mData. set_all() will
/// lock the mutex, update mData and then call notify_all() on the
/// condition_variable.
- void set_all(DATA&& value)
+ void set_all(value_type&& value)
{
- super::update_all([](DATA& data){ data = value; });
+ super::update_all([](value_type& data){ data = value; });
}
/**
@@ -213,9 +252,9 @@ public:
* mutex and, until the stored DATA equals that value, calls wait() on the
* condition_variable.
*/
- void wait_equal(const DATA& value)
+ void wait_equal(const value_type& value)
{
- super::wait([&value](const DATA& data){ return (data == value); });
+ super::wait([&value](const value_type& data){ return (data == value); });
}
/**
@@ -228,10 +267,19 @@ public:
*/
template <typename Clock, typename Duration>
bool wait_until_equal(const std::chrono::time_point<Clock, Duration>& timeout_time,
- const DATA& value)
+ const value_type& value)
{
return super::wait_until(timeout_time,
- [&value](const DATA& data){ return (data == value); });
+ [&value](const value_type& data){ return (data == value); });
+ }
+
+ /**
+ * This wait_until_equal() overload accepts LLDate as the time_point. Its
+ * semantics are the same as the generic wait_until_equal() method.
+ */
+ bool wait_until_equal(const LLDate& timeout_time, const value_type& value)
+ {
+ return wait_until_equal(super::convert(timeout_time), value);
}
/**
@@ -244,10 +292,21 @@ public:
*/
template <typename Rep, typename Period>
bool wait_for_equal(const std::chrono::duration<Rep, Period>& timeout_duration,
- const DATA& value)
+ const value_type& value)
{
return super::wait_for(timeout_duration,
- [&value](const DATA& data){ return (data == value); });
+ [&value](const value_type& data){ return (data == value); });
+ }
+
+ /**
+ * This wait_for_equal() overload accepts F32Milliseconds as the duration.
+ * Any duration unit defined in llunits.h is implicitly convertible to
+ * F32Milliseconds. The semantics of this method are the same as the
+ * generic wait_for_equal() method.
+ */
+ bool wait_for_equal(F32Milliseconds timeout_duration, const value_type& value)
+ {
+ return wait_for_equal(super::convert(timeout_duration), value);
}
/**
@@ -255,9 +314,9 @@ public:
* locks the mutex and, until the stored DATA no longer equals that value,
* calls wait() on the condition_variable.
*/
- void wait_unequal(const DATA& value)
+ void wait_unequal(const value_type& value)
{
- super::wait([&value](const DATA& data){ return (data != value); });
+ super::wait([&value](const value_type& data){ return (data != value); });
}
/**
@@ -270,10 +329,19 @@ public:
*/
template <typename Clock, typename Duration>
bool wait_until_unequal(const std::chrono::time_point<Clock, Duration>& timeout_time,
- const DATA& value)
+ const value_type& value)
{
return super::wait_until(timeout_time,
- [&value](const DATA& data){ return (data != value); });
+ [&value](const value_type& data){ return (data != value); });
+ }
+
+ /**
+ * This wait_until_unequal() overload accepts LLDate as the time_point.
+ * Its semantics are the same as the generic wait_until_unequal() method.
+ */
+ bool wait_until_unequal(const LLDate& timeout_time, const value_type& value)
+ {
+ return wait_until_unequal(super::convert(timeout_time), value);
}
/**
@@ -286,22 +354,48 @@ public:
*/
template <typename Rep, typename Period>
bool wait_for_unequal(const std::chrono::duration<Rep, Period>& timeout_duration,
- const DATA& value)
+ const value_type& value)
{
return super::wait_for(timeout_duration,
- [&value](const DATA& data){ return (data != value); });
+ [&value](const value_type& data){ return (data != value); });
+ }
+
+ /**
+ * This wait_for_unequal() overload accepts F32Milliseconds as the duration.
+ * Any duration unit defined in llunits.h is implicitly convertible to
+ * F32Milliseconds. The semantics of this method are the same as the
+ * generic wait_for_unequal() method.
+ */
+ bool wait_for_unequal(F32Milliseconds timeout_duration, const value_type& value)
+ {
+ return wait_for_unequal(super::convert(timeout_duration), value);
}
+
+protected:
+ using super::convert;
};
/// Using bool as LLScalarCond's DATA seems like a particularly useful case
using LLBoolCond = LLScalarCond<bool>;
-// LLOneShotCond -- init false, set (and wait for) true? Or full suite?
+/// LLOneShotCond -- init false, set (and wait for) true
class LLOneShotCond: public LLBoolCond
{
using super = LLBoolCond;
public:
+ using super::value_type;
+ using super::get;
+ using super::wait;
+ using super::wait_until;
+ using super::wait_for;
+ using super::wait_equal;
+ using super::wait_until_equal;
+ using super::wait_for_equal;
+ using super::wait_unequal;
+ using super::wait_until_unequal;
+ using super::wait_for_unequal;
+
/// The bool stored in LLOneShotCond is initially false
LLOneShotCond(): super(false) {}
@@ -323,7 +417,7 @@ public:
*/
void wait()
{
- super::wait_equal(true);
+ super::wait_unequal(false);
}
/**
@@ -336,7 +430,16 @@ public:
template <typename Clock, typename Duration>
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time)
{
- return super::wait_until_equal(timeout_time, true);
+ return super::wait_until_unequal(timeout_time, false);
+ }
+
+ /**
+ * This wait_until() overload accepts LLDate as the time_point.
+ * Its semantics are the same as the generic wait_until() method.
+ */
+ bool wait_until(const LLDate& timeout_time)
+ {
+ return wait_until(super::convert(timeout_time));
}
/**
@@ -349,7 +452,18 @@ public:
template <typename Rep, typename Period>
bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration)
{
- return super::wait_for_equal(timeout_duration, true);
+ return super::wait_for_unequal(timeout_duration, false);
+ }
+
+ /**
+ * This wait_for() overload accepts F32Milliseconds as the duration.
+ * Any duration unit defined in llunits.h is implicitly convertible to
+ * F32Milliseconds. The semantics of this method are the same as the
+ * generic wait_for() method.
+ */
+ bool wait_for(F32Milliseconds timeout_duration)
+ {
+ return wait_for(super::convert(timeout_duration));
}
};