2015-03-19 18:28:04 +00:00
|
|
|
// Copyright 2015 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
|
|
|
|
#include "packager/media/file/threaded_io_file.h"
|
|
|
|
|
|
|
|
#include "packager/base/bind.h"
|
|
|
|
#include "packager/base/bind_helpers.h"
|
|
|
|
#include "packager/base/threading/platform_thread.h"
|
|
|
|
#include "packager/media/base/closure_thread.h"
|
|
|
|
|
|
|
|
namespace edash_packager {
|
|
|
|
namespace media {
|
|
|
|
|
2015-11-14 02:43:25 +00:00
|
|
|
using base::subtle::NoBarrier_Load;
|
|
|
|
using base::subtle::NoBarrier_Store;
|
|
|
|
|
2015-03-19 18:28:04 +00:00
|
|
|
ThreadedIoFile::ThreadedIoFile(scoped_ptr<File, FileCloser> internal_file,
|
|
|
|
Mode mode,
|
|
|
|
uint64_t io_cache_size,
|
|
|
|
uint64_t io_block_size)
|
|
|
|
: File(internal_file->file_name()),
|
|
|
|
internal_file_(internal_file.Pass()),
|
|
|
|
mode_(mode),
|
|
|
|
cache_(io_cache_size),
|
|
|
|
io_buffer_(io_block_size),
|
|
|
|
size_(0),
|
|
|
|
eof_(false),
|
2015-10-16 20:10:42 +00:00
|
|
|
flushing_(false),
|
|
|
|
flush_complete_event_(false, false),
|
|
|
|
internal_file_error_(0){
|
2015-03-19 18:28:04 +00:00
|
|
|
DCHECK(internal_file_);
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadedIoFile::~ThreadedIoFile() {}
|
|
|
|
|
|
|
|
bool ThreadedIoFile::Open() {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
|
|
|
|
if (!internal_file_->Open())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
size_ = internal_file_->Size();
|
|
|
|
|
|
|
|
thread_.reset(new ClosureThread("ThreadedIoFile",
|
|
|
|
base::Bind(mode_ == kInputMode ?
|
|
|
|
&ThreadedIoFile::RunInInputMode :
|
|
|
|
&ThreadedIoFile::RunInOutputMode,
|
|
|
|
base::Unretained(this))));
|
|
|
|
thread_->Start();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThreadedIoFile::Close() {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
|
|
|
|
if (mode_ == kOutputMode)
|
|
|
|
Flush();
|
|
|
|
|
|
|
|
cache_.Close();
|
|
|
|
thread_->Join();
|
|
|
|
|
|
|
|
bool result = internal_file_.release()->Close();
|
|
|
|
delete this;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t ThreadedIoFile::Read(void* buffer, uint64_t length) {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
DCHECK_EQ(kInputMode, mode_);
|
|
|
|
|
2015-11-14 02:43:25 +00:00
|
|
|
if (NoBarrier_Load(&eof_) && !cache_.BytesCached())
|
2015-03-19 18:28:04 +00:00
|
|
|
return 0;
|
|
|
|
|
2015-11-14 02:43:25 +00:00
|
|
|
if (NoBarrier_Load(&internal_file_error_))
|
|
|
|
return NoBarrier_Load(&internal_file_error_);
|
|
|
|
|
2015-03-19 18:28:04 +00:00
|
|
|
return cache_.Read(buffer, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t ThreadedIoFile::Write(const void* buffer, uint64_t length) {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
DCHECK_EQ(kOutputMode, mode_);
|
|
|
|
|
2015-11-14 02:43:25 +00:00
|
|
|
if (NoBarrier_Load(&internal_file_error_))
|
|
|
|
return NoBarrier_Load(&internal_file_error_);
|
2015-03-19 18:28:04 +00:00
|
|
|
|
|
|
|
size_ += length;
|
|
|
|
return cache_.Write(buffer, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t ThreadedIoFile::Size() {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
|
|
|
|
return size_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThreadedIoFile::Flush() {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
DCHECK_EQ(kOutputMode, mode_);
|
|
|
|
|
2015-10-16 20:10:42 +00:00
|
|
|
flushing_ = true;
|
|
|
|
cache_.Close();
|
|
|
|
flush_complete_event_.Wait();
|
2015-03-19 18:28:04 +00:00
|
|
|
return internal_file_->Flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ThreadedIoFile::RunInInputMode() {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
DCHECK_EQ(kInputMode, mode_);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
int64_t read_result = internal_file_->Read(&io_buffer_[0],
|
|
|
|
io_buffer_.size());
|
|
|
|
if (read_result <= 0) {
|
2015-11-14 02:43:25 +00:00
|
|
|
NoBarrier_Store(&eof_, read_result == 0);
|
|
|
|
NoBarrier_Store(&internal_file_error_, read_result);
|
2015-03-19 18:28:04 +00:00
|
|
|
cache_.Close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cache_.Write(&io_buffer_[0], read_result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-20 17:14:36 +00:00
|
|
|
bool ThreadedIoFile::Seek(uint64_t position) {
|
|
|
|
NOTIMPLEMENTED();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ThreadedIoFile::Tell(uint64_t* position) {
|
|
|
|
NOTIMPLEMENTED();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-19 18:28:04 +00:00
|
|
|
void ThreadedIoFile::RunInOutputMode() {
|
|
|
|
DCHECK(internal_file_);
|
|
|
|
DCHECK(thread_);
|
|
|
|
DCHECK_EQ(kOutputMode, mode_);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
uint64_t write_bytes = cache_.Read(&io_buffer_[0], io_buffer_.size());
|
2015-10-16 20:10:42 +00:00
|
|
|
if (write_bytes == 0) {
|
|
|
|
if (flushing_) {
|
|
|
|
cache_.Reopen();
|
|
|
|
flushing_ = false;
|
|
|
|
flush_complete_event_.Signal();
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2015-11-14 02:43:25 +00:00
|
|
|
uint64_t bytes_written(0);
|
|
|
|
while (bytes_written < write_bytes) {
|
|
|
|
int64_t write_result = internal_file_->Write(
|
|
|
|
&io_buffer_[bytes_written], write_bytes - bytes_written);
|
|
|
|
if (write_result < 0) {
|
|
|
|
NoBarrier_Store(&internal_file_error_, write_result);
|
|
|
|
cache_.Close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bytes_written += write_result;
|
2015-10-16 20:10:42 +00:00
|
|
|
}
|
2015-03-19 18:28:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace media
|
|
|
|
} // namespace edash_packager
|