rcthread.cpp (5446B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* RCThread.cpp - C++ wrapper on NSPR */ 7 8 #include "rcthread.h" 9 #include "rcinrval.h" 10 11 #include <prmem.h> 12 #include <prlog.h> 13 #include <stdio.h> 14 #include <prinit.h> 15 16 static RCPrimordialThread *primordial = NULL; 17 18 void nas_Root(void *arg) 19 { 20 RCThread *him = (RCThread*)arg; 21 while (RCThread::ex_unstarted == him->execution) { 22 (void)PR_Sleep(PR_INTERVAL_NO_TIMEOUT); /* wait for Start() */ 23 } 24 him->RootFunction(); /* he gets a self reference */ 25 if (PR_UNJOINABLE_THREAD == PR_GetThreadState(him->identity)) { 26 delete him; 27 } 28 } /* nas_Root */ 29 30 RCThread::~RCThread() { } 31 32 RCThread::RCThread(): RCBase() { } 33 34 RCThread::RCThread(const RCThread&): RCBase() 35 { 36 PR_NOT_REACHED("Cannot call thread copy constructor"); 37 } /* RCThread::RCThread */ 38 39 RCThread::RCThread( 40 RCThread::Scope scope, RCThread::State join, PRUint32 stackSize): 41 RCBase() 42 { 43 execution = ex_unstarted; 44 identity = PR_CreateThread( 45 PR_USER_THREAD, nas_Root, this, 46 PR_GetThreadPriority(PR_GetCurrentThread()), 47 (PRThreadScope)scope, (PRThreadState)join, stackSize); 48 } /* RCThread::RCThread */ 49 50 void RCThread::operator=(const RCThread&) 51 { 52 PR_NOT_REACHED("Cannot call thread assignment operator"); 53 } /* RCThread::operator= */ 54 55 56 PRStatus RCThread::Start() 57 { 58 PRStatus rv; 59 /* This is an unsafe check, but not too critical */ 60 if (RCThread::ex_unstarted == execution) 61 { 62 execution = RCThread::ex_started; 63 rv = PR_Interrupt(identity); 64 PR_ASSERT(PR_SUCCESS == rv); 65 } 66 else 67 { 68 rv = PR_FAILURE; 69 PR_SetError(PR_INVALID_STATE_ERROR, 0); 70 } 71 return rv; 72 } /* RCThread::Start */ 73 74 PRStatus RCThread::Join() 75 { 76 PRStatus rv; 77 if (RCThread::ex_unstarted == execution) 78 { 79 rv = PR_FAILURE; 80 PR_SetError(PR_INVALID_STATE_ERROR, 0); 81 } 82 else { 83 rv = PR_JoinThread(identity); 84 } 85 if (PR_SUCCESS == rv) { 86 delete this; 87 } 88 return rv; 89 } /* RCThread::Join */ 90 91 PRStatus RCThread::Interrupt() 92 { 93 PRStatus rv; 94 if (RCThread::ex_unstarted == execution) 95 { 96 rv = PR_FAILURE; 97 PR_SetError(PR_INVALID_STATE_ERROR, 0); 98 } 99 else { 100 rv = PR_Interrupt(identity); 101 } 102 return rv; 103 } /* RCThread::Interrupt */ 104 105 void RCThread::ClearInterrupt() { 106 PR_ClearInterrupt(); 107 } 108 109 void RCThread::SetPriority(RCThread::Priority new_priority) 110 { 111 PR_SetThreadPriority(identity, (PRThreadPriority)new_priority); 112 } 113 114 PRThread *RCThread::Self() 115 { 116 return PR_GetCurrentThread(); 117 } 118 119 RCThread::Scope RCThread::GetScope() const 120 { 121 return (RCThread::Scope)PR_GetThreadScope(identity); 122 } 123 124 RCThread::State RCThread::GetState() const 125 { 126 return (RCThread::State)PR_GetThreadState(identity); 127 } 128 129 RCThread::Priority RCThread::GetPriority() const 130 { 131 return (RCThread::Priority)PR_GetThreadPriority(identity); 132 } 133 134 static void _rc_PDDestructor(RCThreadPrivateData* privateData) 135 { 136 PR_ASSERT(NULL != privateData); 137 privateData->Release(); 138 } 139 140 static PRThreadPrivateDTOR _tpd_dtor = (PRThreadPrivateDTOR)_rc_PDDestructor; 141 142 PRStatus RCThread::NewPrivateIndex(PRUintn* index) 143 { 144 return PR_NewThreadPrivateIndex(index, _tpd_dtor); 145 } 146 147 PRStatus RCThread::SetPrivateData(PRUintn index) 148 { 149 return PR_SetThreadPrivate(index, NULL); 150 } 151 152 PRStatus RCThread::SetPrivateData(PRUintn index, RCThreadPrivateData* data) 153 { 154 return PR_SetThreadPrivate(index, data); 155 } 156 157 RCThreadPrivateData* RCThread::GetPrivateData(PRUintn index) 158 { 159 return (RCThreadPrivateData*)PR_GetThreadPrivate(index); 160 } 161 162 PRStatus RCThread::Sleep(const RCInterval& ticks) 163 { 164 PRIntervalTime tmo = ticks; 165 return PR_Sleep(tmo); 166 } 167 168 RCPrimordialThread *RCThread::WrapPrimordialThread() 169 { 170 /* 171 ** This needs to take more care in insuring that the thread 172 ** being wrapped is really the primordial thread. This code 173 ** is assuming that the caller is the primordial thread, and 174 ** there's nothing to insure that. 175 */ 176 if (NULL == primordial) 177 { 178 /* it doesn't have to be perfect */ 179 RCPrimordialThread *me = new RCPrimordialThread(); 180 PR_ASSERT(NULL != me); 181 if (NULL == primordial) 182 { 183 primordial = me; 184 me->execution = RCThread::ex_started; 185 me->identity = PR_GetCurrentThread(); 186 } 187 else { 188 delete me; /* somebody beat us to it */ 189 } 190 } 191 return primordial; 192 } /* RCThread::WrapPrimordialThread */ 193 194 RCPrimordialThread::RCPrimordialThread(): RCThread() { } 195 196 RCPrimordialThread::~RCPrimordialThread() { } 197 198 void RCPrimordialThread::RootFunction() 199 { 200 PR_NOT_REACHED("Primordial thread calling root function"); 201 } /* RCPrimordialThread::RootFunction */ 202 203 PRStatus RCPrimordialThread::Cleanup() { 204 return PR_Cleanup(); 205 } 206 207 PRStatus RCPrimordialThread::SetVirtualProcessors(PRIntn count) 208 { 209 PR_SetConcurrency(count); 210 return PR_SUCCESS; 211 } /* SetVirutalProcessors */ 212 213 RCThreadPrivateData::RCThreadPrivateData() { } 214 215 RCThreadPrivateData::RCThreadPrivateData( 216 const RCThreadPrivateData& him) { } 217 218 RCThreadPrivateData::~RCThreadPrivateData() { } 219 220 /* RCThread.c */