#include "base/synchronization/waitable_event_watcher.h"
#include "base/apple/scoped_dispatch_object.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
namespace base {
struct WaitableEventWatcher::Storage {
apple::ScopedDispatchObject<dispatch_source_t> dispatch_source;
};
WaitableEventWatcher::WaitableEventWatcher()
: storage_(std::make_unique<Storage>()), weak_ptr_factory_(this) {}
WaitableEventWatcher::~WaitableEventWatcher() {
StopWatching();
}
bool WaitableEventWatcher::StartWatching(
WaitableEvent* event,
EventCallback callback,
scoped_refptr<SequencedTaskRunner> task_runner) {
DCHECK(task_runner->RunsTasksInCurrentSequence());
DCHECK(!storage_->dispatch_source ||
dispatch_source_testcancel(storage_->dispatch_source.get()));
receive_right_ = event->receive_right_;
callback_ =
BindOnce(std::move(callback), base::UnsafeDanglingUntriaged(event));
storage_->dispatch_source.reset(dispatch_source_create(
DISPATCH_SOURCE_TYPE_MACH_RECV, receive_right_->Name(), 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
WeakPtr<WaitableEventWatcher> weak_this = weak_ptr_factory_.GetWeakPtr();
const bool auto_reset =
event->policy_ == WaitableEvent::ResetPolicy::AUTOMATIC;
dispatch_source_t source = storage_->dispatch_source.get();
mach_port_t name = receive_right_->Name();
dispatch_source_set_event_handler(storage_->dispatch_source.get(), ^{
if (auto_reset && !WaitableEvent::PeekPort(name, true)) {
return;
}
dispatch_source_cancel(source);
task_runner->PostTask(
FROM_HERE, BindOnce(&WaitableEventWatcher::InvokeCallback, weak_this));
});
dispatch_resume(storage_->dispatch_source.get());
return true;
}
void WaitableEventWatcher::StopWatching() {
callback_.Reset();
receive_right_ = nullptr;
if (storage_->dispatch_source) {
dispatch_source_cancel(storage_->dispatch_source.get());
storage_->dispatch_source.reset();
}
}
void WaitableEventWatcher::InvokeCallback() {
if (callback_.is_null()) {
return;
}
storage_->dispatch_source.reset();
receive_right_ = nullptr;
std::move(callback_).Run();
}
}