Commit 20b379ba authored by Michael Nordman's avatar Michael Nordman Committed by Commit Bot

Revert "Reland "Reimplement base::WaitableEvent with a kqueue on Mac.""

This reverts commit bb3210d3.

Speculative revert for crbug/744550

Bug: 744550
Change-Id: I0b8a2464c2932d00349d3fd9a80ba7595c929ff7

TBR=mark,rsesek

Change-Id: I0b8a2464c2932d00349d3fd9a80ba7595c929ff7
Reviewed-on: https://chromium-review.googlesource.com/580639Reviewed-by: default avatarMichael Nordman <michaeln@chromium.org>
Commit-Queue: Michael Nordman <michaeln@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488706}
parent d702c390
......@@ -775,10 +775,8 @@ component("base") {
"synchronization/read_write_lock_win.cc",
"synchronization/spin_wait.h",
"synchronization/waitable_event.h",
"synchronization/waitable_event_mac.cc",
"synchronization/waitable_event_posix.cc",
"synchronization/waitable_event_watcher.h",
"synchronization/waitable_event_watcher_mac.cc",
"synchronization/waitable_event_watcher_posix.cc",
"synchronization/waitable_event_watcher_win.cc",
"synchronization/waitable_event_win.cc",
......@@ -1512,8 +1510,6 @@ component("base") {
"memory/shared_memory_posix.cc",
"native_library_posix.cc",
"strings/sys_string_conversions_posix.cc",
"synchronization/waitable_event_posix.cc",
"synchronization/waitable_event_watcher_posix.cc",
"threading/platform_thread_internal_posix.cc",
]
......@@ -1640,8 +1636,6 @@ component("base") {
"power_monitor/power_monitor_device_source_ios.mm",
"process/memory_stubs.cc",
"strings/sys_string_conversions_mac.mm",
"synchronization/waitable_event_mac.cc",
"synchronization/waitable_event_watcher_mac.cc",
"threading/platform_thread_mac.mm",
"time/time_conversion_posix.cc",
"time/time_mac.cc",
......
......@@ -13,12 +13,11 @@
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#elif defined(OS_MACOSX)
#include "base/files/scoped_file.h"
#elif defined(OS_POSIX)
#endif
#if defined(OS_POSIX)
#include <list>
#include <utility>
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#endif
......@@ -155,14 +154,6 @@ class BASE_EXPORT WaitableEvent {
#if defined(OS_WIN)
win::ScopedHandle handle_;
#elif defined(OS_MACOSX)
// The kqueue used to signal and wait on a custom user event.
ScopedFD kqueue_;
// Creates a kevent64_s, filling in the values using EV_SET64() with the
// specified flags and filter flags, and then submits it as a change to the
// |kqueue_|.
void PostEvent(uint16_t flags, uint32_t fflags);
#else
// On Windows, you must not close a HANDLE which is currently being waited on.
// The MSDN documentation says that the resulting behaviour is 'undefined'.
......
// Copyright 2017 The Chromium 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 "base/synchronization/waitable_event.h"
#include <sys/event.h>
#include <vector>
#include "base/debug/activity_tracker.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread_restrictions.h"
namespace base {
WaitableEvent::WaitableEvent(ResetPolicy reset_policy,
InitialState initial_state)
: kqueue_(kqueue()) {
PCHECK(kqueue_.is_valid()) << "kqueue";
uint16_t flags = EV_ADD;
if (reset_policy == ResetPolicy::AUTOMATIC)
flags |= EV_CLEAR;
// The initial event registration.
PostEvent(flags, 0);
if (initial_state == InitialState::SIGNALED)
Signal();
}
WaitableEvent::~WaitableEvent() = default;
void WaitableEvent::Reset() {
PostEvent(EV_DISABLE, 0);
}
void WaitableEvent::Signal() {
PostEvent(EV_ENABLE, NOTE_TRIGGER);
}
bool WaitableEvent::IsSignaled() {
// TODO(rsesek): Use KEVENT_FLAG_IMMEDIATE rather than an empty timeout.
timespec ts{};
kevent64_s event;
int rv = kevent64(kqueue_.get(), nullptr, 0, &event, 1, 0, &ts);
PCHECK(rv >= 0) << "kevent64 IsSignaled";
return rv > 0;
}
void WaitableEvent::Wait() {
bool result = TimedWaitUntil(TimeTicks::Max());
DCHECK(result) << "TimedWait() should never fail with infinite timeout";
}
bool WaitableEvent::TimedWait(const TimeDelta& wait_delta) {
return TimedWaitUntil(TimeTicks::Now() + wait_delta);
}
bool WaitableEvent::TimedWaitUntil(const TimeTicks& end_time) {
ThreadRestrictions::AssertWaitAllowed();
// Record the event that this thread is blocking upon (for hang diagnosis).
debug::ScopedEventWaitActivity event_activity(this);
bool indefinite = end_time.is_max();
int rv = 0;
do {
TimeDelta wait_time = end_time - TimeTicks::Now();
if (wait_time < TimeDelta()) {
// A negative delta would be treated by the system as indefinite, but
// it needs to be treated as a poll instead.
wait_time = TimeDelta();
}
timespec timeout = wait_time.ToTimeSpec();
// This does not use HANDLE_EINTR, since retrying the syscall requires
// adjusting the timeout to account for time already waited.
kevent64_s event;
rv = kevent64(kqueue_.get(), nullptr, 0, &event, 1, 0,
indefinite ? nullptr : &timeout);
} while (rv < 0 && errno == EINTR);
PCHECK(rv >= 0) << "kevent64 TimedWait";
return rv > 0;
}
// static
size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables, size_t count) {
ThreadRestrictions::AssertWaitAllowed();
DCHECK(count) << "Cannot wait on no events";
// Record an event (the first) that this thread is blocking upon.
debug::ScopedEventWaitActivity event_activity(raw_waitables[0]);
std::vector<kevent64_s> events(count);
for (size_t i = 0; i < count; ++i) {
EV_SET64(&events[i], raw_waitables[i]->kqueue_.get(), EVFILT_READ,
EV_ADD | EV_CLEAR, 0, 0, i, 0, 0);
}
std::vector<kevent64_s> out_events(count);
ScopedFD wait_many(kqueue());
PCHECK(wait_many.is_valid()) << "kqueue WaitMany";
int rv = HANDLE_EINTR(kevent64(wait_many.get(), events.data(), count,
out_events.data(), count, 0, nullptr));
PCHECK(rv > 0) << "kevent64: WaitMany";
size_t triggered = -1;
for (size_t i = 0; i < static_cast<size_t>(rv); ++i) {
// WaitMany should return the lowest index in |raw_waitables| that was
// triggered.
size_t index = static_cast<size_t>(out_events[i].udata);
triggered = std::min(triggered, index);
}
// The WaitMany kevent has identified which kqueue was signaled. Trigger
// a Wait on it to clear the event within WaitableEvent's kqueue. This
// will not block, since it has been triggered.
raw_waitables[triggered]->Wait();
return triggered;
}
void WaitableEvent::PostEvent(uint16_t flags, uint32_t fflags) {
kevent64_s event;
EV_SET64(&event, reinterpret_cast<uint64_t>(this), EVFILT_USER, flags, fflags,
0, 0, 0, 0);
int rv =
HANDLE_EINTR(kevent64(kqueue_.get(), &event, 1, nullptr, 0, 0, nullptr));
PCHECK(rv == 0) << "kevent64";
}
} // namespace base
......@@ -12,21 +12,12 @@
#if defined(OS_WIN)
#include "base/win/object_watcher.h"
#include "base/win/scoped_handle.h"
#elif defined(OS_MACOSX)
#include <dispatch/dispatch.h>
#include "base/files/scoped_file.h"
#include "base/mac/scoped_dispatch_object.h"
#include "base/memory/weak_ptr.h"
#else
#include "base/callback.h"
#include "base/sequence_checker.h"
#include "base/synchronization/waitable_event.h"
#endif
#if !defined(OS_WIN)
#include "base/callback.h"
#endif
namespace base {
class Flag;
......@@ -110,27 +101,6 @@ class BASE_EXPORT WaitableEventWatcher
EventCallback callback_;
WaitableEvent* event_ = nullptr;
#elif defined(OS_MACOSX)
// Invokes the callback and resets the source. Must be called on the task
// runner on which StartWatching() was called.
void InvokeCallback();
// Closure bound to the event being watched. This will be is_null() if
// nothing is being watched.
OnceClosure callback_;
// A dup()'d descriptor of the kqueue used by the WaitableEvent being
// watched, or the invalid value if nothing is.
ScopedFD kqueue_;
// A TYPE_READ dispatch source on |kqueue_|. When a read event is delivered,
// the kqueue has an event pending, and the bound |callback_| will be
// invoked. This will be null if nothing is currently being watched.
ScopedDispatchObject<dispatch_source_t> source_;
// Used to vend a weak pointer for calling InvokeCallback() from the
// |source_| event handler.
WeakPtrFactory<WaitableEventWatcher> weak_ptr_factory_;
#else
// Instantiated in StartWatching(). Set before the callback runs. Reset in
// StopWatching() or StartWatching().
......
// Copyright 2017 The Chromium 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 "base/synchronization/waitable_event_watcher.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace base {
WaitableEventWatcher::WaitableEventWatcher() : weak_ptr_factory_(this) {}
WaitableEventWatcher::~WaitableEventWatcher() {
StopWatching();
}
bool WaitableEventWatcher::StartWatching(WaitableEvent* event,
EventCallback callback) {
DCHECK(!source_ || dispatch_source_testcancel(source_));
kqueue_.reset(dup(event->kqueue_.get()));
if (!kqueue_.is_valid()) {
PLOG(ERROR) << "dup kqueue";
return false;
}
// Use the global concurrent queue here, since it is only used to thunk
// to the real callback on the target task runner.
source_.reset(dispatch_source_create(
DISPATCH_SOURCE_TYPE_READ, kqueue_.get(), 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
callback_ = BindOnce(std::move(callback), event);
scoped_refptr<SequencedTaskRunner> task_runner =
SequencedTaskRunnerHandle::Get();
WeakPtr<WaitableEventWatcher> weak_this = weak_ptr_factory_.GetWeakPtr();
dispatch_source_set_event_handler(source_, ^{
// Cancel the source immediately, since libdispatch will continue to send
// events until the kqueue is drained.
dispatch_source_cancel(source_);
task_runner->PostTask(
FROM_HERE, BindOnce(&WaitableEventWatcher::InvokeCallback, weak_this));
});
dispatch_resume(source_);
return true;
}
void WaitableEventWatcher::StopWatching() {
callback_.Reset();
if (source_) {
dispatch_source_cancel(source_);
source_.reset();
}
kqueue_.reset();
}
void WaitableEventWatcher::InvokeCallback() {
// The callback can be null if StopWatching() is called between signaling
// and the |callback_| getting run on the target task runner.
if (callback_.is_null())
return;
source_.reset();
std::move(callback_).Run();
}
} // namespace base
......@@ -784,8 +784,6 @@ TEST_F(TaskSchedulerTaskTrackerTest,
for (const auto& thread : post_threads)
thread->Join();
// Clean up unused Thread objects to avoid running out of system resources.
post_threads.clear();
// Call Shutdown() asynchronously.
CallShutdownAsync();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment