xpcom/build/IOInterposer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include <algorithm>
michael@0 6 #include <vector>
michael@0 7
michael@0 8 #include "IOInterposer.h"
michael@0 9
michael@0 10 #include "IOInterposerPrivate.h"
michael@0 11 #include "MainThreadIOLogger.h"
michael@0 12 #include "mozilla/Atomics.h"
michael@0 13 #include "mozilla/Mutex.h"
michael@0 14 #if defined(MOZILLA_INTERNAL_API)
michael@0 15 // We need to undefine MOZILLA_INTERNAL_API for RefPtr.h because IOInterposer
michael@0 16 // does not clean up its data before shutdown.
michael@0 17 #undef MOZILLA_INTERNAL_API
michael@0 18 #include "mozilla/RefPtr.h"
michael@0 19 #define MOZILLA_INTERNAL_API
michael@0 20 #else
michael@0 21 #include "mozilla/RefPtr.h"
michael@0 22 #endif // defined(MOZILLA_INTERNAL_API)
michael@0 23 #include "mozilla/StaticPtr.h"
michael@0 24 #include "mozilla/ThreadLocal.h"
michael@0 25 #if !defined(XP_WIN)
michael@0 26 #include "NSPRInterposer.h"
michael@0 27 #endif // !defined(XP_WIN)
michael@0 28 #include "nsXULAppAPI.h"
michael@0 29 #include "PoisonIOInterposer.h"
michael@0 30
michael@0 31 using namespace mozilla;
michael@0 32
michael@0 33 namespace {
michael@0 34
michael@0 35 /** Find if a vector contains a specific element */
michael@0 36 template<class T>
michael@0 37 bool VectorContains(const std::vector<T>& vector, const T& element)
michael@0 38 {
michael@0 39 return std::find(vector.begin(), vector.end(), element) != vector.end();
michael@0 40 }
michael@0 41
michael@0 42 /** Remove element from a vector */
michael@0 43 template<class T>
michael@0 44 void VectorRemove(std::vector<T>& vector, const T& element)
michael@0 45 {
michael@0 46 typename std::vector<T>::iterator newEnd = std::remove(vector.begin(),
michael@0 47 vector.end(), element);
michael@0 48 vector.erase(newEnd, vector.end());
michael@0 49 }
michael@0 50
michael@0 51 /** Lists of Observers */
michael@0 52 struct ObserverLists : public mozilla::AtomicRefCounted<ObserverLists>
michael@0 53 {
michael@0 54 ObserverLists()
michael@0 55 {
michael@0 56 }
michael@0 57
michael@0 58 ObserverLists(ObserverLists const & aOther)
michael@0 59 : mCreateObservers(aOther.mCreateObservers)
michael@0 60 , mReadObservers(aOther.mReadObservers)
michael@0 61 , mWriteObservers(aOther.mWriteObservers)
michael@0 62 , mFSyncObservers(aOther.mFSyncObservers)
michael@0 63 , mStatObservers(aOther.mStatObservers)
michael@0 64 , mCloseObservers(aOther.mCloseObservers)
michael@0 65 , mStageObservers(aOther.mStageObservers)
michael@0 66 {
michael@0 67 }
michael@0 68 // Lists of observers for I/O events.
michael@0 69 // These are implemented as vectors since they are allowed to survive gecko,
michael@0 70 // without reporting leaks. This is necessary for the IOInterposer to be used
michael@0 71 // for late-write checks.
michael@0 72 std::vector<IOInterposeObserver*> mCreateObservers;
michael@0 73 std::vector<IOInterposeObserver*> mReadObservers;
michael@0 74 std::vector<IOInterposeObserver*> mWriteObservers;
michael@0 75 std::vector<IOInterposeObserver*> mFSyncObservers;
michael@0 76 std::vector<IOInterposeObserver*> mStatObservers;
michael@0 77 std::vector<IOInterposeObserver*> mCloseObservers;
michael@0 78 std::vector<IOInterposeObserver*> mStageObservers;
michael@0 79 };
michael@0 80
michael@0 81 class PerThreadData
michael@0 82 {
michael@0 83 public:
michael@0 84 PerThreadData(bool aIsMainThread = false)
michael@0 85 : mIsMainThread(aIsMainThread)
michael@0 86 , mIsHandlingObservation(false)
michael@0 87 , mCurrentGeneration(0)
michael@0 88 {
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 CallObservers(IOInterposeObserver::Observation& aObservation)
michael@0 93 {
michael@0 94 // Prevent recursive reporting.
michael@0 95 if (mIsHandlingObservation) {
michael@0 96 return;
michael@0 97 }
michael@0 98
michael@0 99 mIsHandlingObservation = true;
michael@0 100 // Decide which list of observers to inform
michael@0 101 std::vector<IOInterposeObserver*>* observers = nullptr;
michael@0 102 switch (aObservation.ObservedOperation()) {
michael@0 103 case IOInterposeObserver::OpCreateOrOpen:
michael@0 104 {
michael@0 105 observers = &mObserverLists->mCreateObservers;
michael@0 106 }
michael@0 107 break;
michael@0 108 case IOInterposeObserver::OpRead:
michael@0 109 {
michael@0 110 observers = &mObserverLists->mReadObservers;
michael@0 111 }
michael@0 112 break;
michael@0 113 case IOInterposeObserver::OpWrite:
michael@0 114 {
michael@0 115 observers = &mObserverLists->mWriteObservers;
michael@0 116 }
michael@0 117 break;
michael@0 118 case IOInterposeObserver::OpFSync:
michael@0 119 {
michael@0 120 observers = &mObserverLists->mFSyncObservers;
michael@0 121 }
michael@0 122 break;
michael@0 123 case IOInterposeObserver::OpStat:
michael@0 124 {
michael@0 125 observers = &mObserverLists->mStatObservers;
michael@0 126 }
michael@0 127 break;
michael@0 128 case IOInterposeObserver::OpClose:
michael@0 129 {
michael@0 130 observers = &mObserverLists->mCloseObservers;
michael@0 131 }
michael@0 132 break;
michael@0 133 case IOInterposeObserver::OpNextStage:
michael@0 134 {
michael@0 135 observers = &mObserverLists->mStageObservers;
michael@0 136 }
michael@0 137 break;
michael@0 138 default:
michael@0 139 {
michael@0 140 // Invalid IO operation, see documentation comment for
michael@0 141 // IOInterposer::Report()
michael@0 142 MOZ_ASSERT(false);
michael@0 143 // Just ignore it in non-debug builds.
michael@0 144 return;
michael@0 145 }
michael@0 146 }
michael@0 147 MOZ_ASSERT(observers);
michael@0 148
michael@0 149 // Inform observers
michael@0 150 for (std::vector<IOInterposeObserver*>::iterator i = observers->begin(),
michael@0 151 e = observers->end(); i != e; ++i)
michael@0 152 {
michael@0 153 (*i)->Observe(aObservation);
michael@0 154 }
michael@0 155 mIsHandlingObservation = false;
michael@0 156 }
michael@0 157
michael@0 158 inline uint32_t
michael@0 159 GetCurrentGeneration() const
michael@0 160 {
michael@0 161 return mCurrentGeneration;
michael@0 162 }
michael@0 163
michael@0 164 inline bool
michael@0 165 IsMainThread() const
michael@0 166 {
michael@0 167 return mIsMainThread;
michael@0 168 }
michael@0 169
michael@0 170 inline void
michael@0 171 SetObserverLists(uint32_t aNewGeneration, RefPtr<ObserverLists>& aNewLists)
michael@0 172 {
michael@0 173 mCurrentGeneration = aNewGeneration;
michael@0 174 mObserverLists = aNewLists;
michael@0 175 }
michael@0 176
michael@0 177 private:
michael@0 178 bool mIsMainThread;
michael@0 179 bool mIsHandlingObservation;
michael@0 180 uint32_t mCurrentGeneration;
michael@0 181 RefPtr<ObserverLists> mObserverLists;
michael@0 182 };
michael@0 183
michael@0 184 class MasterList
michael@0 185 {
michael@0 186 public:
michael@0 187 MasterList()
michael@0 188 : mObservedOperations(IOInterposeObserver::OpNone)
michael@0 189 , mIsEnabled(true)
michael@0 190 {
michael@0 191 }
michael@0 192
michael@0 193 ~MasterList()
michael@0 194 {
michael@0 195 }
michael@0 196
michael@0 197 inline void
michael@0 198 Disable()
michael@0 199 {
michael@0 200 mIsEnabled = false;
michael@0 201 }
michael@0 202
michael@0 203 void
michael@0 204 Register(IOInterposeObserver::Operation aOp, IOInterposeObserver* aObserver)
michael@0 205 {
michael@0 206 IOInterposer::AutoLock lock(mLock);
michael@0 207
michael@0 208 ObserverLists* newLists = nullptr;
michael@0 209 if (mObserverLists) {
michael@0 210 newLists = new ObserverLists(*mObserverLists);
michael@0 211 } else {
michael@0 212 newLists = new ObserverLists();
michael@0 213 }
michael@0 214 // You can register to observe multiple types of observations
michael@0 215 // but you'll never be registered twice for the same observations.
michael@0 216 if (aOp & IOInterposeObserver::OpCreateOrOpen &&
michael@0 217 !VectorContains(newLists->mCreateObservers, aObserver)) {
michael@0 218 newLists->mCreateObservers.push_back(aObserver);
michael@0 219 }
michael@0 220 if (aOp & IOInterposeObserver::OpRead &&
michael@0 221 !VectorContains(newLists->mReadObservers, aObserver)) {
michael@0 222 newLists->mReadObservers.push_back(aObserver);
michael@0 223 }
michael@0 224 if (aOp & IOInterposeObserver::OpWrite &&
michael@0 225 !VectorContains(newLists->mWriteObservers, aObserver)) {
michael@0 226 newLists->mWriteObservers.push_back(aObserver);
michael@0 227 }
michael@0 228 if (aOp & IOInterposeObserver::OpFSync &&
michael@0 229 !VectorContains(newLists->mFSyncObservers, aObserver)) {
michael@0 230 newLists->mFSyncObservers.push_back(aObserver);
michael@0 231 }
michael@0 232 if (aOp & IOInterposeObserver::OpStat &&
michael@0 233 !VectorContains(newLists->mStatObservers, aObserver)) {
michael@0 234 newLists->mStatObservers.push_back(aObserver);
michael@0 235 }
michael@0 236 if (aOp & IOInterposeObserver::OpClose &&
michael@0 237 !VectorContains(newLists->mCloseObservers, aObserver)) {
michael@0 238 newLists->mCloseObservers.push_back(aObserver);
michael@0 239 }
michael@0 240 if (aOp & IOInterposeObserver::OpNextStage &&
michael@0 241 !VectorContains(newLists->mStageObservers, aObserver)) {
michael@0 242 newLists->mStageObservers.push_back(aObserver);
michael@0 243 }
michael@0 244 mObserverLists = newLists;
michael@0 245 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 246 (mObservedOperations | aOp);
michael@0 247
michael@0 248 mCurrentGeneration++;
michael@0 249 }
michael@0 250
michael@0 251 void
michael@0 252 Unregister(IOInterposeObserver::Operation aOp, IOInterposeObserver* aObserver)
michael@0 253 {
michael@0 254 IOInterposer::AutoLock lock(mLock);
michael@0 255
michael@0 256 ObserverLists* newLists = nullptr;
michael@0 257 if (mObserverLists) {
michael@0 258 newLists = new ObserverLists(*mObserverLists);
michael@0 259 } else {
michael@0 260 newLists = new ObserverLists();
michael@0 261 }
michael@0 262
michael@0 263 if (aOp & IOInterposeObserver::OpCreateOrOpen) {
michael@0 264 VectorRemove(newLists->mCreateObservers, aObserver);
michael@0 265 if (newLists->mCreateObservers.empty()) {
michael@0 266 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 267 (mObservedOperations &
michael@0 268 ~IOInterposeObserver::OpCreateOrOpen);
michael@0 269 }
michael@0 270 }
michael@0 271 if (aOp & IOInterposeObserver::OpRead) {
michael@0 272 VectorRemove(newLists->mReadObservers, aObserver);
michael@0 273 if (newLists->mReadObservers.empty()) {
michael@0 274 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 275 (mObservedOperations & ~IOInterposeObserver::OpRead);
michael@0 276 }
michael@0 277 }
michael@0 278 if (aOp & IOInterposeObserver::OpWrite) {
michael@0 279 VectorRemove(newLists->mWriteObservers, aObserver);
michael@0 280 if (newLists->mWriteObservers.empty()) {
michael@0 281 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 282 (mObservedOperations & ~IOInterposeObserver::OpWrite);
michael@0 283 }
michael@0 284 }
michael@0 285 if (aOp & IOInterposeObserver::OpFSync) {
michael@0 286 VectorRemove(newLists->mFSyncObservers, aObserver);
michael@0 287 if (newLists->mFSyncObservers.empty()) {
michael@0 288 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 289 (mObservedOperations & ~IOInterposeObserver::OpFSync);
michael@0 290 }
michael@0 291 }
michael@0 292 if (aOp & IOInterposeObserver::OpStat) {
michael@0 293 VectorRemove(newLists->mStatObservers, aObserver);
michael@0 294 if (newLists->mStatObservers.empty()) {
michael@0 295 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 296 (mObservedOperations & ~IOInterposeObserver::OpStat);
michael@0 297 }
michael@0 298 }
michael@0 299 if (aOp & IOInterposeObserver::OpClose) {
michael@0 300 VectorRemove(newLists->mCloseObservers, aObserver);
michael@0 301 if (newLists->mCloseObservers.empty()) {
michael@0 302 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 303 (mObservedOperations & ~IOInterposeObserver::OpClose);
michael@0 304 }
michael@0 305 }
michael@0 306 if (aOp & IOInterposeObserver::OpNextStage) {
michael@0 307 VectorRemove(newLists->mStageObservers, aObserver);
michael@0 308 if (newLists->mStageObservers.empty()) {
michael@0 309 mObservedOperations = (IOInterposeObserver::Operation)
michael@0 310 (mObservedOperations & ~IOInterposeObserver::OpNextStage);
michael@0 311 }
michael@0 312 }
michael@0 313 mObserverLists = newLists;
michael@0 314 mCurrentGeneration++;
michael@0 315 }
michael@0 316
michael@0 317 void
michael@0 318 Update(PerThreadData &aPtd)
michael@0 319 {
michael@0 320 if (mCurrentGeneration == aPtd.GetCurrentGeneration()) {
michael@0 321 return;
michael@0 322 }
michael@0 323 // If the generation counts don't match then we need to update the current
michael@0 324 // thread's observer list with the new master list.
michael@0 325 IOInterposer::AutoLock lock(mLock);
michael@0 326 aPtd.SetObserverLists(mCurrentGeneration, mObserverLists);
michael@0 327 }
michael@0 328
michael@0 329 inline bool
michael@0 330 IsObservedOperation(IOInterposeObserver::Operation aOp)
michael@0 331 {
michael@0 332 // The quick reader may observe that no locks are being employed here,
michael@0 333 // hence the result of the operations is truly undefined. However, most
michael@0 334 // computers will usually return either true or false, which is good enough.
michael@0 335 // It is not a problem if we occasionally report more or less IO than is
michael@0 336 // actually occurring.
michael@0 337 return mIsEnabled && !!(mObservedOperations & aOp);
michael@0 338 }
michael@0 339
michael@0 340 private:
michael@0 341 RefPtr<ObserverLists> mObserverLists;
michael@0 342 // Note, we cannot use mozilla::Mutex here as the ObserverLists may be leaked
michael@0 343 // (We want to monitor IO during shutdown). Furthermore, as we may have to
michael@0 344 // unregister observers during shutdown an OffTheBooksMutex is not an option
michael@0 345 // either, as its base calls into sDeadlockDetector which may be nullptr
michael@0 346 // during shutdown.
michael@0 347 IOInterposer::Mutex mLock;
michael@0 348 // Flags tracking which operations are being observed
michael@0 349 IOInterposeObserver::Operation mObservedOperations;
michael@0 350 // Used for quickly disabling everything by IOInterposer::Disable()
michael@0 351 Atomic<bool> mIsEnabled;
michael@0 352 // Used to inform threads that the master observer list has changed
michael@0 353 Atomic<uint32_t> mCurrentGeneration;
michael@0 354 };
michael@0 355
michael@0 356 // Special observation used by IOInterposer::EnteringNextStage()
michael@0 357 class NextStageObservation : public IOInterposeObserver::Observation
michael@0 358 {
michael@0 359 public:
michael@0 360 NextStageObservation()
michael@0 361 : IOInterposeObserver::Observation(IOInterposeObserver::OpNextStage,
michael@0 362 "IOInterposer", false)
michael@0 363 {
michael@0 364 mStart = TimeStamp::Now();
michael@0 365 }
michael@0 366 };
michael@0 367
michael@0 368 // List of observers registered
michael@0 369 static StaticAutoPtr<MasterList> sMasterList;
michael@0 370 static ThreadLocal<PerThreadData*> sThreadLocalData;
michael@0 371 } // anonymous namespace
michael@0 372
michael@0 373 IOInterposeObserver::Observation::Observation(Operation aOperation,
michael@0 374 const char* aReference,
michael@0 375 bool aShouldReport)
michael@0 376 : mOperation(aOperation)
michael@0 377 , mReference(aReference)
michael@0 378 , mShouldReport(IOInterposer::IsObservedOperation(aOperation) &&
michael@0 379 aShouldReport)
michael@0 380 {
michael@0 381 if (mShouldReport) {
michael@0 382 mStart = TimeStamp::Now();
michael@0 383 }
michael@0 384 }
michael@0 385
michael@0 386 IOInterposeObserver::Observation::Observation(Operation aOperation,
michael@0 387 const TimeStamp& aStart,
michael@0 388 const TimeStamp& aEnd,
michael@0 389 const char* aReference)
michael@0 390 : mOperation(aOperation)
michael@0 391 , mStart(aStart)
michael@0 392 , mEnd(aEnd)
michael@0 393 , mReference(aReference)
michael@0 394 , mShouldReport(false)
michael@0 395 {
michael@0 396 }
michael@0 397
michael@0 398 const char*
michael@0 399 IOInterposeObserver::Observation::ObservedOperationString() const
michael@0 400 {
michael@0 401 switch(mOperation) {
michael@0 402 case OpCreateOrOpen:
michael@0 403 return "create/open";
michael@0 404 case OpRead:
michael@0 405 return "read";
michael@0 406 case OpWrite:
michael@0 407 return "write";
michael@0 408 case OpFSync:
michael@0 409 return "fsync";
michael@0 410 case OpStat:
michael@0 411 return "stat";
michael@0 412 case OpClose:
michael@0 413 return "close";
michael@0 414 case OpNextStage:
michael@0 415 return "NextStage";
michael@0 416 default:
michael@0 417 return "unknown";
michael@0 418 }
michael@0 419 }
michael@0 420
michael@0 421 void
michael@0 422 IOInterposeObserver::Observation::Report()
michael@0 423 {
michael@0 424 if (mShouldReport) {
michael@0 425 mEnd = TimeStamp::Now();
michael@0 426 IOInterposer::Report(*this);
michael@0 427 }
michael@0 428 }
michael@0 429
michael@0 430 bool
michael@0 431 IOInterposer::Init()
michael@0 432 {
michael@0 433 // Don't initialize twice...
michael@0 434 if (sMasterList) {
michael@0 435 return true;
michael@0 436 }
michael@0 437 if (!sThreadLocalData.init()) {
michael@0 438 return false;
michael@0 439 }
michael@0 440 #if defined(XP_WIN)
michael@0 441 bool isMainThread = XRE_GetWindowsEnvironment() !=
michael@0 442 WindowsEnvironmentType_Metro;
michael@0 443 #else
michael@0 444 bool isMainThread = true;
michael@0 445 #endif
michael@0 446 RegisterCurrentThread(isMainThread);
michael@0 447 sMasterList = new MasterList();
michael@0 448
michael@0 449 MainThreadIOLogger::Init();
michael@0 450
michael@0 451 // Now we initialize the various interposers depending on platform
michael@0 452 InitPoisonIOInterposer();
michael@0 453 // We don't hook NSPR on Windows because PoisonIOInterposer captures a
michael@0 454 // superset of the former's events.
michael@0 455 #if !defined(XP_WIN)
michael@0 456 InitNSPRIOInterposing();
michael@0 457 #endif
michael@0 458 return true;
michael@0 459 }
michael@0 460
michael@0 461 bool
michael@0 462 IOInterposeObserver::IsMainThread()
michael@0 463 {
michael@0 464 if (!sThreadLocalData.initialized()) {
michael@0 465 return false;
michael@0 466 }
michael@0 467 PerThreadData *ptd = sThreadLocalData.get();
michael@0 468 if (!ptd) {
michael@0 469 return false;
michael@0 470 }
michael@0 471 return ptd->IsMainThread();
michael@0 472 }
michael@0 473
michael@0 474 void
michael@0 475 IOInterposer::Clear()
michael@0 476 {
michael@0 477 sMasterList = nullptr;
michael@0 478 }
michael@0 479
michael@0 480 void
michael@0 481 IOInterposer::Disable()
michael@0 482 {
michael@0 483 if (!sMasterList) {
michael@0 484 return;
michael@0 485 }
michael@0 486 sMasterList->Disable();
michael@0 487 }
michael@0 488
michael@0 489 void
michael@0 490 IOInterposer::Report(IOInterposeObserver::Observation& aObservation)
michael@0 491 {
michael@0 492 MOZ_ASSERT(sMasterList);
michael@0 493 if (!sMasterList) {
michael@0 494 return;
michael@0 495 }
michael@0 496
michael@0 497 PerThreadData* ptd = sThreadLocalData.get();
michael@0 498 if (!ptd) {
michael@0 499 // In this case the current thread is not registered with IOInterposer.
michael@0 500 // Alternatively we could take the slow path and just lock everything if
michael@0 501 // we're not registered. That could potentially perform poorly, though.
michael@0 502 return;
michael@0 503 }
michael@0 504 sMasterList->Update(*ptd);
michael@0 505
michael@0 506 // Don't try to report if there's nobody listening.
michael@0 507 if (!IOInterposer::IsObservedOperation(aObservation.ObservedOperation())) {
michael@0 508 return;
michael@0 509 }
michael@0 510
michael@0 511 ptd->CallObservers(aObservation);
michael@0 512 }
michael@0 513
michael@0 514 bool
michael@0 515 IOInterposer::IsObservedOperation(IOInterposeObserver::Operation aOp)
michael@0 516 {
michael@0 517 return sMasterList && sMasterList->IsObservedOperation(aOp);
michael@0 518 }
michael@0 519
michael@0 520 void
michael@0 521 IOInterposer::Register(IOInterposeObserver::Operation aOp,
michael@0 522 IOInterposeObserver* aObserver)
michael@0 523 {
michael@0 524 MOZ_ASSERT(aObserver);
michael@0 525 if (!sMasterList || !aObserver) {
michael@0 526 return;
michael@0 527 }
michael@0 528
michael@0 529 sMasterList->Register(aOp, aObserver);
michael@0 530 }
michael@0 531
michael@0 532 void
michael@0 533 IOInterposer::Unregister(IOInterposeObserver::Operation aOp,
michael@0 534 IOInterposeObserver* aObserver)
michael@0 535 {
michael@0 536 if (!sMasterList) {
michael@0 537 return;
michael@0 538 }
michael@0 539
michael@0 540 sMasterList->Unregister(aOp, aObserver);
michael@0 541 }
michael@0 542
michael@0 543 void
michael@0 544 IOInterposer::RegisterCurrentThread(bool aIsMainThread)
michael@0 545 {
michael@0 546 if (!sThreadLocalData.initialized()) {
michael@0 547 return;
michael@0 548 }
michael@0 549 MOZ_ASSERT(!sThreadLocalData.get());
michael@0 550 PerThreadData* curThreadData = new PerThreadData(aIsMainThread);
michael@0 551 sThreadLocalData.set(curThreadData);
michael@0 552 }
michael@0 553
michael@0 554 void
michael@0 555 IOInterposer::UnregisterCurrentThread()
michael@0 556 {
michael@0 557 if (!sThreadLocalData.initialized()) {
michael@0 558 return;
michael@0 559 }
michael@0 560 PerThreadData* curThreadData = sThreadLocalData.get();
michael@0 561 MOZ_ASSERT(curThreadData);
michael@0 562 sThreadLocalData.set(nullptr);
michael@0 563 delete curThreadData;
michael@0 564 }
michael@0 565
michael@0 566 void
michael@0 567 IOInterposer::EnteringNextStage()
michael@0 568 {
michael@0 569 if (!sMasterList) {
michael@0 570 return;
michael@0 571 }
michael@0 572 NextStageObservation observation;
michael@0 573 Report(observation);
michael@0 574 }
michael@0 575

mercurial