ipc/chromium/src/base/simple_thread.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.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 // WARNING: You should probably be using Thread (thread.h) instead. Thread is
michael@0 6 // Chrome's message-loop based Thread abstraction, and if you are a
michael@0 7 // thread running in the browser, there will likely be assumptions
michael@0 8 // that your thread will have an associated message loop.
michael@0 9 //
michael@0 10 // This is a simple thread interface that backs to a native operating system
michael@0 11 // thread. You should use this only when you want a thread that does not have
michael@0 12 // an associated MessageLoop. Unittesting is the best example of this.
michael@0 13 //
michael@0 14 // The simplest interface to use is DelegateSimpleThread, which will create
michael@0 15 // a new thread, and execute the Delegate's virtual Run() in this new thread
michael@0 16 // until it has completed, exiting the thread.
michael@0 17 //
michael@0 18 // NOTE: You *MUST* call Join on the thread to clean up the underlying thread
michael@0 19 // resources. You are also responsible for destructing the SimpleThread object.
michael@0 20 // It is invalid to destroy a SimpleThread while it is running, or without
michael@0 21 // Start() having been called (and a thread never created). The Delegate
michael@0 22 // object should live as long as a DelegateSimpleThread.
michael@0 23 //
michael@0 24 // Thread Safety: A SimpleThread is not completely thread safe. It is safe to
michael@0 25 // access it from the creating thread or from the newly created thread. This
michael@0 26 // implies that the creator thread should be the thread that calls Join.
michael@0 27 //
michael@0 28 // Example:
michael@0 29 // class MyThreadRunner : public DelegateSimpleThread::Delegate { ... };
michael@0 30 // MyThreadRunner runner;
michael@0 31 // DelegateSimpleThread thread(&runner, "good_name_here");
michael@0 32 // thread.Start();
michael@0 33 // // Start will return after the Thread has been successfully started and
michael@0 34 // // initialized. The newly created thread will invoke runner->Run(), and
michael@0 35 // // run until it returns.
michael@0 36 // thread.Join(); // Wait until the thread has exited. You *MUST* Join!
michael@0 37 // // The SimpleThread object is still valid, however you may not call Join
michael@0 38 // // or Start again.
michael@0 39
michael@0 40 #ifndef BASE_SIMPLE_THREAD_H_
michael@0 41 #define BASE_SIMPLE_THREAD_H_
michael@0 42
michael@0 43 #include <string>
michael@0 44 #include <queue>
michael@0 45 #include <vector>
michael@0 46
michael@0 47 #include "base/basictypes.h"
michael@0 48 #include "base/lock.h"
michael@0 49 #include "base/waitable_event.h"
michael@0 50 #include "base/platform_thread.h"
michael@0 51
michael@0 52 namespace base {
michael@0 53
michael@0 54 // This is the base SimpleThread. You can derive from it and implement the
michael@0 55 // virtual Run method, or you can use the DelegateSimpleThread interface.
michael@0 56 class SimpleThread : public PlatformThread::Delegate {
michael@0 57 public:
michael@0 58 class Options {
michael@0 59 public:
michael@0 60 Options() : stack_size_(0) { }
michael@0 61 ~Options() { }
michael@0 62
michael@0 63 // We use the standard compiler-supplied copy constructor.
michael@0 64
michael@0 65 // A custom stack size, or 0 for the system default.
michael@0 66 void set_stack_size(size_t size) { stack_size_ = size; }
michael@0 67 size_t stack_size() const { return stack_size_; }
michael@0 68 private:
michael@0 69 size_t stack_size_;
michael@0 70 };
michael@0 71
michael@0 72 // Create a SimpleThread. |options| should be used to manage any specific
michael@0 73 // configuration involving the thread creation and management.
michael@0 74 // Every thread has a name, in the form of |name_prefix|/TID, for example
michael@0 75 // "my_thread/321". The thread will not be created until Start() is called.
michael@0 76 explicit SimpleThread(const std::string& name_prefix)
michael@0 77 : name_prefix_(name_prefix), name_(name_prefix),
michael@0 78 thread_(), event_(true, false), tid_(0), joined_(false) { }
michael@0 79 SimpleThread(const std::string& name_prefix, const Options& options)
michael@0 80 : name_prefix_(name_prefix), name_(name_prefix), options_(options),
michael@0 81 thread_(), event_(true, false), tid_(0), joined_(false) { }
michael@0 82
michael@0 83 virtual ~SimpleThread();
michael@0 84
michael@0 85 virtual void Start();
michael@0 86 virtual void Join();
michael@0 87
michael@0 88 // We follow the PlatformThread Delegate interface.
michael@0 89 virtual void ThreadMain();
michael@0 90
michael@0 91 // Subclasses should override the Run method.
michael@0 92 virtual void Run() = 0;
michael@0 93
michael@0 94 // Return the thread name prefix, or "unnamed" if none was supplied.
michael@0 95 std::string name_prefix() { return name_prefix_; }
michael@0 96
michael@0 97 // Return the completed name including TID, only valid after Start().
michael@0 98 std::string name() { return name_; }
michael@0 99
michael@0 100 // Return the thread id, only valid after Start().
michael@0 101 PlatformThreadId tid() { return tid_; }
michael@0 102
michael@0 103 // Return True if Start() has ever been called.
michael@0 104 bool HasBeenStarted() { return event_.IsSignaled(); }
michael@0 105
michael@0 106 // Return True if Join() has evern been called.
michael@0 107 bool HasBeenJoined() { return joined_; }
michael@0 108
michael@0 109 private:
michael@0 110 const std::string name_prefix_;
michael@0 111 std::string name_;
michael@0 112 const Options options_;
michael@0 113 PlatformThreadHandle thread_; // PlatformThread handle, invalid after Join!
michael@0 114 WaitableEvent event_; // Signaled if Start() was ever called.
michael@0 115 PlatformThreadId tid_; // The backing thread's id.
michael@0 116 bool joined_; // True if Join has been called.
michael@0 117 };
michael@0 118
michael@0 119 class DelegateSimpleThread : public SimpleThread {
michael@0 120 public:
michael@0 121 class Delegate {
michael@0 122 public:
michael@0 123 Delegate() { }
michael@0 124 virtual ~Delegate() { }
michael@0 125 virtual void Run() = 0;
michael@0 126 };
michael@0 127
michael@0 128 DelegateSimpleThread(Delegate* delegate,
michael@0 129 const std::string& name_prefix)
michael@0 130 : SimpleThread(name_prefix), delegate_(delegate) { }
michael@0 131 DelegateSimpleThread(Delegate* delegate,
michael@0 132 const std::string& name_prefix,
michael@0 133 const Options& options)
michael@0 134 : SimpleThread(name_prefix, options), delegate_(delegate) { }
michael@0 135
michael@0 136 virtual ~DelegateSimpleThread() { }
michael@0 137 virtual void Run();
michael@0 138 private:
michael@0 139 Delegate* delegate_;
michael@0 140 };
michael@0 141
michael@0 142 // DelegateSimpleThreadPool allows you to start up a fixed number of threads,
michael@0 143 // and then add jobs which will be dispatched to the threads. This is
michael@0 144 // convenient when you have a lot of small work that you want done
michael@0 145 // multi-threaded, but don't want to spawn a thread for each small bit of work.
michael@0 146 //
michael@0 147 // You just call AddWork() to add a delegate to the list of work to be done.
michael@0 148 // JoinAll() will make sure that all outstanding work is processed, and wait
michael@0 149 // for everything to finish. You can reuse a pool, so you can call Start()
michael@0 150 // again after you've called JoinAll().
michael@0 151 class DelegateSimpleThreadPool : public DelegateSimpleThread::Delegate {
michael@0 152 public:
michael@0 153 typedef DelegateSimpleThread::Delegate Delegate;
michael@0 154
michael@0 155 DelegateSimpleThreadPool(const std::string name_prefix, int num_threads)
michael@0 156 : name_prefix_(name_prefix), num_threads_(num_threads),
michael@0 157 dry_(true, false) { }
michael@0 158 ~DelegateSimpleThreadPool();
michael@0 159
michael@0 160 // Start up all of the underlying threads, and start processing work if we
michael@0 161 // have any.
michael@0 162 void Start();
michael@0 163
michael@0 164 // Make sure all outstanding work is finished, and wait for and destroy all
michael@0 165 // of the underlying threads in the pool.
michael@0 166 void JoinAll();
michael@0 167
michael@0 168 // It is safe to AddWork() any time, before or after Start().
michael@0 169 // Delegate* should always be a valid pointer, NULL is reserved internally.
michael@0 170 void AddWork(Delegate* work, int repeat_count);
michael@0 171 void AddWork(Delegate* work) {
michael@0 172 AddWork(work, 1);
michael@0 173 }
michael@0 174
michael@0 175 // We implement the Delegate interface, for running our internal threads.
michael@0 176 virtual void Run();
michael@0 177
michael@0 178 private:
michael@0 179 const std::string name_prefix_;
michael@0 180 int num_threads_;
michael@0 181 std::vector<DelegateSimpleThread*> threads_;
michael@0 182 std::queue<Delegate*> delegates_;
michael@0 183 Lock lock_; // Locks delegates_
michael@0 184 WaitableEvent dry_; // Not signaled when there is no work to do.
michael@0 185 };
michael@0 186
michael@0 187 } // namespace base
michael@0 188
michael@0 189 #endif // BASE_SIMPLE_THREAD_H_

mercurial