1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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/mac/libdispatch_task_runner.h"
6
7#include <stdint.h>
8
9#include "base/callback.h"
10
11namespace base {
12namespace mac {
13
14LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name)
15    : queue_(dispatch_queue_create(name, NULL)),
16      queue_finalized_(false, false) {
17  dispatch_set_context(queue_, this);
18  dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer);
19}
20
21bool LibDispatchTaskRunner::PostDelayedTask(
22    const tracked_objects::Location& /* from_here */,
23    const Closure& task,
24    base::TimeDelta delay) {
25  if (!queue_)
26    return false;
27
28  // The block runtime would implicitly copy the reference, not the object
29  // it's referencing. Copy the closure into block storage so it's available
30  // to run.
31  __block const Closure task_copy = task;
32  void(^run_task)(void) = ^{
33      task_copy.Run();
34  };
35
36  int64_t delay_nano =
37      delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
38  if (delay_nano > 0) {
39    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
40    dispatch_after(time, queue_, run_task);
41  } else {
42    dispatch_async(queue_, run_task);
43  }
44  return true;
45}
46
47bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const {
48  return queue_ == dispatch_get_current_queue();
49}
50
51bool LibDispatchTaskRunner::PostNonNestableDelayedTask(
52    const tracked_objects::Location& from_here,
53    const Closure& task,
54    base::TimeDelta delay) {
55  return PostDelayedTask(from_here, task, delay);
56}
57
58void LibDispatchTaskRunner::Shutdown() {
59  dispatch_release(queue_);
60  queue_ = NULL;
61  queue_finalized_.Wait();
62}
63
64dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const {
65  return queue_;
66}
67
68LibDispatchTaskRunner::~LibDispatchTaskRunner() {
69  if (queue_) {
70    dispatch_set_context(queue_, NULL);
71    dispatch_set_finalizer_f(queue_, NULL);
72    dispatch_release(queue_);
73  }
74}
75
76void LibDispatchTaskRunner::Finalizer(void* context) {
77  LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context);
78  self->queue_finalized_.Signal();
79}
80
81}  // namespace mac
82}  // namespace base
83