michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ 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 mozilla_plugins_MiniShmBase_h michael@0: #define mozilla_plugins_MiniShmBase_h michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "nsDebug.h" michael@0: michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: namespace plugins { michael@0: michael@0: /** michael@0: * This class is used to provide RAII semantics for mapped views. michael@0: * @see ScopedHandle michael@0: */ michael@0: class ScopedMappedFileView michael@0: { michael@0: public: michael@0: explicit michael@0: ScopedMappedFileView(LPVOID aView) michael@0: : mView(aView) michael@0: { michael@0: } michael@0: michael@0: ~ScopedMappedFileView() michael@0: { michael@0: Close(); michael@0: } michael@0: michael@0: void michael@0: Close() michael@0: { michael@0: if (mView) { michael@0: ::UnmapViewOfFile(mView); michael@0: mView = nullptr; michael@0: } michael@0: } michael@0: michael@0: void michael@0: Set(LPVOID aView) michael@0: { michael@0: Close(); michael@0: mView = aView; michael@0: } michael@0: michael@0: LPVOID michael@0: Get() const michael@0: { michael@0: return mView; michael@0: } michael@0: michael@0: LPVOID michael@0: Take() michael@0: { michael@0: LPVOID result = mView; michael@0: mView = nullptr; michael@0: return result; michael@0: } michael@0: michael@0: operator LPVOID() michael@0: { michael@0: return mView; michael@0: } michael@0: michael@0: bool michael@0: IsValid() const michael@0: { michael@0: return (mView); michael@0: } michael@0: michael@0: private: michael@0: DISALLOW_COPY_AND_ASSIGN(ScopedMappedFileView); michael@0: michael@0: LPVOID mView; michael@0: }; michael@0: michael@0: class MiniShmBase; michael@0: michael@0: class MiniShmObserver michael@0: { michael@0: public: michael@0: /** michael@0: * This function is called whenever there is a new shared memory request. michael@0: * @param aMiniShmObj MiniShmBase object that may be used to read and michael@0: * write from shared memory. michael@0: */ michael@0: virtual void OnMiniShmEvent(MiniShmBase *aMiniShmObj) = 0; michael@0: /** michael@0: * This function is called once when a MiniShmParent and a MiniShmChild michael@0: * object have successfully negotiated a connection. michael@0: * michael@0: * @param aMiniShmObj MiniShmBase object that may be used to read and michael@0: * write from shared memory. michael@0: */ michael@0: virtual void OnMiniShmConnect(MiniShmBase *aMiniShmObj) { } michael@0: }; michael@0: michael@0: /** michael@0: * Base class for MiniShm connections. This class defines the common michael@0: * interfaces and code between parent and child. michael@0: */ michael@0: class MiniShmBase michael@0: { michael@0: public: michael@0: /** michael@0: * Obtains a writable pointer into shared memory of type T. michael@0: * typename T must be plain-old-data and contain an unsigned integral michael@0: * member T::identifier that uniquely identifies T with respect to michael@0: * other types used by the protocol being implemented. michael@0: * michael@0: * @param aPtr Pointer to receive the shared memory address. michael@0: * This value is set if and only if the function michael@0: * succeeded. michael@0: * @return NS_OK if and only if aPtr was successfully obtained. michael@0: * NS_ERROR_ILLEGAL_VALUE if type T is not valid for MiniShm. michael@0: * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. michael@0: * NS_ERROR_NOT_AVAILABLE if the memory is not safe to write. michael@0: */ michael@0: template nsresult michael@0: GetWritePtr(T*& aPtr) michael@0: { michael@0: if (!mWriteHeader || !mGuard) { michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: if (sizeof(T) > mPayloadMaxLen || michael@0: T::identifier <= RESERVED_CODE_LAST) { michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: if (::WaitForSingleObject(mGuard, mTimeout) != WAIT_OBJECT_0) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: mWriteHeader->mId = T::identifier; michael@0: mWriteHeader->mPayloadLen = sizeof(T); michael@0: aPtr = reinterpret_cast(mWriteHeader + 1); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * Obtains a readable pointer into shared memory of type T. michael@0: * typename T must be plain-old-data and contain an unsigned integral michael@0: * member T::identifier that uniquely identifies T with respect to michael@0: * other types used by the protocol being implemented. michael@0: * michael@0: * @param aPtr Pointer to receive the shared memory address. michael@0: * This value is set if and only if the function michael@0: * succeeded. michael@0: * @return NS_OK if and only if aPtr was successfully obtained. michael@0: * NS_ERROR_ILLEGAL_VALUE if type T is not valid for MiniShm or if michael@0: * type T does not match the type of the data michael@0: * stored in shared memory. michael@0: * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. michael@0: */ michael@0: template nsresult michael@0: GetReadPtr(const T*& aPtr) michael@0: { michael@0: if (!mReadHeader) { michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: if (mReadHeader->mId != T::identifier || michael@0: sizeof(T) != mReadHeader->mPayloadLen) { michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: aPtr = reinterpret_cast(mReadHeader + 1); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * Fires the peer's event causing its request handler to execute. michael@0: * michael@0: * @return Should return NS_OK if the send was successful. michael@0: */ michael@0: virtual nsresult michael@0: Send() = 0; michael@0: michael@0: protected: michael@0: /** michael@0: * MiniShm reserves some identifier codes for its own use. Any michael@0: * identifiers used by MiniShm protocol implementations must be michael@0: * greater than RESERVED_CODE_LAST. michael@0: */ michael@0: enum ReservedCodes michael@0: { michael@0: RESERVED_CODE_INIT = 0, michael@0: RESERVED_CODE_INIT_COMPLETE = 1, michael@0: RESERVED_CODE_LAST = RESERVED_CODE_INIT_COMPLETE michael@0: }; michael@0: michael@0: struct MiniShmHeader michael@0: { michael@0: unsigned int mId; michael@0: unsigned int mPayloadLen; michael@0: }; michael@0: michael@0: struct MiniShmInit michael@0: { michael@0: enum identifier_t michael@0: { michael@0: identifier = RESERVED_CODE_INIT michael@0: }; michael@0: HANDLE mParentEvent; michael@0: HANDLE mParentGuard; michael@0: HANDLE mChildEvent; michael@0: HANDLE mChildGuard; michael@0: }; michael@0: michael@0: struct MiniShmInitComplete michael@0: { michael@0: enum identifier_t michael@0: { michael@0: identifier = RESERVED_CODE_INIT_COMPLETE michael@0: }; michael@0: bool mSucceeded; michael@0: }; michael@0: michael@0: MiniShmBase() michael@0: : mObserver(nullptr), michael@0: mWriteHeader(nullptr), michael@0: mReadHeader(nullptr), michael@0: mPayloadMaxLen(0), michael@0: mGuard(nullptr), michael@0: mTimeout(INFINITE) michael@0: { michael@0: } michael@0: virtual ~MiniShmBase() michael@0: { } michael@0: michael@0: virtual void michael@0: OnEvent() michael@0: { michael@0: if (mObserver) { michael@0: mObserver->OnMiniShmEvent(this); michael@0: } michael@0: } michael@0: michael@0: virtual void michael@0: OnConnect() michael@0: { michael@0: if (mObserver) { michael@0: mObserver->OnMiniShmConnect(this); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: SetView(LPVOID aView, const unsigned int aSize, bool aIsChild) michael@0: { michael@0: if (!aView || aSize <= 2 * sizeof(MiniShmHeader)) { michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: // Divide the region into halves for parent and child michael@0: if (aIsChild) { michael@0: mReadHeader = static_cast(aView); michael@0: mWriteHeader = reinterpret_cast(static_cast(aView) michael@0: + aSize / 2U); michael@0: } else { michael@0: mWriteHeader = static_cast(aView); michael@0: mReadHeader = reinterpret_cast(static_cast(aView) michael@0: + aSize / 2U); michael@0: } michael@0: mPayloadMaxLen = aSize / 2U - sizeof(MiniShmHeader); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SetGuard(HANDLE aGuard, DWORD aTimeout) michael@0: { michael@0: if (!aGuard || !aTimeout) { michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: mGuard = aGuard; michael@0: mTimeout = aTimeout; michael@0: return NS_OK; michael@0: } michael@0: michael@0: inline void michael@0: SetObserver(MiniShmObserver *aObserver) { mObserver = aObserver; } michael@0: michael@0: /** michael@0: * Obtains a writable pointer into shared memory of type T. This version michael@0: * differs from GetWritePtr in that it allows typename T to be one of michael@0: * the private data structures declared in MiniShmBase. michael@0: * michael@0: * @param aPtr Pointer to receive the shared memory address. michael@0: * This value is set if and only if the function michael@0: * succeeded. michael@0: * @return NS_OK if and only if aPtr was successfully obtained. michael@0: * NS_ERROR_ILLEGAL_VALUE if type T not an internal MiniShm struct. michael@0: * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. michael@0: */ michael@0: template nsresult michael@0: GetWritePtrInternal(T*& aPtr) michael@0: { michael@0: if (!mWriteHeader) { michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: if (sizeof(T) > mPayloadMaxLen || michael@0: T::identifier > RESERVED_CODE_LAST) { michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: mWriteHeader->mId = T::identifier; michael@0: mWriteHeader->mPayloadLen = sizeof(T); michael@0: aPtr = reinterpret_cast(mWriteHeader + 1); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static VOID CALLBACK michael@0: SOnEvent(PVOID aContext, BOOLEAN aIsTimer) michael@0: { michael@0: MiniShmBase* object = static_cast(aContext); michael@0: object->OnEvent(); michael@0: } michael@0: michael@0: private: michael@0: MiniShmObserver* mObserver; michael@0: MiniShmHeader* mWriteHeader; michael@0: MiniShmHeader* mReadHeader; michael@0: unsigned int mPayloadMaxLen; michael@0: HANDLE mGuard; michael@0: DWORD mTimeout; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(MiniShmBase); michael@0: }; michael@0: michael@0: } // namespace plugins michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_plugins_MiniShmBase_h michael@0: