Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_WIN_SCOPED_HANDLE_H_
      6 #define BASE_WIN_SCOPED_HANDLE_H_
      7 
      8 #include <windows.h>
      9 
     10 #include "base/base_export.h"
     11 #include "base/basictypes.h"
     12 #include "base/location.h"
     13 #include "base/logging.h"
     14 #include "base/move.h"
     15 
     16 namespace base {
     17 namespace win {
     18 
     19 // TODO(rvargas): remove this with the rest of the verifier.
     20 #if defined(COMPILER_MSVC)
     21 // MSDN says to #include <intrin.h>, but that breaks the VS2005 build.
     22 extern "C" {
     23   void* _ReturnAddress();
     24 }
     25 #define BASE_WIN_GET_CALLER _ReturnAddress()
     26 #elif defined(COMPILER_GCC)
     27 #define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\
     28     __builtin_return_address(0))
     29 #endif
     30 
     31 // Generic wrapper for raw handles that takes care of closing handles
     32 // automatically. The class interface follows the style of
     33 // the ScopedStdioHandle class with a few additions:
     34 //   - IsValid() method can tolerate multiple invalid handle values such as NULL
     35 //     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
     36 //   - Receive() method allows to receive a handle value from a function that
     37 //     takes a raw handle pointer only.
     38 template <class Traits, class Verifier>
     39 class GenericScopedHandle {
     40   MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
     41 
     42  public:
     43   typedef typename Traits::Handle Handle;
     44 
     45   // Helper object to contain the effect of Receive() to the function that needs
     46   // a pointer, and allow proper tracking of the handle.
     47   class Receiver {
     48    public:
     49     explicit Receiver(GenericScopedHandle* owner)
     50         : handle_(Traits::NullHandle()),
     51           owner_(owner) {}
     52     ~Receiver() { owner_->Set(handle_); }
     53 
     54     operator Handle*() { return &handle_; }
     55 
     56    private:
     57     Handle handle_;
     58     GenericScopedHandle* owner_;
     59   };
     60 
     61   GenericScopedHandle() : handle_(Traits::NullHandle()) {}
     62 
     63   explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
     64     Set(handle);
     65   }
     66 
     67   // Move constructor for C++03 move emulation of this type.
     68   GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) {
     69     Set(other.object->Take());
     70   }
     71 
     72   ~GenericScopedHandle() {
     73     Close();
     74   }
     75 
     76   bool IsValid() const {
     77     return Traits::IsHandleValid(handle_);
     78   }
     79 
     80   // Move operator= for C++03 move emulation of this type.
     81   GenericScopedHandle& operator=(RValue other) {
     82     if (this != other.object) {
     83       Set(other.object->Take());
     84     }
     85     return *this;
     86   }
     87 
     88   void Set(Handle handle) {
     89     if (handle_ != handle) {
     90       Close();
     91 
     92       if (Traits::IsHandleValid(handle)) {
     93         handle_ = handle;
     94         Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
     95                                 tracked_objects::GetProgramCounter());
     96       }
     97     }
     98   }
     99 
    100   Handle Get() const {
    101     return handle_;
    102   }
    103 
    104   operator Handle() const {
    105     return handle_;
    106   }
    107 
    108   // This method is intended to be used with functions that require a pointer to
    109   // a destination handle, like so:
    110   //    void CreateRequiredHandle(Handle* out_handle);
    111   //    ScopedHandle a;
    112   //    CreateRequiredHandle(a.Receive());
    113   Receiver Receive() {
    114     DCHECK(!Traits::IsHandleValid(handle_)) << "Handle must be NULL";
    115     return Receiver(this);
    116   }
    117 
    118   // Transfers ownership away from this object.
    119   Handle Take() {
    120     Handle temp = handle_;
    121     handle_ = Traits::NullHandle();
    122     if (Traits::IsHandleValid(temp)) {
    123       Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
    124                              tracked_objects::GetProgramCounter());
    125     }
    126     return temp;
    127   }
    128 
    129   // Explicitly closes the owned handle.
    130   void Close() {
    131     if (Traits::IsHandleValid(handle_)) {
    132       Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
    133                              tracked_objects::GetProgramCounter());
    134 
    135       if (!Traits::CloseHandle(handle_))
    136         CHECK(false);
    137 
    138       handle_ = Traits::NullHandle();
    139     }
    140   }
    141 
    142  private:
    143   Handle handle_;
    144 };
    145 
    146 #undef BASE_WIN_GET_CALLER
    147 
    148 // The traits class for Win32 handles that can be closed via CloseHandle() API.
    149 class HandleTraits {
    150  public:
    151   typedef HANDLE Handle;
    152 
    153   // Closes the handle.
    154   static bool CloseHandle(HANDLE handle) {
    155     return ::CloseHandle(handle) != FALSE;
    156   }
    157 
    158   // Returns true if the handle value is valid.
    159   static bool IsHandleValid(HANDLE handle) {
    160     return handle != NULL && handle != INVALID_HANDLE_VALUE;
    161   }
    162 
    163   // Returns NULL handle value.
    164   static HANDLE NullHandle() {
    165     return NULL;
    166   }
    167 
    168  private:
    169   DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
    170 };
    171 
    172 // Do-nothing verifier.
    173 class DummyVerifierTraits {
    174  public:
    175   typedef HANDLE Handle;
    176 
    177   static void StartTracking(HANDLE handle, const void* owner,
    178                             const void* pc1, const void* pc2) {}
    179   static void StopTracking(HANDLE handle, const void* owner,
    180                            const void* pc1, const void* pc2) {}
    181 
    182  private:
    183   DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
    184 };
    185 
    186 // Performs actual run-time tracking.
    187 class BASE_EXPORT VerifierTraits {
    188  public:
    189   typedef HANDLE Handle;
    190 
    191   static void StartTracking(HANDLE handle, const void* owner,
    192                             const void* pc1, const void* pc2);
    193   static void StopTracking(HANDLE handle, const void* owner,
    194                            const void* pc1, const void* pc2);
    195 
    196  private:
    197   DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
    198 };
    199 
    200 typedef GenericScopedHandle<HandleTraits, DummyVerifierTraits> ScopedHandle;
    201 
    202 }  // namespace win
    203 }  // namespace base
    204 
    205 #endif  // BASE_SCOPED_HANDLE_WIN_H_
    206