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