1 // Copyright 2014 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "android/base/synchronization/AndroidMessageChannel.h"
16 
17 namespace android {
18 namespace base {
19 namespace guest {
20 
MessageChannelBase(size_t capacity)21 MessageChannelBase::MessageChannelBase(size_t capacity) : mCapacity(capacity) {}
22 
size() const23 size_t MessageChannelBase::size() const {
24     AutoLock lock(mLock);
25     return mCount;
26 }
27 
stop()28 void MessageChannelBase::stop() {
29     android::base::guest::AutoLock lock(mLock);
30     mStopped = true;
31     mCount = 0;
32     mCanRead.broadcast();
33     mCanWrite.broadcastAndUnlock(&lock);
34 }
35 
isStopped() const36 bool MessageChannelBase::isStopped() const {
37     AutoLock lock(mLock);
38     return isStoppedLocked();
39 }
40 
waitForEmpty()41 void MessageChannelBase::waitForEmpty() {
42     AutoLock lock(mLock);
43     while (mCount > 0) {
44         mCanWrite.wait(&lock);
45     }
46 }
47 
beforeWrite()48 size_t MessageChannelBase::beforeWrite() {
49     mLock.lock();
50     while (mCount >= mCapacity && !mStopped) {
51         mCanWrite.wait(&mLock);
52     }
53     // Return value is undefined if stopped, so let's save a branch and skip the
54     // check for it.
55     size_t result = mPos + mCount;
56     if (result >= mCapacity) {
57         result -= mCapacity;
58     }
59     return result;
60 }
61 
beforeTryWrite()62 Optional<size_t> MessageChannelBase::beforeTryWrite() {
63     mLock.lock();
64 
65     if (mCount >= mCapacity || mStopped) {
66         return {};
67     }
68     size_t result = mPos + mCount;
69     if (result >= mCapacity) {
70         result -= mCapacity;
71     }
72     return result;
73 }
74 
afterWrite(bool success)75 void MessageChannelBase::afterWrite(bool success) {
76     if (success) {
77         ++mCount;
78     }
79     mCanRead.signalAndUnlock(&mLock);
80 }
81 
beforeRead()82 size_t MessageChannelBase::beforeRead() {
83     mLock.lock();
84     while (mCount == 0 && !mStopped) {
85         mCanRead.wait(&mLock);
86     }
87     return mPos; // return value is undefined if stopped, so let's save a branch
88 }
89 
beforeTryRead()90 Optional<size_t> MessageChannelBase::beforeTryRead() {
91     mLock.lock();
92 
93     if (mCount == 0 || mStopped) {
94         return {};
95     }
96     return mPos;
97 }
98 
beforeTimedRead(uint64_t wallTimeUs)99 Optional<size_t> MessageChannelBase::beforeTimedRead(uint64_t wallTimeUs) {
100     mLock.lock();
101 
102     while (mCount == 0 && !mStopped) {
103         if (!mCanRead.timedWait(&mLock, wallTimeUs)) {
104             return {};
105         }
106     }
107     return mPos;
108 }
109 
afterRead(bool success)110 void MessageChannelBase::afterRead(bool success) {
111     if (success) {
112         if (++mPos == mCapacity) {
113             mPos = 0U;
114         }
115         --mCount;
116     }
117     mCanWrite.signalAndUnlock(&mLock);
118 }
119 
120 }  // namespace guest
121 }  // namespace base
122 }  // namespace android
123