]> git.saurik.com Git - wxWidgets.git/blame - src/motif/thread.cpp
OnExit() is called for modules which were initialized even if the init of
[wxWidgets.git] / src / motif / thread.cpp
CommitLineData
4bb6408c
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: thread.cpp
aaa38880 3// Purpose: wxThread Implementation for Posix threads
4bb6408c 4// Author: Original from Wolfram Gloger/Guilhem Lavaux
aaa38880 5// Modified by: Robert Roebling
4bb6408c
JS
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
b412f9be
JS
16#include "wx/defs.h"
17
18#if wxUSE_THREADS
19
4bb6408c
JS
20#include "wx/module.h"
21#include "wx/thread.h"
22#include "wx/utils.h"
aaa38880 23#include "wx/log.h"
4bb6408c 24
b412f9be
JS
25#include <stdio.h>
26#include <unistd.h>
27#include <pthread.h>
28#include <errno.h>
29
aaa38880
RR
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
44enum thread_state
45{
4bb6408c
JS
46 STATE_IDLE = 0,
47 STATE_RUNNING,
aaa38880
RR
48 STATE_PAUSING,
49 STATE_PAUSED,
4bb6408c
JS
50 STATE_CANCELED,
51 STATE_EXITED
52};
53
aaa38880
RR
54//--------------------------------------------------------------------
55// global data
56//--------------------------------------------------------------------
4bb6408c 57
aaa38880 58static pthread_t p_mainid;
4bb6408c 59
aaa38880
RR
60wxMutex *wxMainMutex = (wxMutex*) NULL; /* controls access to all GUI functions */
61
62/* TODO for Xt */
63
64static int p_thrd_pipe[2] = { -1, -1 };
65
66//-------------------------------------------------------------------------
67// global functions
68//-------------------------------------------------------------------------
4bb6408c 69
aaa38880
RR
70static void wxThreadGuiInit()
71{
72/* TODO for Xt */
73}
74
75static void wxThreadGuiExit()
76{
77/* TODO for Xt */
78}
79
80void wxMutexGuiEnter()
81{
82 if (wxMainMutex)
83 wxMainMutex->Lock();
84}
85
86void wxMutexGuiLeave()
87{
88 if (wxMainMutex)
89 wxMainMutex->Unlock();
90}
91
92//--------------------------------------------------------------------
93// wxMutex (Posix implementation)
94//--------------------------------------------------------------------
95
96class wxMutexInternal
97{
4bb6408c 98public:
aaa38880 99 pthread_mutex_t p_mutex;
4bb6408c
JS
100};
101
102wxMutex::wxMutex()
103{
104 p_internal = new wxMutexInternal;
aaa38880 105 pthread_mutex_init(&(p_internal->p_mutex), NULL);
4bb6408c
JS
106 m_locked = 0;
107}
108
109wxMutex::~wxMutex()
110{
111 if (m_locked > 0)
aaa38880
RR
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;
4bb6408c
JS
116}
117
118wxMutexError wxMutex::Lock()
119{
aaa38880
RR
120 int err;
121
122 err = pthread_mutex_lock(&(p_internal->p_mutex));
123 if (err == EDEADLK)
124 return wxMUTEX_DEAD_LOCK;
125
4bb6408c 126 m_locked++;
88150e60 127 return wxMUTEX_NO_ERROR;
4bb6408c
JS
128}
129
130wxMutexError wxMutex::TryLock()
131{
aaa38880
RR
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 }
4bb6408c 142 m_locked++;
88150e60 143 return wxMUTEX_NO_ERROR;
4bb6408c
JS
144}
145
146wxMutexError wxMutex::Unlock()
147{
148 if (m_locked > 0)
149 m_locked--;
aaa38880
RR
150 else
151 return wxMUTEX_UNLOCKED;
152
153 pthread_mutex_unlock(&(p_internal->p_mutex));
88150e60 154 return wxMUTEX_NO_ERROR;
4bb6408c
JS
155}
156
aaa38880
RR
157//--------------------------------------------------------------------
158// wxCondition (Posix implementation)
159//--------------------------------------------------------------------
160
161class wxConditionInternal
162{
4bb6408c 163public:
aaa38880 164 pthread_cond_t p_condition;
4bb6408c
JS
165};
166
167wxCondition::wxCondition()
168{
169 p_internal = new wxConditionInternal;
aaa38880 170 pthread_cond_init(&(p_internal->p_condition), NULL);
4bb6408c
JS
171}
172
173wxCondition::~wxCondition()
174{
aaa38880
RR
175 pthread_cond_destroy(&(p_internal->p_condition));
176 delete p_internal;
4bb6408c
JS
177}
178
179void wxCondition::Wait(wxMutex& mutex)
180{
aaa38880 181 pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
4bb6408c
JS
182}
183
aaa38880 184bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
4bb6408c 185{
aaa38880 186 struct timespec tspec;
4bb6408c 187
aaa38880
RR
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);
4bb6408c
JS
191}
192
193void wxCondition::Signal()
194{
aaa38880 195 pthread_cond_signal(&(p_internal->p_condition));
4bb6408c
JS
196}
197
198void wxCondition::Broadcast()
199{
aaa38880 200 pthread_cond_broadcast(&(p_internal->p_condition));
4bb6408c
JS
201}
202
aaa38880
RR
203//--------------------------------------------------------------------
204// wxThread (Posix implementation)
205//--------------------------------------------------------------------
206
207class wxThreadInternal
208{
4bb6408c 209public:
aaa38880
RR
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;
4bb6408c
JS
217};
218
aaa38880 219void *wxThreadInternal::PthreadStart(void *ptr)
4bb6408c 220{
aaa38880 221 wxThread *thread = (wxThread *)ptr;
4bb6408c 222
aaa38880
RR
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;
4bb6408c
JS
230}
231
aaa38880 232wxThreadError wxThread::Create()
4bb6408c 233{
aaa38880
RR
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
88150e60 264 return wxTHREAD_NO_ERROR;
4bb6408c
JS
265}
266
aaa38880 267void wxThread::SetPriority(int prio)
4bb6408c 268{
aaa38880
RR
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;
4bb6408c
JS
277}
278
aaa38880 279int wxThread::GetPriority() const
4bb6408c 280{
aaa38880 281 return p_internal->prio;
4bb6408c
JS
282}
283
aaa38880 284void wxThread::DeferDestroy(bool on)
4bb6408c 285{
aaa38880
RR
286 if (on)
287 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
288 else
289 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
4bb6408c
JS
290}
291
aaa38880 292wxThreadError wxThread::Destroy()
4bb6408c 293{
aaa38880
RR
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;
4bb6408c
JS
304}
305
aaa38880 306wxThreadError wxThread::Pause()
4bb6408c 307{
aaa38880
RR
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;
4bb6408c
JS
316}
317
aaa38880 318wxThreadError wxThread::Resume()
4bb6408c 319{
aaa38880
RR
320 if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED)
321 p_internal->state = STATE_RUNNING;
322
323 return wxTHREAD_NO_ERROR;
4bb6408c
JS
324}
325
326void *wxThread::Join()
327{
aaa38880
RR
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;
4bb6408c
JS
347}
348
349unsigned long wxThread::GetID() const
350{
aaa38880 351 return p_internal->thread_id;
4bb6408c
JS
352}
353
aaa38880 354void wxThread::Exit(void *status)
4bb6408c 355{
aaa38880
RR
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);
4bb6408c
JS
362}
363
aaa38880 364void wxThread::TestDestroy()
4bb6408c 365{
aaa38880
RR
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
378bool wxThread::IsMain()
379{
380 return (bool)pthread_equal(pthread_self(), p_mainid);
4bb6408c
JS
381}
382
383bool wxThread::IsRunning() const
384{
aaa38880 385 return (p_internal->state == STATE_RUNNING);
4bb6408c
JS
386}
387
aaa38880 388bool wxThread::IsAlive() const
4bb6408c 389{
aaa38880
RR
390 return (p_internal->state == STATE_RUNNING) ||
391 (p_internal->state == STATE_PAUSING) ||
392 (p_internal->state == STATE_PAUSED);
4bb6408c
JS
393}
394
395wxThread::wxThread()
396{
397 p_internal = new wxThreadInternal();
4bb6408c
JS
398}
399
400wxThread::~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.
408void wxThread::OnExit()
409{
410 Join();
411}
412
aaa38880
RR
413//--------------------------------------------------------------------
414// wxThreadModule
415//--------------------------------------------------------------------
416
06cfab17
RR
417class wxThreadModule : public wxModule
418{
419public:
420 virtual bool OnInit();
421 virtual void OnExit();
422
423private:
424 DECLARE_DYNAMIC_CLASS(wxThreadModule)
425};
426
d524867f
RR
427IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
428
429bool wxThreadModule::OnInit()
aaa38880 430{
d524867f
RR
431 wxMainMutex = new wxMutex();
432 wxThreadGuiInit();
433 p_mainid = pthread_self();
434 wxMainMutex->Lock();
aaa38880 435
d524867f
RR
436 return TRUE;
437}
aaa38880 438
d524867f
RR
439void wxThreadModule::OnExit()
440{
441 wxMainMutex->Unlock();
442 wxThreadGuiExit();
443 delete wxMainMutex;
4bb6408c
JS
444};
445
b412f9be
JS
446#endif
447 // wxUSE_THREADS