DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (d38398e5144e)

VCS Links

SourceSurfaceSharedData

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_
#define MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_

#include "mozilla/gfx/2D.h"
#include "mozilla/Mutex.h"
#include "mozilla/ipc/SharedMemoryBasic.h"

namespace mozilla {
namespace gfx {

/**
 * This class is used to wrap shared (as in process) data buffers used by a
 * source surface.
 */
class SourceSurfaceSharedData final : public DataSourceSurface
{
  typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;

public:
  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)

  SourceSurfaceSharedData()
    : mMutex("SourceSurfaceSharedData")
    , mStride(0)
    , mMapCount(0)
    , mFormat(SurfaceFormat::UNKNOWN)
    , mClosed(false)
    , mFinalized(false)
    , mShared(false)
  {
  }

  bool Init(const IntSize &aSize,
            int32_t aStride,
            SurfaceFormat aFormat);

  uint8_t* GetData() override
  {
    MutexAutoLock lock(mMutex);
    return GetDataInternal();
  }

  int32_t Stride() override { return mStride; }

  SurfaceType GetType() const override { return SurfaceType::DATA_SHARED; }
  IntSize GetSize() const override { return mSize; }
  SurfaceFormat GetFormat() const override { return mFormat; }

  void GuaranteePersistance() override;

  void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                              size_t& aHeapSizeOut,
                              size_t& aNonHeapSizeOut) const override;

  bool OnHeap() const override
  {
    return false;
  }

  /**
   * Although Map (and Moz2D in general) isn't normally threadsafe,
   * we want to allow it for SourceSurfaceSharedData since it should
   * always be fine (for reading at least).
   *
   * This is the same as the base class implementation except using
   * mMapCount instead of mIsMapped since that breaks for multithread.
   *
   * Additionally if a reallocation happened while there were active
   * mappings, then we guarantee that GetData will continue to return
   * the same data pointer by retaining the old shared buffer until
   * the last mapping is freed via Unmap.
   */
  bool Map(MapType, MappedSurface *aMappedSurface) override
  {
    MutexAutoLock lock(mMutex);
    ++mMapCount;
    aMappedSurface->mData = GetDataInternal();
    aMappedSurface->mStride = mStride;
    return true;
  }

  void Unmap() override
  {
    MutexAutoLock lock(mMutex);
    MOZ_ASSERT(mMapCount > 0);
    if (--mMapCount == 0) {
      mOldBuf = nullptr;
    }
  }

  /**
   * Get a handle to share to another process for this buffer. Returns:
   *   NS_OK -- success, aHandle is valid.
   *   NS_ERROR_NOT_AVAILABLE -- handle was closed, need to reallocate.
   *   NS_ERROR_FAILURE -- failed to create a handle to share.
   */
  nsresult ShareToProcess(base::ProcessId aPid,
                          SharedMemoryBasic::Handle& aHandle);

  /**
   * Indicates the buffer is not expected to be shared with any more processes.
   * May release the handle if possible (see CloseHandleInternal).
   */
  void FinishedSharing()
  {
    MutexAutoLock lock(mMutex);
    mShared = true;
    CloseHandleInternal();
  }

  /**
   * Indicates whether or not the buffer can be shared with another process
   * without reallocating. Note that this is racy and should only be used for
   * informational/reporting purposes.
   */
  bool CanShare() const
  {
    MutexAutoLock lock(mMutex);
    return !mClosed;
  }

  /**
   * Allocate a new shared memory buffer so that we can get a new handle for
   * sharing to new processes. ShareToProcess must have failed with
   * NS_ERROR_NOT_AVAILABLE in order for this to be safe to call. Returns true
   * if the operation succeeds. If it fails, there is no state change.
   */
  bool ReallocHandle();

  /**
   * Indicates we have finished writing to the buffer and it may be marked as
   * read only. May release the handle if possible (see CloseHandleInternal).
   */
  void Finalize();

private:
  ~SourceSurfaceSharedData() override
  {
    MOZ_ASSERT(mMapCount == 0);
  }

  uint8_t* GetDataInternal() const;

  size_t GetDataLength() const
  {
    return static_cast<size_t>(mStride) * mSize.height;
  }

  size_t GetAlignedDataLength() const
  {
    return mozilla::ipc::SharedMemory::PageAlignedSize(GetDataLength());
  }

  /**
   * Attempt to close the handle. Only if the buffer has been both finalized
   * and we have completed sharing will it be released.
   */
  void CloseHandleInternal();

  mutable Mutex mMutex;
  int32_t mStride;
  int32_t mMapCount;
  IntSize mSize;
  RefPtr<SharedMemoryBasic> mBuf;
  RefPtr<SharedMemoryBasic> mOldBuf;
  SurfaceFormat mFormat;
  bool mClosed : 1;
  bool mFinalized : 1;
  bool mShared : 1;
};

} // namespace gfx
} // namespace mozilla

#endif /* MOZILLA_GFX_SOURCESURFACESHAREDDATA_H_ */