Shaka Player Embedded
shared_lock.cc
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
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 // https://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 "src/util/shared_lock.h"
16 
17 #include <glog/logging.h>
18 
19 namespace shaka {
20 namespace util {
21 
23 #ifdef USE_PTHREAD
24  CHECK_EQ(pthread_rwlock_init(&lock_, nullptr), 0);
25 #endif
26 }
27 
29 #ifdef USE_PTHREAD
30  CHECK_EQ(pthread_rwlock_destroy(&lock_), 0);
31 #else
32  DCHECK(!is_exclusive_) << "Trying to destroy a locked mutex";
33  DCHECK_EQ(0, shared_count_) << "Trying to destroy a locked mutex";
34 #endif
35 }
36 
38 #ifdef USE_PTHREAD
39  CHECK_EQ(pthread_rwlock_unlock(&lock_), 0);
40 #else
41  {
42  std::unique_lock<std::mutex> lock(mutex_);
43  DCHECK(is_exclusive_) << "Trying to unlock an already unlocked mutex";
44  DCHECK_EQ(shared_count_, 0) << "Cannot have shared locks in exclusive mode";
45  is_exclusive_ = false;
46  }
47  signal_.notify_all();
48 #endif
49 }
50 
52 #ifdef USE_PTHREAD
53  CHECK_EQ(pthread_rwlock_unlock(&lock_), 0);
54 #else
55  {
56  std::unique_lock<std::mutex> lock(mutex_);
57  DCHECK(!is_exclusive_) << "Cannot hold unique lock with shared lock";
58  DCHECK_GT(shared_count_, 0) << "Trying to unlock an already unlocked mutex";
59  shared_count_--;
60  }
61  signal_.notify_all();
62 #endif
63 }
64 
65 bool shared_mutex::maybe_try_lock(bool only_try) {
66 #ifdef USE_PTHREAD
67  const int code = only_try ? pthread_rwlock_trywrlock(&lock_)
68  : pthread_rwlock_wrlock(&lock_);
69  CHECK(code == 0 || code == EBUSY);
70  return code == 0;
71 #else
72  // Note this lock is only held transitively, so it shouldn't block for long.
73  std::unique_lock<std::mutex> lock(mutex_);
74  while (is_exclusive_ || shared_count_ > 0) {
75  if (only_try)
76  return false;
77  is_exclusive_waiting_ = true;
78  signal_.wait(lock);
79  }
80  is_exclusive_ = true;
81  is_exclusive_waiting_ = false;
82  return true;
83 #endif
84 }
85 
86 bool shared_mutex::maybe_try_lock_shared(bool only_try) {
87 #ifdef USE_PTHREAD
88  const int code = only_try ? pthread_rwlock_tryrdlock(&lock_)
89  : pthread_rwlock_rdlock(&lock_);
90  CHECK(code == 0 || code == EBUSY);
91  return code == 0;
92 #else
93  // Note this lock is only held transitively, so it shouldn't block for long.
94  std::unique_lock<std::mutex> lock(mutex_);
95 
96  // Wait if there is an exclusive lock waiting. This ensures that if there
97  // are a bunch of readers, a writer can still get in.
98  while (is_exclusive_ || is_exclusive_waiting_) {
99  if (only_try)
100  return false;
101  signal_.wait(lock);
102  }
103  shared_count_++;
104  return true;
105 #endif
106 }
107 
108 } // namespace util
109 } // namespace shaka