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 #if defined(_MSC_VER)
12 #include <windows.h>
13 #endif
14
15 #include "single_rw_fifo.h"
16
17 #include <assert.h>
18
UpdatePos(int pos,int capacity)19 static int UpdatePos(int pos, int capacity) {
20 return (pos + 1) % capacity;
21 }
22
23 namespace webrtc {
24
25 namespace subtle {
26
27 // Start with compiler support, then processor-specific hacks
28 #if defined(__GNUC__) || defined(__clang__)
29 // Available on GCC and clang - others?
MemoryBarrier()30 inline void MemoryBarrier() {
31 __sync_synchronize();
32 }
33
34 #elif defined(_MSC_VER)
35 inline void MemoryBarrier() {
36 ::MemoryBarrier();
37 }
38
39 #elif defined(__aarch64__)
40 // From http://http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_arm64_gcc.h
41 inline void MemoryBarrier() {
42 __asm__ __volatile__ ("dmb ish" ::: "memory");
43 }
44
45 #elif defined(__ARMEL__)
46 // From http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_arm_gcc.h
47 inline void MemoryBarrier() {
48 // Note: This is a function call, which is also an implicit compiler barrier.
49 typedef void (*KernelMemoryBarrierFunc)();
50 ((KernelMemoryBarrierFunc)0xffff0fa0)();
51 }
52
53 #elif defined(__x86_64__) || defined (__i386__)
54 // From http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_x86_gcc.h
55 // mfence exists on x64 and x86 platforms containing SSE2.
56 // x86 platforms that don't have SSE2 will crash with SIGILL.
57 // If this code needs to run on such platforms in the future,
58 // add runtime CPU detection here.
59 inline void MemoryBarrier() {
60 __asm__ __volatile__("mfence" : : : "memory");
61 }
62
63 #elif defined(__MIPSEL__)
64 // From http://src.chromium.org/viewvc/chrome/trunk/src/base/atomicops_internals_mips_gcc.h
65 inline void MemoryBarrier() {
66 __asm__ __volatile__("sync" : : : "memory");
67 }
68
69 #else
70 #error Add an implementation of MemoryBarrier() for this platform!
71 #endif
72
73 } // namespace subtle
74
SingleRwFifo(int capacity)75 SingleRwFifo::SingleRwFifo(int capacity)
76 : queue_(new int8_t*[capacity]),
77 capacity_(capacity),
78 size_(0),
79 read_pos_(0),
80 write_pos_(0)
81 {
82 }
83
~SingleRwFifo()84 SingleRwFifo::~SingleRwFifo() {
85 }
86
Push(int8_t * mem)87 void SingleRwFifo::Push(int8_t* mem) {
88 assert(mem);
89
90 // Ensure that there is space for the new data in the FIFO.
91 // Note there is only one writer meaning that the other thread is guaranteed
92 // only to decrease the size.
93 const int free_slots = capacity() - size();
94 if (free_slots <= 0) {
95 // Size can be queried outside of the Push function. The caller is assumed
96 // to ensure that Push will be successful before calling it.
97 assert(false);
98 return;
99 }
100 queue_.get()[write_pos_] = mem;
101 // Memory barrier ensures that |size_| is updated after the size has changed.
102 subtle::MemoryBarrier();
103 ++size_;
104 write_pos_ = UpdatePos(write_pos_, capacity());
105 }
106
Pop()107 int8_t* SingleRwFifo::Pop() {
108 int8_t* ret_val = NULL;
109 if (size() <= 0) {
110 // Size can be queried outside of the Pop function. The caller is assumed
111 // to ensure that Pop will be successfull before calling it.
112 assert(false);
113 return ret_val;
114 }
115 ret_val = queue_.get()[read_pos_];
116 // Memory barrier ensures that |size_| is updated after the size has changed.
117 subtle::MemoryBarrier();
118 --size_;
119 read_pos_ = UpdatePos(read_pos_, capacity());
120 return ret_val;
121 }
122
123 } // namespace webrtc
124