security/sandbox/chromium/base/threading/sequenced_worker_pool.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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.
     5 #ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_
     6 #define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
     8 #include <cstddef>
     9 #include <string>
    11 #include "base/base_export.h"
    12 #include "base/basictypes.h"
    13 #include "base/callback_forward.h"
    14 #include "base/memory/ref_counted.h"
    15 #include "base/memory/scoped_ptr.h"
    16 #include "base/task_runner.h"
    18 namespace tracked_objects {
    19 class Location;
    20 }  // namespace tracked_objects
    22 namespace base {
    24 class MessageLoopProxy;
    26 template <class T> class DeleteHelper;
    28 class SequencedTaskRunner;
    30 // A worker thread pool that enforces ordering between sets of tasks. It also
    31 // allows you to specify what should happen to your tasks on shutdown.
    32 //
    33 // To enforce ordering, get a unique sequence token from the pool and post all
    34 // tasks you want to order with the token. All tasks with the same token are
    35 // guaranteed to execute serially, though not necessarily on the same thread.
    36 // This means that:
    37 //
    38 //   - No two tasks with the same token will run at the same time.
    39 //
    40 //   - Given two tasks T1 and T2 with the same token such that T2 will
    41 //     run after T1, then T2 will start after T1 is destroyed.
    42 //
    43 //   - If T2 will run after T1, then all memory changes in T1 and T1's
    44 //     destruction will be visible to T2.
    45 //
    46 // Example:
    47 //   SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
    48 //   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
    49 //                                FROM_HERE, base::Bind(...));
    50 //   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
    51 //                                FROM_HERE, base::Bind(...));
    52 //
    53 // You can make named sequence tokens to make it easier to share a token
    54 // across different components.
    55 //
    56 // You can also post tasks to the pool without ordering using PostWorkerTask.
    57 // These will be executed in an unspecified order. The order of execution
    58 // between tasks with different sequence tokens is also unspecified.
    59 //
    60 // This class may be leaked on shutdown to facilitate fast shutdown. The
    61 // expected usage, however, is to call Shutdown(), which correctly accounts
    62 // for CONTINUE_ON_SHUTDOWN behavior and is required for BLOCK_SHUTDOWN
    63 // behavior.
    64 //
    65 // Implementation note: This does not use a base::WorkerPool since that does
    66 // not enforce shutdown semantics or allow us to specify how many worker
    67 // threads to run. For the typical use case of random background work, we don't
    68 // necessarily want to be super aggressive about creating threads.
    69 //
    70 // Note that SequencedWorkerPool is RefCountedThreadSafe (inherited
    71 // from TaskRunner).
    72 class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
    73  public:
    74   // Defines what should happen to a task posted to the worker pool on
    75   // shutdown.
    76   enum WorkerShutdown {
    77     // Tasks posted with this mode which have not run at shutdown will be
    78     // deleted rather than run, and any tasks with this mode running at
    79     // shutdown will be ignored (the worker thread will not be joined).
    80     //
    81     // This option provides a nice way to post stuff you don't want blocking
    82     // shutdown. For example, you might be doing a slow DNS lookup and if it's
    83     // blocked on the OS, you may not want to stop shutdown, since the result
    84     // doesn't really matter at that point.
    85     //
    86     // However, you need to be very careful what you do in your callback when
    87     // you use this option. Since the thread will continue to run until the OS
    88     // terminates the process, the app can be in the process of tearing down
    89     // when you're running. This means any singletons or global objects you
    90     // use may suddenly become invalid out from under you. For this reason,
    91     // it's best to use this only for slow but simple operations like the DNS
    92     // example.
    93     CONTINUE_ON_SHUTDOWN,
    95     // Tasks posted with this mode that have not started executing at
    96     // shutdown will be deleted rather than executed. However, any tasks that
    97     // have already begun executing when shutdown is called will be allowed
    98     // to continue, and will block shutdown until completion.
    99     //
   100     // Note: Because Shutdown() may block while these tasks are executing,
   101     // care must be taken to ensure that they do not block on the thread that
   102     // called Shutdown(), as this may lead to deadlock.
   103     SKIP_ON_SHUTDOWN,
   105     // Tasks posted with this mode will block shutdown until they're
   106     // executed. Since this can have significant performance implications,
   107     // use sparingly.
   108     //
   109     // Generally, this should be used only for user data, for example, a task
   110     // writing a preference file.
   111     //
   112     // If a task is posted during shutdown, it will not get run since the
   113     // workers may already be stopped. In this case, the post operation will
   114     // fail (return false) and the task will be deleted.
   115     BLOCK_SHUTDOWN,
   116   };
   118   // Opaque identifier that defines sequencing of tasks posted to the worker
   119   // pool.
   120   class SequenceToken {
   121    public:
   122     SequenceToken() : id_(0) {}
   123     ~SequenceToken() {}
   125     bool Equals(const SequenceToken& other) const {
   126       return id_ == other.id_;
   127     }
   129     // Returns false if current thread is executing an unsequenced task.
   130     bool IsValid() const {
   131       return id_ != 0;
   132     }
   134    private:
   135     friend class SequencedWorkerPool;
   137     explicit SequenceToken(int id) : id_(id) {}
   139     int id_;
   140   };
   142   // Allows tests to perform certain actions.
   143   class TestingObserver {
   144    public:
   145     virtual ~TestingObserver() {}
   146     virtual void OnHasWork() = 0;
   147     virtual void WillWaitForShutdown() = 0;
   148     virtual void OnDestruct() = 0;
   149   };
   151   // Gets the SequencedToken of the current thread.
   152   // If current thread is not a SequencedWorkerPool worker thread or is running
   153   // an unsequenced task, returns an invalid SequenceToken.
   154   static SequenceToken GetSequenceTokenForCurrentThread();
   156   // When constructing a SequencedWorkerPool, there must be a
   157   // MessageLoop on the current thread unless you plan to deliberately
   158   // leak it.
   160   // Pass the maximum number of threads (they will be lazily created as needed)
   161   // and a prefix for the thread name to aid in debugging.
   162   SequencedWorkerPool(size_t max_threads,
   163                       const std::string& thread_name_prefix);
   165   // Like above, but with |observer| for testing.  Does not take
   166   // ownership of |observer|.
   167   SequencedWorkerPool(size_t max_threads,
   168                       const std::string& thread_name_prefix,
   169                       TestingObserver* observer);
   171   // Returns a unique token that can be used to sequence tasks posted to
   172   // PostSequencedWorkerTask(). Valid tokens are always nonzero.
   173   SequenceToken GetSequenceToken();
   175   // Returns the sequence token associated with the given name. Calling this
   176   // function multiple times with the same string will always produce the
   177   // same sequence token. If the name has not been used before, a new token
   178   // will be created.
   179   SequenceToken GetNamedSequenceToken(const std::string& name);
   181   // Returns a SequencedTaskRunner wrapper which posts to this
   182   // SequencedWorkerPool using the given sequence token. Tasks with nonzero
   183   // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
   184   // are posted with BLOCK_SHUTDOWN behavior.
   185   scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner(
   186       SequenceToken token);
   188   // Returns a SequencedTaskRunner wrapper which posts to this
   189   // SequencedWorkerPool using the given sequence token. Tasks with nonzero
   190   // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
   191   // are posted with the given shutdown behavior.
   192   scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior(
   193       SequenceToken token,
   194       WorkerShutdown shutdown_behavior);
   196   // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using
   197   // the given shutdown behavior. Tasks with nonzero delay are posted with
   198   // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the
   199   // given shutdown behavior.
   200   scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior(
   201       WorkerShutdown shutdown_behavior);
   203   // Posts the given task for execution in the worker pool. Tasks posted with
   204   // this function will execute in an unspecified order on a background thread.
   205   // Returns true if the task was posted. If your tasks have ordering
   206   // requirements, see PostSequencedWorkerTask().
   207   //
   208   // This class will attempt to delete tasks that aren't run
   209   // (non-block-shutdown semantics) but can't guarantee that this happens. If
   210   // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there
   211   // will be no workers available to delete these tasks. And there may be
   212   // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN
   213   // tasks. Deleting those tasks before the previous one has completed could
   214   // cause nondeterministic crashes because the task could be keeping some
   215   // objects alive which do work in their destructor, which could voilate the
   216   // assumptions of the running task.
   217   //
   218   // The task will be guaranteed to run to completion before shutdown
   219   // (BLOCK_SHUTDOWN semantics).
   220   //
   221   // Returns true if the task was posted successfully. This may fail during
   222   // shutdown regardless of the specified ShutdownBehavior.
   223   bool PostWorkerTask(const tracked_objects::Location& from_here,
   224                       const Closure& task);
   226   // Same as PostWorkerTask but allows a delay to be specified (although doing
   227   // so changes the shutdown behavior). The task will be run after the given
   228   // delay has elapsed.
   229   //
   230   // If the delay is nonzero, the task won't be guaranteed to run to completion
   231   // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
   232   // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the
   233   // task will be guaranteed to run to completion before shutdown
   234   // (BLOCK_SHUTDOWN semantics).
   235   bool PostDelayedWorkerTask(const tracked_objects::Location& from_here,
   236                              const Closure& task,
   237                              TimeDelta delay);
   239   // Same as PostWorkerTask but allows specification of the shutdown behavior.
   240   bool PostWorkerTaskWithShutdownBehavior(
   241       const tracked_objects::Location& from_here,
   242       const Closure& task,
   243       WorkerShutdown shutdown_behavior);
   245   // Like PostWorkerTask above, but provides sequencing semantics. This means
   246   // that tasks posted with the same sequence token (see GetSequenceToken())
   247   // are guaranteed to execute in order. This is useful in cases where you're
   248   // doing operations that may depend on previous ones, like appending to a
   249   // file.
   250   //
   251   // The task will be guaranteed to run to completion before shutdown
   252   // (BLOCK_SHUTDOWN semantics).
   253   //
   254   // Returns true if the task was posted successfully. This may fail during
   255   // shutdown regardless of the specified ShutdownBehavior.
   256   bool PostSequencedWorkerTask(SequenceToken sequence_token,
   257                                const tracked_objects::Location& from_here,
   258                                const Closure& task);
   260   // Like PostSequencedWorkerTask above, but allows you to specify a named
   261   // token, which saves an extra call to GetNamedSequenceToken.
   262   bool PostNamedSequencedWorkerTask(const std::string& token_name,
   263                                     const tracked_objects::Location& from_here,
   264                                     const Closure& task);
   266   // Same as PostSequencedWorkerTask but allows a delay to be specified
   267   // (although doing so changes the shutdown behavior). The task will be run
   268   // after the given delay has elapsed.
   269   //
   270   // If the delay is nonzero, the task won't be guaranteed to run to completion
   271   // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
   272   // If the delay is zero, this behaves exactly like PostSequencedWorkerTask,
   273   // i.e. the task will be guaranteed to run to completion before shutdown
   274   // (BLOCK_SHUTDOWN semantics).
   275   bool PostDelayedSequencedWorkerTask(
   276       SequenceToken sequence_token,
   277       const tracked_objects::Location& from_here,
   278       const Closure& task,
   279       TimeDelta delay);
   281   // Same as PostSequencedWorkerTask but allows specification of the shutdown
   282   // behavior.
   283   bool PostSequencedWorkerTaskWithShutdownBehavior(
   284       SequenceToken sequence_token,
   285       const tracked_objects::Location& from_here,
   286       const Closure& task,
   287       WorkerShutdown shutdown_behavior);
   289   // TaskRunner implementation. Forwards to PostDelayedWorkerTask().
   290   virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
   291                                const Closure& task,
   292                                TimeDelta delay) OVERRIDE;
   293   virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
   295   // Returns true if the current thread is processing a task with the given
   296   // sequence_token.
   297   bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
   299   // Blocks until all pending tasks are complete. This should only be called in
   300   // unit tests when you want to validate something that should have happened.
   301   // This will not flush delayed tasks; delayed tasks get deleted.
   302   //
   303   // Note that calling this will not prevent other threads from posting work to
   304   // the queue while the calling thread is waiting on Flush(). In this case,
   305   // Flush will return only when there's no more work in the queue. Normally,
   306   // this doesn't come up since in a test, all the work is being posted from
   307   // the main thread.
   308   void FlushForTesting();
   310   // Spuriously signal that there is work to be done.
   311   void SignalHasWorkForTesting();
   313   // Implements the worker pool shutdown. This should be called during app
   314   // shutdown, and will discard/join with appropriate tasks before returning.
   315   // After this call, subsequent calls to post tasks will fail.
   316   //
   317   // Must be called from the same thread this object was constructed on.
   318   void Shutdown() { Shutdown(0); }
   320   // A variant that allows an arbitrary number of new blocking tasks to
   321   // be posted during shutdown from within tasks that execute during shutdown.
   322   // Only tasks designated as BLOCKING_SHUTDOWN will be allowed, and only if
   323   // posted by tasks that are not designated as CONTINUE_ON_SHUTDOWN. Once
   324   // the limit is reached, subsequent calls to post task fail in all cases.
   325   //
   326   // Must be called from the same thread this object was constructed on.
   327   void Shutdown(int max_new_blocking_tasks_after_shutdown);
   329   // Check if Shutdown was called for given threading pool. This method is used
   330   // for aborting time consuming operation to avoid blocking shutdown.
   331   //
   332   // Can be called from any thread.
   333   bool IsShutdownInProgress();
   335  protected:
   336   virtual ~SequencedWorkerPool();
   338   virtual void OnDestruct() const OVERRIDE;
   340  private:
   341   friend class RefCountedThreadSafe<SequencedWorkerPool>;
   342   friend class DeleteHelper<SequencedWorkerPool>;
   344   class Inner;
   345   class Worker;
   347   const scoped_refptr<MessageLoopProxy> constructor_message_loop_;
   349   // Avoid pulling in too many headers by putting (almost) everything
   350   // into |inner_|.
   351   const scoped_ptr<Inner> inner_;
   353   DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
   354 };
   356 }  // namespace base
   358 #endif  // BASE_THREADING_SEQUENCED_WORKER_POOL_H_

mercurial