|
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 #include "IOInterposer.h" |
|
6 #include "NSPRInterposer.h" |
|
7 |
|
8 #include "prio.h" |
|
9 #include "private/pprio.h" |
|
10 |
|
11 namespace { |
|
12 |
|
13 using namespace mozilla; |
|
14 |
|
15 /* Original IO methods */ |
|
16 PRCloseFN sCloseFn = nullptr; |
|
17 PRReadFN sReadFn = nullptr; |
|
18 PRWriteFN sWriteFn = nullptr; |
|
19 PRFsyncFN sFSyncFn = nullptr; |
|
20 PRFileInfoFN sFileInfoFn = nullptr; |
|
21 PRFileInfo64FN sFileInfo64Fn = nullptr; |
|
22 |
|
23 /** |
|
24 * RAII class for timing the duration of an NSPR I/O call and reporting the |
|
25 * result to the IOInterposeObserver API. |
|
26 */ |
|
27 class NSPRIOAutoObservation : public IOInterposeObserver::Observation |
|
28 { |
|
29 public: |
|
30 NSPRIOAutoObservation(IOInterposeObserver::Operation aOp) |
|
31 : IOInterposeObserver::Observation(aOp, "NSPRIOInterposer") |
|
32 { |
|
33 } |
|
34 |
|
35 ~NSPRIOAutoObservation() |
|
36 { |
|
37 Report(); |
|
38 } |
|
39 }; |
|
40 |
|
41 PRStatus PR_CALLBACK interposedClose(PRFileDesc* aFd) |
|
42 { |
|
43 // If we don't have a valid original function pointer something is very wrong. |
|
44 NS_ASSERTION(sCloseFn, "NSPR IO Interposing: sCloseFn is NULL"); |
|
45 |
|
46 NSPRIOAutoObservation timer(IOInterposeObserver::OpClose); |
|
47 return sCloseFn(aFd); |
|
48 } |
|
49 |
|
50 int32_t PR_CALLBACK interposedRead(PRFileDesc* aFd, void* aBuf, int32_t aAmt) |
|
51 { |
|
52 // If we don't have a valid original function pointer something is very wrong. |
|
53 NS_ASSERTION(sReadFn, "NSPR IO Interposing: sReadFn is NULL"); |
|
54 |
|
55 NSPRIOAutoObservation timer(IOInterposeObserver::OpRead); |
|
56 return sReadFn(aFd, aBuf, aAmt); |
|
57 } |
|
58 |
|
59 int32_t PR_CALLBACK interposedWrite(PRFileDesc* aFd, const void* aBuf, |
|
60 int32_t aAmt) |
|
61 { |
|
62 // If we don't have a valid original function pointer something is very wrong. |
|
63 NS_ASSERTION(sWriteFn, "NSPR IO Interposing: sWriteFn is NULL"); |
|
64 |
|
65 NSPRIOAutoObservation timer(IOInterposeObserver::OpWrite); |
|
66 return sWriteFn(aFd, aBuf, aAmt); |
|
67 } |
|
68 |
|
69 PRStatus PR_CALLBACK interposedFSync(PRFileDesc* aFd) |
|
70 { |
|
71 // If we don't have a valid original function pointer something is very wrong. |
|
72 NS_ASSERTION(sFSyncFn, "NSPR IO Interposing: sFSyncFn is NULL"); |
|
73 |
|
74 NSPRIOAutoObservation timer(IOInterposeObserver::OpFSync); |
|
75 return sFSyncFn(aFd); |
|
76 } |
|
77 |
|
78 PRStatus PR_CALLBACK interposedFileInfo(PRFileDesc *aFd, PRFileInfo *aInfo) |
|
79 { |
|
80 // If we don't have a valid original function pointer something is very wrong. |
|
81 NS_ASSERTION(sFileInfoFn, "NSPR IO Interposing: sFileInfoFn is NULL"); |
|
82 |
|
83 NSPRIOAutoObservation timer(IOInterposeObserver::OpStat); |
|
84 return sFileInfoFn(aFd, aInfo); |
|
85 } |
|
86 |
|
87 PRStatus PR_CALLBACK interposedFileInfo64(PRFileDesc *aFd, PRFileInfo64 *aInfo) |
|
88 { |
|
89 // If we don't have a valid original function pointer something is very wrong. |
|
90 NS_ASSERTION(sFileInfo64Fn, "NSPR IO Interposing: sFileInfo64Fn is NULL"); |
|
91 |
|
92 NSPRIOAutoObservation timer(IOInterposeObserver::OpStat); |
|
93 return sFileInfo64Fn(aFd, aInfo); |
|
94 } |
|
95 |
|
96 } // anonymous namespace |
|
97 |
|
98 namespace mozilla { |
|
99 |
|
100 void InitNSPRIOInterposing() |
|
101 { |
|
102 // Check that we have not interposed any of the IO methods before |
|
103 MOZ_ASSERT(!sCloseFn && !sReadFn && !sWriteFn && !sFSyncFn && !sFileInfoFn && |
|
104 !sFileInfo64Fn); |
|
105 |
|
106 // We can't actually use this assertion because we initialize this code |
|
107 // before XPCOM is initialized, so NS_IsMainThread() always returns false. |
|
108 // MOZ_ASSERT(NS_IsMainThread()); |
|
109 |
|
110 // Get IO methods from NSPR and const cast the structure so we can modify it. |
|
111 PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods()); |
|
112 |
|
113 // Something is badly wrong if we don't get IO methods... However, we don't |
|
114 // want to crash over that in non-debug builds. This is unlikely to happen |
|
115 // so an assert is enough, no need to report it to the caller. |
|
116 MOZ_ASSERT(methods); |
|
117 if (!methods) { |
|
118 return; |
|
119 } |
|
120 |
|
121 // Store original functions |
|
122 sCloseFn = methods->close; |
|
123 sReadFn = methods->read; |
|
124 sWriteFn = methods->write; |
|
125 sFSyncFn = methods->fsync; |
|
126 sFileInfoFn = methods->fileInfo; |
|
127 sFileInfo64Fn = methods->fileInfo64; |
|
128 |
|
129 // Overwrite with our interposed functions |
|
130 methods->close = &interposedClose; |
|
131 methods->read = &interposedRead; |
|
132 methods->write = &interposedWrite; |
|
133 methods->fsync = &interposedFSync; |
|
134 methods->fileInfo = &interposedFileInfo; |
|
135 methods->fileInfo64 = &interposedFileInfo64; |
|
136 } |
|
137 |
|
138 void ClearNSPRIOInterposing() |
|
139 { |
|
140 // If we have already cleared IO interposing, or not initialized it this is |
|
141 // actually bad. |
|
142 MOZ_ASSERT(sCloseFn && sReadFn && sWriteFn && sFSyncFn && sFileInfoFn && |
|
143 sFileInfo64Fn); |
|
144 |
|
145 // Get IO methods from NSPR and const cast the structure so we can modify it. |
|
146 PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods()); |
|
147 |
|
148 // Something is badly wrong if we don't get IO methods... However, we don't |
|
149 // want to crash over that in non-debug builds. This is unlikely to happen |
|
150 // so an assert is enough, no need to report it to the caller. |
|
151 MOZ_ASSERT(methods); |
|
152 if (!methods) { |
|
153 return; |
|
154 } |
|
155 |
|
156 // Restore original functions |
|
157 methods->close = sCloseFn; |
|
158 methods->read = sReadFn; |
|
159 methods->write = sWriteFn; |
|
160 methods->fsync = sFSyncFn; |
|
161 methods->fileInfo = sFileInfoFn; |
|
162 methods->fileInfo64 = sFileInfo64Fn; |
|
163 |
|
164 // Forget about original functions |
|
165 sCloseFn = nullptr; |
|
166 sReadFn = nullptr; |
|
167 sWriteFn = nullptr; |
|
168 sFSyncFn = nullptr; |
|
169 sFileInfoFn = nullptr; |
|
170 sFileInfo64Fn = nullptr; |
|
171 } |
|
172 |
|
173 } // namespace mozilla |
|
174 |