blob: e2e58c5d31f15416886849d628aafd8ee913b899 [file] [log] [blame]
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SINGLE_STATE_QUEUE_H
18#define SINGLE_STATE_QUEUE_H
19
20// Non-blocking single element state queue, or
21// Non-blocking single-reader / single-writer multi-word atomic load / store
22
23#include <stdint.h>
Andy Hung9b829242014-12-12 15:35:41 -080024#include <cutils/atomic.h>
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -080025
26namespace android {
27
28template<typename T> class SingleStateQueue {
29
30public:
31
32 class Mutator;
33 class Observer;
34
35 struct Shared {
36 // needs to be part of a union so don't define constructor or destructor
37
38 friend class Mutator;
39 friend class Observer;
40
41private:
42 void init() { mAck = 0; mSequence = 0; }
43
44 volatile int32_t mAck;
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -080045 volatile int32_t mSequence;
46 T mValue;
47 };
48
49 class Mutator {
50 public:
Andy Hung9b829242014-12-12 15:35:41 -080051 Mutator(Shared *shared)
52 : mSequence(0), mShared(shared)
53 {
54 // exactly one of Mutator and Observer must initialize, currently it is Observer
55 // shared->init();
56 }
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -080057
58 // push new value onto state queue, overwriting previous value;
59 // returns a sequence number which can be used with ack()
Andy Hung9b829242014-12-12 15:35:41 -080060 int32_t push(const T& value)
61 {
62 Shared *shared = mShared;
63 int32_t sequence = mSequence;
64 sequence++;
65 android_atomic_acquire_store(sequence, &shared->mSequence);
66 shared->mValue = value;
67 sequence++;
68 android_atomic_release_store(sequence, &shared->mSequence);
69 mSequence = sequence;
70 // consider signalling a futex here, if we know that observer is waiting
71 return sequence;
72 }
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -080073
74 // return true if most recent push has been observed
Andy Hung9b829242014-12-12 15:35:41 -080075 bool ack() const
76 {
77 return mShared->mAck - mSequence == 0;
78 }
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -080079
80 // return true if a push with specified sequence number or later has been observed
Andy Hung9b829242014-12-12 15:35:41 -080081 bool ack(int32_t sequence) const
82 {
83 // this relies on 2's complement rollover to detect an ancient sequence number
84 return mShared->mAck - sequence >= 0;
85 }
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -080086
87 private:
88 int32_t mSequence;
89 Shared * const mShared;
90 };
91
92 class Observer {
93 public:
Andy Hung9b829242014-12-12 15:35:41 -080094 Observer(Shared *shared)
95 : mSequence(0), mSeed(1), mShared(shared)
96 {
97 // exactly one of Mutator and Observer must initialize, currently it is Observer
98 shared->init();
99 }
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -0800100
101 // return true if value has changed
Andy Hung9b829242014-12-12 15:35:41 -0800102 bool poll(T& value)
103 {
104 Shared *shared = mShared;
105 int32_t before = shared->mSequence;
106 if (before == mSequence) {
107 return false;
108 }
109 for (int tries = 0; ; ) {
110 const int MAX_TRIES = 5;
111 if (before & 1) {
112 if (++tries >= MAX_TRIES) {
113 return false;
114 }
115 before = shared->mSequence;
116 } else {
117 android_memory_barrier();
118 T temp = shared->mValue;
119 int32_t after = android_atomic_release_load(&shared->mSequence);
120 if (after == before) {
121 value = temp;
122 shared->mAck = before;
123 mSequence = before;
124 return true;
125 }
126 if (++tries >= MAX_TRIES) {
127 return false;
128 }
129 before = after;
130 }
131 }
132 }
Glenn Kasten5c4cc0d2012-11-26 10:40:24 -0800133
134 private:
135 int32_t mSequence;
136 int mSeed; // for PRNG
137 Shared * const mShared;
138 };
139
140#if 0
141 SingleStateQueue(void /*Shared*/ *shared);
142 /*virtual*/ ~SingleStateQueue() { }
143
144 static size_t size() { return sizeof(Shared); }
145#endif
146
147};
148
149} // namespace android
150
151#endif // SINGLE_STATE_QUEUE_H