blob: 45784f76c2d604c14af38e893ee3c95311173af8 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "garnet/bin/mediaplayer/util/threadsafe_callback_joiner.h"
#include <lib/async/cpp/task.h>
namespace media_player {
std::ostream& operator<<(std::ostream& os, ThreadsafeCallbackJoiner* value) {
return os << "ThreadsafeCallbackJoiner#" << std::hex << uint64_t(value);
}
// static
std::shared_ptr<ThreadsafeCallbackJoiner> ThreadsafeCallbackJoiner::Create() {
return std::make_shared<ThreadsafeCallbackJoiner>();
}
ThreadsafeCallbackJoiner::ThreadsafeCallbackJoiner() {}
ThreadsafeCallbackJoiner::~ThreadsafeCallbackJoiner() {}
void ThreadsafeCallbackJoiner::Spawn() {
std::lock_guard<std::mutex> locker(mutex_);
++counter_;
}
void ThreadsafeCallbackJoiner::Complete() {
fit::closure callback;
async_dispatcher_t* dispatcher;
{
std::lock_guard<std::mutex> locker(mutex_);
FXL_DCHECK(counter_ != 0);
--counter_;
if (counter_ != 0 || !join_callback_) {
return;
}
std::swap(callback, join_callback_);
std::swap(dispatcher, join_callback_dispatcher_);
}
async::PostTask(dispatcher,
[shared_this = shared_from_this(),
callback = std::move(callback)]() { callback(); });
}
fit::closure ThreadsafeCallbackJoiner::NewCallback() {
Spawn();
std::shared_ptr<ThreadsafeCallbackJoiner> this_ptr = shared_from_this();
FXL_DCHECK(!this_ptr.unique());
return [this_ptr]() {
FXL_DCHECK(this_ptr);
this_ptr->Complete();
};
}
void ThreadsafeCallbackJoiner::WhenJoined(async_dispatcher_t* dispatcher,
fit::closure join_callback) {
FXL_DCHECK(dispatcher);
FXL_DCHECK(join_callback);
{
std::lock_guard<std::mutex> locker(mutex_);
FXL_DCHECK(!join_callback_);
if (counter_ != 0) {
join_callback_ = std::move(join_callback);
join_callback_dispatcher_ = dispatcher;
return;
}
}
async::PostTask(dispatcher, [shared_this = shared_from_this(),
join_callback = std::move(join_callback)]() {
join_callback();
});
}
bool ThreadsafeCallbackJoiner::Cancel() {
std::lock_guard<std::mutex> locker(mutex_);
if (join_callback_) {
join_callback_ = nullptr;
join_callback_dispatcher_ = nullptr;
return true;
}
return false;
}
} // namespace media_player