LCOV - code coverage report
Current view: directory - src/trusted/weak_ref - weak_ref.h (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 23 0 0.0 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /* -*- c++ -*- */
       2                 : /*
       3                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       4                 :  * Use of this source code is governed by a BSD-style license that can be
       5                 :  * found in the LICENSE file.
       6                 :  */
       7                 : 
       8                 : // A form of weak reference for use by CallOnMainThread (COMT) and
       9                 : // other callback situations.  This class is essentially a thread-safe
      10                 : // refcounted class that is used to hold pointers to resources that
      11                 : // may "go away" due to the plugin instance being destroyed.
      12                 : // Generally resource cleanup should be handled by the contained
      13                 : // class's dtor.
      14                 : //
      15                 : // Here is the intended use case.  Every plug-in instance contains a
      16                 : // reference to a WeakRefAnchor object.  Callbacks must use only
      17                 : // resources pointed to by a WeakRef object -- when COMT is invoked,
      18                 : // the COMT-queue owns a reference to the WeakRef object.  When a
      19                 : // WeakRefAnchor object is abandoned (typically in the plug-in dtor),
      20                 : // it ensures that all associated callbacks will either not be called
      21                 : // (if the callback takes a resource pointer) or will be invoked with
      22                 : // a WeakRef<Resource>* object which yields NULL when the
      23                 : // ReleaseAndUnref method is invoked on it.  After the callback fires,
      24                 : // the resource associated with the callback is deleted.  This is
      25                 : // required when, for example, the completion callback resource is the
      26                 : // I/O buffer into which a Read operation is writing; we must wait for
      27                 : // the Read completion event before we can deallocate the destination
      28                 : // buffer.
      29                 : //
      30                 : // In the normal execution, the callback data is present, and the
      31                 : // callback function should or save its contents elsewhere if needed;
      32                 : // the callback data is deleted after the callback function returns.
      33                 : 
      34                 : 
      35                 : // EXAMPLE USAGE
      36                 : //
      37                 : // class Foo {
      38                 : //   Foo() : anchor_(new WeakRefAnchor);
      39                 : //   ~Foo() {
      40                 : //     anchor_->Abandon();
      41                 : //   }
      42                 : //   static void DoOperation_MainThread(void* vargs, int32_t result) {
      43                 : //     WeakRef<OpArgument>* args =
      44                 : //       reinterpret_cast<WeakRef<OpArgument>*>(vargs);
      45                 : //     scoped_ptr<OpArgument> p;
      46                 : //     args->ReleaseAndUnref(&p);
      47                 : //     if (p != NULL) {
      48                 : //       ... stash away elements of p...
      49                 : //     }
      50                 : //   }
      51                 : //   ScheduleOperation() {
      52                 : //      OpArgument* args = new OpArgument(...);
      53                 : //      pp::CompletionCallback cc(DoOperation_MainThread,
      54                 : //   WeakRefAnchor* anchor_;
      55                 : // };
      56                 : //
      57                 : // Improved syntactic sugar makes this even simpler in
      58                 : // <call_on_main_thread.h>.
      59                 : 
      60                 : 
      61                 : // This class operates much like CompletionCallbackFactory (if
      62                 : // instantiated with a thread-safe RefCount class), except that
      63                 : // appropriate memory barriers are included to ensure that partial
      64                 : // memory writes are not seen by other threads.  Here is the memory
      65                 : // consistency issue:
      66                 : //
      67                 : // In <completion_callback.h>'s CompletionCallbackFactory<T>, the only
      68                 : // memory barriers are with the refcount adjustment.  In
      69                 : // ResetBackPointer, we follow DropFactory() immediately by Release().
      70                 : // Imagine another thread that reads the factory_ value via
      71                 : // back_pointer_->GetObject().  The assignment of NULL to
      72                 : // back_pointer_->factory_ may result in more than one bus cycle. That
      73                 : // means a read from another thread may yield a garbled value,
      74                 : // comprised of some combination of the original pointer bits and
      75                 : // zeros -- this may occur even on Intel architectures where any
      76                 : // visible memory changes must be in the original write order, if the
      77                 : // pointer were to span cache lines (e.g., packed attribute used).
      78                 : 
      79                 : #ifndef NATIVE_CLIENT_SRC_TRUSTED_WEAK_REF_WEAK_REF_H_
      80                 : #define NATIVE_CLIENT_SRC_TRUSTED_WEAK_REF_WEAK_REF_H_
      81                 : 
      82                 : #include "native_client/src/include/portability.h"
      83                 : #include "native_client/src/include/nacl_base.h"
      84                 : #include "native_client/src/include/nacl_scoped_ptr.h"
      85                 : #include "native_client/src/shared/platform/refcount_base.h"
      86                 : #include "native_client/src/shared/platform/nacl_check.h"
      87                 : #include "native_client/src/shared/platform/nacl_log.h"
      88                 : #include "native_client/src/shared/platform/nacl_sync.h"
      89                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      90                 : #include "native_client/src/shared/platform/nacl_sync_raii.h"
      91                 : 
      92                 : namespace nacl {
      93                 : 
      94                 : static char const* const kWeakRefModuleName = "weak_ref";
      95                 : 
      96                 : class WeakRefAnchor;
      97                 : 
      98                 : class AnchoredResource : public RefCountBase {
      99                 :  public:
     100                 :   explicit AnchoredResource(WeakRefAnchor* anchor);
     101                 : 
     102                 :   virtual ~AnchoredResource();
     103                 : 
     104                 :   // covariant impl of Ref()
     105                 :   AnchoredResource* Ref() {
     106                 :     return reinterpret_cast<AnchoredResource*>(RefCountBase::Ref());
     107                 :   }
     108                 : 
     109                 :  protected:
     110                 :   friend class WeakRefAnchor;
     111                 : 
     112                 :   WeakRefAnchor* anchor_;
     113                 :   NaClMutex mu_;
     114                 : 
     115                 :   DISALLOW_COPY_AND_ASSIGN(AnchoredResource);
     116                 : };
     117                 : 
     118                 : template <typename R> class WeakRef;  // fwd
     119                 : 
     120                 : // Plugin instance should hold a reference, and pass new references to
     121                 : // the WeakRefAnchor to any threads that may need to create callbacks.
     122                 : // The plugin instance should invoke Abandon before Unref'ing its
     123                 : // pointer to its WeakRefAnchor object.  When all threads that may
     124                 : // want to invoke COMT have exited (through some unspecified
     125                 : // notification mechanism, e.g., RPC channel closure, then the
     126                 : // WeakRefAnchor will get reclaimed.
     127                 : 
     128                 : class WeakRefAnchor : public RefCountBase {
     129                 :  public:
     130                 :   WeakRefAnchor();
     131                 : 
     132                 :   // covariant impl of Ref()
     133               0 :   WeakRefAnchor* Ref() {
     134               0 :     return reinterpret_cast<WeakRefAnchor*>(RefCountBase::Ref());
     135                 :   }
     136                 :   bool is_abandoned();
     137                 : 
     138                 :   // Mark anchor as abandoned.  Does not Unref(), so caller still has
     139                 :   // to do that.
     140                 :   void Abandon();
     141                 : 
     142                 :   // If MakeWeakRef fails, i.e., the WeakRefAnchor had been abandoned
     143                 :   // in the main thread, then it returns NULL and the caller is
     144                 :   // responsible for releasing the resource represented by
     145                 :   // raw_resource; if MakeWeakRef succeeds, then it takes ownership of
     146                 :   // raw_resource and has wrapped in in the WeakRef<R>* object, which
     147                 :   // can be used as argument to the callback function for COMT.  After
     148                 :   // ownership passes, the caller must not continue to use the
     149                 :   // raw_resource, since the main thread may Abandon the anchor at any
     150                 :   // time and cause raw_resource to have its dtor invoked in
     151                 :   // WeakRef<R>::reset_mu.
     152                 :   template <typename R>
     153               0 :   WeakRef<R>* MakeWeakRef(R* raw_resource) {
     154               0 :     WeakRef<R>* rp = NULL;
     155               0 :     NaClLog2(kWeakRefModuleName, 4,
     156                 :              "Entered WeakRef<R>::MakeWeakRef, raw 0x%"NACL_PRIxPTR"\n",
     157                 :              (uintptr_t) raw_resource);
     158               0 :     CHECK(raw_resource != NULL);
     159               0 :     rp = new WeakRef<R>(this, raw_resource);
     160                 :     // If the WeakRefAnchor was already abandoned, we make a WeakRef anyway,
     161                 :     // and the use of the WeakRef will discover this.
     162               0 :     CHECK(rp != NULL);
     163               0 :     NaClLog2(kWeakRefModuleName, 4,
     164                 :              "Leaving WeakRef<R>::MakeWeakRef, weak_ref 0x%"NACL_PRIxPTR"\n",
     165                 :              (uintptr_t) rp);
     166               0 :     return rp;
     167                 :   }
     168                 : 
     169                 :  protected:
     170                 :   ~WeakRefAnchor();
     171                 : 
     172                 :  private:
     173                 :   NaClMutex mu_;
     174                 : 
     175                 :   bool abandoned_;
     176                 : 
     177                 :   DISALLOW_COPY_AND_ASSIGN(WeakRefAnchor);
     178                 : };
     179                 : 
     180                 : // The resource type R should contain everything that a callback
     181                 : // function needs.  In particular, it may contain a reference to a
     182                 : // WeakRefAnchor object if the callback function may in turn want to
     183                 : // schedule more callbacks -- and the WeakRefAnchor refcount should be
     184                 : // properly managed (releasing when R is destroyed, incremented when a
     185                 : // reference is passed to another resource R' for the chained
     186                 : // callback).  If a reference to the plugin or other associated object
     187                 : // is needed, that can be a "naked" pointer in the callback use case
     188                 : // since the callback is only invoked on the main thread, and the
     189                 : // plugin can only be shut down in the main thread (it cannot go
     190                 : // away).  In general, for use cases where the WeakRef resource might
     191                 : // be used in an arbitrary other thread, no naked, non-refcounted
     192                 : // objects should be referred to from WeakRef wrapped resources.
     193                 : //
     194                 : template <typename R>
     195                 : class WeakRef : public AnchoredResource {
     196                 :   // public base class, needed for win64_newlib_dbg.  why?
     197                 :  public:
     198                 :   // Single use!  Invoked only from main thread, so anchor will not be
     199                 :   // doing Abandon() at the same time.  After ReleaseAndUnref, caller
     200                 :   // must not use the pointer to the WeakRef object further.
     201               0 :   void ReleaseAndUnref(scoped_ptr<R>* out_ptr) {
     202               0 :     NaClLog2(kWeakRefModuleName, 4,
     203                 :              "Entered WeakRef<R>::ReleaseAndUnref: this 0x%"NACL_PRIxPTR"\n",
     204                 :              (uintptr_t) this);
     205                 :     do {
     206               0 :       nacl::MutexLocker take(&mu_);
     207               0 :       if (anchor_->is_abandoned()) {
     208               0 :         delete resource_.release();
     209               0 :         out_ptr->reset();
     210                 :       } else {
     211               0 :         out_ptr->reset(resource_.release());
     212                 :       }
     213                 :     } while (0);
     214               0 :     NaClLog2(kWeakRefModuleName, 4,
     215                 :              "Leaving ReleaseAndUnref: raw: out_ptr->get() 0x%"NACL_PRIxPTR"\n",
     216                 :              (uintptr_t) out_ptr->get());
     217               0 :     Unref();  // release ref associated with the callback
     218                 :   }
     219                 : 
     220                 :  protected:
     221               0 :   virtual ~WeakRef() {}
     222                 : 
     223                 :  private:
     224                 :   friend class WeakRefAnchor;
     225                 : 
     226               0 :   WeakRef(WeakRefAnchor* anchor, R* resource)
     227                 :       : AnchoredResource(anchor),
     228               0 :         resource_(resource) {
     229               0 :     CHECK(resource != NULL);
     230                 :   }
     231                 : 
     232                 :   scoped_ptr<R> resource_;  // NULL when anchor object is destroyed.
     233                 : 
     234                 :   DISALLOW_COPY_AND_ASSIGN(WeakRef);
     235                 : };
     236                 : 
     237                 : }  // namespace nacl
     238                 : 
     239                 : #endif

Generated by: LCOV version 1.7