1cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk/*
2cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * Copyright (C) 2015 The Android Open Source Project
3cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk *
4cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * you may not use this file except in compliance with the License.
6cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * You may obtain a copy of the License at
7cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk *
8cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk *
10cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * Unless required by applicable law or agreed to in writing, software
11cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * See the License for the specific language governing permissions and
14cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk * limitations under the License.
15cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk */
16cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
17cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk#include "AutoConditionLock.h"
18cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
19cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunknamespace android {
20cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
21cc776718c0be7c31fe5ab4fc1446d377be60369fRuben BrunkWaitableMutexWrapper::WaitableMutexWrapper(Mutex* mutex) : mMutex{mutex}, mState{false} {}
22cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
23cc776718c0be7c31fe5ab4fc1446d377be60369fRuben BrunkWaitableMutexWrapper::~WaitableMutexWrapper() {}
24cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
25cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk// Locks manager-owned mutex
26cc776718c0be7c31fe5ab4fc1446d377be60369fRuben BrunkAutoConditionLock::AutoConditionLock(const std::shared_ptr<WaitableMutexWrapper>& manager) :
2734713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang        mManager{manager}, mAutoLock{manager->mMutex}, mAcquired(false) {}
28cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
29cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk// Unlocks manager-owned mutex
30cc776718c0be7c31fe5ab4fc1446d377be60369fRuben BrunkAutoConditionLock::~AutoConditionLock() {
31cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Unset the condition and wake everyone up before releasing lock
3234713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang    if (mAcquired) {
3334713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang        mManager->mState = false;
3434713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang        mManager->mCondition.broadcast();
3534713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang    }
36cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk}
37cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
38cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunkstd::unique_ptr<AutoConditionLock> AutoConditionLock::waitAndAcquire(
39cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        const std::shared_ptr<WaitableMutexWrapper>& manager, nsecs_t waitTime) {
40cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
41cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    if (manager == nullptr || manager->mMutex == nullptr) {
42cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        // Bad input, return null
43cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        return std::unique_ptr<AutoConditionLock>{nullptr};
44cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    }
45cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
46cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Acquire scoped lock
47cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    std::unique_ptr<AutoConditionLock> scopedLock(new AutoConditionLock(manager));
48cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
49cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Figure out what time in the future we should hit the timeout
50cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + waitTime;
51cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
52cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Wait until we timeout, or success
53cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    while(manager->mState) {
54cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        status_t ret = manager->mCondition.waitRelative(*(manager->mMutex), waitTime);
55cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        if (ret != NO_ERROR) {
56cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk            // Timed out or whatever, return null
57cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk            return std::unique_ptr<AutoConditionLock>{nullptr};
58cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        }
59cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        waitTime = failTime - systemTime(SYSTEM_TIME_MONOTONIC);
60cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    }
61cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
62cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Set the condition and return
63cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    manager->mState = true;
6434713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang    scopedLock->mAcquired = true;
65cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    return scopedLock;
66cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk}
67cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
68cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunkstd::unique_ptr<AutoConditionLock> AutoConditionLock::waitAndAcquire(
69cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        const std::shared_ptr<WaitableMutexWrapper>& manager) {
70cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
71cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    if (manager == nullptr || manager->mMutex == nullptr) {
72cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        // Bad input, return null
73cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        return std::unique_ptr<AutoConditionLock>{nullptr};
74cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    }
75cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
76cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Acquire scoped lock
77cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    std::unique_ptr<AutoConditionLock> scopedLock(new AutoConditionLock(manager));
78cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
79cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Wait until we timeout, or success
80cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    while(manager->mState) {
81cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        status_t ret = manager->mCondition.wait(*(manager->mMutex));
82cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        if (ret != NO_ERROR) {
83cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk            // Timed out or whatever, return null
84cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk            return std::unique_ptr<AutoConditionLock>{nullptr};
85cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk        }
86cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    }
87cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
88cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    // Set the condition and return
89cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    manager->mState = true;
9034713c04b5e1a897b0fd905a89622059a787f7a7Shuzhen Wang    scopedLock->mAcquired = true;
91cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk    return scopedLock;
92cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk}
93cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk
94cc776718c0be7c31fe5ab4fc1446d377be60369fRuben Brunk}; // namespace android
95