1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/apple/dispatch_source_mach.h"
6
7 #include "base/apple/scoped_dispatch_object.h"
8
9 namespace base::apple {
10
11 struct DispatchSourceMach::Storage {
12 // The dispatch queue used to service the source_.
13 ScopedDispatchObject<dispatch_queue_t> queue;
14
15 // A MACH_RECV dispatch source.
16 ScopedDispatchObject<dispatch_source_t> source;
17
18 // Semaphore used to wait on the |source_|'s cancellation in the destructor.
19 ScopedDispatchObject<dispatch_semaphore_t> source_canceled;
20 };
21
22 DispatchSourceMach::DispatchSourceMach(const char* name,
23 mach_port_t port,
24 void (^event_handler)())
25 : DispatchSourceMach(dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL),
26 port,
27 event_handler) {
28 // Since the queue was created above in the delegated constructor, and it was
29 // subsequently retained, release it here.
30 dispatch_release(storage_->queue.get());
31 }
32
33 DispatchSourceMach::DispatchSourceMach(dispatch_queue_t queue,
34 mach_port_t port,
35 void (^event_handler)())
36 : storage_(std::make_unique<Storage>()) {
37 storage_->queue.reset(queue, base::scoped_policy::RETAIN);
38 storage_->source.reset(dispatch_source_create(
39 DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, storage_->queue.get()));
40 storage_->source_canceled.reset(dispatch_semaphore_create(0));
41
42 dispatch_source_set_event_handler(storage_->source.get(), event_handler);
43 dispatch_source_set_cancel_handler(storage_->source.get(), ^{
44 dispatch_semaphore_signal(storage_->source_canceled.get());
45 });
46 }
47
~DispatchSourceMach()48 DispatchSourceMach::~DispatchSourceMach() {
49 // Cancel the source and wait for the semaphore to be signaled. This will
50 // ensure the source managed by this class is not used after it is freed.
51 dispatch_source_cancel(storage_->source.get());
52 storage_->source.reset();
53
54 dispatch_semaphore_wait(storage_->source_canceled.get(),
55 DISPATCH_TIME_FOREVER);
56 }
57
Resume()58 void DispatchSourceMach::Resume() {
59 dispatch_resume(storage_->source.get());
60 }
61
Queue() const62 dispatch_queue_t DispatchSourceMach::Queue() const {
63 return storage_->queue.get();
64 }
65
66 } // namespace base::apple
67