|  | // Copyright (c) 2012 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/mac/libdispatch_task_runner.h" | 
|  |  | 
|  | #include "base/callback.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace mac { | 
|  |  | 
|  | LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name) | 
|  | : queue_(dispatch_queue_create(name, NULL)), | 
|  | queue_finalized_(false, false) { | 
|  | dispatch_set_context(queue_, this); | 
|  | dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer); | 
|  | } | 
|  |  | 
|  | bool LibDispatchTaskRunner::PostDelayedTask( | 
|  | const tracked_objects::Location& from_here, | 
|  | const Closure& task, | 
|  | base::TimeDelta delay) { | 
|  | if (!queue_) | 
|  | return false; | 
|  |  | 
|  | // The block runtime would implicitly copy the reference, not the object | 
|  | // it's referencing. Copy the closure into block storage so it's available | 
|  | // to run. | 
|  | __block const Closure task_copy = task; | 
|  | void(^run_task)(void) = ^{ | 
|  | task_copy.Run(); | 
|  | }; | 
|  |  | 
|  | int64 delay_nano = | 
|  | delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond; | 
|  | if (delay_nano > 0) { | 
|  | dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano); | 
|  | dispatch_after(time, queue_, run_task); | 
|  | } else { | 
|  | dispatch_async(queue_, run_task); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const { | 
|  | return queue_ == dispatch_get_current_queue(); | 
|  | } | 
|  |  | 
|  | bool LibDispatchTaskRunner::PostNonNestableDelayedTask( | 
|  | const tracked_objects::Location& from_here, | 
|  | const Closure& task, | 
|  | base::TimeDelta delay) { | 
|  | return PostDelayedTask(from_here, task, delay); | 
|  | } | 
|  |  | 
|  | void LibDispatchTaskRunner::Shutdown() { | 
|  | dispatch_release(queue_); | 
|  | queue_ = NULL; | 
|  | queue_finalized_.Wait(); | 
|  | } | 
|  |  | 
|  | dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const { | 
|  | return queue_; | 
|  | } | 
|  |  | 
|  | LibDispatchTaskRunner::~LibDispatchTaskRunner() { | 
|  | if (queue_) { | 
|  | dispatch_set_context(queue_, NULL); | 
|  | dispatch_set_finalizer_f(queue_, NULL); | 
|  | dispatch_release(queue_); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LibDispatchTaskRunner::Finalizer(void* context) { | 
|  | LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context); | 
|  | self->queue_finalized_.Signal(); | 
|  | } | 
|  |  | 
|  | }  // namespace mac | 
|  | }  // namespace base |