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