blob: 026b1bd477f3c05ace60f1ea733c65741ed795e7 [file] [log] [blame]
brians2fdfc072013-02-26 05:35:15 +00001#ifndef AOS_COMMON_ONCE_H_
2#define AOS_COMMON_ONCE_H_
3
4#include <stdint.h>
5
6#include "aos/common/gtest_prod.h"
7
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_;
53 // Whether or not it is running. Gets atomically swapped from 0 to 1 by the
54 // thread that actually runs function_.
55 volatile int run_;
56 // 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_.
58 volatile bool done_;
59 // What function_ returned when it was executed.
60 T *result_;
61
62 FRIEND_TEST_NAMESPACE(OnceTest, MemoryClearing, testing);
63};
64
65} // namespace aos
66
67#include "aos/common/once-tmpl.h"
68
69#endif // AOS_COMMON_ONCE_H_