DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
threaded_io_file.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/media/file/threaded_io_file.h"
8 
9 #include "packager/base/bind.h"
10 #include "packager/base/bind_helpers.h"
11 #include "packager/base/location.h"
12 #include "packager/base/threading/worker_pool.h"
13 
14 namespace shaka {
15 namespace media {
16 
17 using base::subtle::NoBarrier_Load;
18 using base::subtle::NoBarrier_Store;
19 
20 ThreadedIoFile::ThreadedIoFile(std::unique_ptr<File, FileCloser> internal_file,
21  Mode mode,
22  uint64_t io_cache_size,
23  uint64_t io_block_size)
24  : File(internal_file->file_name()),
25  internal_file_(std::move(internal_file)),
26  mode_(mode),
27  cache_(io_cache_size),
28  io_buffer_(io_block_size),
29  position_(0),
30  size_(0),
31  eof_(false),
32  flushing_(false),
33  flush_complete_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
34  base::WaitableEvent::InitialState::NOT_SIGNALED),
35  internal_file_error_(0),
36  task_exit_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
37  base::WaitableEvent::InitialState::NOT_SIGNALED) {
38  DCHECK(internal_file_);
39 }
40 
41 ThreadedIoFile::~ThreadedIoFile() {}
42 
44  DCHECK(internal_file_);
45 
46  if (!internal_file_->Open())
47  return false;
48 
49  position_ = 0;
50  size_ = internal_file_->Size();
51 
52  base::WorkerPool::PostTask(FROM_HERE, base::Bind(&ThreadedIoFile::TaskHandler,
53  base::Unretained(this)),
54  true /* task_is_slow */);
55  return true;
56 }
57 
59  DCHECK(internal_file_);
60 
61  if (mode_ == kOutputMode)
62  Flush();
63 
64  cache_.Close();
65  task_exit_event_.Wait();
66 
67  bool result = internal_file_.release()->Close();
68  delete this;
69  return result;
70 }
71 
72 int64_t ThreadedIoFile::Read(void* buffer, uint64_t length) {
73  DCHECK(internal_file_);
74  DCHECK_EQ(kInputMode, mode_);
75 
76  if (NoBarrier_Load(&eof_) && !cache_.BytesCached())
77  return 0;
78 
79  if (NoBarrier_Load(&internal_file_error_))
80  return NoBarrier_Load(&internal_file_error_);
81 
82 
83  uint64_t bytes_read = cache_.Read(buffer, length);
84  position_ += bytes_read;
85 
86  return bytes_read;
87 }
88 
89 int64_t ThreadedIoFile::Write(const void* buffer, uint64_t length) {
90  DCHECK(internal_file_);
91  DCHECK_EQ(kOutputMode, mode_);
92 
93  if (NoBarrier_Load(&internal_file_error_))
94  return NoBarrier_Load(&internal_file_error_);
95 
96  uint64_t bytes_written = cache_.Write(buffer, length);
97  position_ += bytes_written;
98  if (position_ > size_)
99  size_ = position_;
100 
101  return bytes_written;
102 }
103 
105  DCHECK(internal_file_);
106 
107  return size_;
108 }
109 
111  DCHECK(internal_file_);
112  DCHECK_EQ(kOutputMode, mode_);
113 
114  flushing_ = true;
115  cache_.Close();
116  flush_complete_event_.Wait();
117  return internal_file_->Flush();
118 }
119 
120 bool ThreadedIoFile::Seek(uint64_t position) {
121  if (mode_ == kOutputMode) {
122  // Writing. Just flush the cache and seek.
123  if (!Flush()) return false;
124  if (!internal_file_->Seek(position)) return false;
125  } else {
126  // Reading. Close cache, wait for thread task to exit, seek, and re-post
127  // the task.
128  cache_.Close();
129  task_exit_event_.Wait();
130  bool result = internal_file_->Seek(position);
131  if (!result) {
132  // Seek failed. Seek to logical position instead.
133  if (!internal_file_->Seek(position_) && (position != position_)) {
134  LOG(WARNING) << "Seek failed. ThreadedIoFile left in invalid state.";
135  }
136  }
137  cache_.Reopen();
138  eof_ = false;
139  base::WorkerPool::PostTask(
140  FROM_HERE,
141  base::Bind(&ThreadedIoFile::TaskHandler, base::Unretained(this)),
142  true /* task_is_slow */);
143  if (!result) return false;
144  }
145  position_ = position;
146  return true;
147 }
148 
149 bool ThreadedIoFile::Tell(uint64_t* position) {
150  DCHECK(position);
151 
152  *position = position_;
153  return true;
154 }
155 
156 void ThreadedIoFile::TaskHandler() {
157  if (mode_ == kInputMode)
158  RunInInputMode();
159  else
160  RunInOutputMode();
161  task_exit_event_.Signal();
162 }
163 
164 void ThreadedIoFile::RunInInputMode() {
165  DCHECK(internal_file_);
166  DCHECK_EQ(kInputMode, mode_);
167 
168  while (true) {
169  int64_t read_result = internal_file_->Read(&io_buffer_[0],
170  io_buffer_.size());
171  if (read_result <= 0) {
172  NoBarrier_Store(&eof_, read_result == 0);
173  NoBarrier_Store(&internal_file_error_, read_result);
174  cache_.Close();
175  return;
176  }
177  if (cache_.Write(&io_buffer_[0], read_result) == 0) {
178  return;
179  }
180  }
181 }
182 
183 void ThreadedIoFile::RunInOutputMode() {
184  DCHECK(internal_file_);
185  DCHECK_EQ(kOutputMode, mode_);
186 
187  while (true) {
188  uint64_t write_bytes = cache_.Read(&io_buffer_[0], io_buffer_.size());
189  if (write_bytes == 0) {
190  if (flushing_) {
191  cache_.Reopen();
192  flushing_ = false;
193  flush_complete_event_.Signal();
194  } else {
195  return;
196  }
197  } else {
198  uint64_t bytes_written(0);
199  while (bytes_written < write_bytes) {
200  int64_t write_result = internal_file_->Write(
201  &io_buffer_[bytes_written], write_bytes - bytes_written);
202  if (write_result < 0) {
203  NoBarrier_Store(&internal_file_error_, write_result);
204  cache_.Close();
205  return;
206  }
207  bytes_written += write_result;
208  }
209  }
210  }
211 }
212 
213 } // namespace media
214 } // namespace shaka
bool Tell(uint64_t *position) override
bool Seek(uint64_t position) override
int64_t Write(const void *buffer, uint64_t length) override
void Reopen()
Reopens the cache. Any data still in the cache will be lost.
Definition: io_cache.cc:118
uint64_t Read(void *buffer, uint64_t size)
Definition: io_cache.cc:40
bool Open() override
Internal open. Should not be used directly.
uint64_t BytesCached()
Definition: io_cache.cc:127
uint64_t Write(const void *buffer, uint64_t size)
Definition: io_cache.cc:68
int64_t Read(void *buffer, uint64_t length) override