]>
Commit | Line | Data |
---|---|---|
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 | ||
44 | enum 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 | 58 | static pthread_t p_mainid; |
4bb6408c | 59 | |
aaa38880 RR |
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 | //------------------------------------------------------------------------- | |
4bb6408c | 69 | |
aaa38880 RR |
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 | { | |
4bb6408c | 98 | public: |
aaa38880 | 99 | pthread_mutex_t p_mutex; |
4bb6408c JS |
100 | }; |
101 | ||
102 | wxMutex::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 | ||
109 | wxMutex::~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 | ||
118 | wxMutexError 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 | ||
130 | wxMutexError 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 | ||
146 | wxMutexError 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 | ||
161 | class wxConditionInternal | |
162 | { | |
4bb6408c | 163 | public: |
aaa38880 | 164 | pthread_cond_t p_condition; |
4bb6408c JS |
165 | }; |
166 | ||
167 | wxCondition::wxCondition() | |
168 | { | |
169 | p_internal = new wxConditionInternal; | |
aaa38880 | 170 | pthread_cond_init(&(p_internal->p_condition), NULL); |
4bb6408c JS |
171 | } |
172 | ||
173 | wxCondition::~wxCondition() | |
174 | { | |
aaa38880 RR |
175 | pthread_cond_destroy(&(p_internal->p_condition)); |
176 | delete p_internal; | |
4bb6408c JS |
177 | } |
178 | ||
179 | void wxCondition::Wait(wxMutex& mutex) | |
180 | { | |
aaa38880 | 181 | pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex)); |
4bb6408c JS |
182 | } |
183 | ||
aaa38880 | 184 | bool 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 | ||
193 | void wxCondition::Signal() | |
194 | { | |
aaa38880 | 195 | pthread_cond_signal(&(p_internal->p_condition)); |
4bb6408c JS |
196 | } |
197 | ||
198 | void 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 | ||
207 | class wxThreadInternal | |
208 | { | |
4bb6408c | 209 | public: |
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 | 219 | void *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 | 232 | wxThreadError 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 | 267 | void 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 | 279 | int wxThread::GetPriority() const |
4bb6408c | 280 | { |
aaa38880 | 281 | return p_internal->prio; |
4bb6408c JS |
282 | } |
283 | ||
aaa38880 | 284 | void 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 | 292 | wxThreadError 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 | 306 | wxThreadError 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 | 318 | wxThreadError 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 | ||
326 | void *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 | ||
349 | unsigned long wxThread::GetID() const | |
350 | { | |
aaa38880 | 351 | return p_internal->thread_id; |
4bb6408c JS |
352 | } |
353 | ||
aaa38880 | 354 | void 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 | 364 | void 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 | ||
378 | bool wxThread::IsMain() | |
379 | { | |
380 | return (bool)pthread_equal(pthread_self(), p_mainid); | |
4bb6408c JS |
381 | } |
382 | ||
383 | bool wxThread::IsRunning() const | |
384 | { | |
aaa38880 | 385 | return (p_internal->state == STATE_RUNNING); |
4bb6408c JS |
386 | } |
387 | ||
aaa38880 | 388 | bool 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 | ||
395 | wxThread::wxThread() | |
396 | { | |
397 | p_internal = new wxThreadInternal(); | |
4bb6408c JS |
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 | ||
aaa38880 RR |
413 | //-------------------------------------------------------------------- |
414 | // wxThreadModule | |
415 | //-------------------------------------------------------------------- | |
416 | ||
06cfab17 RR |
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 | ||
d524867f RR |
427 | IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) |
428 | ||
429 | bool 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 |
439 | void wxThreadModule::OnExit() |
440 | { | |
441 | wxMainMutex->Unlock(); | |
442 | wxThreadGuiExit(); | |
443 | delete wxMainMutex; | |
4bb6408c JS |
444 | }; |
445 | ||
b412f9be JS |
446 | #endif |
447 | // wxUSE_THREADS |