1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/build/PoisonIOInterposerBase.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,150 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 ci et: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/Mutex.h" 1.11 +#include "mozilla/Scoped.h" 1.12 + 1.13 +#include <algorithm> 1.14 +#include <vector> 1.15 + 1.16 +#include "PoisonIOInterposer.h" 1.17 + 1.18 +// Auxiliary method to convert file descriptors to ids 1.19 +#if defined(XP_WIN32) 1.20 +#include <io.h> 1.21 +inline intptr_t FileDescriptorToID(int aFd) { 1.22 + return _get_osfhandle(aFd); 1.23 +} 1.24 +#else 1.25 +inline intptr_t FileDescriptorToID(int aFd) { 1.26 + return aFd; 1.27 +} 1.28 +#endif /* if not XP_WIN32 */ 1.29 + 1.30 +using namespace mozilla; 1.31 + 1.32 +namespace { 1.33 +struct DebugFilesAutoLockTraits { 1.34 + typedef PRLock *type; 1.35 + const static type empty() { 1.36 + return nullptr; 1.37 + } 1.38 + const static void release(type aL) { 1.39 + PR_Unlock(aL); 1.40 + } 1.41 +}; 1.42 + 1.43 +class DebugFilesAutoLock : public Scoped<DebugFilesAutoLockTraits> { 1.44 + static PRLock *Lock; 1.45 +public: 1.46 + static void Clear(); 1.47 + static PRLock *getDebugFileIDsLock() { 1.48 + // On windows this static is not thread safe, but we know that the first 1.49 + // call is from 1.50 + // * An early registration of a debug FD or 1.51 + // * The call to InitWritePoisoning. 1.52 + // Since the early debug FDs are logs created early in the main thread 1.53 + // and no writes are trapped before InitWritePoisoning, we are safe. 1.54 + if (!Lock) { 1.55 + Lock = PR_NewLock(); 1.56 + } 1.57 + 1.58 + // We have to use something lower level than a mutex. If we don't, we 1.59 + // can get recursive in here when called from logging a call to free. 1.60 + return Lock; 1.61 + } 1.62 + 1.63 + DebugFilesAutoLock() : 1.64 + Scoped<DebugFilesAutoLockTraits>(getDebugFileIDsLock()) { 1.65 + PR_Lock(get()); 1.66 + } 1.67 +}; 1.68 + 1.69 +PRLock *DebugFilesAutoLock::Lock; 1.70 +void DebugFilesAutoLock::Clear() { 1.71 + MOZ_ASSERT(Lock != nullptr); 1.72 + Lock = nullptr; 1.73 +} 1.74 + 1.75 +// Return a vector used to hold the IDs of the current debug files. On unix 1.76 +// an ID is a file descriptor. On Windows it is a file HANDLE. 1.77 +std::vector<intptr_t>* getDebugFileIDs() { 1.78 + PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(DebugFilesAutoLock::getDebugFileIDsLock()); 1.79 + // We have to use new as some write happen during static destructors 1.80 + // so an static std::vector might be destroyed while we still need it. 1.81 + static std::vector<intptr_t> *DebugFileIDs = new std::vector<intptr_t>(); 1.82 + return DebugFileIDs; 1.83 +} 1.84 + 1.85 +} // anonymous namespace 1.86 + 1.87 +namespace mozilla{ 1.88 + 1.89 +// Auxiliary Method to test if a file descriptor is registered to be ignored 1.90 +// by the poisoning IO interposer 1.91 +bool IsDebugFile(intptr_t aFileID) { 1.92 + DebugFilesAutoLock lockedScope; 1.93 + 1.94 + std::vector<intptr_t> &Vec = *getDebugFileIDs(); 1.95 + return std::find(Vec.begin(), Vec.end(), aFileID) != Vec.end(); 1.96 +} 1.97 + 1.98 +// Clean-up for the registered debug files. 1.99 +// We should probably make sure all debug files are unregistered instead. 1.100 +// But as the poison IO interposer is used for late-write checks we're not 1.101 +// disabling it at any point yet. So Really no need for this. 1.102 +// 1.103 +// void ClearDebugFileRegister() { 1.104 +// PRLock *Lock; 1.105 +// { 1.106 +// DebugFilesAutoLock lockedScope; 1.107 +// delete getDebugFileIDs(); 1.108 +// Lock = DebugFilesAutoLock::getDebugFileIDsLock(); 1.109 +// DebugFilesAutoLock::Clear(); 1.110 +// } 1.111 +// PR_DestroyLock(Lock); 1.112 +// } 1.113 + 1.114 +} // namespace mozilla 1.115 + 1.116 +extern "C" { 1.117 + 1.118 + void MozillaRegisterDebugFD(int fd) { 1.119 + intptr_t fileId = FileDescriptorToID(fd); 1.120 + DebugFilesAutoLock lockedScope; 1.121 + std::vector<intptr_t> &Vec = *getDebugFileIDs(); 1.122 + MOZ_ASSERT(std::find(Vec.begin(), Vec.end(), fileId) == Vec.end()); 1.123 + Vec.push_back(fileId); 1.124 + } 1.125 + 1.126 + void MozillaRegisterDebugFILE(FILE *f) { 1.127 + int fd = fileno(f); 1.128 + if (fd == 1 || fd == 2) { 1.129 + return; 1.130 + } 1.131 + MozillaRegisterDebugFD(fd); 1.132 + } 1.133 + 1.134 + void MozillaUnRegisterDebugFD(int fd) { 1.135 + DebugFilesAutoLock lockedScope; 1.136 + intptr_t fileId = FileDescriptorToID(fd); 1.137 + std::vector<intptr_t> &Vec = *getDebugFileIDs(); 1.138 + std::vector<intptr_t>::iterator i = 1.139 + std::find(Vec.begin(), Vec.end(), fileId); 1.140 + MOZ_ASSERT(i != Vec.end()); 1.141 + Vec.erase(i); 1.142 + } 1.143 + 1.144 + void MozillaUnRegisterDebugFILE(FILE *f) { 1.145 + int fd = fileno(f); 1.146 + if (fd == 1 || fd == 2) { 1.147 + return; 1.148 + } 1.149 + fflush(f); 1.150 + MozillaUnRegisterDebugFD(fd); 1.151 + } 1.152 + 1.153 +} 1.154 \ No newline at end of file