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