]>
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$ | |
8 | // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | #ifdef __GNUG__ | |
12 | #pragma implementation "thread.h" | |
13 | #endif | |
14 | ||
15 | #include <stdio.h> | |
16 | #include <unistd.h> | |
17 | #include <sched.h> | |
18 | #include <pthread.h> | |
19 | ||
20 | enum thread_state { | |
21 | STATE_IDLE = 0, | |
22 | STATE_RUNNING, | |
23 | STATE_CANCELED, | |
24 | STATE_EXITED | |
25 | }; | |
26 | ||
27 | ///////////////////////////////////////////////////////////////////////////// | |
28 | // Static variables | |
29 | ///////////////////////////////////////////////////////////////////////////// | |
30 | ||
31 | #include "thread.h" | |
32 | ||
33 | static pthread_t p_mainid; | |
34 | wxMutex wxMainMutex; // controls access to all GUI functions | |
35 | ||
36 | ///////////////////////////////////////////////////////////////////////////// | |
37 | // GUI thread manager | |
38 | ///////////////////////////////////////////////////////////////////////////// | |
39 | #include "threadgui.inc" | |
40 | ||
41 | ///////////////////////////////////////////////////////////////////////////// | |
42 | // wxThread: Posix Thread implementation (Mutex) | |
43 | ///////////////////////////////////////////////////////////////////////////// | |
44 | ||
45 | class wxMutexInternal { | |
46 | public: | |
47 | pthread_mutex_t p_mutex; | |
48 | }; | |
49 | ||
ee4f8c2a | 50 | wxMutex::wxMutex() |
7c351dad GL |
51 | { |
52 | p_internal = new wxMutexInternal; | |
53 | pthread_mutex_init(&(p_internal->p_mutex), NULL); | |
b89156b5 | 54 | m_locked = 0; |
7c351dad GL |
55 | } |
56 | ||
ee4f8c2a | 57 | wxMutex::~wxMutex() |
7c351dad | 58 | { |
b89156b5 GL |
59 | if (m_locked > 0) |
60 | wxDebugMsg("wxMutex warning: freeing a locked mutex (%d locks)\n", | |
61 | m_locked); | |
62 | ||
7c351dad GL |
63 | pthread_mutex_destroy(&(p_internal->p_mutex)); |
64 | delete p_internal; | |
65 | } | |
66 | ||
ee4f8c2a | 67 | wxMutexError wxMutex::Lock() |
7c351dad GL |
68 | { |
69 | int err; | |
70 | ||
71 | err = pthread_mutex_lock(&(p_internal->p_mutex)); | |
b89156b5 GL |
72 | if (err == EDEADLK) |
73 | return MUTEX_DEAD_LOCK; | |
7c351dad GL |
74 | m_locked++; |
75 | return MUTEX_NO_ERROR; | |
76 | } | |
77 | ||
ee4f8c2a | 78 | wxMutexError wxMutex::TryLock() |
7c351dad GL |
79 | { |
80 | int err; | |
81 | ||
82 | if (m_locked) | |
83 | return MUTEX_BUSY; | |
84 | err = pthread_mutex_trylock(&(p_internal->p_mutex)); | |
85 | switch (err) { | |
86 | case EBUSY: return MUTEX_BUSY; | |
87 | } | |
88 | m_locked++; | |
89 | return MUTEX_NO_ERROR; | |
90 | } | |
91 | ||
ee4f8c2a | 92 | wxMutexError wxMutex::Unlock() |
7c351dad | 93 | { |
b89156b5 GL |
94 | if (m_locked > 0) |
95 | m_locked--; | |
96 | else | |
97 | return MUTEX_UNLOCKED; | |
7c351dad GL |
98 | pthread_mutex_unlock(&(p_internal->p_mutex)); |
99 | return MUTEX_NO_ERROR; | |
100 | } | |
101 | ||
102 | ///////////////////////////////////////////////////////////////////////////// | |
103 | // wxThread: Posix Thread implementation (Condition) | |
104 | ///////////////////////////////////////////////////////////////////////////// | |
105 | ||
106 | class wxConditionInternal { | |
107 | public: | |
108 | pthread_cond_t p_condition; | |
109 | }; | |
110 | ||
ee4f8c2a | 111 | wxCondition::wxCondition() |
7c351dad GL |
112 | { |
113 | p_internal = new wxConditionInternal; | |
114 | pthread_cond_init(&(p_internal->p_condition), NULL); | |
115 | } | |
116 | ||
ee4f8c2a | 117 | wxCondition::~wxCondition() |
7c351dad GL |
118 | { |
119 | pthread_cond_destroy(&(p_internal->p_condition)); | |
120 | delete p_internal; | |
121 | } | |
122 | ||
123 | void wxCondition::Wait(wxMutex& mutex) | |
124 | { | |
125 | pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex)); | |
126 | } | |
127 | ||
128 | bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) | |
129 | { | |
130 | struct timespec tspec; | |
131 | ||
132 | tspec.tv_sec = time(NULL)+sec; | |
133 | tspec.tv_nsec = nsec; | |
134 | return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT); | |
135 | } | |
136 | ||
ee4f8c2a | 137 | void wxCondition::Signal() |
7c351dad GL |
138 | { |
139 | pthread_cond_signal(&(p_internal->p_condition)); | |
140 | } | |
141 | ||
ee4f8c2a | 142 | void wxCondition::Broadcast() |
7c351dad GL |
143 | { |
144 | pthread_cond_broadcast(&(p_internal->p_condition)); | |
145 | } | |
146 | ||
147 | ///////////////////////////////////////////////////////////////////////////// | |
148 | // wxThread: Posix Thread implementation (Thread) | |
149 | ///////////////////////////////////////////////////////////////////////////// | |
150 | ||
151 | class wxThreadInternal { | |
152 | public: | |
153 | wxThreadInternal() { state = STATE_IDLE; } | |
154 | ~wxThreadInternal() {} | |
155 | static void *PthreadStart(void *ptr); | |
156 | pthread_t thread_id; | |
157 | int state; | |
158 | int prio; | |
159 | }; | |
160 | ||
161 | void *wxThreadInternal::PthreadStart(void *ptr) | |
162 | { | |
163 | wxThread *thread = (wxThread *)ptr; | |
164 | ||
165 | pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |
166 | void* status = thread->Entry(); | |
167 | thread->Exit(status); | |
168 | ||
169 | return NULL; | |
170 | } | |
171 | ||
172 | wxThreadError wxThread::Create() | |
173 | { | |
174 | pthread_attr_t a; | |
175 | int min_prio, max_prio, p; | |
176 | struct sched_param sp; | |
177 | ||
178 | if (p_internal->state != STATE_IDLE) | |
179 | return THREAD_RUNNING; | |
180 | ||
181 | // Change thread priority | |
182 | pthread_attr_init(&a); | |
183 | pthread_attr_getschedpolicy(&a, &p); | |
184 | ||
185 | min_prio = sched_get_priority_min(p); | |
186 | max_prio = sched_get_priority_max(p); | |
187 | ||
188 | pthread_attr_getschedparam(&a, &sp); | |
189 | sp.sched_priority = min_prio + | |
190 | (p_internal->prio*(max_prio-min_prio))/100; | |
191 | pthread_attr_setschedparam(&a, &sp); | |
192 | ||
193 | // this is the point of no return | |
194 | p_internal->state = STATE_RUNNING; | |
195 | if (pthread_create(&p_internal->thread_id, &a, | |
196 | wxThreadInternal::PthreadStart, (void *)this) != 0) { | |
197 | p_internal->state = STATE_IDLE; | |
198 | pthread_attr_destroy(&a); | |
199 | return THREAD_NO_RESOURCE; | |
200 | } | |
201 | pthread_attr_destroy(&a); | |
202 | return THREAD_NO_ERROR; | |
203 | } | |
204 | ||
205 | void wxThread::SetPriority(int prio) | |
206 | { | |
207 | if (p_internal->state == STATE_RUNNING) | |
208 | return; | |
209 | ||
210 | if (prio > 100) | |
211 | prio = 100; | |
212 | if (prio < 0) | |
213 | prio = 0; | |
214 | p_internal->prio = prio; | |
215 | } | |
216 | ||
ee4f8c2a | 217 | int wxThread::GetPriority() const |
7c351dad GL |
218 | { |
219 | return p_internal->prio; | |
220 | } | |
221 | ||
222 | void wxThread::DeferDestroy(bool on) | |
223 | { | |
224 | if (on) | |
225 | pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); | |
226 | else | |
227 | pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |
228 | } | |
229 | ||
ee4f8c2a | 230 | wxThreadError wxThread::Destroy() |
7c351dad GL |
231 | { |
232 | int res = 0; | |
233 | ||
234 | if (p_internal->state == STATE_RUNNING) { | |
235 | res = pthread_cancel(p_internal->thread_id); | |
236 | if (res == 0) | |
237 | p_internal->state = STATE_CANCELED; | |
238 | } | |
239 | return THREAD_NO_ERROR; | |
240 | } | |
241 | ||
242 | void *wxThread::Join() | |
243 | { | |
244 | void* status = 0; | |
245 | ||
246 | if (p_internal->state != STATE_IDLE) { | |
247 | bool do_unlock = wxThread::IsMain(); | |
248 | ||
249 | while (p_internal->state == STATE_RUNNING) | |
250 | wxYield(); | |
251 | ||
252 | if (do_unlock) | |
253 | wxMainMutex.Unlock(); | |
254 | pthread_join(p_internal->thread_id, &status); | |
255 | if (do_unlock) | |
256 | wxMainMutex.Lock(); | |
257 | p_internal->state = STATE_IDLE; | |
258 | } | |
259 | return status; | |
260 | } | |
261 | ||
ee4f8c2a | 262 | unsigned long wxThread::GetID() const |
7c351dad GL |
263 | { |
264 | return (unsigned long)p_internal->thread_id; | |
265 | } | |
266 | ||
267 | void wxThread::Exit(void *status) | |
268 | { | |
269 | wxThread* ptr = this; | |
270 | ||
271 | THREAD_SEND_EXIT_MSG(ptr); | |
272 | p_internal->state = STATE_EXITED; | |
273 | pthread_exit(status); | |
274 | } | |
275 | ||
276 | void wxThread::TestDestroy() | |
277 | { | |
278 | pthread_testcancel(); | |
279 | } | |
280 | ||
ee4f8c2a | 281 | bool wxThread::IsMain() const |
7c351dad GL |
282 | { |
283 | return (bool)pthread_equal(pthread_self(), p_mainid); | |
284 | } | |
285 | ||
286 | wxThread::wxThread() | |
287 | { | |
288 | p_internal = new wxThreadInternal(); | |
289 | } | |
290 | ||
291 | wxThread::~wxThread() | |
292 | { | |
293 | Destroy(); | |
294 | Join(); | |
295 | delete p_internal; | |
296 | } | |
297 | ||
298 | // The default callback just joins the thread and throws away the result. | |
299 | void wxThread::OnExit() | |
300 | { | |
301 | } | |
302 | ||
303 | // Automatic initialization | |
304 | class wxThreadModule : public wxModule { | |
305 | DECLARE_DYNAMIC_CLASS(wxThreadModule) | |
306 | public: | |
ee4f8c2a | 307 | virtual bool OnInit() { |
7c351dad GL |
308 | wxThreadGuiInit(); |
309 | p_mainid = pthread_self(); | |
310 | wxMainMutex.Lock(); | |
311 | ||
312 | return TRUE; | |
313 | } | |
314 | ||
ee4f8c2a | 315 | virtual void OnExit() { |
7c351dad GL |
316 | wxMainMutex.Unlock(); |
317 | wxThreadGuiExit(); | |
318 | } | |
319 | }; | |
320 | ||
321 | IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) |