VirtualBox

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

最後變更 在這個檔案從31232是 1,由 vboxsync 提交於 55 年 前

import

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.6 KB
 
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 "prlog.h"
41#include "nsAutoLock.h"
42
43PRUintn nsThread::kIThreadSelfIndex = 0;
44static nsIThread *gMainThread = 0;
45
46#if defined(PR_LOGGING)
47//
48// Log module for nsIThread logging...
49//
50// To enable logging (see prlog.h for full details):
51//
52// set NSPR_LOG_MODULES=nsIThread:5
53// set NSPR_LOG_FILE=nspr.log
54//
55// this enables PR_LOG_DEBUG level information and places all output in
56// the file nspr.log
57//
58// gSocketLog is defined in nsSocketTransport.cpp
59//
60PRLogModuleInfo* nsIThreadLog = nsnull;
61
62#endif /* PR_LOGGING */
63
64////////////////////////////////////////////////////////////////////////////////
65
66nsThread::nsThread()
67 : mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull)
68{
69#if defined(PR_LOGGING)
70 //
71 // Initialize the global PRLogModule for nsIThread logging
72 // if necessary...
73 //
74 if (nsIThreadLog == nsnull) {
75 nsIThreadLog = PR_NewLogModule("nsIThread");
76 }
77#endif /* PR_LOGGING */
78
79 // enforce matching of constants to enums in prthread.h
80 NS_ASSERTION(int(nsIThread::PRIORITY_LOW) == int(PR_PRIORITY_LOW) &&
81 int(nsIThread::PRIORITY_NORMAL) == int(PRIORITY_NORMAL) &&
82 int(nsIThread::PRIORITY_HIGH) == int(PRIORITY_HIGH) &&
83 int(nsIThread::PRIORITY_URGENT) == int(PRIORITY_URGENT) &&
84 int(nsIThread::SCOPE_LOCAL) == int(PR_LOCAL_THREAD) &&
85 int(nsIThread::SCOPE_GLOBAL) == int(PR_GLOBAL_THREAD) &&
86 int(nsIThread::STATE_JOINABLE) == int(PR_JOINABLE_THREAD) &&
87 int(nsIThread::STATE_UNJOINABLE) == int(PR_UNJOINABLE_THREAD),
88 "Bad constant in nsIThread!");
89}
90
91nsThread::~nsThread()
92{
93 if (mStartLock)
94 PR_DestroyLock(mStartLock);
95
96 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
97 ("nsIThread %p destroyed\n", this));
98
99 // This code used to free the nsIThreadLog loginfo stuff
100 // Don't do that; loginfo structures are owned by nspr
101 // and would be freed if we ever called PR_Cleanup()
102 // see bug 142072
103}
104
105void
106nsThread::Main(void* arg)
107{
108 nsThread* self = (nsThread*)arg;
109
110 self->WaitUntilReadyToStartMain();
111
112 nsresult rv = NS_OK;
113 rv = self->RegisterThreadSelf();
114 NS_ASSERTION(rv == NS_OK, "failed to set thread self");
115
116 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
117 ("nsIThread %p start run %p\n", self, self->mRunnable.get()));
118 rv = self->mRunnable->Run();
119 NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed");
120
121#ifdef DEBUG
122 // Because a thread can die after gMainThread dies and takes nsIThreadLog with it,
123 // we need to check for it being null so that we don't crash on shutdown.
124 if (nsIThreadLog) {
125 PRThreadState state;
126 rv = self->GetState(&state);
127 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
128 ("nsIThread %p end run %p\n", self, self->mRunnable.get()));
129 }
130#endif
131
132 // explicitly drop the runnable now in case there are circular references
133 // between it and the thread object
134 self->mRunnable = nsnull;
135}
136
137void
138nsThread::Exit(void* arg)
139{
140 nsThread* self = (nsThread*)arg;
141
142 if (self->mDead) {
143 NS_ERROR("attempt to Exit() thread twice");
144 return;
145 }
146
147 self->mDead = PR_TRUE;
148
149#if defined(PR_LOGGING)
150 if (nsIThreadLog) {
151 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
152 ("nsIThread %p exited\n", self));
153 }
154#endif
155 NS_RELEASE(self);
156}
157
158NS_METHOD
159nsThread::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
160{
161 nsThread* thread = new nsThread();
162 if (!thread) return NS_ERROR_OUT_OF_MEMORY;
163 nsresult rv = thread->QueryInterface(aIID, aResult);
164 if (NS_FAILED(rv)) delete thread;
165 return rv;
166}
167
168NS_IMPL_THREADSAFE_ISUPPORTS1(nsThread, nsIThread)
169
170NS_IMETHODIMP
171nsThread::Join()
172{
173 // don't check for mDead here because nspr calls Exit (cleaning up
174 // thread-local storage) before they let us join with the thread
175
176 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
177 ("nsIThread %p start join\n", this));
178 if (!mThread)
179 return NS_ERROR_NOT_INITIALIZED;
180 PRStatus status = PR_JoinThread(mThread);
181 // XXX can't use NS_RELEASE here because the macro wants to set
182 // this to null (bad c++)
183 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
184 ("nsIThread %p end join\n", this));
185 if (status == PR_SUCCESS) {
186 NS_RELEASE_THIS(); // most likely the final release of this thread
187 return NS_OK;
188 }
189 else
190 return NS_ERROR_FAILURE;
191}
192
193NS_IMETHODIMP
194nsThread::GetPriority(PRThreadPriority *result)
195{
196 if (mDead)
197 return NS_ERROR_FAILURE;
198 if (!mThread)
199 return NS_ERROR_NOT_INITIALIZED;
200 *result = PR_GetThreadPriority(mThread);
201 return NS_OK;
202}
203
204NS_IMETHODIMP
205nsThread::SetPriority(PRThreadPriority value)
206{
207 if (mDead)
208 return NS_ERROR_FAILURE;
209 if (!mThread)
210 return NS_ERROR_NOT_INITIALIZED;
211 PR_SetThreadPriority(mThread, value);
212 return NS_OK;
213}
214
215NS_IMETHODIMP
216nsThread::Interrupt()
217{
218 if (mDead)
219 return NS_ERROR_FAILURE;
220 if (!mThread)
221 return NS_ERROR_NOT_INITIALIZED;
222 PRStatus status = PR_Interrupt(mThread);
223 return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
224}
225
226NS_IMETHODIMP
227nsThread::GetScope(PRThreadScope *result)
228{
229 if (mDead)
230 return NS_ERROR_FAILURE;
231 if (!mThread)
232 return NS_ERROR_NOT_INITIALIZED;
233 *result = PR_GetThreadScope(mThread);
234 return NS_OK;
235}
236
237NS_IMETHODIMP
238nsThread::GetState(PRThreadState *result)
239{
240 if (mDead)
241 return NS_ERROR_FAILURE;
242 if (!mThread)
243 return NS_ERROR_NOT_INITIALIZED;
244 *result = PR_GetThreadState(mThread);
245 return NS_OK;
246}
247
248NS_IMETHODIMP
249nsThread::GetPRThread(PRThread* *result)
250{
251 if (mDead) {
252 *result = nsnull;
253 return NS_ERROR_FAILURE;
254 }
255 *result = mThread;
256 return NS_OK;
257}
258
259NS_IMETHODIMP
260nsThread::Init(nsIRunnable* runnable,
261 PRUint32 stackSize,
262 PRThreadPriority priority,
263 PRThreadScope scope,
264 PRThreadState state)
265{
266 NS_ENSURE_ARG_POINTER(runnable);
267 mRunnable = runnable;
268
269 NS_ADDREF_THIS(); // released in nsThread::Exit
270 if (state == PR_JOINABLE_THREAD)
271 NS_ADDREF_THIS(); // released in nsThread::Join
272 mStartLock = PR_NewLock();
273 if (mStartLock == nsnull)
274 return NS_ERROR_OUT_OF_MEMORY;
275 PR_Lock(mStartLock);
276 mThread = PR_CreateThread(PR_USER_THREAD, Main, this,
277 priority, scope, state, stackSize);
278 PR_Unlock(mStartLock);
279 PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
280 ("nsIThread %p created\n", this));
281
282 if (mThread == nsnull)
283 return NS_ERROR_OUT_OF_MEMORY;
284 return NS_OK;
285}
286
287/* readonly attribute nsIThread currentThread; */
288NS_IMETHODIMP
289nsThread::GetCurrentThread(nsIThread * *aCurrentThread)
290{
291 return GetIThread(PR_GetCurrentThread(), aCurrentThread);
292}
293
294/* void sleep (in PRUint32 msec); */
295NS_IMETHODIMP
296nsThread::Sleep(PRUint32 msec)
297{
298 if (PR_GetCurrentThread() != mThread)
299 return NS_ERROR_FAILURE;
300
301 if (PR_Sleep(PR_MillisecondsToInterval(msec)) != PR_SUCCESS)
302 return NS_ERROR_FAILURE;
303
304 return NS_OK;
305}
306
307NS_COM nsresult
308NS_NewThread(nsIThread* *result,
309 nsIRunnable* runnable,
310 PRUint32 stackSize,
311 PRThreadState state,
312 PRThreadPriority priority,
313 PRThreadScope scope)
314{
315 nsresult rv;
316 nsThread* thread = new nsThread();
317 if (thread == nsnull)
318 return NS_ERROR_OUT_OF_MEMORY;
319 NS_ADDREF(thread);
320
321 rv = thread->Init(runnable, stackSize, priority, scope, state);
322 if (NS_FAILED(rv)) {
323 NS_RELEASE(thread);
324 return rv;
325 }
326
327 *result = thread;
328 return NS_OK;
329}
330
331NS_COM nsresult
332NS_NewThread(nsIThread* *result,
333 PRUint32 stackSize,
334 PRThreadState state,
335 PRThreadPriority priority,
336 PRThreadScope scope)
337{
338 nsThread* thread = new nsThread();
339 if (thread == nsnull)
340 return NS_ERROR_OUT_OF_MEMORY;
341 NS_ADDREF(thread);
342 *result = thread;
343 return NS_OK;
344}
345
346////////////////////////////////////////////////////////////////////////////////
347
348nsresult
349nsThread::RegisterThreadSelf()
350{
351 PRStatus status;
352
353 if (kIThreadSelfIndex == 0) {
354 status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit);
355 if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
356 }
357
358 status = PR_SetThreadPrivate(kIThreadSelfIndex, this);
359 if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
360
361 return NS_OK;
362}
363
364void
365nsThread::WaitUntilReadyToStartMain()
366{
367 PR_Lock(mStartLock);
368 PR_Unlock(mStartLock);
369 PR_DestroyLock(mStartLock);
370 mStartLock = nsnull;
371}
372
373NS_COM nsresult
374nsIThread::GetCurrent(nsIThread* *result)
375{
376 return GetIThread(PR_GetCurrentThread(), result);
377}
378
379NS_COM nsresult
380nsIThread::GetIThread(PRThread* prthread, nsIThread* *result)
381{
382 PRStatus status;
383 nsThread* thread;
384
385 if (nsThread::kIThreadSelfIndex == 0) {
386 status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit);
387 if (status != PR_SUCCESS) return NS_ERROR_FAILURE;
388 }
389
390 thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex);
391 if (thread == nsnull) {
392 // if the current thread doesn't have an nsIThread associated
393 // with it, make one
394 thread = new nsThread();
395 if (thread == nsnull)
396 return NS_ERROR_OUT_OF_MEMORY;
397 NS_ADDREF(thread); // released by Exit
398 thread->SetPRThread(prthread);
399 nsresult rv = thread->RegisterThreadSelf();
400 if (NS_FAILED(rv)) return rv;
401 }
402 NS_ADDREF(thread);
403 *result = thread;
404 return NS_OK;
405}
406
407NS_COM nsresult
408nsIThread::SetMainThread()
409{
410 // strictly speaking, it could be set twice. but practically speaking,
411 // it's almost certainly an error if it is
412 if (gMainThread != 0) {
413 NS_ERROR("Setting main thread twice?");
414 return NS_ERROR_FAILURE;
415 }
416 return GetCurrent(&gMainThread);
417}
418
419NS_COM nsresult
420nsIThread::GetMainThread(nsIThread **result)
421{
422 NS_ASSERTION(result, "bad result pointer");
423 if (gMainThread == 0)
424 return NS_ERROR_FAILURE;
425 *result = gMainThread;
426 NS_ADDREF(gMainThread);
427 return NS_OK;
428}
429
430NS_COM PRBool
431nsIThread::IsMainThread()
432{
433 if (gMainThread == 0)
434 return PR_TRUE;
435
436 PRThread *theMainThread;
437 gMainThread->GetPRThread(&theMainThread);
438 return theMainThread == PR_GetCurrentThread();
439}
440
441void
442nsThread::Shutdown()
443{
444 if (gMainThread) {
445 // XXX nspr doesn't seem to be calling the main thread's destructor
446 // callback, so let's help it out:
447 nsThread::Exit(NS_STATIC_CAST(nsThread*, gMainThread));
448 nsrefcnt cnt;
449 NS_RELEASE2(gMainThread, cnt);
450 NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown.");
451 gMainThread = nsnull;
452
453 kIThreadSelfIndex = 0;
454 }
455}
456
457////////////////////////////////////////////////////////////////////////////////
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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