1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #pragma once 6 7 /* 8 * Wrapper - Helper class for wrapper objects. 9 * 10 * This helps to construct a shared_ptr object which wraps access to an 11 * underlying handle. (The handle could be a pointer to some low-level type, a 12 * conventional C handle, an int ID, a GUID, etc.) 13 * 14 * Usage: 15 * To obtain a FooPtr from a foo_handle_t, call 16 * FooPtr Foo::wrap(foo_handle_t); 17 * 18 * To implement Foo using Wrapper, Foo needs to include this macro in its class 19 * definition: 20 * CSF_DECLARE_WRAP(Foo, foo_handle_t); 21 * It also needs to include this in the cpp file, to provide the wrap() 22 * implementation and define the static Wrapper. 23 * CSF_IMPLEMENT_WRAP(Foo, foo_handle_t); 24 * These are all declared in common/Wrapper.h - Foo.h needs to include this 25 * too. 26 * The client needs to declare Foo(foo_handle_t) as private, and provide a 27 * suitable implementation, as well as implementing wrappers for any other 28 * functions to be exposed. 29 * The client needs to implement ~Foo() to perform any cleanup as usual. 30 * 31 * wrap() will always return the same FooPtr for a given foo_handle_t, it will 32 * not construct additional objects if a suitable one already exists. 33 * changeHandle() is used in rare cases where the underlying handle is changed, 34 * but the wrapper object is intended to remain. This is the 35 * case for the "fake" CC_DPCall generated on 36 * CC_DPLine::CreateCall(), where the correct IDPCall* is 37 * provided later. 38 * reset() is a cleanup step to wipe the handle map and allow memory to be 39 * reclaimed. 40 * 41 * Future enhancements: 42 * - For now, objects remain in the map forever. Better would be to add a 43 * releaseHandle() function which would allow the map to be emptied as 44 * underlying handles expired. While we can't force the client to give up 45 * its shared_ptr<Foo> objects, we can remove our own copy, for instance on a 46 * call ended event. 47 */ 48 49 #include <map> 50 #include "prlock.h" 51 #include "mozilla/Assertions.h" 52 53 /* 54 * Wrapper has its own autolock class because the instances are declared 55 * statically and mozilla::Mutex will not work properly when instantiated 56 * in a static constructor. 57 */ 58 59 class LockNSPR { 60 public: LockNSPR()61 LockNSPR() : lock_(nullptr) { 62 lock_ = PR_NewLock(); 63 MOZ_ASSERT(lock_); 64 } ~LockNSPR()65 ~LockNSPR() { PR_DestroyLock(lock_); } 66 Acquire()67 void Acquire() { PR_Lock(lock_); } 68 Release()69 void Release() { PR_Unlock(lock_); } 70 71 private: 72 PRLock* lock_; 73 }; 74 75 class AutoLockNSPR { 76 public: AutoLockNSPR(LockNSPR & lock)77 explicit AutoLockNSPR(LockNSPR& lock) : lock_(lock) { lock_.Acquire(); } ~AutoLockNSPR()78 ~AutoLockNSPR() { lock_.Release(); } 79 80 private: 81 LockNSPR& lock_; 82 }; 83 84 template <class T> 85 class Wrapper { 86 private: 87 typedef std::map<typename T::Handle, typename T::Ptr> HandleMapType; 88 HandleMapType handleMap; 89 LockNSPR handleMapMutex; 90 91 public: Wrapper()92 Wrapper() {} 93 wrap(typename T::Handle handle)94 typename T::Ptr wrap(typename T::Handle handle) { 95 AutoLockNSPR lock(handleMapMutex); 96 typename HandleMapType::iterator it = handleMap.find(handle); 97 if (it != handleMap.end()) { 98 return it->second; 99 } else { 100 typename T::Ptr p(new T(handle)); 101 handleMap[handle] = p; 102 return p; 103 } 104 } 105 changeHandle(typename T::Handle oldHandle,typename T::Handle newHandle)106 bool changeHandle(typename T::Handle oldHandle, 107 typename T::Handle newHandle) { 108 AutoLockNSPR lock(handleMapMutex); 109 typename HandleMapType::iterator it = handleMap.find(oldHandle); 110 if (it != handleMap.end()) { 111 typename T::Ptr p = it->second; 112 handleMap.erase(it); 113 handleMap[newHandle] = p; 114 return true; 115 } else { 116 return false; 117 } 118 } 119 release(typename T::Handle handle)120 bool release(typename T::Handle handle) { 121 AutoLockNSPR lock(handleMapMutex); 122 typename HandleMapType::iterator it = handleMap.find(handle); 123 if (it != handleMap.end()) { 124 handleMap.erase(it); 125 return true; 126 } else { 127 return false; 128 } 129 } 130 reset()131 void reset() { 132 AutoLockNSPR lock(handleMapMutex); 133 handleMap.clear(); 134 } 135 }; 136 137 #define CSF_DECLARE_WRAP(classname, handletype) \ 138 public: \ 139 static classname##Ptr wrap(handletype handle); \ 140 static void reset(); \ 141 static void release(handletype handle); \ 142 \ 143 private: \ 144 friend class Wrapper<classname>; \ 145 typedef classname##Ptr Ptr; \ 146 typedef handletype Handle; \ 147 static Wrapper<classname>& getWrapper() { \ 148 static Wrapper<classname> wrapper; \ 149 return wrapper; \ 150 } 151 152 #define CSF_IMPLEMENT_WRAP(classname, handletype) \ 153 classname##Ptr classname::wrap(handletype handle) { \ 154 return getWrapper().wrap(handle); \ 155 } \ 156 void classname::reset() { getWrapper().reset(); } \ 157 void classname::release(handletype handle) { getWrapper().release(handle); } 158