1 /*
2  * Copyright (C) 2015 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 "ring.h"
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <atomic>
22 
23 namespace android {
24 
RingBuffer(size_t size)25 RingBuffer::RingBuffer(size_t size)
26     : mSize(size),
27       mData((sensors_event_t *)malloc(sizeof(sensors_event_t) * mSize)),
28       mReadPos(0),
29       mWritePos(0) {
30 }
31 
~RingBuffer()32 RingBuffer::~RingBuffer() {
33     free(mData);
34     mData = NULL;
35 }
36 
write(const sensors_event_t * ev,size_t size)37 ssize_t RingBuffer::write(const sensors_event_t *ev, size_t size) {
38     Mutex::Autolock autoLock(mLock);
39 
40     size_t numAvailableToRead = mWritePos - mReadPos;
41     size_t numAvailableToWrite = mSize - numAvailableToRead;
42 
43     if (size > numAvailableToWrite) {
44         size = numAvailableToWrite;
45     }
46 
47     size_t writePos = (mWritePos % mSize);
48     size_t copy = mSize - writePos;
49 
50     if (copy > size) {
51         copy = size;
52     }
53 
54     memcpy(&mData[writePos], ev, copy * sizeof(sensors_event_t));
55 
56     if (size > copy) {
57         memcpy(mData, &ev[copy], (size - copy) * sizeof(sensors_event_t));
58     }
59 
60     mWritePos += size;
61 
62     if (numAvailableToRead == 0 && size > 0) {
63         mNotEmptyCondition.broadcast();
64     }
65 
66     return size;
67 }
68 
read(sensors_event_t * ev,size_t size)69 ssize_t RingBuffer::read(sensors_event_t *ev, size_t size) {
70     Mutex::Autolock autoLock(mLock);
71 
72     size_t numAvailableToRead;
73     for (;;) {
74         numAvailableToRead = mWritePos - mReadPos;
75         if (numAvailableToRead > 0) {
76             break;
77         }
78 
79         mNotEmptyCondition.wait(mLock);
80     }
81 
82     if (size > numAvailableToRead) {
83         size = numAvailableToRead;
84     }
85 
86     size_t readPos = (mReadPos % mSize);
87     size_t copy = mSize - readPos;
88 
89     if (copy > size) {
90         copy = size;
91     }
92 
93     memcpy(ev, &mData[readPos], copy * sizeof(sensors_event_t));
94 
95     if (size > copy) {
96         memcpy(&ev[copy], mData, (size - copy) * sizeof(sensors_event_t));
97     }
98 
99     mReadPos += size;
100 
101     return size;
102 }
103 
LockfreeBuffer(void * buf,size_t size)104 LockfreeBuffer::LockfreeBuffer(void* buf, size_t size)
105         : mData((sensors_event_t *)buf), mSize(size/sizeof(sensors_event_t)),
106         mWritePos(0), mCounter(1) {
107     memset(mData, 0, size);
108 }
109 
~LockfreeBuffer()110 LockfreeBuffer::~LockfreeBuffer() {
111     memset(mData, 0, mSize*sizeof(sensors_event_t));
112 }
113 
write(const sensors_event_t * ev,size_t size)114 void LockfreeBuffer::write(const sensors_event_t *ev, size_t size) {
115     if (!mSize) {
116         return;
117     }
118 
119     while(size--) {
120         // part before reserved0 field
121         memcpy(&mData[mWritePos], ev, offsetof(sensors_event_t, reserved0));
122         // part after reserved0 field
123         memcpy(reinterpret_cast<char *>(&mData[mWritePos]) + offsetof(sensors_event_t, timestamp),
124                reinterpret_cast<const char *>(ev) + offsetof(sensors_event_t, timestamp),
125                sizeof(sensors_event_t) - offsetof(sensors_event_t, timestamp));
126         // barrier before writing the atomic counter
127         std::atomic_thread_fence(std::memory_order_release);
128         mData[mWritePos].reserved0 = mCounter++;
129         // barrier after writing the atomic counter
130         std::atomic_thread_fence(std::memory_order_release);
131         ++ev;
132 
133         if (++mWritePos >= mSize) {
134             mWritePos = 0;
135         }
136     }
137 }
138 
139 }  // namespace android
140 
141