blob: d7eb0d3b434455c5d25693bd502d7945af10d007 [file] [log] [blame]
Sabina Davis2ed5ea22017-09-26 22:27:42 -07001#ifndef AOS_ONCE_H_
2#define AOS_ONCE_H_
brians2fdfc072013-02-26 05:35:15 +00003
4#include <stdint.h>
5
John Park33858a32018-09-28 23:05:48 -07006#include "aos/gtest_prod.h"
brians2fdfc072013-02-26 05:35:15 +00007
8namespace aos {
9namespace testing {
10
11FORWARD_DECLARE_TEST_CASE(OnceTest, MemoryClearing);
12
13} // namespace testing
14
15// Designed for the same thing as pthread_once: to run something exactly 1 time.
16//
17// Intended use case:
18// const char *CalculateSomethingCool() {
19// static ::aos::Once<const char> once(DoCalculateSomethingCool);
20// return once.Get();
21// }
22//
23// IMPORTANT: Instances _must_ be placed in memory that gets 0-initialized
24// automatically or Reset() must be called exactly once!!
25// The expected use case is to use one of these as a static variable, and those
26// do get 0-initialized under the C++ standard. Global variables are treated the
27// same way by the C++ Standard.
28// Placing an instance in shared memory (and using Reset()) is also supported.
29// The constructor does not initialize all of the member variables!
30// This is because initializing them in the constructor creates a race condition
31// if initialization of static variables isn't thread safe.
32template<typename T>
33class Once {
34 public:
35 typedef T *(*Function)();
36 explicit Once(Function function);
37
38 // Returns the result of calling function_. The first call will actually run
39 // it and then any other ones will block (if necessary) until it's finished
40 // and then return the same thing.
41 T *Get();
42
43 // Will clear out all the member variables. If this is going to be used
44 // instead of creating an instance in 0-initialized memory, then this method
45 // must be called exactly once before Get() is called anywhere.
46 // This method can also be called to run the function again the next time
47 // Get() is called. However, calling it again is not thread safe.
48 void Reset();
49
50 private:
51 // The function to run to calculate result_.
52 Function function_;
Brian Silverman4968c202014-05-19 17:04:02 -070053 // Whether or not it is running. Gets atomically swapped from false to true by
54 // the thread that actually runs function_.
55 bool run_;
brians2fdfc072013-02-26 05:35:15 +000056 // Whether or not it is done. Gets set to true after the thread that is
57 // running function_ finishes running it and storing the result in result_.
Brian Silverman4968c202014-05-19 17:04:02 -070058 bool done_;
brians2fdfc072013-02-26 05:35:15 +000059 // What function_ returned when it was executed.
60 T *result_;
61
62 FRIEND_TEST_NAMESPACE(OnceTest, MemoryClearing, testing);
63};
64
65} // namespace aos
66
Sabina Davis2ed5ea22017-09-26 22:27:42 -070067#include "aos/once-tmpl.h"
brians2fdfc072013-02-26 05:35:15 +000068
Sabina Davis2ed5ea22017-09-26 22:27:42 -070069#endif // AOS_ONCE_H_