]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/threadpsx.cpp
* Posix/SGI/No threads added
[wxWidgets.git] / src / gtk1 / 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(void)
51 {
52 p_internal = new wxMutexInternal;
53 pthread_mutex_init(&(p_internal->p_mutex), NULL);
54 m_locked = false;
55 }
56
57 wxMutex::~wxMutex(void)
58 {
59 if (m_locked)
60 pthread_mutex_unlock(&(p_internal->p_mutex));
61 pthread_mutex_destroy(&(p_internal->p_mutex));
62 delete p_internal;
63 }
64
65 wxMutexError wxMutex::Lock(void)
66 {
67 int err;
68
69 err = pthread_mutex_lock(&(p_internal->p_mutex));
70 switch (err) {
71 case EDEADLK: return MUTEX_DEAD_LOCK;
72 }
73 m_locked++;
74 return MUTEX_NO_ERROR;
75 }
76
77 wxMutexError wxMutex::TryLock(void)
78 {
79 int err;
80
81 if (m_locked)
82 return MUTEX_BUSY;
83 err = pthread_mutex_trylock(&(p_internal->p_mutex));
84 switch (err) {
85 case EBUSY: return MUTEX_BUSY;
86 }
87 m_locked++;
88 return MUTEX_NO_ERROR;
89 }
90
91 wxMutexError wxMutex::Unlock(void)
92 {
93 if (m_locked > 0) m_locked--;
94 pthread_mutex_unlock(&(p_internal->p_mutex));
95 return MUTEX_NO_ERROR;
96 }
97
98 /////////////////////////////////////////////////////////////////////////////
99 // wxThread: Posix Thread implementation (Condition)
100 /////////////////////////////////////////////////////////////////////////////
101
102 class wxConditionInternal {
103 public:
104 pthread_cond_t p_condition;
105 };
106
107 wxCondition::wxCondition(void)
108 {
109 p_internal = new wxConditionInternal;
110 pthread_cond_init(&(p_internal->p_condition), NULL);
111 }
112
113 wxCondition::~wxCondition(void)
114 {
115 pthread_cond_destroy(&(p_internal->p_condition));
116 delete p_internal;
117 }
118
119 void wxCondition::Wait(wxMutex& mutex)
120 {
121 pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
122 }
123
124 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
125 {
126 struct timespec tspec;
127
128 tspec.tv_sec = time(NULL)+sec;
129 tspec.tv_nsec = nsec;
130 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
131 }
132
133 void wxCondition::Signal(void)
134 {
135 pthread_cond_signal(&(p_internal->p_condition));
136 }
137
138 void wxCondition::Broadcast(void)
139 {
140 pthread_cond_broadcast(&(p_internal->p_condition));
141 }
142
143 /////////////////////////////////////////////////////////////////////////////
144 // wxThread: Posix Thread implementation (Thread)
145 /////////////////////////////////////////////////////////////////////////////
146
147 class wxThreadInternal {
148 public:
149 wxThreadInternal() { state = STATE_IDLE; }
150 ~wxThreadInternal() {}
151 static void *PthreadStart(void *ptr);
152 pthread_t thread_id;
153 int state;
154 int prio;
155 };
156
157 void *wxThreadInternal::PthreadStart(void *ptr)
158 {
159 wxThread *thread = (wxThread *)ptr;
160
161 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
162 void* status = thread->Entry();
163 thread->Exit(status);
164
165 return NULL;
166 }
167
168 wxThreadError wxThread::Create()
169 {
170 pthread_attr_t a;
171 int min_prio, max_prio, p;
172 struct sched_param sp;
173
174 if (p_internal->state != STATE_IDLE)
175 return THREAD_RUNNING;
176
177 // Change thread priority
178 pthread_attr_init(&a);
179 pthread_attr_getschedpolicy(&a, &p);
180
181 min_prio = sched_get_priority_min(p);
182 max_prio = sched_get_priority_max(p);
183
184 pthread_attr_getschedparam(&a, &sp);
185 sp.sched_priority = min_prio +
186 (p_internal->prio*(max_prio-min_prio))/100;
187 pthread_attr_setschedparam(&a, &sp);
188
189 // this is the point of no return
190 p_internal->state = STATE_RUNNING;
191 if (pthread_create(&p_internal->thread_id, &a,
192 wxThreadInternal::PthreadStart, (void *)this) != 0) {
193 p_internal->state = STATE_IDLE;
194 pthread_attr_destroy(&a);
195 return THREAD_NO_RESOURCE;
196 }
197 pthread_attr_destroy(&a);
198 return THREAD_NO_ERROR;
199 }
200
201 void wxThread::SetPriority(int prio)
202 {
203 if (p_internal->state == STATE_RUNNING)
204 return;
205
206 if (prio > 100)
207 prio = 100;
208 if (prio < 0)
209 prio = 0;
210 p_internal->prio = prio;
211 }
212
213 int wxThread::GetPriority(void)
214 {
215 return p_internal->prio;
216 }
217
218 void wxThread::DeferDestroy(bool on)
219 {
220 if (on)
221 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
222 else
223 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
224 }
225
226 wxThreadError wxThread::Destroy(void)
227 {
228 int res = 0;
229
230 if (p_internal->state == STATE_RUNNING) {
231 res = pthread_cancel(p_internal->thread_id);
232 if (res == 0)
233 p_internal->state = STATE_CANCELED;
234 }
235 return THREAD_NO_ERROR;
236 }
237
238 void *wxThread::Join()
239 {
240 void* status = 0;
241
242 if (p_internal->state != STATE_IDLE) {
243 bool do_unlock = wxThread::IsMain();
244
245 while (p_internal->state == STATE_RUNNING)
246 wxYield();
247
248 if (do_unlock)
249 wxMainMutex.Unlock();
250 pthread_join(p_internal->thread_id, &status);
251 if (do_unlock)
252 wxMainMutex.Lock();
253 p_internal->state = STATE_IDLE;
254 }
255 return status;
256 }
257
258 unsigned long wxThread::GetID()
259 {
260 return (unsigned long)p_internal->thread_id;
261 }
262
263 void wxThread::Exit(void *status)
264 {
265 wxThread* ptr = this;
266
267 THREAD_SEND_EXIT_MSG(ptr);
268 p_internal->state = STATE_EXITED;
269 pthread_exit(status);
270 }
271
272 void wxThread::TestDestroy()
273 {
274 pthread_testcancel();
275 }
276
277 bool wxThread::IsMain(void)
278 {
279 return (bool)pthread_equal(pthread_self(), p_mainid);
280 }
281
282 wxThread::wxThread()
283 {
284 p_internal = new wxThreadInternal();
285 }
286
287 wxThread::~wxThread()
288 {
289 Destroy();
290 Join();
291 delete p_internal;
292 }
293
294 // The default callback just joins the thread and throws away the result.
295 void wxThread::OnExit()
296 {
297 }
298
299 // Automatic initialization
300 class wxThreadModule : public wxModule {
301 DECLARE_DYNAMIC_CLASS(wxThreadModule)
302 public:
303 virtual bool OnInit(void) {
304 wxThreadGuiInit();
305 p_mainid = pthread_self();
306 wxMainMutex.Lock();
307
308 return TRUE;
309 }
310
311 virtual void OnExit(void) {
312 wxMainMutex.Unlock();
313 wxThreadGuiExit();
314 }
315 };
316
317 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)