• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2005, 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 
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 Thread *CurrentThread();
56   static void SetCurrent(Thread *thread);
57   void Add(Thread *thread);
58   void Remove(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   static Thread *WrapCurrentThread();
74   static void UnwrapCurrentThread();
75 
76   static void StopAllThreads_();  // Experimental
77 
78 private:
79   Thread *main_thread_;
80   std::vector<Thread *> threads_;
81   CriticalSection crit_;
82 
83 #ifdef POSIX
84   static pthread_key_t key_;
85 #endif
86 
87 #ifdef WIN32
88   static DWORD key_;
89 #endif
90 };
91 
92 class Thread;
93 
94 struct _SendMessage {
_SendMessage_SendMessage95   _SendMessage() {}
96   Thread *thread;
97   Message msg;
98   bool *ready;
99 };
100 
101 enum ThreadPriority {
102   PRIORITY_HIGH,
103   PRIORITY_ABOVE_NORMAL,
104   PRIORITY_NORMAL,
105   PRIORITY_IDLE,
106 };
107 
108 class Runnable {
109  public:
~Runnable()110   virtual ~Runnable() {}
111   virtual void Run(Thread* thread) = 0;
112 };
113 
114 class Thread : public MessageQueue {
115 public:
116   Thread(SocketServer* ss = NULL);
117   virtual ~Thread();
118 
Current()119   static inline Thread* Current() {
120     return ThreadManager::CurrentThread();
121   }
122 
IsCurrent()123   bool IsCurrent() const {
124     return (ThreadManager::CurrentThread() == this);
125   }
126 
127   // Sleeps the calling thread for the specified number of milliseconds, during
128   // which time no processing is performed. Returns false if sleeping was
129   // interrupted by a signal (POSIX only).
130   static bool SleepMs(int millis);
131 
132   // Sets the thread's name, for debugging. Must be called before Start().
133   // If |obj| is non-NULL, its value is appended to |name|.
name()134   const std::string& name() const { return name_; }
135   bool SetName(const std::string& name, const void* obj);
136 
137   // Sets the thread's priority. Must be called before Start().
priority()138   ThreadPriority priority() const { return priority_; }
139   bool SetPriority(ThreadPriority priority);
140 
141   // Starts the execution of the thread.
started()142   bool started() const { return started_; }
143   bool Start(Runnable* runnable = NULL);
144 
145   // Tells the thread to stop and waits until it is joined.
146   // Never call Stop on the current thread.  Instead use the inherited Quit
147   // function which will exit the base MessageQueue without terminating the
148   // underlying OS thread.
149   virtual void Stop();
150 
151   // By default, Thread::Run() calls ProcessMessages(kForever).  To do other
152   // work, override Run().  To receive and dispatch messages, call
153   // ProcessMessages occasionally.
154   virtual void Run();
155 
156   virtual void Send(MessageHandler *phandler, uint32 id = 0,
157       MessageData *pdata = NULL);
158 
159   // From MessageQueue
160   virtual void Clear(MessageHandler *phandler, uint32 id = MQID_ANY,
161                      MessageList* removed = NULL);
162   virtual void ReceiveSends();
163 
164   // ProcessMessages will process I/O and dispatch messages until:
165   //  1) cms milliseconds have elapsed (returns true)
166   //  2) Stop() is called (returns false)
167   bool ProcessMessages(int cms);
168 
169   // Returns true if this is a thread that we created using the standard
170   // constructor, false if it was created by a call to
171   // ThreadManager::WrapCurrentThread().  The main thread of an application
172   // is generally not owned, since the OS representation of the thread
173   // obviously exists before we can get to it.
174   // You cannot call Start on non-owned threads.
175   bool IsOwned();
176 
177 #ifdef WIN32
GetHandle()178   HANDLE GetHandle() {
179     return thread_;
180   }
181 #elif POSIX
GetPThread()182   pthread_t GetPThread() {
183     return thread_;
184   }
185 #endif
186 
187 private:
188   static void *PreRun(void *pv);
189   // Blocks the calling thread until this thread has terminated.
190   void Join();
191 
192   std::list<_SendMessage> sendlist_;
193   std::string name_;
194   ThreadPriority priority_;
195   bool started_;
196   bool has_sends_;
197 
198 #ifdef POSIX
199   pthread_t thread_;
200 #endif
201 
202 #ifdef WIN32
203   HANDLE thread_;
204 #endif
205 
206   bool owned_;
207 
208   friend class ThreadManager;
209 };
210 
211 // AutoThread automatically installs itself at construction
212 // uninstalls at destruction, if a Thread object is
213 // _not already_ associated with the current OS thread.
214 
215 class AutoThread : public Thread {
216 public:
217   AutoThread(SocketServer* ss = 0);
218   virtual ~AutoThread();
219 };
220 
221 // Win32 extension for threads that need to use COM
222 #ifdef WIN32
223 class ComThread : public Thread {
224  protected:
225   virtual void Run();
226 };
227 #endif
228 
229 // Provides an easy way to install/uninstall a socketserver on a thread.
230 class SocketServerScope {
231  public:
SocketServerScope(SocketServer * ss)232   explicit SocketServerScope(SocketServer* ss) {
233     old_ss_ = Thread::Current()->socketserver();
234     Thread::Current()->set_socketserver(ss);
235   }
~SocketServerScope()236   ~SocketServerScope() {
237     Thread::Current()->set_socketserver(old_ss_);
238   }
239  private:
240   SocketServer* old_ss_;
241 };
242 
243 }  // namespace talk_base
244 
245 #endif  // TALK_BASE_THREAD_H_
246