Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004 Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #ifndef TALK_BASE_THREAD_H_
     29 #define TALK_BASE_THREAD_H_
     30 
     31 #include <algorithm>
     32 #include <list>
     33 #include <string>
     34 #include <vector>
     35 
     36 #ifdef POSIX
     37 #include <pthread.h>
     38 #endif
     39 #include "talk/base/constructormagic.h"
     40 #include "talk/base/messagequeue.h"
     41 
     42 #ifdef WIN32
     43 #include "talk/base/win32.h"
     44 #endif
     45 
     46 namespace talk_base {
     47 
     48 class Thread;
     49 
     50 class ThreadManager {
     51  public:
     52   ThreadManager();
     53   ~ThreadManager();
     54 
     55   static ThreadManager* Instance();
     56 
     57   Thread* CurrentThread();
     58   void SetCurrentThread(Thread* thread);
     59 
     60   // Returns a thread object with its thread_ ivar set
     61   // to whatever the OS uses to represent the thread.
     62   // If there already *is* a Thread object corresponding to this thread,
     63   // this method will return that.  Otherwise it creates a new Thread
     64   // object whose wrapped() method will return true, and whose
     65   // handle will, on Win32, be opened with only synchronization privileges -
     66   // if you need more privilegs, rather than changing this method, please
     67   // write additional code to adjust the privileges, or call a different
     68   // factory method of your own devising, because this one gets used in
     69   // unexpected contexts (like inside browser plugins) and it would be a
     70   // shame to break it.  It is also conceivable on Win32 that we won't even
     71   // be able to get synchronization privileges, in which case the result
     72   // will have a NULL handle.
     73   Thread *WrapCurrentThread();
     74   void UnwrapCurrentThread();
     75 
     76  private:
     77 #ifdef POSIX
     78   pthread_key_t key_;
     79 #endif
     80 
     81 #ifdef WIN32
     82   DWORD key_;
     83 #endif
     84 
     85   DISALLOW_COPY_AND_ASSIGN(ThreadManager);
     86 };
     87 
     88 struct _SendMessage {
     89   _SendMessage() {}
     90   Thread *thread;
     91   Message msg;
     92   bool *ready;
     93 };
     94 
     95 enum ThreadPriority {
     96   PRIORITY_IDLE = -1,
     97   PRIORITY_NORMAL = 0,
     98   PRIORITY_ABOVE_NORMAL = 1,
     99   PRIORITY_HIGH = 2,
    100 };
    101 
    102 class Runnable {
    103  public:
    104   virtual ~Runnable() {}
    105   virtual void Run(Thread* thread) = 0;
    106 
    107  protected:
    108   Runnable() {}
    109 
    110  private:
    111   DISALLOW_COPY_AND_ASSIGN(Runnable);
    112 };
    113 
    114 class Thread : public MessageQueue {
    115  public:
    116   explicit Thread(SocketServer* ss = NULL);
    117   virtual ~Thread();
    118 
    119   static Thread* Current();
    120 
    121   bool IsCurrent() const {
    122     return Current() == this;
    123   }
    124 
    125   // Sleeps the calling thread for the specified number of milliseconds, during
    126   // which time no processing is performed. Returns false if sleeping was
    127   // interrupted by a signal (POSIX only).
    128   static bool SleepMs(int millis);
    129 
    130   // Sets the thread's name, for debugging. Must be called before Start().
    131   // If |obj| is non-NULL, its value is appended to |name|.
    132   const std::string& name() const { return name_; }
    133   bool SetName(const std::string& name, const void* obj);
    134 
    135   // Sets the thread's priority. Must be called before Start().
    136   ThreadPriority priority() const { return priority_; }
    137   bool SetPriority(ThreadPriority priority);
    138 
    139   // Starts the execution of the thread.
    140   bool started() const { return started_; }
    141   bool Start(Runnable* runnable = NULL);
    142 
    143   // Used for fire-and-forget threads.  Deletes this thread object when the
    144   // Run method returns.
    145   void Release() {
    146     delete_self_when_complete_ = true;
    147   }
    148 
    149   // Tells the thread to stop and waits until it is joined.
    150   // Never call Stop on the current thread.  Instead use the inherited Quit
    151   // function which will exit the base MessageQueue without terminating the
    152   // underlying OS thread.
    153   virtual void Stop();
    154 
    155   // By default, Thread::Run() calls ProcessMessages(kForever).  To do other
    156   // work, override Run().  To receive and dispatch messages, call
    157   // ProcessMessages occasionally.
    158   virtual void Run();
    159 
    160   virtual void Send(MessageHandler *phandler, uint32 id = 0,
    161       MessageData *pdata = NULL);
    162 
    163   // Convenience method to invoke a functor on another thread.  Caller must
    164   // provide the |ReturnT| template argument, which cannot (easily) be deduced.
    165   // Uses Send() internally, which blocks the current thread until execution
    166   // is complete.
    167   // Ex: bool result = thread.Invoke<bool>(&MyFunctionReturningBool);
    168   template <class ReturnT, class FunctorT>
    169   ReturnT Invoke(const FunctorT& functor) {
    170     FunctorMessageHandler<ReturnT, FunctorT> handler(functor);
    171     Send(&handler);
    172     return handler.result();
    173   }
    174 
    175   // From MessageQueue
    176   virtual void Clear(MessageHandler *phandler, uint32 id = MQID_ANY,
    177                      MessageList* removed = NULL);
    178   virtual void ReceiveSends();
    179 
    180   // ProcessMessages will process I/O and dispatch messages until:
    181   //  1) cms milliseconds have elapsed (returns true)
    182   //  2) Stop() is called (returns false)
    183   bool ProcessMessages(int cms);
    184 
    185   // Returns true if this is a thread that we created using the standard
    186   // constructor, false if it was created by a call to
    187   // ThreadManager::WrapCurrentThread().  The main thread of an application
    188   // is generally not owned, since the OS representation of the thread
    189   // obviously exists before we can get to it.
    190   // You cannot call Start on non-owned threads.
    191   bool IsOwned();
    192 
    193 #ifdef WIN32
    194   HANDLE GetHandle() const {
    195     return thread_;
    196   }
    197   DWORD GetId() const {
    198     return thread_id_;
    199   }
    200 #elif POSIX
    201   pthread_t GetPThread() {
    202     return thread_;
    203   }
    204 #endif
    205 
    206   // This method should be called when thread is created using non standard
    207   // method, like derived implementation of talk_base::Thread and it can not be
    208   // started by calling Start(). This will set started flag to true and
    209   // owned to false. This must be called from the current thread.
    210   // NOTE: These methods should be used by the derived classes only, added here
    211   // only for testing.
    212   bool WrapCurrent();
    213   void UnwrapCurrent();
    214 
    215  protected:
    216   // Blocks the calling thread until this thread has terminated.
    217   void Join();
    218 
    219  private:
    220   // Helper class to facilitate executing a functor on a thread.
    221   template <class ReturnT, class FunctorT>
    222   class FunctorMessageHandler : public MessageHandler {
    223    public:
    224     explicit FunctorMessageHandler(const FunctorT& functor)
    225         : functor_(functor) {}
    226     virtual void OnMessage(Message* msg) {
    227       result_ = functor_();
    228     }
    229     const ReturnT& result() const { return result_; }
    230    private:
    231     FunctorT functor_;
    232     ReturnT result_;
    233   };
    234 
    235   // Specialization for ReturnT of void.
    236   template <class FunctorT>
    237   class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
    238    public:
    239     explicit FunctorMessageHandler(const FunctorT& functor)
    240         : functor_(functor) {}
    241     virtual void OnMessage(Message* msg) { functor_(); }
    242     void result() const {}
    243    private:
    244     FunctorT functor_;
    245   };
    246 
    247   static void *PreRun(void *pv);
    248 
    249   // ThreadManager calls this instead WrapCurrent() because
    250   // ThreadManager::Instance() cannot be used while ThreadManager is
    251   // being created.
    252   bool WrapCurrentWithThreadManager(ThreadManager* thread_manager);
    253 
    254   std::list<_SendMessage> sendlist_;
    255   std::string name_;
    256   ThreadPriority priority_;
    257   bool started_;
    258   bool has_sends_;
    259 
    260 #ifdef POSIX
    261   pthread_t thread_;
    262 #endif
    263 
    264 #ifdef WIN32
    265   HANDLE thread_;
    266   DWORD thread_id_;
    267 #endif
    268 
    269   bool owned_;
    270   bool delete_self_when_complete_;
    271 
    272   friend class ThreadManager;
    273 
    274   DISALLOW_COPY_AND_ASSIGN(Thread);
    275 };
    276 
    277 // AutoThread automatically installs itself at construction
    278 // uninstalls at destruction, if a Thread object is
    279 // _not already_ associated with the current OS thread.
    280 
    281 class AutoThread : public Thread {
    282  public:
    283   explicit AutoThread(SocketServer* ss = 0);
    284   virtual ~AutoThread();
    285 
    286  private:
    287   DISALLOW_COPY_AND_ASSIGN(AutoThread);
    288 };
    289 
    290 // Win32 extension for threads that need to use COM
    291 #ifdef WIN32
    292 class ComThread : public Thread {
    293  public:
    294   ComThread() {}
    295 
    296  protected:
    297   virtual void Run();
    298 
    299  private:
    300   DISALLOW_COPY_AND_ASSIGN(ComThread);
    301 };
    302 #endif
    303 
    304 // Provides an easy way to install/uninstall a socketserver on a thread.
    305 class SocketServerScope {
    306  public:
    307   explicit SocketServerScope(SocketServer* ss) {
    308     old_ss_ = Thread::Current()->socketserver();
    309     Thread::Current()->set_socketserver(ss);
    310   }
    311   ~SocketServerScope() {
    312     Thread::Current()->set_socketserver(old_ss_);
    313   }
    314 
    315  private:
    316   SocketServer* old_ss_;
    317 
    318   DISALLOW_IMPLICIT_CONSTRUCTORS(SocketServerScope);
    319 };
    320 
    321 }  // namespace talk_base
    322 
    323 #endif  // TALK_BASE_THREAD_H_
    324