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#ifndef BASE_CRITICAL_CLOSURE_H_
6#define BASE_CRITICAL_CLOSURE_H_
7
8#include "base/callback.h"
9#include "base/macros.h"
10#include "build/build_config.h"
11
12#if defined(OS_IOS)
13#include "base/bind.h"
14#include "base/ios/scoped_critical_action.h"
15#endif
16
17namespace base {
18
19namespace internal {
20
21#if defined(OS_IOS)
22// Returns true if multi-tasking is supported on this iOS device.
23bool IsMultiTaskingSupported();
24
25// This class wraps a closure so it can continue to run for a period of time
26// when the application goes to the background by using
27// |ios::ScopedCriticalAction|.
28template <typename R>
29class CriticalClosure {
30 public:
31  explicit CriticalClosure(const Callback<R(void)>& closure)
32      : closure_(closure) {}
33
34  ~CriticalClosure() {}
35
36  R Run() {
37    return closure_.Run();
38  }
39
40 private:
41  ios::ScopedCriticalAction critical_action_;
42  Callback<R(void)> closure_;
43
44  DISALLOW_COPY_AND_ASSIGN(CriticalClosure);
45};
46#endif  // defined(OS_IOS)
47
48}  // namespace internal
49
50// Returns a closure (which may return a result, but must not require any extra
51// arguments) that will continue to run for a period of time when the
52// application goes to the background if possible on platforms where
53// applications don't execute while backgrounded, otherwise the original task is
54// returned.
55//
56// Example:
57//   file_task_runner_->PostTask(
58//       FROM_HERE,
59//       MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
60//
61// Note new closures might be posted in this closure. If the new closures need
62// background running time, |MakeCriticalClosure| should be applied on them
63// before posting.
64#if defined(OS_IOS)
65template <typename R>
66Callback<R(void)> MakeCriticalClosure(const Callback<R(void)>& closure) {
67  DCHECK(internal::IsMultiTaskingSupported());
68  return base::Bind(&internal::CriticalClosure<R>::Run,
69                    Owned(new internal::CriticalClosure<R>(closure)));
70}
71#else  // defined(OS_IOS)
72template <typename R>
73inline Callback<R(void)> MakeCriticalClosure(const Callback<R(void)>& closure) {
74  // No-op for platforms where the application does not need to acquire
75  // background time for closures to finish when it goes into the background.
76  return closure;
77}
78#endif  // defined(OS_IOS)
79
80}  // namespace base
81
82#endif  // BASE_CRITICAL_CLOSURE_H_
83