tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Wrapper.h (5144B)


      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 
     51 #include "mozilla/Assertions.h"
     52 #include "prlock.h"
     53 
     54 /*
     55 * Wrapper has its own autolock class because the instances are declared
     56 * statically and mozilla::Mutex will not work properly when instantiated
     57 * in a static constructor.
     58 */
     59 
     60 class LockNSPR {
     61 public:
     62  LockNSPR() : lock_(nullptr) {
     63    lock_ = PR_NewLock();
     64    MOZ_ASSERT(lock_);
     65  }
     66  ~LockNSPR() { PR_DestroyLock(lock_); }
     67 
     68  void Acquire() { PR_Lock(lock_); }
     69 
     70  void Release() { PR_Unlock(lock_); }
     71 
     72 private:
     73  PRLock* lock_;
     74 };
     75 
     76 class AutoLockNSPR {
     77 public:
     78  explicit AutoLockNSPR(LockNSPR& lock) : lock_(lock) { lock_.Acquire(); }
     79  ~AutoLockNSPR() { lock_.Release(); }
     80 
     81 private:
     82  LockNSPR& lock_;
     83 };
     84 
     85 template <class T>
     86 class Wrapper {
     87 private:
     88  typedef std::map<typename T::Handle, typename T::Ptr> HandleMapType;
     89  HandleMapType handleMap;
     90  LockNSPR handleMapMutex;
     91 
     92 public:
     93  Wrapper() {}
     94 
     95  typename T::Ptr wrap(typename T::Handle handle) {
     96    AutoLockNSPR lock(handleMapMutex);
     97    typename HandleMapType::iterator it = handleMap.find(handle);
     98    if (it != handleMap.end()) {
     99      return it->second;
    100    } else {
    101      typename T::Ptr p(new T(handle));
    102      handleMap[handle] = p;
    103      return p;
    104    }
    105  }
    106 
    107  bool changeHandle(typename T::Handle oldHandle,
    108                    typename T::Handle newHandle) {
    109    AutoLockNSPR lock(handleMapMutex);
    110    typename HandleMapType::iterator it = handleMap.find(oldHandle);
    111    if (it != handleMap.end()) {
    112      typename T::Ptr p = it->second;
    113      handleMap.erase(it);
    114      handleMap[newHandle] = p;
    115      return true;
    116    } else {
    117      return false;
    118    }
    119  }
    120 
    121  bool release(typename T::Handle handle) {
    122    AutoLockNSPR lock(handleMapMutex);
    123    typename HandleMapType::iterator it = handleMap.find(handle);
    124    if (it != handleMap.end()) {
    125      handleMap.erase(it);
    126      return true;
    127    } else {
    128      return false;
    129    }
    130  }
    131 
    132  void reset() {
    133    AutoLockNSPR lock(handleMapMutex);
    134    handleMap.clear();
    135  }
    136 };
    137 
    138 #define CSF_DECLARE_WRAP(classname, handletype)  \
    139 public:                                         \
    140  static classname##Ptr wrap(handletype handle); \
    141  static void reset();                           \
    142  static void release(handletype handle);        \
    143                                                 \
    144 private:                                        \
    145  friend class Wrapper<classname>;               \
    146  typedef classname##Ptr Ptr;                    \
    147  typedef handletype Handle;                     \
    148  static Wrapper<classname>& getWrapper() {      \
    149    static Wrapper<classname> wrapper;           \
    150    return wrapper;                              \
    151  }
    152 
    153 #define CSF_IMPLEMENT_WRAP(classname, handletype)     \
    154  classname##Ptr classname::wrap(handletype handle) { \
    155    return getWrapper().wrap(handle);                 \
    156  }                                                   \
    157  void classname::reset() { getWrapper().reset(); }   \
    158  void classname::release(handletype handle) { getWrapper().release(handle); }