michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef _nsCacheRequest_h_ michael@0: #define _nsCacheRequest_h_ michael@0: michael@0: #include "nspr.h" michael@0: #include "mozilla/CondVar.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsICache.h" michael@0: #include "nsICacheListener.h" michael@0: #include "nsCacheSession.h" michael@0: #include "nsCacheService.h" michael@0: michael@0: michael@0: class nsCacheRequest : public PRCList michael@0: { michael@0: typedef mozilla::CondVar CondVar; michael@0: typedef mozilla::MutexAutoLock MutexAutoLock; michael@0: typedef mozilla::Mutex Mutex; michael@0: michael@0: private: michael@0: friend class nsCacheService; michael@0: friend class nsCacheEntry; michael@0: friend class nsProcessRequestEvent; michael@0: michael@0: nsCacheRequest( const nsACString & key, michael@0: nsICacheListener * listener, michael@0: nsCacheAccessMode accessRequested, michael@0: bool blockingMode, michael@0: nsCacheSession * session) michael@0: : mKey(key), michael@0: mInfo(0), michael@0: mListener(listener), michael@0: mLock("nsCacheRequest.mLock"), michael@0: mCondVar(mLock, "nsCacheRequest.mCondVar"), michael@0: mProfileDir(session->ProfileDir()) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCacheRequest); michael@0: PR_INIT_CLIST(this); michael@0: SetAccessRequested(accessRequested); michael@0: SetStoragePolicy(session->StoragePolicy()); michael@0: if (session->IsStreamBased()) MarkStreamBased(); michael@0: if (session->WillDoomEntriesIfExpired()) MarkDoomEntriesIfExpired(); michael@0: if (session->IsPrivate()) MarkPrivate(); michael@0: if (blockingMode == nsICache::BLOCKING) MarkBlockingMode(); michael@0: MarkWaitingForValidation(); michael@0: NS_IF_ADDREF(mListener); michael@0: } michael@0: michael@0: ~nsCacheRequest() michael@0: { michael@0: MOZ_COUNT_DTOR(nsCacheRequest); michael@0: NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "request still on a list"); michael@0: michael@0: if (mListener) michael@0: nsCacheService::ReleaseObject_Locked(mListener, mThread); michael@0: } michael@0: michael@0: /** michael@0: * Simple Accessors michael@0: */ michael@0: enum CacheRequestInfo { michael@0: eStoragePolicyMask = 0x000000FF, michael@0: eStreamBasedMask = 0x00000100, michael@0: ePrivateMask = 0x00000200, michael@0: eDoomEntriesIfExpiredMask = 0x00001000, michael@0: eBlockingModeMask = 0x00010000, michael@0: eWaitingForValidationMask = 0x00100000, michael@0: eAccessRequestedMask = 0xFF000000 michael@0: }; michael@0: michael@0: void SetAccessRequested(nsCacheAccessMode mode) michael@0: { michael@0: NS_ASSERTION(mode <= 0xFF, "too many bits in nsCacheAccessMode"); michael@0: mInfo &= ~eAccessRequestedMask; michael@0: mInfo |= mode << 24; michael@0: } michael@0: michael@0: nsCacheAccessMode AccessRequested() michael@0: { michael@0: return (nsCacheAccessMode)((mInfo >> 24) & 0xFF); michael@0: } michael@0: michael@0: void MarkStreamBased() { mInfo |= eStreamBasedMask; } michael@0: bool IsStreamBased() { return (mInfo & eStreamBasedMask) != 0; } michael@0: michael@0: michael@0: void MarkDoomEntriesIfExpired() { mInfo |= eDoomEntriesIfExpiredMask; } michael@0: bool WillDoomEntriesIfExpired() { return (0 != (mInfo & eDoomEntriesIfExpiredMask)); } michael@0: michael@0: void MarkBlockingMode() { mInfo |= eBlockingModeMask; } michael@0: bool IsBlocking() { return (0 != (mInfo & eBlockingModeMask)); } michael@0: bool IsNonBlocking() { return !(mInfo & eBlockingModeMask); } michael@0: michael@0: void SetStoragePolicy(nsCacheStoragePolicy policy) michael@0: { michael@0: NS_ASSERTION(policy <= 0xFF, "too many bits in nsCacheStoragePolicy"); michael@0: mInfo &= ~eStoragePolicyMask; // clear storage policy bits michael@0: mInfo |= policy; // or in new bits michael@0: } michael@0: michael@0: nsCacheStoragePolicy StoragePolicy() michael@0: { michael@0: return (nsCacheStoragePolicy)(mInfo & eStoragePolicyMask); michael@0: } michael@0: michael@0: void MarkPrivate() { mInfo |= ePrivateMask; } michael@0: void MarkPublic() { mInfo &= ~ePrivateMask; } michael@0: bool IsPrivate() { return (mInfo & ePrivateMask) != 0; } michael@0: michael@0: void MarkWaitingForValidation() { mInfo |= eWaitingForValidationMask; } michael@0: void DoneWaitingForValidation() { mInfo &= ~eWaitingForValidationMask; } michael@0: bool WaitingForValidation() michael@0: { michael@0: return (mInfo & eWaitingForValidationMask) != 0; michael@0: } michael@0: michael@0: nsresult michael@0: WaitForValidation(void) michael@0: { michael@0: if (!WaitingForValidation()) { // flag already cleared michael@0: MarkWaitingForValidation(); // set up for next time michael@0: return NS_OK; // early exit; michael@0: } michael@0: { michael@0: MutexAutoLock lock(mLock); michael@0: while (WaitingForValidation()) { michael@0: mCondVar.Wait(); michael@0: } michael@0: MarkWaitingForValidation(); // set up for next time michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: void WakeUp(void) { michael@0: DoneWaitingForValidation(); michael@0: MutexAutoLock lock(mLock); michael@0: mCondVar.Notify(); michael@0: } michael@0: michael@0: /** michael@0: * Data members michael@0: */ michael@0: nsCString mKey; michael@0: uint32_t mInfo; michael@0: nsICacheListener * mListener; // strong ref michael@0: nsCOMPtr mThread; michael@0: Mutex mLock; michael@0: CondVar mCondVar; michael@0: nsCOMPtr mProfileDir; michael@0: }; michael@0: michael@0: #endif // _nsCacheRequest_h_