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