Home | History | Annotate | Download | only in android
      1 /*
      2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/audio_device/android/single_rw_fifo.h"
     12 
     13 #include <assert.h>
     14 
     15 static int UpdatePos(int pos, int capacity) {
     16   return (pos + 1) % capacity;
     17 }
     18 
     19 namespace webrtc {
     20 
     21 namespace subtle {
     22 
     23 #if defined(__aarch64__)
     24 // From http://http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_arm64_gcc.h
     25 inline void MemoryBarrier() {
     26   __asm__ __volatile__ ("dmb ish" ::: "memory");
     27 }
     28 
     29 #elif defined(__ARMEL__)
     30 // From http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_arm_gcc.h
     31 inline void MemoryBarrier() {
     32   // Note: This is a function call, which is also an implicit compiler barrier.
     33   typedef void (*KernelMemoryBarrierFunc)();
     34   ((KernelMemoryBarrierFunc)0xffff0fa0)();
     35 }
     36 
     37 #elif defined(__x86_64__) || defined (__i386__)
     38 // From http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_x86_gcc.h
     39 // mfence exists on x64 and x86 platforms containing SSE2.
     40 // x86 platforms that don't have SSE2 will crash with SIGILL.
     41 // If this code needs to run on such platforms in the future,
     42 // add runtime CPU detection here.
     43 inline void MemoryBarrier() {
     44   __asm__ __volatile__("mfence" : : : "memory");
     45 }
     46 
     47 #else
     48 #error Add an implementation of MemoryBarrier() for this platform!
     49 #endif
     50 
     51 }  // namespace subtle
     52 
     53 SingleRwFifo::SingleRwFifo(int capacity)
     54     : capacity_(capacity),
     55       size_(0),
     56       read_pos_(0),
     57       write_pos_(0) {
     58   queue_.reset(new int8_t*[capacity_]);
     59 }
     60 
     61 SingleRwFifo::~SingleRwFifo() {
     62 }
     63 
     64 void SingleRwFifo::Push(int8_t* mem) {
     65   assert(mem);
     66 
     67   // Ensure that there is space for the new data in the FIFO.
     68   // Note there is only one writer meaning that the other thread is guaranteed
     69   // only to decrease the size.
     70   const int free_slots = capacity() - size();
     71   if (free_slots <= 0) {
     72     // Size can be queried outside of the Push function. The caller is assumed
     73     // to ensure that Push will be successful before calling it.
     74     assert(false);
     75     return;
     76   }
     77   queue_[write_pos_] = mem;
     78   // Memory barrier ensures that |size_| is updated after the size has changed.
     79   subtle::MemoryBarrier();
     80   ++size_;
     81   write_pos_ = UpdatePos(write_pos_, capacity());
     82 }
     83 
     84 int8_t* SingleRwFifo::Pop() {
     85   int8_t* ret_val = NULL;
     86   if (size() <= 0) {
     87     // Size can be queried outside of the Pop function. The caller is assumed
     88     // to ensure that Pop will be successfull before calling it.
     89     assert(false);
     90     return ret_val;
     91   }
     92   ret_val = queue_[read_pos_];
     93   // Memory barrier ensures that |size_| is updated after the size has changed.
     94   subtle::MemoryBarrier();
     95   --size_;
     96   read_pos_ = UpdatePos(read_pos_, capacity());
     97   return ret_val;
     98 }
     99 
    100 }  // namespace webrtc
    101