summaryrefslogtreecommitdiffstats
path: root/ipc/glue/SharedMemory.h
blob: 818fad5e69adf6605f39c3d1766c72146ffd8cbf (plain)
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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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_ipc_SharedMemory_h
#define mozilla_ipc_SharedMemory_h

#include "nsDebug.h"
#include "nsISupportsImpl.h"  // NS_INLINE_DECL_REFCOUNTING
#include "mozilla/Attributes.h"

#include "base/process.h"
#include "chrome/common/ipc_message_utils.h"

//
// This is a low-level wrapper around platform shared memory.  Don't
// use it directly; use Shmem allocated through IPDL interfaces.
//
namespace {
enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
}  // namespace

namespace mozilla {

namespace ipc {
class SharedMemory;
}  // namespace ipc

namespace ipc {

class SharedMemory {
 protected:
  virtual ~SharedMemory() {
    Unmapped();
    Destroyed();
  }

 public:
  enum OpenRights {
    RightsReadOnly = RightsRead,
    RightsReadWrite = RightsRead | RightsWrite,
  };

  size_t Size() const { return mMappedSize; }

  virtual void* memory() const = 0;

  virtual bool Create(size_t size) = 0;
  virtual bool Map(size_t nBytes, void* fixed_address = nullptr) = 0;
  virtual void Unmap() = 0;

  virtual void CloseHandle() = 0;

  virtual bool WriteHandle(IPC::MessageWriter* aWriter) = 0;
  virtual bool ReadHandle(IPC::MessageReader* aReader) = 0;

  void Protect(char* aAddr, size_t aSize, int aRights) {
    char* memStart = reinterpret_cast<char*>(memory());
    if (!memStart) MOZ_CRASH("SharedMemory region points at NULL!");
    char* memEnd = memStart + Size();

    char* protStart = aAddr;
    if (!protStart) MOZ_CRASH("trying to Protect() a NULL region!");
    char* protEnd = protStart + aSize;

    if (!(memStart <= protStart && protEnd <= memEnd))
      MOZ_CRASH("attempt to Protect() a region outside this SharedMemory");

    // checks alignment etc.
    SystemProtect(aAddr, aSize, aRights);
  }

  // bug 1168843, compositor thread may create shared memory instances that are
  // destroyed by main thread on shutdown, so this must use thread-safe RC to
  // avoid hitting assertion
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)

  static void SystemProtect(char* aAddr, size_t aSize, int aRights);
  [[nodiscard]] static bool SystemProtectFallible(char* aAddr, size_t aSize,
                                                  int aRights);
  static size_t SystemPageSize();
  static size_t PageAlignedSize(size_t aSize);

 protected:
  SharedMemory();

  // Implementations should call these methods on shmem usage changes,
  // but *only if* the OS-specific calls are known to have succeeded.
  // The methods are expected to be called in the pattern
  //
  //   Created (Mapped Unmapped)* Destroy
  //
  // but this isn't checked.
  void Created(size_t aNBytes);
  void Mapped(size_t aNBytes);
  void Unmapped();
  void Destroyed();

  // The size of the shmem region requested in Create(), if
  // successful.  SharedMemory instances that are opened from a
  // foreign handle have an alloc size of 0, even though they have
  // access to the alloc-size information.
  size_t mAllocSize;
  // The size of the region mapped in Map(), if successful.  All
  // SharedMemorys that are mapped have a non-zero mapped size.
  size_t mMappedSize;
};

template <typename HandleImpl>
class SharedMemoryCommon : public SharedMemory {
 public:
  typedef HandleImpl Handle;

  virtual Handle CloneHandle() = 0;
  virtual Handle TakeHandle() = 0;
  virtual bool IsHandleValid(const Handle& aHandle) const = 0;
  virtual bool SetHandle(Handle aHandle, OpenRights aRights) = 0;

  virtual void CloseHandle() override { TakeHandle(); }

  virtual bool WriteHandle(IPC::MessageWriter* aWriter) override {
    Handle handle = CloneHandle();
    if (!handle) {
      return false;
    }
    IPC::WriteParam(aWriter, std::move(handle));
    return true;
  }

  virtual bool ReadHandle(IPC::MessageReader* aReader) override {
    Handle handle;
    return IPC::ReadParam(aReader, &handle) && IsHandleValid(handle) &&
           SetHandle(std::move(handle), RightsReadWrite);
  }
};

}  // namespace ipc
}  // namespace mozilla

#endif  // ifndef mozilla_ipc_SharedMemory_h