* Hope this is the last bug fix in the wxThread merge ...
[wxWidgets.git] / src / gtk1 / threadsgi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: threadsgi.cpp
3 // Purpose: wxThread (SGI) 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
18 #include <signal.h>
19 #include <sys/wait.h>
20 #include <sys/prctl.h>
21 #include "wx/thread.h"
22 #include "wx/module.h"
23 #include "wx/utils.h"
24
25 enum thread_state {
26 STATE_IDLE = 0,
27 STATE_RUNNING,
28 STATE_CANCELED,
29 STATE_EXITED
30 };
31
32 /////////////////////////////////////////////////////////////////////////////
33 // Static variables
34 /////////////////////////////////////////////////////////////////////////////
35
36 static int p_mainid;
37 wxMutex wxMainMutex;
38
39 #include "threadgui.inc"
40
41 /////////////////////////////////////////////////////////////////////////////
42 // Unix implementations (SGI threads)
43 /////////////////////////////////////////////////////////////////////////////
44
45 class wxMutexInternal {
46 public:
47 abilock_t p_mutex;
48 };
49
50 wxMutex::wxMutex()
51 {
52 m_locked = 0;
53 p_internal = new wxMutexInternal;
54 init_lock(&(p_internal->p_mutex));
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 delete p_internal;
63 }
64
65 wxMutexError wxMutex::Lock()
66 {
67 spin_lock(&(p_internal->p_mutex));
68 m_locked++;
69 return MUTEX_NO_ERROR;
70 }
71
72 wxMutexError wxMutex::TryLock()
73 {
74 if (acquire_lock(&(p_internal->p_mutex)) != 0)
75 return MUTEX_BUSY;
76 m_locked++;
77 return MUTEX_NO_ERROR;
78 }
79
80 wxMutexError wxMutex::Unlock()
81 {
82 if (m_locked == 0)
83 return MUTEX_UNLOCKED;
84 release_lock(&(p_internal->p_mutex));
85 m_locked--;
86 return MUTEX_NO_ERROR;
87 }
88
89 // GL: Don't know how it works on SGI. Wolfram ?
90
91 wxCondition::wxCondition() {}
92 wxCondition::~wxCondition() {}
93 int wxCondition::Wait(wxMutex& WXUNUSED(mutex)) { return 0;}
94 int wxCondition::Wait(wxMutex& WXUNUSED(mutex), unsigned long WXUNUSED(sec),
95 unsigned long WXUNUSED(nsec)) { return 0; }
96 int wxCondition::Signal() { return 0; }
97 int wxCondition::Broadcast() { return 0; }
98
99 class
100 wxThreadPrivate {
101 public:
102 wxThreadPrivate() { thread_id = 0; state = STATE_IDLE; }
103 ~wxThreadPrivate() {}
104 static void SprocStart(void *ptr);
105 static void SignalHandler(int sig);
106 public:
107 int state, thread_id;
108 void* exit_status;
109 };
110
111 void wxThreadPrivate::SprocStart(void *ptr)
112 {
113 void* status;
114
115 wxThread *thr = (wxThread *)ptr;
116
117 thr->p_internal->thread_id = getpid();
118 thr->p_internal->exit_status = 0;
119 status = thr->Entry();
120 thr->Exit(status);
121 }
122
123 void wxThread::Exit(void* status)
124 {
125 wxThread* ptr = this;
126 THREAD_SEND_EXIT_MSG(ptr);
127 p_internal->state = STATE_EXITED;
128 p_internal->exit_status = status;
129 _exit(0);
130 }
131
132 wxThreadError wxThread::Create()
133 {
134 if (p_internal->state != STATE_IDLE)
135 return THREAD_RUNNING;
136 p_internal->state = STATE_RUNNING;
137 if (sproc(p_internal->SprocStart, PR_SALL, this) < 0) {
138 p_internal->state = STATE_IDLE;
139 return THREAD_NO_RESOURCE;
140 }
141 return THREAD_NO_ERROR;
142 }
143
144 void wxThread::Destroy()
145 {
146 if (p_internal->state == STATE_RUNNING)
147 p_internal->state = STATE_CANCELED;
148 }
149
150 void *wxThread::Join()
151 {
152 if (p_internal->state != STATE_IDLE) {
153 bool do_unlock = wxThread::IsMain();
154 int stat;
155
156 if (do_unlock)
157 wxMainMutex.Unlock();
158 waitpid(p_internal->thread_id, &stat, 0);
159 if (do_unlock)
160 wxMainMutex.Lock();
161 if (!WIFEXITED(stat) && !WIFSIGNALED(stat))
162 return 0;
163 p_internal->state = STATE_IDLE;
164 return p_internal->exit_status;
165 }
166 return 0;
167 }
168
169 unsigned long wxThread::GetID() const
170 {
171 return (unsigned long)p_internal->thread_id;
172 }
173
174 void wxThread::TestDestroy()
175 {
176 if (p_internal->state == STATE_CANCELED) {
177 p_internal->exit_status = 0;
178 _exit(0);
179 }
180 }
181
182 void wxThread::SetPriority(int prio)
183 {
184 }
185
186 int wxThread::GetPriority() const
187 {
188 return 0;
189 }
190
191 bool wxThreadIsMain()
192 {
193 return (int)getpid() == main_id;
194 }
195
196 wxThread::wxThread()
197 {
198 p_internal = new wxThreadPrivate();
199 }
200
201 wxThread::~wxThread()
202 {
203 Cancel();
204 Join();
205 delete p_internal;
206 }
207
208 // The default callback just joins the thread and throws away the result.
209 void wxThread::OnExit()
210 {
211 Join();
212 }
213
214 // Global initialization
215 class wxThreadModule : public wxModule {
216 DECLARE_DYNAMIC_CLASS(wxThreadModule)
217 public:
218 virtual bool OnInit() {
219 wxThreadGuiInit();
220 p_mainid = (int)getpid();
221 wxMainMutex.Lock();
222 }
223
224 virtual void OnExit() {
225 wxMainMutex.Unlock();
226 wxThreadGuiExit();
227 }
228 };
229
230 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)