xpcom/build/NSPRInterposer.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:31152a92d11f
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

mercurial