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