12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/mac/libdispatch_task_runner.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace base {
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace mac {
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : queue_(dispatch_queue_create(name, NULL)),
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      queue_finalized_(false, false) {
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dispatch_set_context(queue_, this);
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer);
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LibDispatchTaskRunner::PostDelayedTask(
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const tracked_objects::Location& from_here,
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Closure& task,
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta delay) {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!queue_)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The block runtime would implicitly copy the reference, not the object
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it's referencing. Copy the closure into block storage so it's available
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to run.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  __block const Closure task_copy = task;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void(^run_task)(void) = ^{
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      task_copy.Run();
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int64 delay_nano =
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delay_nano > 0) {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dispatch_after(time, queue_, run_task);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dispatch_async(queue_, run_task);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return queue_ == dispatch_get_current_queue();
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LibDispatchTaskRunner::PostNonNestableDelayedTask(
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const tracked_objects::Location& from_here,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Closure& task,
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta delay) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return PostDelayedTask(from_here, task, delay);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LibDispatchTaskRunner::Shutdown() {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dispatch_release(queue_);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  queue_ = NULL;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  queue_finalized_.Wait();
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return queue_;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LibDispatchTaskRunner::~LibDispatchTaskRunner() {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (queue_) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dispatch_set_context(queue_, NULL);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dispatch_set_finalizer_f(queue_, NULL);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dispatch_release(queue_);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void LibDispatchTaskRunner::Finalizer(void* context) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  self->queue_finalized_.Signal();
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace mac
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace base
81