1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/nsThreadUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,370 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsThreadUtils.h" 1.11 +#include "mozilla/Attributes.h" 1.12 +#include "mozilla/Likely.h" 1.13 + 1.14 +#ifdef MOZILLA_INTERNAL_API 1.15 +# include "nsThreadManager.h" 1.16 +#else 1.17 +# include "nsXPCOMCIDInternal.h" 1.18 +# include "nsIThreadManager.h" 1.19 +# include "nsServiceManagerUtils.h" 1.20 +#endif 1.21 + 1.22 +#ifdef XP_WIN 1.23 +#include <windows.h> 1.24 +#include "mozilla/WindowsVersion.h" 1.25 +using mozilla::IsVistaOrLater; 1.26 +#elif defined(XP_MACOSX) 1.27 +#include <sys/resource.h> 1.28 +#endif 1.29 + 1.30 +#include <pratom.h> 1.31 +#include <prthread.h> 1.32 + 1.33 +#ifndef XPCOM_GLUE_AVOID_NSPR 1.34 + 1.35 +NS_IMPL_ISUPPORTS(nsRunnable, nsIRunnable) 1.36 + 1.37 +NS_IMETHODIMP 1.38 +nsRunnable::Run() 1.39 +{ 1.40 + // Do nothing 1.41 + return NS_OK; 1.42 +} 1.43 + 1.44 +NS_IMPL_ISUPPORTS(nsCancelableRunnable, nsICancelableRunnable, 1.45 + nsIRunnable) 1.46 + 1.47 +NS_IMETHODIMP 1.48 +nsCancelableRunnable::Run() 1.49 +{ 1.50 + // Do nothing 1.51 + return NS_OK; 1.52 +} 1.53 + 1.54 +NS_IMETHODIMP 1.55 +nsCancelableRunnable::Cancel() 1.56 +{ 1.57 + // Do nothing 1.58 + return NS_OK; 1.59 +} 1.60 + 1.61 +#endif // XPCOM_GLUE_AVOID_NSPR 1.62 + 1.63 +//----------------------------------------------------------------------------- 1.64 + 1.65 +NS_METHOD 1.66 +NS_NewThread(nsIThread **result, nsIRunnable *event, uint32_t stackSize) 1.67 +{ 1.68 + nsCOMPtr<nsIThread> thread; 1.69 +#ifdef MOZILLA_INTERNAL_API 1.70 + nsresult rv = nsThreadManager::get()-> 1.71 + nsThreadManager::NewThread(0, stackSize, getter_AddRefs(thread)); 1.72 +#else 1.73 + nsresult rv; 1.74 + nsCOMPtr<nsIThreadManager> mgr = 1.75 + do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); 1.76 + if (NS_WARN_IF(NS_FAILED(rv))) 1.77 + return rv; 1.78 + 1.79 + rv = mgr->NewThread(0, stackSize, getter_AddRefs(thread)); 1.80 +#endif 1.81 + if (NS_WARN_IF(NS_FAILED(rv))) 1.82 + return rv; 1.83 + 1.84 + if (event) { 1.85 + rv = thread->Dispatch(event, NS_DISPATCH_NORMAL); 1.86 + if (NS_WARN_IF(NS_FAILED(rv))) 1.87 + return rv; 1.88 + } 1.89 + 1.90 + *result = nullptr; 1.91 + thread.swap(*result); 1.92 + return NS_OK; 1.93 +} 1.94 + 1.95 +NS_METHOD 1.96 +NS_GetCurrentThread(nsIThread **result) 1.97 +{ 1.98 +#ifdef MOZILLA_INTERNAL_API 1.99 + return nsThreadManager::get()->nsThreadManager::GetCurrentThread(result); 1.100 +#else 1.101 + nsresult rv; 1.102 + nsCOMPtr<nsIThreadManager> mgr = 1.103 + do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); 1.104 + if (NS_WARN_IF(NS_FAILED(rv))) 1.105 + return rv; 1.106 + return mgr->GetCurrentThread(result); 1.107 +#endif 1.108 +} 1.109 + 1.110 +NS_METHOD 1.111 +NS_GetMainThread(nsIThread **result) 1.112 +{ 1.113 +#ifdef MOZILLA_INTERNAL_API 1.114 + return nsThreadManager::get()->nsThreadManager::GetMainThread(result); 1.115 +#else 1.116 + nsresult rv; 1.117 + nsCOMPtr<nsIThreadManager> mgr = 1.118 + do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); 1.119 + if (NS_WARN_IF(NS_FAILED(rv))) 1.120 + return rv; 1.121 + return mgr->GetMainThread(result); 1.122 +#endif 1.123 +} 1.124 + 1.125 +#if defined(MOZILLA_INTERNAL_API) && defined(XP_WIN) 1.126 +extern DWORD gTLSThreadIDIndex; 1.127 +bool 1.128 +NS_IsMainThread() 1.129 +{ 1.130 + return TlsGetValue(gTLSThreadIDIndex) == (void*) mozilla::threads::Main; 1.131 +} 1.132 +#elif defined(MOZILLA_INTERNAL_API) && defined(NS_TLS) 1.133 +#ifdef MOZ_ASAN 1.134 +// Temporary workaround, see bug 895845 1.135 +bool NS_IsMainThread() 1.136 +{ 1.137 + return gTLSThreadID == mozilla::threads::Main; 1.138 +} 1.139 +#else 1.140 +// NS_IsMainThread() is defined inline in MainThreadUtils.h 1.141 +#endif 1.142 +#else 1.143 +#ifdef MOZILLA_INTERNAL_API 1.144 +bool NS_IsMainThread() 1.145 +{ 1.146 + bool result = false; 1.147 + nsThreadManager::get()->nsThreadManager::GetIsMainThread(&result); 1.148 + return bool(result); 1.149 +} 1.150 +#else 1.151 +bool NS_IsMainThread() 1.152 +{ 1.153 + bool result = false; 1.154 + nsCOMPtr<nsIThreadManager> mgr = 1.155 + do_GetService(NS_THREADMANAGER_CONTRACTID); 1.156 + if (mgr) 1.157 + mgr->GetIsMainThread(&result); 1.158 + return bool(result); 1.159 +} 1.160 +#endif 1.161 +#endif 1.162 + 1.163 +NS_METHOD 1.164 +NS_DispatchToCurrentThread(nsIRunnable *event) 1.165 +{ 1.166 +#ifdef MOZILLA_INTERNAL_API 1.167 + nsIThread *thread = NS_GetCurrentThread(); 1.168 + if (!thread) { return NS_ERROR_UNEXPECTED; } 1.169 +#else 1.170 + nsCOMPtr<nsIThread> thread; 1.171 + nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread)); 1.172 + if (NS_WARN_IF(NS_FAILED(rv))) 1.173 + return rv; 1.174 +#endif 1.175 + return thread->Dispatch(event, NS_DISPATCH_NORMAL); 1.176 +} 1.177 + 1.178 +NS_METHOD 1.179 +NS_DispatchToMainThread(nsIRunnable *event, uint32_t dispatchFlags) 1.180 +{ 1.181 + nsCOMPtr<nsIThread> thread; 1.182 + nsresult rv = NS_GetMainThread(getter_AddRefs(thread)); 1.183 + if (NS_WARN_IF(NS_FAILED(rv))) 1.184 + return rv; 1.185 + return thread->Dispatch(event, dispatchFlags); 1.186 +} 1.187 + 1.188 +#ifndef XPCOM_GLUE_AVOID_NSPR 1.189 +NS_METHOD 1.190 +NS_ProcessPendingEvents(nsIThread *thread, PRIntervalTime timeout) 1.191 +{ 1.192 + nsresult rv = NS_OK; 1.193 + 1.194 +#ifdef MOZILLA_INTERNAL_API 1.195 + if (!thread) { 1.196 + thread = NS_GetCurrentThread(); 1.197 + if (NS_WARN_IF(!thread)) 1.198 + return NS_ERROR_UNEXPECTED; 1.199 + } 1.200 +#else 1.201 + nsCOMPtr<nsIThread> current; 1.202 + if (!thread) { 1.203 + rv = NS_GetCurrentThread(getter_AddRefs(current)); 1.204 + if (NS_WARN_IF(NS_FAILED(rv))) 1.205 + return rv; 1.206 + thread = current.get(); 1.207 + } 1.208 +#endif 1.209 + 1.210 + PRIntervalTime start = PR_IntervalNow(); 1.211 + for (;;) { 1.212 + bool processedEvent; 1.213 + rv = thread->ProcessNextEvent(false, &processedEvent); 1.214 + if (NS_FAILED(rv) || !processedEvent) 1.215 + break; 1.216 + if (PR_IntervalNow() - start > timeout) 1.217 + break; 1.218 + } 1.219 + return rv; 1.220 +} 1.221 +#endif // XPCOM_GLUE_AVOID_NSPR 1.222 + 1.223 +inline bool 1.224 +hasPendingEvents(nsIThread *thread) 1.225 +{ 1.226 + bool val; 1.227 + return NS_SUCCEEDED(thread->HasPendingEvents(&val)) && val; 1.228 +} 1.229 + 1.230 +bool 1.231 +NS_HasPendingEvents(nsIThread *thread) 1.232 +{ 1.233 + if (!thread) { 1.234 +#ifndef MOZILLA_INTERNAL_API 1.235 + nsCOMPtr<nsIThread> current; 1.236 + NS_GetCurrentThread(getter_AddRefs(current)); 1.237 + return hasPendingEvents(current); 1.238 +#else 1.239 + thread = NS_GetCurrentThread(); 1.240 + if (NS_WARN_IF(!thread)) 1.241 + return false; 1.242 +#endif 1.243 + } 1.244 + return hasPendingEvents(thread); 1.245 +} 1.246 + 1.247 +bool 1.248 +NS_ProcessNextEvent(nsIThread *thread, bool mayWait) 1.249 +{ 1.250 +#ifdef MOZILLA_INTERNAL_API 1.251 + if (!thread) { 1.252 + thread = NS_GetCurrentThread(); 1.253 + if (NS_WARN_IF(!thread)) 1.254 + return false; 1.255 + } 1.256 +#else 1.257 + nsCOMPtr<nsIThread> current; 1.258 + if (!thread) { 1.259 + NS_GetCurrentThread(getter_AddRefs(current)); 1.260 + if (NS_WARN_IF(!current)) 1.261 + return false; 1.262 + thread = current.get(); 1.263 + } 1.264 +#endif 1.265 + bool val; 1.266 + return NS_SUCCEEDED(thread->ProcessNextEvent(mayWait, &val)) && val; 1.267 +} 1.268 + 1.269 +#ifndef XPCOM_GLUE_AVOID_NSPR 1.270 + 1.271 +namespace { 1.272 + 1.273 +class nsNameThreadRunnable MOZ_FINAL : public nsIRunnable 1.274 +{ 1.275 +public: 1.276 + nsNameThreadRunnable(const nsACString &name) : mName(name) { } 1.277 + 1.278 + NS_DECL_THREADSAFE_ISUPPORTS 1.279 + NS_DECL_NSIRUNNABLE 1.280 + 1.281 +protected: 1.282 + const nsCString mName; 1.283 +}; 1.284 + 1.285 +NS_IMPL_ISUPPORTS(nsNameThreadRunnable, nsIRunnable) 1.286 + 1.287 +NS_IMETHODIMP 1.288 +nsNameThreadRunnable::Run() 1.289 +{ 1.290 + PR_SetCurrentThreadName(mName.BeginReading()); 1.291 + return NS_OK; 1.292 +} 1.293 + 1.294 +} // anonymous namespace 1.295 + 1.296 +void 1.297 +NS_SetThreadName(nsIThread *thread, const nsACString &name) 1.298 +{ 1.299 + if (!thread) 1.300 + return; 1.301 + 1.302 + thread->Dispatch(new nsNameThreadRunnable(name), 1.303 + nsIEventTarget::DISPATCH_NORMAL); 1.304 +} 1.305 + 1.306 +#else // !XPCOM_GLUE_AVOID_NSPR 1.307 + 1.308 +void 1.309 +NS_SetThreadName(nsIThread *thread, const nsACString &name) 1.310 +{ 1.311 + // No NSPR, no love. 1.312 +} 1.313 + 1.314 +#endif 1.315 + 1.316 +#ifdef MOZILLA_INTERNAL_API 1.317 +nsIThread * 1.318 +NS_GetCurrentThread() { 1.319 + return nsThreadManager::get()->GetCurrentThread(); 1.320 +} 1.321 +#endif 1.322 + 1.323 +// nsThreadPoolNaming 1.324 +void 1.325 +nsThreadPoolNaming::SetThreadPoolName(const nsACString & aPoolName, 1.326 + nsIThread * aThread) 1.327 +{ 1.328 + nsCString name(aPoolName); 1.329 + name.Append(NS_LITERAL_CSTRING(" #")); 1.330 + name.AppendInt(++mCounter, 10); // The counter is declared as volatile 1.331 + 1.332 + if (aThread) { 1.333 + // Set on the target thread 1.334 + NS_SetThreadName(aThread, name); 1.335 + } 1.336 + else { 1.337 + // Set on the current thread 1.338 + PR_SetCurrentThreadName(name.BeginReading()); 1.339 + } 1.340 +} 1.341 + 1.342 +// nsAutoLowPriorityIO 1.343 +nsAutoLowPriorityIO::nsAutoLowPriorityIO() 1.344 +{ 1.345 +#if defined(XP_WIN) 1.346 + lowIOPrioritySet = IsVistaOrLater() && 1.347 + SetThreadPriority(GetCurrentThread(), 1.348 + THREAD_MODE_BACKGROUND_BEGIN); 1.349 +#elif defined(XP_MACOSX) 1.350 + oldPriority = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD); 1.351 + lowIOPrioritySet = oldPriority != -1 && 1.352 + setiopolicy_np(IOPOL_TYPE_DISK, 1.353 + IOPOL_SCOPE_THREAD, 1.354 + IOPOL_THROTTLE) != -1; 1.355 +#else 1.356 + lowIOPrioritySet = false; 1.357 +#endif 1.358 +} 1.359 + 1.360 +nsAutoLowPriorityIO::~nsAutoLowPriorityIO() 1.361 +{ 1.362 +#if defined(XP_WIN) 1.363 + if (MOZ_LIKELY(lowIOPrioritySet)) { 1.364 + // On Windows the old thread priority is automatically restored 1.365 + SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END); 1.366 + } 1.367 +#elif defined(XP_MACOSX) 1.368 + if (MOZ_LIKELY(lowIOPrioritySet)) { 1.369 + setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, oldPriority); 1.370 + } 1.371 +#endif 1.372 +} 1.373 +