1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/build/NSPRInterposer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,174 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "IOInterposer.h" 1.9 +#include "NSPRInterposer.h" 1.10 + 1.11 +#include "prio.h" 1.12 +#include "private/pprio.h" 1.13 + 1.14 +namespace { 1.15 + 1.16 +using namespace mozilla; 1.17 + 1.18 +/* Original IO methods */ 1.19 +PRCloseFN sCloseFn = nullptr; 1.20 +PRReadFN sReadFn = nullptr; 1.21 +PRWriteFN sWriteFn = nullptr; 1.22 +PRFsyncFN sFSyncFn = nullptr; 1.23 +PRFileInfoFN sFileInfoFn = nullptr; 1.24 +PRFileInfo64FN sFileInfo64Fn = nullptr; 1.25 + 1.26 +/** 1.27 + * RAII class for timing the duration of an NSPR I/O call and reporting the 1.28 + * result to the IOInterposeObserver API. 1.29 + */ 1.30 +class NSPRIOAutoObservation : public IOInterposeObserver::Observation 1.31 +{ 1.32 +public: 1.33 + NSPRIOAutoObservation(IOInterposeObserver::Operation aOp) 1.34 + : IOInterposeObserver::Observation(aOp, "NSPRIOInterposer") 1.35 + { 1.36 + } 1.37 + 1.38 + ~NSPRIOAutoObservation() 1.39 + { 1.40 + Report(); 1.41 + } 1.42 +}; 1.43 + 1.44 +PRStatus PR_CALLBACK interposedClose(PRFileDesc* aFd) 1.45 +{ 1.46 + // If we don't have a valid original function pointer something is very wrong. 1.47 + NS_ASSERTION(sCloseFn, "NSPR IO Interposing: sCloseFn is NULL"); 1.48 + 1.49 + NSPRIOAutoObservation timer(IOInterposeObserver::OpClose); 1.50 + return sCloseFn(aFd); 1.51 +} 1.52 + 1.53 +int32_t PR_CALLBACK interposedRead(PRFileDesc* aFd, void* aBuf, int32_t aAmt) 1.54 +{ 1.55 + // If we don't have a valid original function pointer something is very wrong. 1.56 + NS_ASSERTION(sReadFn, "NSPR IO Interposing: sReadFn is NULL"); 1.57 + 1.58 + NSPRIOAutoObservation timer(IOInterposeObserver::OpRead); 1.59 + return sReadFn(aFd, aBuf, aAmt); 1.60 +} 1.61 + 1.62 +int32_t PR_CALLBACK interposedWrite(PRFileDesc* aFd, const void* aBuf, 1.63 + int32_t aAmt) 1.64 +{ 1.65 + // If we don't have a valid original function pointer something is very wrong. 1.66 + NS_ASSERTION(sWriteFn, "NSPR IO Interposing: sWriteFn is NULL"); 1.67 + 1.68 + NSPRIOAutoObservation timer(IOInterposeObserver::OpWrite); 1.69 + return sWriteFn(aFd, aBuf, aAmt); 1.70 +} 1.71 + 1.72 +PRStatus PR_CALLBACK interposedFSync(PRFileDesc* aFd) 1.73 +{ 1.74 + // If we don't have a valid original function pointer something is very wrong. 1.75 + NS_ASSERTION(sFSyncFn, "NSPR IO Interposing: sFSyncFn is NULL"); 1.76 + 1.77 + NSPRIOAutoObservation timer(IOInterposeObserver::OpFSync); 1.78 + return sFSyncFn(aFd); 1.79 +} 1.80 + 1.81 +PRStatus PR_CALLBACK interposedFileInfo(PRFileDesc *aFd, PRFileInfo *aInfo) 1.82 +{ 1.83 + // If we don't have a valid original function pointer something is very wrong. 1.84 + NS_ASSERTION(sFileInfoFn, "NSPR IO Interposing: sFileInfoFn is NULL"); 1.85 + 1.86 + NSPRIOAutoObservation timer(IOInterposeObserver::OpStat); 1.87 + return sFileInfoFn(aFd, aInfo); 1.88 +} 1.89 + 1.90 +PRStatus PR_CALLBACK interposedFileInfo64(PRFileDesc *aFd, PRFileInfo64 *aInfo) 1.91 +{ 1.92 + // If we don't have a valid original function pointer something is very wrong. 1.93 + NS_ASSERTION(sFileInfo64Fn, "NSPR IO Interposing: sFileInfo64Fn is NULL"); 1.94 + 1.95 + NSPRIOAutoObservation timer(IOInterposeObserver::OpStat); 1.96 + return sFileInfo64Fn(aFd, aInfo); 1.97 +} 1.98 + 1.99 +} // anonymous namespace 1.100 + 1.101 +namespace mozilla { 1.102 + 1.103 +void InitNSPRIOInterposing() 1.104 +{ 1.105 + // Check that we have not interposed any of the IO methods before 1.106 + MOZ_ASSERT(!sCloseFn && !sReadFn && !sWriteFn && !sFSyncFn && !sFileInfoFn && 1.107 + !sFileInfo64Fn); 1.108 + 1.109 + // We can't actually use this assertion because we initialize this code 1.110 + // before XPCOM is initialized, so NS_IsMainThread() always returns false. 1.111 + // MOZ_ASSERT(NS_IsMainThread()); 1.112 + 1.113 + // Get IO methods from NSPR and const cast the structure so we can modify it. 1.114 + PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods()); 1.115 + 1.116 + // Something is badly wrong if we don't get IO methods... However, we don't 1.117 + // want to crash over that in non-debug builds. This is unlikely to happen 1.118 + // so an assert is enough, no need to report it to the caller. 1.119 + MOZ_ASSERT(methods); 1.120 + if (!methods) { 1.121 + return; 1.122 + } 1.123 + 1.124 + // Store original functions 1.125 + sCloseFn = methods->close; 1.126 + sReadFn = methods->read; 1.127 + sWriteFn = methods->write; 1.128 + sFSyncFn = methods->fsync; 1.129 + sFileInfoFn = methods->fileInfo; 1.130 + sFileInfo64Fn = methods->fileInfo64; 1.131 + 1.132 + // Overwrite with our interposed functions 1.133 + methods->close = &interposedClose; 1.134 + methods->read = &interposedRead; 1.135 + methods->write = &interposedWrite; 1.136 + methods->fsync = &interposedFSync; 1.137 + methods->fileInfo = &interposedFileInfo; 1.138 + methods->fileInfo64 = &interposedFileInfo64; 1.139 +} 1.140 + 1.141 +void ClearNSPRIOInterposing() 1.142 +{ 1.143 + // If we have already cleared IO interposing, or not initialized it this is 1.144 + // actually bad. 1.145 + MOZ_ASSERT(sCloseFn && sReadFn && sWriteFn && sFSyncFn && sFileInfoFn && 1.146 + sFileInfo64Fn); 1.147 + 1.148 + // Get IO methods from NSPR and const cast the structure so we can modify it. 1.149 + PRIOMethods* methods = const_cast<PRIOMethods*>(PR_GetFileMethods()); 1.150 + 1.151 + // Something is badly wrong if we don't get IO methods... However, we don't 1.152 + // want to crash over that in non-debug builds. This is unlikely to happen 1.153 + // so an assert is enough, no need to report it to the caller. 1.154 + MOZ_ASSERT(methods); 1.155 + if (!methods) { 1.156 + return; 1.157 + } 1.158 + 1.159 + // Restore original functions 1.160 + methods->close = sCloseFn; 1.161 + methods->read = sReadFn; 1.162 + methods->write = sWriteFn; 1.163 + methods->fsync = sFSyncFn; 1.164 + methods->fileInfo = sFileInfoFn; 1.165 + methods->fileInfo64 = sFileInfo64Fn; 1.166 + 1.167 + // Forget about original functions 1.168 + sCloseFn = nullptr; 1.169 + sReadFn = nullptr; 1.170 + sWriteFn = nullptr; 1.171 + sFSyncFn = nullptr; 1.172 + sFileInfoFn = nullptr; 1.173 + sFileInfo64Fn = nullptr; 1.174 +} 1.175 + 1.176 +} // namespace mozilla 1.177 +