Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifndef CacheIOThread__h__
6 : #define CacheIOThread__h__
7 :
8 : #include "nsIThreadInternal.h"
9 : #include "nsISupportsImpl.h"
10 : #include "prthread.h"
11 : #include "nsTArray.h"
12 : #include "nsAutoPtr.h"
13 : #include "mozilla/Monitor.h"
14 : #include "mozilla/DebugOnly.h"
15 : #include "mozilla/Atomics.h"
16 : #include "mozilla/UniquePtr.h"
17 :
18 : class nsIRunnable;
19 :
20 : namespace mozilla {
21 : namespace net {
22 :
23 : namespace detail {
24 : // A class keeping platform specific information needed to watch and
25 : // cancel any long blocking synchronous IO. Must be predeclared here
26 : // since including windows.h breaks stuff with number of macro definition
27 : // conflicts.
28 : class BlockingIOWatcher;
29 : }
30 :
31 : class CacheIOThread : public nsIThreadObserver
32 : {
33 : virtual ~CacheIOThread();
34 :
35 : public:
36 : NS_DECL_THREADSAFE_ISUPPORTS
37 : NS_DECL_NSITHREADOBSERVER
38 :
39 : CacheIOThread();
40 :
41 : typedef nsTArray<nsCOMPtr<nsIRunnable>> EventQueue;
42 :
43 : enum ELevel : uint32_t {
44 : OPEN_PRIORITY,
45 : READ_PRIORITY,
46 : MANAGEMENT, // Doesn't do any actual I/O
47 : OPEN,
48 : READ,
49 : WRITE_PRIORITY,
50 : WRITE,
51 : INDEX,
52 : EVICT,
53 : LAST_LEVEL,
54 :
55 : // This is actually executed as the first level, but we want this enum
56 : // value merely as an indicator while other values are used as indexes
57 : // to the queue array. Hence put at end and not as the first.
58 : XPCOM_LEVEL
59 : };
60 :
61 : nsresult Init();
62 : nsresult Dispatch(nsIRunnable* aRunnable, uint32_t aLevel);
63 : nsresult Dispatch(already_AddRefed<nsIRunnable>, uint32_t aLevel);
64 : // Makes sure that any previously posted event to OPEN or OPEN_PRIORITY
65 : // levels (such as file opennings and dooms) are executed before aRunnable
66 : // that is intended to evict stuff from the cache.
67 : nsresult DispatchAfterPendingOpens(nsIRunnable* aRunnable);
68 : bool IsCurrentThread();
69 :
70 : uint32_t QueueSize(bool highPriority);
71 :
72 32 : uint32_t EventCounter() const { return mEventCounter; }
73 :
74 : /**
75 : * Callable only on this thread, checks if there is an event waiting in
76 : * the event queue with a higher execution priority. If so, the result
77 : * is true and the current event handler should break it's work and return
78 : * from Run() method immediately. The event handler will be rerun again
79 : * when all more priority events are processed. Events pending after this
80 : * handler (i.e. the one that called YieldAndRerun()) will not execute sooner
81 : * then this handler is executed w/o a call to YieldAndRerun().
82 : */
83 0 : static bool YieldAndRerun()
84 : {
85 0 : return sSelf ? sSelf->YieldInternal() : false;
86 : }
87 :
88 : void Shutdown();
89 : // This method checks if there is a long blocking IO on the
90 : // IO thread and tries to cancel it. It waits maximum of
91 : // two seconds.
92 : void CancelBlockingIO();
93 : already_AddRefed<nsIEventTarget> Target();
94 :
95 : // A stack class used to annotate running interruptable I/O event
96 : class Cancelable
97 : {
98 : bool mCancelable;
99 : public:
100 : explicit Cancelable(bool aCancelable);
101 : ~Cancelable();
102 : };
103 :
104 : // Memory reporting
105 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
106 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
107 :
108 : private:
109 : static void ThreadFunc(void* aClosure);
110 : void ThreadFunc();
111 : void LoopOneLevel(uint32_t aLevel);
112 : bool EventsPending(uint32_t aLastLevel = LAST_LEVEL);
113 : nsresult DispatchInternal(already_AddRefed<nsIRunnable> aRunnable, uint32_t aLevel);
114 : bool YieldInternal();
115 :
116 : static CacheIOThread* sSelf;
117 :
118 : mozilla::Monitor mMonitor;
119 : PRThread* mThread;
120 : UniquePtr<detail::BlockingIOWatcher> mBlockingIOWatcher;
121 : Atomic<nsIThread *> mXPCOMThread;
122 : Atomic<uint32_t, Relaxed> mLowestLevelWaiting;
123 : uint32_t mCurrentlyExecutingLevel;
124 :
125 : // Keeps the length of the each event queue, since LoopOneLevel moves all
126 : // events into a local array.
127 : Atomic<int32_t> mQueueLength[LAST_LEVEL];
128 :
129 : EventQueue mEventQueue[LAST_LEVEL];
130 : // Raised when nsIEventTarget.Dispatch() is called on this thread
131 : Atomic<bool, Relaxed> mHasXPCOMEvents;
132 : // See YieldAndRerun() above
133 : bool mRerunCurrentEvent;
134 : // Signal to process all pending events and then shutdown
135 : // Synchronized by mMonitor
136 : bool mShutdown;
137 : // If > 0 there is currently an I/O operation on the thread that
138 : // can be canceled when after shutdown, see the Shutdown() method
139 : // for usage. Made a counter to allow nesting of the Cancelable class.
140 : Atomic<uint32_t, Relaxed> mIOCancelableEvents;
141 : // Event counter that increases with every event processed.
142 : Atomic<uint32_t, Relaxed> mEventCounter;
143 : #ifdef DEBUG
144 : bool mInsideLoop;
145 : #endif
146 : };
147 :
148 : } // namespace net
149 : } // namespace mozilla
150 :
151 : #endif
|