xpcom/glue/nsThreadUtils.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "nsThreadUtils.h"
michael@0 8 #include "mozilla/Attributes.h"
michael@0 9 #include "mozilla/Likely.h"
michael@0 10
michael@0 11 #ifdef MOZILLA_INTERNAL_API
michael@0 12 # include "nsThreadManager.h"
michael@0 13 #else
michael@0 14 # include "nsXPCOMCIDInternal.h"
michael@0 15 # include "nsIThreadManager.h"
michael@0 16 # include "nsServiceManagerUtils.h"
michael@0 17 #endif
michael@0 18
michael@0 19 #ifdef XP_WIN
michael@0 20 #include <windows.h>
michael@0 21 #include "mozilla/WindowsVersion.h"
michael@0 22 using mozilla::IsVistaOrLater;
michael@0 23 #elif defined(XP_MACOSX)
michael@0 24 #include <sys/resource.h>
michael@0 25 #endif
michael@0 26
michael@0 27 #include <pratom.h>
michael@0 28 #include <prthread.h>
michael@0 29
michael@0 30 #ifndef XPCOM_GLUE_AVOID_NSPR
michael@0 31
michael@0 32 NS_IMPL_ISUPPORTS(nsRunnable, nsIRunnable)
michael@0 33
michael@0 34 NS_IMETHODIMP
michael@0 35 nsRunnable::Run()
michael@0 36 {
michael@0 37 // Do nothing
michael@0 38 return NS_OK;
michael@0 39 }
michael@0 40
michael@0 41 NS_IMPL_ISUPPORTS(nsCancelableRunnable, nsICancelableRunnable,
michael@0 42 nsIRunnable)
michael@0 43
michael@0 44 NS_IMETHODIMP
michael@0 45 nsCancelableRunnable::Run()
michael@0 46 {
michael@0 47 // Do nothing
michael@0 48 return NS_OK;
michael@0 49 }
michael@0 50
michael@0 51 NS_IMETHODIMP
michael@0 52 nsCancelableRunnable::Cancel()
michael@0 53 {
michael@0 54 // Do nothing
michael@0 55 return NS_OK;
michael@0 56 }
michael@0 57
michael@0 58 #endif // XPCOM_GLUE_AVOID_NSPR
michael@0 59
michael@0 60 //-----------------------------------------------------------------------------
michael@0 61
michael@0 62 NS_METHOD
michael@0 63 NS_NewThread(nsIThread **result, nsIRunnable *event, uint32_t stackSize)
michael@0 64 {
michael@0 65 nsCOMPtr<nsIThread> thread;
michael@0 66 #ifdef MOZILLA_INTERNAL_API
michael@0 67 nsresult rv = nsThreadManager::get()->
michael@0 68 nsThreadManager::NewThread(0, stackSize, getter_AddRefs(thread));
michael@0 69 #else
michael@0 70 nsresult rv;
michael@0 71 nsCOMPtr<nsIThreadManager> mgr =
michael@0 72 do_GetService(NS_THREADMANAGER_CONTRACTID, &rv);
michael@0 73 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 74 return rv;
michael@0 75
michael@0 76 rv = mgr->NewThread(0, stackSize, getter_AddRefs(thread));
michael@0 77 #endif
michael@0 78 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 79 return rv;
michael@0 80
michael@0 81 if (event) {
michael@0 82 rv = thread->Dispatch(event, NS_DISPATCH_NORMAL);
michael@0 83 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 84 return rv;
michael@0 85 }
michael@0 86
michael@0 87 *result = nullptr;
michael@0 88 thread.swap(*result);
michael@0 89 return NS_OK;
michael@0 90 }
michael@0 91
michael@0 92 NS_METHOD
michael@0 93 NS_GetCurrentThread(nsIThread **result)
michael@0 94 {
michael@0 95 #ifdef MOZILLA_INTERNAL_API
michael@0 96 return nsThreadManager::get()->nsThreadManager::GetCurrentThread(result);
michael@0 97 #else
michael@0 98 nsresult rv;
michael@0 99 nsCOMPtr<nsIThreadManager> mgr =
michael@0 100 do_GetService(NS_THREADMANAGER_CONTRACTID, &rv);
michael@0 101 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 102 return rv;
michael@0 103 return mgr->GetCurrentThread(result);
michael@0 104 #endif
michael@0 105 }
michael@0 106
michael@0 107 NS_METHOD
michael@0 108 NS_GetMainThread(nsIThread **result)
michael@0 109 {
michael@0 110 #ifdef MOZILLA_INTERNAL_API
michael@0 111 return nsThreadManager::get()->nsThreadManager::GetMainThread(result);
michael@0 112 #else
michael@0 113 nsresult rv;
michael@0 114 nsCOMPtr<nsIThreadManager> mgr =
michael@0 115 do_GetService(NS_THREADMANAGER_CONTRACTID, &rv);
michael@0 116 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 117 return rv;
michael@0 118 return mgr->GetMainThread(result);
michael@0 119 #endif
michael@0 120 }
michael@0 121
michael@0 122 #if defined(MOZILLA_INTERNAL_API) && defined(XP_WIN)
michael@0 123 extern DWORD gTLSThreadIDIndex;
michael@0 124 bool
michael@0 125 NS_IsMainThread()
michael@0 126 {
michael@0 127 return TlsGetValue(gTLSThreadIDIndex) == (void*) mozilla::threads::Main;
michael@0 128 }
michael@0 129 #elif defined(MOZILLA_INTERNAL_API) && defined(NS_TLS)
michael@0 130 #ifdef MOZ_ASAN
michael@0 131 // Temporary workaround, see bug 895845
michael@0 132 bool NS_IsMainThread()
michael@0 133 {
michael@0 134 return gTLSThreadID == mozilla::threads::Main;
michael@0 135 }
michael@0 136 #else
michael@0 137 // NS_IsMainThread() is defined inline in MainThreadUtils.h
michael@0 138 #endif
michael@0 139 #else
michael@0 140 #ifdef MOZILLA_INTERNAL_API
michael@0 141 bool NS_IsMainThread()
michael@0 142 {
michael@0 143 bool result = false;
michael@0 144 nsThreadManager::get()->nsThreadManager::GetIsMainThread(&result);
michael@0 145 return bool(result);
michael@0 146 }
michael@0 147 #else
michael@0 148 bool NS_IsMainThread()
michael@0 149 {
michael@0 150 bool result = false;
michael@0 151 nsCOMPtr<nsIThreadManager> mgr =
michael@0 152 do_GetService(NS_THREADMANAGER_CONTRACTID);
michael@0 153 if (mgr)
michael@0 154 mgr->GetIsMainThread(&result);
michael@0 155 return bool(result);
michael@0 156 }
michael@0 157 #endif
michael@0 158 #endif
michael@0 159
michael@0 160 NS_METHOD
michael@0 161 NS_DispatchToCurrentThread(nsIRunnable *event)
michael@0 162 {
michael@0 163 #ifdef MOZILLA_INTERNAL_API
michael@0 164 nsIThread *thread = NS_GetCurrentThread();
michael@0 165 if (!thread) { return NS_ERROR_UNEXPECTED; }
michael@0 166 #else
michael@0 167 nsCOMPtr<nsIThread> thread;
michael@0 168 nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread));
michael@0 169 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 170 return rv;
michael@0 171 #endif
michael@0 172 return thread->Dispatch(event, NS_DISPATCH_NORMAL);
michael@0 173 }
michael@0 174
michael@0 175 NS_METHOD
michael@0 176 NS_DispatchToMainThread(nsIRunnable *event, uint32_t dispatchFlags)
michael@0 177 {
michael@0 178 nsCOMPtr<nsIThread> thread;
michael@0 179 nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
michael@0 180 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 181 return rv;
michael@0 182 return thread->Dispatch(event, dispatchFlags);
michael@0 183 }
michael@0 184
michael@0 185 #ifndef XPCOM_GLUE_AVOID_NSPR
michael@0 186 NS_METHOD
michael@0 187 NS_ProcessPendingEvents(nsIThread *thread, PRIntervalTime timeout)
michael@0 188 {
michael@0 189 nsresult rv = NS_OK;
michael@0 190
michael@0 191 #ifdef MOZILLA_INTERNAL_API
michael@0 192 if (!thread) {
michael@0 193 thread = NS_GetCurrentThread();
michael@0 194 if (NS_WARN_IF(!thread))
michael@0 195 return NS_ERROR_UNEXPECTED;
michael@0 196 }
michael@0 197 #else
michael@0 198 nsCOMPtr<nsIThread> current;
michael@0 199 if (!thread) {
michael@0 200 rv = NS_GetCurrentThread(getter_AddRefs(current));
michael@0 201 if (NS_WARN_IF(NS_FAILED(rv)))
michael@0 202 return rv;
michael@0 203 thread = current.get();
michael@0 204 }
michael@0 205 #endif
michael@0 206
michael@0 207 PRIntervalTime start = PR_IntervalNow();
michael@0 208 for (;;) {
michael@0 209 bool processedEvent;
michael@0 210 rv = thread->ProcessNextEvent(false, &processedEvent);
michael@0 211 if (NS_FAILED(rv) || !processedEvent)
michael@0 212 break;
michael@0 213 if (PR_IntervalNow() - start > timeout)
michael@0 214 break;
michael@0 215 }
michael@0 216 return rv;
michael@0 217 }
michael@0 218 #endif // XPCOM_GLUE_AVOID_NSPR
michael@0 219
michael@0 220 inline bool
michael@0 221 hasPendingEvents(nsIThread *thread)
michael@0 222 {
michael@0 223 bool val;
michael@0 224 return NS_SUCCEEDED(thread->HasPendingEvents(&val)) && val;
michael@0 225 }
michael@0 226
michael@0 227 bool
michael@0 228 NS_HasPendingEvents(nsIThread *thread)
michael@0 229 {
michael@0 230 if (!thread) {
michael@0 231 #ifndef MOZILLA_INTERNAL_API
michael@0 232 nsCOMPtr<nsIThread> current;
michael@0 233 NS_GetCurrentThread(getter_AddRefs(current));
michael@0 234 return hasPendingEvents(current);
michael@0 235 #else
michael@0 236 thread = NS_GetCurrentThread();
michael@0 237 if (NS_WARN_IF(!thread))
michael@0 238 return false;
michael@0 239 #endif
michael@0 240 }
michael@0 241 return hasPendingEvents(thread);
michael@0 242 }
michael@0 243
michael@0 244 bool
michael@0 245 NS_ProcessNextEvent(nsIThread *thread, bool mayWait)
michael@0 246 {
michael@0 247 #ifdef MOZILLA_INTERNAL_API
michael@0 248 if (!thread) {
michael@0 249 thread = NS_GetCurrentThread();
michael@0 250 if (NS_WARN_IF(!thread))
michael@0 251 return false;
michael@0 252 }
michael@0 253 #else
michael@0 254 nsCOMPtr<nsIThread> current;
michael@0 255 if (!thread) {
michael@0 256 NS_GetCurrentThread(getter_AddRefs(current));
michael@0 257 if (NS_WARN_IF(!current))
michael@0 258 return false;
michael@0 259 thread = current.get();
michael@0 260 }
michael@0 261 #endif
michael@0 262 bool val;
michael@0 263 return NS_SUCCEEDED(thread->ProcessNextEvent(mayWait, &val)) && val;
michael@0 264 }
michael@0 265
michael@0 266 #ifndef XPCOM_GLUE_AVOID_NSPR
michael@0 267
michael@0 268 namespace {
michael@0 269
michael@0 270 class nsNameThreadRunnable MOZ_FINAL : public nsIRunnable
michael@0 271 {
michael@0 272 public:
michael@0 273 nsNameThreadRunnable(const nsACString &name) : mName(name) { }
michael@0 274
michael@0 275 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 276 NS_DECL_NSIRUNNABLE
michael@0 277
michael@0 278 protected:
michael@0 279 const nsCString mName;
michael@0 280 };
michael@0 281
michael@0 282 NS_IMPL_ISUPPORTS(nsNameThreadRunnable, nsIRunnable)
michael@0 283
michael@0 284 NS_IMETHODIMP
michael@0 285 nsNameThreadRunnable::Run()
michael@0 286 {
michael@0 287 PR_SetCurrentThreadName(mName.BeginReading());
michael@0 288 return NS_OK;
michael@0 289 }
michael@0 290
michael@0 291 } // anonymous namespace
michael@0 292
michael@0 293 void
michael@0 294 NS_SetThreadName(nsIThread *thread, const nsACString &name)
michael@0 295 {
michael@0 296 if (!thread)
michael@0 297 return;
michael@0 298
michael@0 299 thread->Dispatch(new nsNameThreadRunnable(name),
michael@0 300 nsIEventTarget::DISPATCH_NORMAL);
michael@0 301 }
michael@0 302
michael@0 303 #else // !XPCOM_GLUE_AVOID_NSPR
michael@0 304
michael@0 305 void
michael@0 306 NS_SetThreadName(nsIThread *thread, const nsACString &name)
michael@0 307 {
michael@0 308 // No NSPR, no love.
michael@0 309 }
michael@0 310
michael@0 311 #endif
michael@0 312
michael@0 313 #ifdef MOZILLA_INTERNAL_API
michael@0 314 nsIThread *
michael@0 315 NS_GetCurrentThread() {
michael@0 316 return nsThreadManager::get()->GetCurrentThread();
michael@0 317 }
michael@0 318 #endif
michael@0 319
michael@0 320 // nsThreadPoolNaming
michael@0 321 void
michael@0 322 nsThreadPoolNaming::SetThreadPoolName(const nsACString & aPoolName,
michael@0 323 nsIThread * aThread)
michael@0 324 {
michael@0 325 nsCString name(aPoolName);
michael@0 326 name.Append(NS_LITERAL_CSTRING(" #"));
michael@0 327 name.AppendInt(++mCounter, 10); // The counter is declared as volatile
michael@0 328
michael@0 329 if (aThread) {
michael@0 330 // Set on the target thread
michael@0 331 NS_SetThreadName(aThread, name);
michael@0 332 }
michael@0 333 else {
michael@0 334 // Set on the current thread
michael@0 335 PR_SetCurrentThreadName(name.BeginReading());
michael@0 336 }
michael@0 337 }
michael@0 338
michael@0 339 // nsAutoLowPriorityIO
michael@0 340 nsAutoLowPriorityIO::nsAutoLowPriorityIO()
michael@0 341 {
michael@0 342 #if defined(XP_WIN)
michael@0 343 lowIOPrioritySet = IsVistaOrLater() &&
michael@0 344 SetThreadPriority(GetCurrentThread(),
michael@0 345 THREAD_MODE_BACKGROUND_BEGIN);
michael@0 346 #elif defined(XP_MACOSX)
michael@0 347 oldPriority = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD);
michael@0 348 lowIOPrioritySet = oldPriority != -1 &&
michael@0 349 setiopolicy_np(IOPOL_TYPE_DISK,
michael@0 350 IOPOL_SCOPE_THREAD,
michael@0 351 IOPOL_THROTTLE) != -1;
michael@0 352 #else
michael@0 353 lowIOPrioritySet = false;
michael@0 354 #endif
michael@0 355 }
michael@0 356
michael@0 357 nsAutoLowPriorityIO::~nsAutoLowPriorityIO()
michael@0 358 {
michael@0 359 #if defined(XP_WIN)
michael@0 360 if (MOZ_LIKELY(lowIOPrioritySet)) {
michael@0 361 // On Windows the old thread priority is automatically restored
michael@0 362 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
michael@0 363 }
michael@0 364 #elif defined(XP_MACOSX)
michael@0 365 if (MOZ_LIKELY(lowIOPrioritySet)) {
michael@0 366 setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_THREAD, oldPriority);
michael@0 367 }
michael@0 368 #endif
michael@0 369 }
michael@0 370

mercurial