michael@0: // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef BASE_THREAD_H_ michael@0: #define BASE_THREAD_H_ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "base/message_loop.h" michael@0: #include "base/platform_thread.h" michael@0: michael@0: namespace base { michael@0: michael@0: // A simple thread abstraction that establishes a MessageLoop on a new thread. michael@0: // The consumer uses the MessageLoop of the thread to cause code to execute on michael@0: // the thread. When this object is destroyed the thread is terminated. All michael@0: // pending tasks queued on the thread's message loop will run to completion michael@0: // before the thread is terminated. michael@0: class Thread : PlatformThread::Delegate { michael@0: public: michael@0: struct Options { michael@0: // Specifies the type of message loop that will be allocated on the thread. michael@0: MessageLoop::Type message_loop_type; michael@0: michael@0: // Specifies the maximum stack size that the thread is allowed to use. michael@0: // This does not necessarily correspond to the thread's initial stack size. michael@0: // A value of 0 indicates that the default maximum should be used. michael@0: size_t stack_size; michael@0: michael@0: // Specifies the transient and permanent hang timeouts for background hang michael@0: // monitoring. A value of 0 indicates there is no timeout. michael@0: uint32_t transient_hang_timeout; michael@0: uint32_t permanent_hang_timeout; michael@0: michael@0: Options() michael@0: : message_loop_type(MessageLoop::TYPE_DEFAULT) michael@0: , stack_size(0) michael@0: , transient_hang_timeout(0) michael@0: , permanent_hang_timeout(0) {} michael@0: Options(MessageLoop::Type type, size_t size) michael@0: : message_loop_type(type) michael@0: , stack_size(size) michael@0: , transient_hang_timeout(0) michael@0: , permanent_hang_timeout(0) {} michael@0: }; michael@0: michael@0: // Constructor. michael@0: // name is a display string to identify the thread. michael@0: explicit Thread(const char *name); michael@0: michael@0: // Destroys the thread, stopping it if necessary. michael@0: // michael@0: // NOTE: If you are subclassing from Thread, and you wish for your CleanUp michael@0: // method to be called, then you need to call Stop() from your destructor. michael@0: // michael@0: virtual ~Thread(); michael@0: michael@0: // Starts the thread. Returns true if the thread was successfully started; michael@0: // otherwise, returns false. Upon successful return, the message_loop() michael@0: // getter will return non-null. michael@0: // michael@0: // Note: This function can't be called on Windows with the loader lock held; michael@0: // i.e. during a DllMain, global object construction or destruction, atexit() michael@0: // callback. michael@0: bool Start(); michael@0: michael@0: // Starts the thread. Behaves exactly like Start in addition to allow to michael@0: // override the default options. michael@0: // michael@0: // Note: This function can't be called on Windows with the loader lock held; michael@0: // i.e. during a DllMain, global object construction or destruction, atexit() michael@0: // callback. michael@0: bool StartWithOptions(const Options& options); michael@0: michael@0: // Signals the thread to exit and returns once the thread has exited. After michael@0: // this method returns, the Thread object is completely reset and may be used michael@0: // as if it were newly constructed (i.e., Start may be called again). michael@0: // michael@0: // Stop may be called multiple times and is simply ignored if the thread is michael@0: // already stopped. michael@0: // michael@0: // NOTE: This method is optional. It is not strictly necessary to call this michael@0: // method as the Thread's destructor will take care of stopping the thread if michael@0: // necessary. michael@0: // michael@0: void Stop(); michael@0: michael@0: // Signals the thread to exit in the near future. michael@0: // michael@0: // WARNING: This function is not meant to be commonly used. Use at your own michael@0: // risk. Calling this function will cause message_loop() to become invalid in michael@0: // the near future. This function was created to workaround a specific michael@0: // deadlock on Windows with printer worker thread. In any other case, Stop() michael@0: // should be used. michael@0: // michael@0: // StopSoon should not be called multiple times as it is risky to do so. It michael@0: // could cause a timing issue in message_loop() access. Call Stop() to reset michael@0: // the thread object once it is known that the thread has quit. michael@0: void StopSoon(); michael@0: michael@0: // Returns the message loop for this thread. Use the MessageLoop's michael@0: // PostTask methods to execute code on the thread. This only returns michael@0: // non-null after a successful call to Start. After Stop has been called, michael@0: // this will return NULL. michael@0: // michael@0: // NOTE: You must not call this MessageLoop's Quit method directly. Use michael@0: // the Thread's Stop method instead. michael@0: // michael@0: MessageLoop* message_loop() const { return message_loop_; } michael@0: michael@0: // Set the name of this thread (for display in debugger too). michael@0: const std::string &thread_name() { return name_; } michael@0: michael@0: // The native thread handle. michael@0: PlatformThreadHandle thread_handle() { return thread_; } michael@0: michael@0: // The thread ID. michael@0: PlatformThreadId thread_id() const { return thread_id_; } michael@0: michael@0: // Reset thread ID as current thread. michael@0: PlatformThreadId reset_thread_id() { michael@0: thread_id_ = PlatformThread::CurrentId(); michael@0: return thread_id_; michael@0: } michael@0: michael@0: // Returns true if the thread has been started, and not yet stopped. michael@0: // When a thread is running, the thread_id_ is non-zero. michael@0: bool IsRunning() const { return thread_id_ != 0; } michael@0: michael@0: protected: michael@0: // Called just prior to starting the message loop michael@0: virtual void Init() {} michael@0: michael@0: // Called just after the message loop ends michael@0: virtual void CleanUp() {} michael@0: michael@0: static void SetThreadWasQuitProperly(bool flag); michael@0: static bool GetThreadWasQuitProperly(); michael@0: michael@0: private: michael@0: // PlatformThread::Delegate methods: michael@0: virtual void ThreadMain(); michael@0: michael@0: // We piggy-back on the startup_data_ member to know if we successfully michael@0: // started the thread. This way we know that we need to call Join. michael@0: bool thread_was_started() const { return startup_data_ != NULL; } michael@0: michael@0: // Used to pass data to ThreadMain. michael@0: struct StartupData; michael@0: StartupData* startup_data_; michael@0: michael@0: // The thread's handle. michael@0: PlatformThreadHandle thread_; michael@0: michael@0: // The thread's message loop. Valid only while the thread is alive. Set michael@0: // by the created thread. michael@0: MessageLoop* message_loop_; michael@0: michael@0: // Our thread's ID. michael@0: PlatformThreadId thread_id_; michael@0: michael@0: // The name of the thread. Used for debugging purposes. michael@0: std::string name_; michael@0: michael@0: friend class ThreadQuitTask; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(Thread); michael@0: }; michael@0: michael@0: } // namespace base michael@0: michael@0: #endif // BASE_THREAD_H_