1 /*
2  * Copyright (C) 2016 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 #include <errno.h>
18 #include <limits.h>
19 #include <audio_utils/fifo_index.h>
20 #include <audio_utils/futex.h>
21 
22 // These are not implemented within <audio_utils/fifo_index.h>
23 // so that we don't expose futex.
24 
loadAcquire()25 uint32_t audio_utils_fifo_index::loadAcquire()
26 {
27     return atomic_load_explicit(&mIndex, std::memory_order_acquire);
28 }
29 
storeRelease(uint32_t value)30 void audio_utils_fifo_index::storeRelease(uint32_t value)
31 {
32     atomic_store_explicit(&mIndex, value, std::memory_order_release);
33 }
34 
wait(int op,uint32_t expected,const struct timespec * timeout)35 int audio_utils_fifo_index::wait(int op, uint32_t expected, const struct timespec *timeout)
36 {
37     return sys_futex(&mIndex, op, expected, timeout, NULL, 0);
38 }
39 
wake(int op,int waiters)40 int audio_utils_fifo_index::wake(int op, int waiters)
41 {
42     return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
43 }
44 
loadConsume()45 uint32_t audio_utils_fifo_index::loadConsume()
46 {
47     return atomic_load_explicit(&mIndex, std::memory_order_consume);
48 }
49 
50 ////
51 
RefIndexDeferredStoreReleaseDeferredWake(audio_utils_fifo_index & index)52 RefIndexDeferredStoreReleaseDeferredWake::RefIndexDeferredStoreReleaseDeferredWake(
53         audio_utils_fifo_index& index)
54     : mIndex(index), mValue(0), mWriteback(false), mWaiters(0), mWakeOp(FUTEX_WAIT_PRIVATE)
55 {
56 }
57 
~RefIndexDeferredStoreReleaseDeferredWake()58 RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake()
59 {
60     writeback();
61     wakeNowIfNeeded();
62 }
63 
set(uint32_t value)64 void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) {
65     mValue = value;
66     mWriteback = true;
67 }
68 
writeback()69 void RefIndexDeferredStoreReleaseDeferredWake::writeback()
70 {
71     if (mWriteback) {
72         // TODO When part of a collection, should use relaxed for all but the last writeback
73         mIndex.storeRelease(mValue);
74         mWriteback = false;
75     }
76 }
77 
writethrough(uint32_t value)78 void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) {
79     set(value);
80     writeback();
81 }
82 
wakeDeferred(int op,int waiters)83 void RefIndexDeferredStoreReleaseDeferredWake::wakeDeferred(int op, int waiters)
84 {
85     if (waiters <= 0) {
86         return;
87     }
88     // default is FUTEX_WAKE_PRIVATE
89     if (op == FUTEX_WAKE) {
90         mWakeOp = FUTEX_WAKE;
91     }
92     if (waiters < INT_MAX - mWaiters) {
93         mWaiters += waiters;
94     } else {
95         mWaiters = INT_MAX;
96     }
97 }
98 
wakeNowIfNeeded()99 void RefIndexDeferredStoreReleaseDeferredWake::wakeNowIfNeeded()
100 {
101     if (mWaiters > 0) {
102         mIndex.wake(mWakeOp, mWaiters);
103         mWaiters = 0;
104         mWakeOp = FUTEX_WAKE_PRIVATE;
105     }
106 }
107 
wakeNow(int op,int waiters)108 void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters)
109 {
110     wakeDeferred(op, waiters);
111     wakeNowIfNeeded();
112 }
113 
114 ////
115 
RefIndexCachedLoadAcquireDeferredWait(audio_utils_fifo_index & index)116 RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait(
117         audio_utils_fifo_index& index)
118     : mIndex(index), mValue(0), mLoaded(false)
119 {
120 }
121 
~RefIndexCachedLoadAcquireDeferredWait()122 RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait()
123 {
124 }
125 
get()126 uint32_t RefIndexCachedLoadAcquireDeferredWait::get()
127 {
128     prefetch();
129     return mValue;
130 }
131 
prefetch()132 void RefIndexCachedLoadAcquireDeferredWait::prefetch()
133 {
134     if (!mLoaded) {
135         // TODO When part of a collection, should use relaxed for all but the last load
136         mValue = mIndex.loadAcquire();
137         mLoaded = true;
138     }
139 }
140 
invalidate()141 void RefIndexCachedLoadAcquireDeferredWait::invalidate()
142 {
143     mLoaded = false;
144 }
145 
146 #if 0
147 uint32_t RefIndexCachedLoadAcquireDeferredWait::readthrough()
148 {
149     invalidate();
150     return get();
151 }
152 #endif
153 
wait(int op,const struct timespec * timeout)154 int RefIndexCachedLoadAcquireDeferredWait::wait(int op, const struct timespec *timeout)
155 {
156     if (!mLoaded) {
157         return -EINVAL;
158     }
159     int err = mIndex.wait(op, mValue /*expected*/, timeout);
160     invalidate();
161     return err;
162 }
163