]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/threadpsx.cpp
Corrected some problems I introduced, added tabevent.tex.
[wxWidgets.git] / src / gtk / threadpsx.cpp
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
50 wxMutex::wxMutex()
51 {
52 p_internal = new wxMutexInternal;
53 pthread_mutex_init(&(p_internal->p_mutex), NULL);
54 m_locked = 0;
55 }
56
57 wxMutex::~wxMutex()
58 {
59 if (m_locked > 0)
60 wxDebugMsg("wxMutex warning: freeing a locked mutex (%d locks)\n",
61 m_locked);
62
63 pthread_mutex_destroy(&(p_internal->p_mutex));
64 delete p_internal;
65 }
66
67 wxMutexError wxMutex::Lock()
68 {
69 int err;
70
71 err = pthread_mutex_lock(&(p_internal->p_mutex));
72 if (err == EDEADLK)
73 return MUTEX_DEAD_LOCK;
74 m_locked++;
75 return MUTEX_NO_ERROR;
76 }
77
78 wxMutexError wxMutex::TryLock()
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
92 wxMutexError wxMutex::Unlock()
93 {
94 if (m_locked > 0)
95 m_locked--;
96 else
97 return MUTEX_UNLOCKED;
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
111 wxCondition::wxCondition()
112 {
113 p_internal = new wxConditionInternal;
114 pthread_cond_init(&(p_internal->p_condition), NULL);
115 }
116
117 wxCondition::~wxCondition()
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
137 void wxCondition::Signal()
138 {
139 pthread_cond_signal(&(p_internal->p_condition));
140 }
141
142 void wxCondition::Broadcast()
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
217 int wxThread::GetPriority() const
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
230 wxThreadError wxThread::Destroy()
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
262 unsigned long wxThread::GetID() const
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
281 bool wxThread::IsMain()
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:
307 virtual bool OnInit() {
308 wxThreadGuiInit();
309 p_mainid = pthread_self();
310 wxMainMutex.Lock();
311
312 return TRUE;
313 }
314
315 virtual void OnExit() {
316 wxMainMutex.Unlock();
317 wxThreadGuiExit();
318 }
319 };
320
321 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)