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