VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp@ 101991

Last change on this file since 101991 was 101991, checked in by vboxsync, 15 months ago

libs/xpcom: Convert nsThread.cpp from PR_LOG to IPRT's logging infrastructure, bugref:10545

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38#include "nsThread.h"
39#include "prmem.h"
40#include "nsAutoLock.h"
41
42#include <iprt/assert.h>
43#include <VBox/log.h>
44
45RTTLS nsThread::kIThreadSelfIndex = NIL_RTTLS;
46static nsIThread *gMainThread = 0;
47
48////////////////////////////////////////////////////////////////////////////////
49
50nsThread::nsThread()
51 : mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull)
52{
53 // enforce matching of constants to enums in prthread.h
54 NS_ASSERTION(int(nsIThread::PRIORITY_LOW) == int(PR_PRIORITY_LOW) &&
55 int(nsIThread::PRIORITY_NORMAL) == int(PRIORITY_NORMAL) &&
56 int(nsIThread::PRIORITY_HIGH) == int(PRIORITY_HIGH) &&
57 int(nsIThread::PRIORITY_URGENT) == int(PRIORITY_URGENT) &&
58 int(nsIThread::SCOPE_LOCAL) == int(PR_LOCAL_THREAD) &&
59 int(nsIThread::SCOPE_GLOBAL) == int(PR_GLOBAL_THREAD) &&
60 int(nsIThread::STATE_JOINABLE) == int(PR_JOINABLE_THREAD) &&
61 int(nsIThread::STATE_UNJOINABLE) == int(PR_UNJOINABLE_THREAD),
62 "Bad constant in nsIThread!");
63}
64
65nsThread::~nsThread()
66{
67 if (mStartLock)
68 PR_DestroyLock(mStartLock);
69
70 Log(("nsIThread %p destroyed\n", this));
71
72 // This code used to free the nsIThreadLog loginfo stuff
73 // Don't do that; loginfo structures are owned by nspr
74 // and would be freed if we ever called PR_Cleanup()
75 // see bug 142072
76}
77
78void
79nsThread::Main(void* arg)
80{
81 nsThread* self = (nsThread*)arg;
82
83 self->WaitUntilReadyToStartMain();
84
85 nsresult rv = NS_OK;
86 rv = self->RegisterThreadSelf();
87 NS_ASSERTION(rv == NS_OK, "failed to set thread self");
88
89 Log(("nsIThread %p start run %p\n", self, self->mRunnable.get()));
90 rv = self->mRunnable->Run();
91 NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed");
92
93#ifdef LOG_ENABLED
94 // Because a thread can die after gMainThread dies and takes nsIThreadLog with it,
95 // we need to check for it being null so that we don't crash on shutdown.
96 PRThreadState state;
97 rv = self->GetState(&state);
98 Log(("nsIThread %p end run %p\n", self, self->mRunnable.get()));
99#endif
100
101 // explicitly drop the runnable now in case there are circular references
102 // between it and the thread object
103 self->mRunnable = nsnull;
104}
105
106DECLCALLBACK(void)
107nsThread::Exit(void* arg)
108{
109 nsThread* self = (nsThread*)arg;
110
111 if (self->mDead) {
112 NS_ERROR("attempt to Exit() thread twice");
113 return;
114 }
115
116 self->mDead = PR_TRUE;
117
118 Log(("nsIThread %p exited\n", self));
119 NS_RELEASE(self);
120}
121
122NS_METHOD
123nsThread::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
124{
125 nsThread* thread = new nsThread();
126 if (!thread) return NS_ERROR_OUT_OF_MEMORY;
127 nsresult rv = thread->QueryInterface(aIID, aResult);
128 if (NS_FAILED(rv)) delete thread;
129 return rv;
130}
131
132NS_IMPL_THREADSAFE_ISUPPORTS1(nsThread, nsIThread)
133
134NS_IMETHODIMP
135nsThread::Join()
136{
137 // don't check for mDead here because nspr calls Exit (cleaning up
138 // thread-local storage) before they let us join with the thread
139
140 Log(("nsIThread %p start join\n", this));
141 if (!mThread)
142 return NS_ERROR_NOT_INITIALIZED;
143 PRStatus status = PR_JoinThread(mThread);
144 // XXX can't use NS_RELEASE here because the macro wants to set
145 // this to null (bad c++)
146 Log(("nsIThread %p end join\n", this));
147 if (status == PR_SUCCESS) {
148 NS_RELEASE_THIS(); // most likely the final release of this thread
149 return NS_OK;
150 }
151 else
152 return NS_ERROR_FAILURE;
153}
154
155NS_IMETHODIMP
156nsThread::GetPriority(PRThreadPriority *result)
157{
158 if (mDead)
159 return NS_ERROR_FAILURE;
160 if (!mThread)
161 return NS_ERROR_NOT_INITIALIZED;
162 *result = PR_GetThreadPriority(mThread);
163 return NS_OK;
164}
165
166NS_IMETHODIMP
167nsThread::SetPriority(PRThreadPriority value)
168{
169 if (mDead)
170 return NS_ERROR_FAILURE;
171 if (!mThread)
172 return NS_ERROR_NOT_INITIALIZED;
173 PR_SetThreadPriority(mThread, value);
174 return NS_OK;
175}
176
177NS_IMETHODIMP
178nsThread::Interrupt()
179{
180 if (mDead)
181 return NS_ERROR_FAILURE;
182 if (!mThread)
183 return NS_ERROR_NOT_INITIALIZED;
184 PRStatus status = PR_Interrupt(mThread);
185 return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
186}
187
188NS_IMETHODIMP
189nsThread::GetScope(PRThreadScope *result)
190{
191 if (mDead)
192 return NS_ERROR_FAILURE;
193 if (!mThread)
194 return NS_ERROR_NOT_INITIALIZED;
195 *result = PR_GetThreadScope(mThread);
196 return NS_OK;
197}
198
199NS_IMETHODIMP
200nsThread::GetState(PRThreadState *result)
201{
202 if (mDead)
203 return NS_ERROR_FAILURE;
204 if (!mThread)
205 return NS_ERROR_NOT_INITIALIZED;
206 *result = PR_GetThreadState(mThread);
207 return NS_OK;
208}
209
210NS_IMETHODIMP
211nsThread::GetPRThread(PRThread* *result)
212{
213 if (mDead) {
214 *result = nsnull;
215 return NS_ERROR_FAILURE;
216 }
217 *result = mThread;
218 return NS_OK;
219}
220
221NS_IMETHODIMP
222nsThread::Init(nsIRunnable* runnable,
223 PRUint32 stackSize,
224 PRThreadPriority priority,
225 PRThreadScope scope,
226 PRThreadState state)
227{
228 NS_ENSURE_ARG_POINTER(runnable);
229 mRunnable = runnable;
230
231 NS_ADDREF_THIS(); // released in nsThread::Exit
232 if (state == PR_JOINABLE_THREAD)
233 NS_ADDREF_THIS(); // released in nsThread::Join
234 mStartLock = PR_NewLock();
235 if (mStartLock == nsnull)
236 return NS_ERROR_OUT_OF_MEMORY;
237 PR_Lock(mStartLock);
238 mThread = PR_CreateThread(PR_USER_THREAD, Main, this,
239 priority, scope, state, stackSize);
240 PR_Unlock(mStartLock);
241 Log(("nsIThread %p created\n", this));
242
243 if (mThread == nsnull)
244 return NS_ERROR_OUT_OF_MEMORY;
245 return NS_OK;
246}
247
248/* readonly attribute nsIThread currentThread; */
249NS_IMETHODIMP
250nsThread::GetCurrentThread(nsIThread * *aCurrentThread)
251{
252 return GetIThread(PR_GetCurrentThread(), aCurrentThread);
253}
254
255/* void sleep (in PRUint32 msec); */
256NS_IMETHODIMP
257nsThread::Sleep(PRUint32 msec)
258{
259 if (PR_GetCurrentThread() != mThread)
260 return NS_ERROR_FAILURE;
261
262 if (RTThreadSleep(msec) != VINF_SUCCESS)
263 return NS_ERROR_FAILURE;
264
265 return NS_OK;
266}
267
268NS_COM nsresult
269NS_NewThread(nsIThread* *result,
270 nsIRunnable* runnable,
271 PRUint32 stackSize,
272 PRThreadState state,
273 PRThreadPriority priority,
274 PRThreadScope scope)
275{
276 nsresult rv;
277 nsThread* thread = new nsThread();
278 if (thread == nsnull)
279 return NS_ERROR_OUT_OF_MEMORY;
280 NS_ADDREF(thread);
281
282 rv = thread->Init(runnable, stackSize, priority, scope, state);
283 if (NS_FAILED(rv)) {
284 NS_RELEASE(thread);
285 return rv;
286 }
287
288 *result = thread;
289 return NS_OK;
290}
291
292NS_COM nsresult
293NS_NewThread(nsIThread* *result,
294 PRUint32 stackSize,
295 PRThreadState state,
296 PRThreadPriority priority,
297 PRThreadScope scope)
298{
299 nsThread* thread = new nsThread();
300 if (thread == nsnull)
301 return NS_ERROR_OUT_OF_MEMORY;
302 NS_ADDREF(thread);
303 *result = thread;
304 return NS_OK;
305}
306
307////////////////////////////////////////////////////////////////////////////////
308
309nsresult
310nsThread::RegisterThreadSelf()
311{
312 int vrc;
313
314 if (kIThreadSelfIndex == NIL_RTTLS) {
315 vrc = RTTlsAllocEx(&kIThreadSelfIndex, Exit);
316 if (RT_FAILURE(vrc)) return NS_ERROR_FAILURE;
317 }
318
319 vrc = RTTlsSet(kIThreadSelfIndex, this);
320 if (RT_FAILURE(vrc)) return NS_ERROR_FAILURE;
321
322 return NS_OK;
323}
324
325void
326nsThread::WaitUntilReadyToStartMain()
327{
328 PR_Lock(mStartLock);
329 PR_Unlock(mStartLock);
330 PR_DestroyLock(mStartLock);
331 mStartLock = nsnull;
332}
333
334NS_COM nsresult
335nsIThread::GetCurrent(nsIThread* *result)
336{
337 return GetIThread(PR_GetCurrentThread(), result);
338}
339
340NS_COM nsresult
341nsIThread::GetIThread(PRThread* prthread, nsIThread* *result)
342{
343 nsThread* thread;
344
345 if (nsThread::kIThreadSelfIndex == NIL_RTTLS) {
346 int vrc = RTTlsAllocEx(&nsThread::kIThreadSelfIndex, nsThread::Exit);
347 if (RT_FAILURE(vrc)) return NS_ERROR_FAILURE;
348 }
349
350 thread = (nsThread*)RTTlsGet(nsThread::kIThreadSelfIndex);
351 if (thread == nsnull) {
352 // if the current thread doesn't have an nsIThread associated
353 // with it, make one
354 thread = new nsThread();
355 if (thread == nsnull)
356 return NS_ERROR_OUT_OF_MEMORY;
357 NS_ADDREF(thread); // released by Exit
358 thread->SetPRThread(prthread);
359 nsresult rv = thread->RegisterThreadSelf();
360 if (NS_FAILED(rv)) return rv;
361 }
362 NS_ADDREF(thread);
363 *result = thread;
364 return NS_OK;
365}
366
367NS_COM nsresult
368nsIThread::SetMainThread()
369{
370 // strictly speaking, it could be set twice. but practically speaking,
371 // it's almost certainly an error if it is
372 if (gMainThread != 0) {
373 NS_ERROR("Setting main thread twice?");
374 return NS_ERROR_FAILURE;
375 }
376 return GetCurrent(&gMainThread);
377}
378
379NS_COM nsresult
380nsIThread::GetMainThread(nsIThread **result)
381{
382 NS_ASSERTION(result, "bad result pointer");
383 if (gMainThread == 0)
384 return NS_ERROR_FAILURE;
385 *result = gMainThread;
386 NS_ADDREF(gMainThread);
387 return NS_OK;
388}
389
390NS_COM PRBool
391nsIThread::IsMainThread()
392{
393 if (gMainThread == 0)
394 return PR_TRUE;
395
396 PRThread *theMainThread;
397 gMainThread->GetPRThread(&theMainThread);
398 return theMainThread == PR_GetCurrentThread();
399}
400
401void
402nsThread::Shutdown()
403{
404 if (gMainThread) {
405 // XXX nspr doesn't seem to be calling the main thread's destructor
406 // callback, so let's help it out:
407 nsThread::Exit(NS_STATIC_CAST(nsThread*, gMainThread));
408 nsrefcnt cnt;
409 NS_RELEASE2(gMainThread, cnt);
410 NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown.");
411 gMainThread = nsnull;
412
413 int vrc = RTTlsFree(kIThreadSelfIndex);
414 AssertRC(vrc); RT_NOREF(vrc);
415 kIThreadSelfIndex = NIL_RTTLS;
416 }
417}
418
419////////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette