Home | History | Annotate | Download | only in audio_utils
      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 
     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 writer32 can also inline it
     31 void audio_utils_fifo_index::storeRelease(uint32_t value)
     32 {
     33     atomic_store_explicit(&mIndex, value, std::memory_order_release);
     34 }
     35 
     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 
     41 int audio_utils_fifo_index::wake(int op, int waiters)
     42 {
     43     return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
     44 }
     45 
     46 uint32_t audio_utils_fifo_index::loadConsume()
     47 {
     48     return atomic_load_explicit(&mIndex, std::memory_order_consume);
     49 }
     50 
     51 ////
     52 
     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 
     59 RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake()
     60 {
     61     writeback();
     62     wakeNowIfNeeded();
     63 }
     64 
     65 void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) {
     66     mValue = value;
     67     mWriteback = true;
     68 }
     69 
     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 
     79 void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) {
     80     set(value);
     81     writeback();
     82 }
     83 
     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 
    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 
    109 void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters)
    110 {
    111     wakeDeferred(op, waiters);
    112     wakeNowIfNeeded();
    113 }
    114 
    115 ////
    116 
    117 RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait(
    118         audio_utils_fifo_index& index)
    119     : mIndex(index), mValue(0), mLoaded(false)
    120 {
    121 }
    122 
    123 RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait()
    124 {
    125 }
    126 
    127 uint32_t RefIndexCachedLoadAcquireDeferredWait::get()
    128 {
    129     prefetch();
    130     return mValue;
    131 }
    132 
    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 
    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 
    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