]> git.saurik.com Git - wxWidgets.git/blob - src/motif/thread.cpp
96d7af417a3904bcd5958de6dc7be953ec9a08f8
[wxWidgets.git] / src / motif / thread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: thread.cpp
3 // Purpose: wxThread Implementation for Posix threads
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux
5 // Modified by: Robert Roebling
6 // Created: 04/22/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "thread.h"
14 #endif
15
16 #include "wx/defs.h"
17
18 #if wxUSE_THREADS
19
20 #include "wx/module.h"
21 #include "wx/thread.h"
22 #include "wx/utils.h"
23 #include "wx/log.h"
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <pthread.h>
28 #include <errno.h>
29
30 #include <stdio.h>
31 #include <unistd.h>
32
33 // for select()
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #ifdef __sgi
37 #include <bstring.h>
38 #endif
39
40 //--------------------------------------------------------------------
41 // constants
42 //--------------------------------------------------------------------
43
44 enum thread_state
45 {
46 STATE_IDLE = 0,
47 STATE_RUNNING,
48 STATE_PAUSING,
49 STATE_PAUSED,
50 STATE_CANCELED,
51 STATE_EXITED
52 };
53
54 //--------------------------------------------------------------------
55 // global data
56 //--------------------------------------------------------------------
57
58 static pthread_t p_mainid;
59
60 wxMutex *wxMainMutex = (wxMutex*) NULL; /* controls access to all GUI functions */
61
62 /* TODO for Xt */
63
64 static int p_thrd_pipe[2] = { -1, -1 };
65
66 //-------------------------------------------------------------------------
67 // global functions
68 //-------------------------------------------------------------------------
69
70 static void wxThreadGuiInit()
71 {
72 /* TODO for Xt */
73 }
74
75 static void wxThreadGuiExit()
76 {
77 /* TODO for Xt */
78 }
79
80 void wxMutexGuiEnter()
81 {
82 if (wxMainMutex)
83 wxMainMutex->Lock();
84 }
85
86 void wxMutexGuiLeave()
87 {
88 if (wxMainMutex)
89 wxMainMutex->Unlock();
90 }
91
92 //--------------------------------------------------------------------
93 // wxMutex (Posix implementation)
94 //--------------------------------------------------------------------
95
96 class wxMutexInternal
97 {
98 public:
99 pthread_mutex_t p_mutex;
100 };
101
102 wxMutex::wxMutex()
103 {
104 p_internal = new wxMutexInternal;
105 pthread_mutex_init(&(p_internal->p_mutex), NULL);
106 m_locked = 0;
107 }
108
109 wxMutex::~wxMutex()
110 {
111 if (m_locked > 0)
112 wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked );
113
114 pthread_mutex_destroy(&(p_internal->p_mutex));
115 delete p_internal;
116 }
117
118 wxMutexError wxMutex::Lock()
119 {
120 int err;
121
122 err = pthread_mutex_lock(&(p_internal->p_mutex));
123 if (err == EDEADLK)
124 return wxMUTEX_DEAD_LOCK;
125
126 m_locked++;
127 return wxMUTEX_NO_ERROR;
128 }
129
130 wxMutexError wxMutex::TryLock()
131 {
132 int err;
133
134 if (m_locked)
135 return wxMUTEX_BUSY;
136
137 err = pthread_mutex_trylock(&(p_internal->p_mutex));
138 switch (err)
139 {
140 case EBUSY: return wxMUTEX_BUSY;
141 }
142 m_locked++;
143 return wxMUTEX_NO_ERROR;
144 }
145
146 wxMutexError wxMutex::Unlock()
147 {
148 if (m_locked > 0)
149 m_locked--;
150 else
151 return wxMUTEX_UNLOCKED;
152
153 pthread_mutex_unlock(&(p_internal->p_mutex));
154 return wxMUTEX_NO_ERROR;
155 }
156
157 //--------------------------------------------------------------------
158 // wxCondition (Posix implementation)
159 //--------------------------------------------------------------------
160
161 class wxConditionInternal
162 {
163 public:
164 pthread_cond_t p_condition;
165 };
166
167 wxCondition::wxCondition()
168 {
169 p_internal = new wxConditionInternal;
170 pthread_cond_init(&(p_internal->p_condition), NULL);
171 }
172
173 wxCondition::~wxCondition()
174 {
175 pthread_cond_destroy(&(p_internal->p_condition));
176 delete p_internal;
177 }
178
179 void wxCondition::Wait(wxMutex& mutex)
180 {
181 pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
182 }
183
184 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
185 {
186 struct timespec tspec;
187
188 tspec.tv_sec = time(NULL)+sec;
189 tspec.tv_nsec = nsec;
190 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
191 }
192
193 void wxCondition::Signal()
194 {
195 pthread_cond_signal(&(p_internal->p_condition));
196 }
197
198 void wxCondition::Broadcast()
199 {
200 pthread_cond_broadcast(&(p_internal->p_condition));
201 }
202
203 //--------------------------------------------------------------------
204 // wxThread (Posix implementation)
205 //--------------------------------------------------------------------
206
207 class wxThreadInternal
208 {
209 public:
210 wxThreadInternal() { state = STATE_IDLE; }
211 ~wxThreadInternal() {}
212 static void *PthreadStart(void *ptr);
213 pthread_t thread_id;
214 int state;
215 int prio;
216 int defer_destroy;
217 };
218
219 void *wxThreadInternal::PthreadStart(void *ptr)
220 {
221 wxThread *thread = (wxThread *)ptr;
222
223 // Call the main entry
224 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
225 void* status = thread->Entry();
226
227 thread->Exit(status);
228
229 return NULL;
230 }
231
232 wxThreadError wxThread::Create()
233 {
234 pthread_attr_t a;
235 int min_prio, max_prio, p;
236 struct sched_param sp;
237
238 if (p_internal->state != STATE_IDLE)
239 return wxTHREAD_RUNNING;
240
241 // Change thread priority
242 pthread_attr_init(&a);
243 pthread_attr_getschedpolicy(&a, &p);
244
245 min_prio = sched_get_priority_min(p);
246 max_prio = sched_get_priority_max(p);
247
248 pthread_attr_getschedparam(&a, &sp);
249 sp.sched_priority = min_prio +
250 (p_internal->prio*(max_prio-min_prio))/100;
251 pthread_attr_setschedparam(&a, &sp);
252
253 // this is the point of no return
254 p_internal->state = STATE_RUNNING;
255 if (pthread_create(&p_internal->thread_id, &a,
256 wxThreadInternal::PthreadStart, (void *)this) != 0)
257 {
258 p_internal->state = STATE_IDLE;
259 pthread_attr_destroy(&a);
260 return wxTHREAD_NO_RESOURCE;
261 }
262 pthread_attr_destroy(&a);
263
264 return wxTHREAD_NO_ERROR;
265 }
266
267 void wxThread::SetPriority(int prio)
268 {
269 if (p_internal->state == STATE_RUNNING)
270 return;
271
272 if (prio > 100) prio = 100;
273
274 if (prio < 0) prio = 0;
275
276 p_internal->prio = prio;
277 }
278
279 int wxThread::GetPriority() const
280 {
281 return p_internal->prio;
282 }
283
284 void wxThread::DeferDestroy(bool on)
285 {
286 if (on)
287 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
288 else
289 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
290 }
291
292 wxThreadError wxThread::Destroy()
293 {
294 int res = 0;
295
296 if (p_internal->state == STATE_RUNNING)
297 {
298 res = pthread_cancel(p_internal->thread_id);
299 if (res == 0)
300 p_internal->state = STATE_CANCELED;
301 }
302
303 return wxTHREAD_NO_ERROR;
304 }
305
306 wxThreadError wxThread::Pause()
307 {
308 if (p_internal->state != STATE_RUNNING)
309 return wxTHREAD_NOT_RUNNING;
310
311 if (!p_internal->defer_destroy)
312 return wxTHREAD_MISC_ERROR;
313
314 p_internal->state = STATE_PAUSING;
315 return wxTHREAD_NO_ERROR;
316 }
317
318 wxThreadError wxThread::Resume()
319 {
320 if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED)
321 p_internal->state = STATE_RUNNING;
322
323 return wxTHREAD_NO_ERROR;
324 }
325
326 void *wxThread::Join()
327 {
328 void* status = 0;
329
330 if (p_internal->state != STATE_IDLE)
331 {
332 bool do_unlock = wxThread::IsMain();
333
334 while (p_internal->state == STATE_RUNNING)
335 wxYield();
336
337 if (do_unlock) wxMainMutex->Unlock();
338
339 pthread_join(p_internal->thread_id, &status);
340
341 if (do_unlock) wxMainMutex->Lock();
342
343 p_internal->state = STATE_IDLE;
344 }
345
346 return status;
347 }
348
349 unsigned long wxThread::GetID() const
350 {
351 return p_internal->thread_id;
352 }
353
354 void wxThread::Exit(void *status)
355 {
356 wxThread* ptr = this;
357
358 /* THREAD_SEND_EXIT_MSG(ptr); TODO for Xt */
359
360 p_internal->state = STATE_EXITED;
361 pthread_exit(status);
362 }
363
364 void wxThread::TestDestroy()
365 {
366 if (p_internal->state == STATE_PAUSING)
367 {
368 p_internal->state = STATE_PAUSED;
369 while (p_internal->state == STATE_PAUSED)
370 {
371 pthread_testcancel();
372 usleep(1);
373 }
374 }
375 pthread_testcancel();
376 }
377
378 bool wxThread::IsMain()
379 {
380 return (bool)pthread_equal(pthread_self(), p_mainid);
381 }
382
383 bool wxThread::IsRunning() const
384 {
385 return (p_internal->state == STATE_RUNNING);
386 }
387
388 bool wxThread::IsAlive() const
389 {
390 return (p_internal->state == STATE_RUNNING) ||
391 (p_internal->state == STATE_PAUSING) ||
392 (p_internal->state == STATE_PAUSED);
393 }
394
395 wxThread::wxThread()
396 {
397 p_internal = new wxThreadInternal();
398 }
399
400 wxThread::~wxThread()
401 {
402 Destroy();
403 Join();
404 delete p_internal;
405 }
406
407 // The default callback just joins the thread and throws away the result.
408 void wxThread::OnExit()
409 {
410 Join();
411 }
412
413 //--------------------------------------------------------------------
414 // wxThreadModule
415 //--------------------------------------------------------------------
416
417 class wxThreadModule : public wxModule
418 {
419 public:
420 virtual bool OnInit();
421 virtual void OnExit();
422
423 private:
424 DECLARE_DYNAMIC_CLASS(wxThreadModule)
425 };
426
427 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
428
429 bool wxThreadModule::OnInit()
430 {
431 wxMainMutex = new wxMutex();
432 wxThreadGuiInit();
433 p_mainid = pthread_self();
434 wxMainMutex->Lock();
435
436 return TRUE;
437 }
438
439 void wxThreadModule::OnExit()
440 {
441 wxMainMutex->Unlock();
442 wxThreadGuiExit();
443 delete wxMainMutex;
444 };
445
446 #endif
447 // wxUSE_THREADS