Tue, 06 Jan 2015 21:39:09 +0100
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.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsThreadUtils_h__
8 #define nsThreadUtils_h__
10 #include "prthread.h"
11 #include "prinrval.h"
12 #include "MainThreadUtils.h"
13 #include "nsIThreadManager.h"
14 #include "nsIThread.h"
15 #include "nsIRunnable.h"
16 #include "nsICancelableRunnable.h"
17 #include "nsStringGlue.h"
18 #include "nsCOMPtr.h"
19 #include "nsAutoPtr.h"
20 #include "mozilla/Likely.h"
22 //-----------------------------------------------------------------------------
23 // These methods are alternatives to the methods on nsIThreadManager, provided
24 // for convenience.
26 /**
27 * Set name of the target thread. This operation is asynchronous.
28 */
29 extern NS_COM_GLUE void
30 NS_SetThreadName(nsIThread *thread, const nsACString &name);
32 /**
33 * Static length version of the above function checking length of the
34 * name at compile time.
35 */
36 template <size_t LEN>
37 inline NS_COM_GLUE void
38 NS_SetThreadName(nsIThread *thread, const char (&name)[LEN])
39 {
40 static_assert(LEN <= 16,
41 "Thread name must be no more than 16 characters");
42 NS_SetThreadName(thread, nsDependentCString(name));
43 }
45 /**
46 * Create a new thread, and optionally provide an initial event for the thread.
47 *
48 * @param result
49 * The resulting nsIThread object.
50 * @param initialEvent
51 * The initial event to run on this thread. This parameter may be null.
52 * @param stackSize
53 * The size in bytes to reserve for the thread's stack.
54 *
55 * @returns NS_ERROR_INVALID_ARG
56 * Indicates that the given name is not unique.
57 */
58 extern NS_COM_GLUE NS_METHOD
59 NS_NewThread(nsIThread **result,
60 nsIRunnable *initialEvent = nullptr,
61 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
63 /**
64 * Creates a named thread, otherwise the same as NS_NewThread
65 */
66 template <size_t LEN>
67 inline NS_METHOD
68 NS_NewNamedThread(const char (&name)[LEN],
69 nsIThread **result,
70 nsIRunnable *initialEvent = nullptr,
71 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE)
72 {
73 // Hold a ref while dispatching the initial event to match NS_NewThread()
74 nsCOMPtr<nsIThread> thread;
75 nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr, stackSize);
76 if (NS_WARN_IF(NS_FAILED(rv)))
77 return rv;
78 NS_SetThreadName<LEN>(thread, name);
79 if (initialEvent) {
80 rv = thread->Dispatch(initialEvent, NS_DISPATCH_NORMAL);
81 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Initial event dispatch failed");
82 }
84 *result = nullptr;
85 thread.swap(*result);
86 return rv;
87 }
89 /**
90 * Get a reference to the current thread.
91 *
92 * @param result
93 * The resulting nsIThread object.
94 */
95 extern NS_COM_GLUE NS_METHOD
96 NS_GetCurrentThread(nsIThread **result);
98 /**
99 * Dispatch the given event to the current thread.
100 *
101 * @param event
102 * The event to dispatch.
103 *
104 * @returns NS_ERROR_INVALID_ARG
105 * If event is null.
106 */
107 extern NS_COM_GLUE NS_METHOD
108 NS_DispatchToCurrentThread(nsIRunnable *event);
110 /**
111 * Dispatch the given event to the main thread.
112 *
113 * @param event
114 * The event to dispatch.
115 * @param dispatchFlags
116 * The flags to pass to the main thread's dispatch method.
117 *
118 * @returns NS_ERROR_INVALID_ARG
119 * If event is null.
120 */
121 extern NS_COM_GLUE NS_METHOD
122 NS_DispatchToMainThread(nsIRunnable *event,
123 uint32_t dispatchFlags = NS_DISPATCH_NORMAL);
125 #ifndef XPCOM_GLUE_AVOID_NSPR
126 /**
127 * Process all pending events for the given thread before returning. This
128 * method simply calls ProcessNextEvent on the thread while HasPendingEvents
129 * continues to return true and the time spent in NS_ProcessPendingEvents
130 * does not exceed the given timeout value.
131 *
132 * @param thread
133 * The thread object for which to process pending events. If null, then
134 * events will be processed for the current thread.
135 * @param timeout
136 * The maximum number of milliseconds to spend processing pending events.
137 * Events are not pre-empted to honor this timeout. Rather, the timeout
138 * value is simply used to determine whether or not to process another event.
139 * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout.
140 */
141 extern NS_COM_GLUE NS_METHOD
142 NS_ProcessPendingEvents(nsIThread *thread,
143 PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT);
144 #endif
146 /**
147 * Shortcut for nsIThread::HasPendingEvents.
148 *
149 * It is an error to call this function when the given thread is not the
150 * current thread. This function will return false if called from some
151 * other thread.
152 *
153 * @param thread
154 * The current thread or null.
155 *
156 * @returns
157 * A boolean value that if "true" indicates that there are pending events
158 * in the current thread's event queue.
159 */
160 extern NS_COM_GLUE bool
161 NS_HasPendingEvents(nsIThread *thread = nullptr);
163 /**
164 * Shortcut for nsIThread::ProcessNextEvent.
165 *
166 * It is an error to call this function when the given thread is not the
167 * current thread. This function will simply return false if called
168 * from some other thread.
169 *
170 * @param thread
171 * The current thread or null.
172 * @param mayWait
173 * A boolean parameter that if "true" indicates that the method may block
174 * the calling thread to wait for a pending event.
175 *
176 * @returns
177 * A boolean value that if "true" indicates that an event from the current
178 * thread's event queue was processed.
179 */
180 extern NS_COM_GLUE bool
181 NS_ProcessNextEvent(nsIThread *thread = nullptr, bool mayWait = true);
183 //-----------------------------------------------------------------------------
184 // Helpers that work with nsCOMPtr:
186 inline already_AddRefed<nsIThread>
187 do_GetCurrentThread() {
188 nsIThread *thread = nullptr;
189 NS_GetCurrentThread(&thread);
190 return already_AddRefed<nsIThread>(thread);
191 }
193 inline already_AddRefed<nsIThread>
194 do_GetMainThread() {
195 nsIThread *thread = nullptr;
196 NS_GetMainThread(&thread);
197 return already_AddRefed<nsIThread>(thread);
198 }
200 //-----------------------------------------------------------------------------
202 #ifdef MOZILLA_INTERNAL_API
203 // Fast access to the current thread. Do not release the returned pointer! If
204 // you want to use this pointer from some other thread, then you will need to
205 // AddRef it. Otherwise, you should only consider this pointer valid from code
206 // running on the current thread.
207 extern NS_COM_GLUE nsIThread *NS_GetCurrentThread();
208 #endif
210 //-----------------------------------------------------------------------------
212 #ifndef XPCOM_GLUE_AVOID_NSPR
214 #undef IMETHOD_VISIBILITY
215 #define IMETHOD_VISIBILITY NS_COM_GLUE
217 // This class is designed to be subclassed.
218 class NS_COM_GLUE nsRunnable : public nsIRunnable
219 {
220 public:
221 NS_DECL_THREADSAFE_ISUPPORTS
222 NS_DECL_NSIRUNNABLE
224 nsRunnable() {
225 }
227 protected:
228 virtual ~nsRunnable() {
229 }
230 };
232 // This class is designed to be subclassed.
233 class NS_COM_GLUE nsCancelableRunnable : public nsICancelableRunnable
234 {
235 public:
236 NS_DECL_THREADSAFE_ISUPPORTS
237 NS_DECL_NSIRUNNABLE
238 NS_DECL_NSICANCELABLERUNNABLE
240 nsCancelableRunnable() {
241 }
243 protected:
244 virtual ~nsCancelableRunnable() {
245 }
246 };
248 #undef IMETHOD_VISIBILITY
249 #define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN
251 // An event that can be used to call a method on a class. The class type must
252 // support reference counting. This event supports Revoke for use
253 // with nsRevocableEventPtr.
254 template <class ClassType,
255 typename ReturnType = void,
256 bool Owning = true>
257 class nsRunnableMethod : public nsRunnable
258 {
259 public:
260 virtual void Revoke() = 0;
262 // These ReturnTypeEnforcer classes set up a blacklist for return types that
263 // we know are not safe. The default ReturnTypeEnforcer compiles just fine but
264 // already_AddRefed will not.
265 template <typename OtherReturnType>
266 class ReturnTypeEnforcer
267 {
268 public:
269 typedef int ReturnTypeIsSafe;
270 };
272 template <class T>
273 class ReturnTypeEnforcer<already_AddRefed<T> >
274 {
275 // No ReturnTypeIsSafe makes this illegal!
276 };
278 // Make sure this return type is safe.
279 typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
280 };
282 template <class ClassType, typename Arg, bool Owning>
283 struct nsRunnableMethodReceiver {
284 ClassType *mObj;
285 Arg mArg;
286 nsRunnableMethodReceiver(ClassType *obj, Arg arg)
287 : mObj(obj)
288 , mArg(arg)
289 { NS_IF_ADDREF(mObj); }
290 ~nsRunnableMethodReceiver() { Revoke(); }
291 void Revoke() { NS_IF_RELEASE(mObj); }
292 };
294 template <class ClassType, bool Owning>
295 struct nsRunnableMethodReceiver<ClassType, void, Owning> {
296 ClassType *mObj;
297 nsRunnableMethodReceiver(ClassType *obj) : mObj(obj)
298 { NS_IF_ADDREF(mObj); }
299 ~nsRunnableMethodReceiver() { Revoke(); }
300 void Revoke() { NS_IF_RELEASE(mObj); }
301 };
303 template <class ClassType>
304 struct nsRunnableMethodReceiver<ClassType, void, false> {
305 ClassType *mObj;
306 nsRunnableMethodReceiver(ClassType *obj) : mObj(obj) {}
307 void Revoke() { mObj = nullptr; }
308 };
310 template <typename Method, bool Owning> struct nsRunnableMethodTraits;
312 template <class C, typename R, typename A, bool Owning>
313 struct nsRunnableMethodTraits<R (C::*)(A), Owning> {
314 typedef C class_type;
315 typedef R return_type;
316 typedef A arg_type;
317 typedef nsRunnableMethod<C, R, Owning> base_type;
318 };
320 template <class C, typename R, bool Owning>
321 struct nsRunnableMethodTraits<R (C::*)(), Owning> {
322 typedef C class_type;
323 typedef R return_type;
324 typedef void arg_type;
325 typedef nsRunnableMethod<C, R, Owning> base_type;
326 };
328 #ifdef NS_HAVE_STDCALL
329 template <class C, typename R, typename A, bool Owning>
330 struct nsRunnableMethodTraits<R (__stdcall C::*)(A), Owning> {
331 typedef C class_type;
332 typedef R return_type;
333 typedef A arg_type;
334 typedef nsRunnableMethod<C, R, Owning> base_type;
335 };
337 template <class C, typename R, bool Owning>
338 struct nsRunnableMethodTraits<R (NS_STDCALL C::*)(), Owning> {
339 typedef C class_type;
340 typedef R return_type;
341 typedef void arg_type;
342 typedef nsRunnableMethod<C, R, Owning> base_type;
343 };
344 #endif
346 template <typename Method, typename Arg, bool Owning>
347 class nsRunnableMethodImpl
348 : public nsRunnableMethodTraits<Method, Owning>::base_type
349 {
350 typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
351 nsRunnableMethodReceiver<ClassType, Arg, Owning> mReceiver;
352 Method mMethod;
353 public:
354 nsRunnableMethodImpl(ClassType *obj,
355 Method method,
356 Arg arg)
357 : mReceiver(obj, arg)
358 , mMethod(method)
359 {}
360 NS_IMETHOD Run() {
361 if (MOZ_LIKELY(mReceiver.mObj))
362 ((*mReceiver.mObj).*mMethod)(mReceiver.mArg);
363 return NS_OK;
364 }
365 void Revoke() {
366 mReceiver.Revoke();
367 }
368 };
370 template <typename Method, bool Owning>
371 class nsRunnableMethodImpl<Method, void, Owning>
372 : public nsRunnableMethodTraits<Method, Owning>::base_type
373 {
374 typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
375 nsRunnableMethodReceiver<ClassType, void, Owning> mReceiver;
376 Method mMethod;
378 public:
379 nsRunnableMethodImpl(ClassType *obj,
380 Method method)
381 : mReceiver(obj)
382 , mMethod(method)
383 {}
385 NS_IMETHOD Run() {
386 if (MOZ_LIKELY(mReceiver.mObj))
387 ((*mReceiver.mObj).*mMethod)();
388 return NS_OK;
389 }
391 void Revoke() {
392 mReceiver.Revoke();
393 }
394 };
396 // Use this template function like so:
397 //
398 // nsCOMPtr<nsIRunnable> event =
399 // NS_NewRunnableMethod(myObject, &MyClass::HandleEvent);
400 // NS_DispatchToCurrentThread(event);
401 //
402 // Statically enforced constraints:
403 // - myObject must be of (or implicitly convertible to) type MyClass
404 // - MyClass must defined AddRef and Release methods
405 //
406 template<typename PtrType, typename Method>
407 typename nsRunnableMethodTraits<Method, true>::base_type*
408 NS_NewRunnableMethod(PtrType ptr, Method method)
409 {
410 return new nsRunnableMethodImpl<Method, void, true>(ptr, method);
411 }
413 template<typename T>
414 struct dependent_type
415 {
416 typedef T type;
417 };
420 // Similar to NS_NewRunnableMethod. Call like so:
421 // Type myArg;
422 // nsCOMPtr<nsIRunnable> event =
423 // NS_NewRunnableMethodWithArg<Type>(myObject, &MyClass::HandleEvent, myArg);
424 template<typename Arg, typename Method, typename PtrType>
425 typename nsRunnableMethodTraits<Method, true>::base_type*
426 NS_NewRunnableMethodWithArg(PtrType ptr, Method method, typename dependent_type<Arg>::type arg)
427 {
428 return new nsRunnableMethodImpl<Method, Arg, true>(ptr, method, arg);
429 }
431 template<typename PtrType, typename Method>
432 typename nsRunnableMethodTraits<Method, false>::base_type*
433 NS_NewNonOwningRunnableMethod(PtrType ptr, Method method)
434 {
435 return new nsRunnableMethodImpl<Method, void, false>(ptr, method);
436 }
438 #endif // XPCOM_GLUE_AVOID_NSPR
440 // This class is designed to be used when you have an event class E that has a
441 // pointer back to resource class R. If R goes away while E is still pending,
442 // then it is important to "revoke" E so that it does not try use R after R has
443 // been destroyed. nsRevocableEventPtr makes it easy for R to manage such
444 // situations:
445 //
446 // class R;
447 //
448 // class E : public nsRunnable {
449 // public:
450 // void Revoke() {
451 // mResource = nullptr;
452 // }
453 // private:
454 // R *mResource;
455 // };
456 //
457 // class R {
458 // public:
459 // void EventHandled() {
460 // mEvent.Forget();
461 // }
462 // private:
463 // nsRevocableEventPtr<E> mEvent;
464 // };
465 //
466 // void R::PostEvent() {
467 // // Make sure any pending event is revoked.
468 // mEvent->Revoke();
469 //
470 // nsCOMPtr<nsIRunnable> event = new E();
471 // if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) {
472 // // Keep pointer to event so we can revoke it.
473 // mEvent = event;
474 // }
475 // }
476 //
477 // NS_IMETHODIMP E::Run() {
478 // if (!mResource)
479 // return NS_OK;
480 // ...
481 // mResource->EventHandled();
482 // return NS_OK;
483 // }
484 //
485 template <class T>
486 class nsRevocableEventPtr {
487 public:
488 nsRevocableEventPtr()
489 : mEvent(nullptr) {
490 }
492 ~nsRevocableEventPtr() {
493 Revoke();
494 }
496 const nsRevocableEventPtr& operator=(T *event) {
497 if (mEvent != event) {
498 Revoke();
499 mEvent = event;
500 }
501 return *this;
502 }
504 void Revoke() {
505 if (mEvent) {
506 mEvent->Revoke();
507 mEvent = nullptr;
508 }
509 }
511 void Forget() {
512 mEvent = nullptr;
513 }
515 bool IsPending() {
516 return mEvent != nullptr;
517 }
519 T *get() { return mEvent; }
521 private:
522 // Not implemented
523 nsRevocableEventPtr(const nsRevocableEventPtr&);
524 nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
526 nsRefPtr<T> mEvent;
527 };
529 /**
530 * A simple helper to suffix thread pool name
531 * with incremental numbers.
532 */
533 class nsThreadPoolNaming
534 {
535 public:
536 nsThreadPoolNaming() : mCounter(0) {}
538 /**
539 * Creates and sets next thread name as "<aPoolName> #<n>"
540 * on the specified thread. If no thread is specified (aThread
541 * is null) then the name is synchronously set on the current thread.
542 */
543 void SetThreadPoolName(const nsACString & aPoolName,
544 nsIThread * aThread = nullptr);
546 private:
547 volatile uint32_t mCounter;
549 nsThreadPoolNaming(const nsThreadPoolNaming &) MOZ_DELETE;
550 void operator=(const nsThreadPoolNaming &) MOZ_DELETE;
551 };
553 /**
554 * Thread priority in most operating systems affect scheduling, not IO. This
555 * helper is used to set the current thread to low IO priority for the lifetime
556 * of the created object. You can only use this low priority IO setting within
557 * the context of the current thread.
558 */
559 class MOZ_STACK_CLASS nsAutoLowPriorityIO
560 {
561 public:
562 nsAutoLowPriorityIO();
563 ~nsAutoLowPriorityIO();
565 private:
566 bool lowIOPrioritySet;
567 #if defined(XP_MACOSX)
568 int oldPriority;
569 #endif
570 };
574 #endif // nsThreadUtils_h__