Shaka Packager SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
io_cache.cc
1 // Copyright 2015 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/file/io_cache.h"
8 
9 #include <string.h>
10 
11 #include <algorithm>
12 
13 #include "packager/base/logging.h"
14 
15 namespace shaka {
16 
17 using base::AutoLock;
18 using base::AutoUnlock;
19 
20 IoCache::IoCache(uint64_t cache_size)
21  : cache_size_(cache_size),
22  read_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
23  base::WaitableEvent::InitialState::NOT_SIGNALED),
24  write_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
25  base::WaitableEvent::InitialState::NOT_SIGNALED),
26  // Make the buffer one byte larger than the cache so that when the
27  // condition r_ptr == w_ptr is unambiguous (buffer empty).
28  circular_buffer_(cache_size + 1),
29  end_ptr_(&circular_buffer_[0] + cache_size + 1),
30  r_ptr_(circular_buffer_.data()),
31  w_ptr_(circular_buffer_.data()),
32  closed_(false) {}
33 
34 IoCache::~IoCache() {
35  Close();
36 }
37 
38 uint64_t IoCache::Read(void* buffer, uint64_t size) {
39  DCHECK(buffer);
40 
41  AutoLock lock(lock_);
42  while (!closed_ && (BytesCachedInternal() == 0)) {
43  AutoUnlock unlock(lock_);
44  write_event_.Wait();
45  }
46 
47  size = std::min(size, BytesCachedInternal());
48  uint64_t first_chunk_size(
49  std::min(size, static_cast<uint64_t>(end_ptr_ - r_ptr_)));
50  memcpy(buffer, r_ptr_, first_chunk_size);
51  r_ptr_ += first_chunk_size;
52  DCHECK_GE(end_ptr_, r_ptr_);
53  if (r_ptr_ == end_ptr_)
54  r_ptr_ = &circular_buffer_[0];
55  uint64_t second_chunk_size(size - first_chunk_size);
56  if (second_chunk_size) {
57  memcpy(static_cast<uint8_t*>(buffer) + first_chunk_size, r_ptr_,
58  second_chunk_size);
59  r_ptr_ += second_chunk_size;
60  DCHECK_GT(end_ptr_, r_ptr_);
61  }
62  read_event_.Signal();
63  return size;
64 }
65 
66 uint64_t IoCache::Write(const void* buffer, uint64_t size) {
67  DCHECK(buffer);
68 
69  const uint8_t* r_ptr(static_cast<const uint8_t*>(buffer));
70  uint64_t bytes_left(size);
71  while (bytes_left) {
72  AutoLock lock(lock_);
73  while (!closed_ && (BytesFreeInternal() == 0)) {
74  AutoUnlock unlock(lock_);
75  read_event_.Wait();
76  }
77  if (closed_)
78  return 0;
79 
80  uint64_t write_size(std::min(bytes_left, BytesFreeInternal()));
81  uint64_t first_chunk_size(
82  std::min(write_size, static_cast<uint64_t>(end_ptr_ - w_ptr_)));
83  memcpy(w_ptr_, r_ptr, first_chunk_size);
84  w_ptr_ += first_chunk_size;
85  DCHECK_GE(end_ptr_, w_ptr_);
86  if (w_ptr_ == end_ptr_)
87  w_ptr_ = &circular_buffer_[0];
88  r_ptr += first_chunk_size;
89  uint64_t second_chunk_size(write_size - first_chunk_size);
90  if (second_chunk_size) {
91  memcpy(w_ptr_, r_ptr, second_chunk_size);
92  w_ptr_ += second_chunk_size;
93  DCHECK_GT(end_ptr_, w_ptr_);
94  r_ptr += second_chunk_size;
95  }
96  bytes_left -= write_size;
97  write_event_.Signal();
98  }
99  return size;
100 }
101 
102 void IoCache::Clear() {
103  AutoLock lock(lock_);
104  r_ptr_ = w_ptr_ = circular_buffer_.data();
105  // Let any writers know that there is room in the cache.
106  read_event_.Signal();
107 }
108 
109 void IoCache::Close() {
110  AutoLock lock(lock_);
111  closed_ = true;
112  read_event_.Signal();
113  write_event_.Signal();
114 }
115 
116 void IoCache::Reopen() {
117  AutoLock lock(lock_);
118  CHECK(closed_);
119  r_ptr_ = w_ptr_ = circular_buffer_.data();
120  closed_ = false;
121  read_event_.Reset();
122  write_event_.Reset();
123 }
124 
125 uint64_t IoCache::BytesCached() {
126  AutoLock lock(lock_);
127  return BytesCachedInternal();
128 }
129 
130 uint64_t IoCache::BytesFree() {
131  AutoLock lock(lock_);
132  return BytesFreeInternal();
133 }
134 
135 uint64_t IoCache::BytesCachedInternal() {
136  return (r_ptr_ <= w_ptr_)
137  ? w_ptr_ - r_ptr_
138  : (end_ptr_ - r_ptr_) + (w_ptr_ - circular_buffer_.data());
139 }
140 
141 uint64_t IoCache::BytesFreeInternal() {
142  return cache_size_ - BytesCachedInternal();
143 }
144 
145 void IoCache::WaitUntilEmptyOrClosed() {
146  AutoLock lock(lock_);
147  while (!closed_ && BytesCachedInternal()) {
148  AutoUnlock unlock(lock_);
149  read_event_.Wait();
150  }
151 }
152 
153 } // namespace shaka