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
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
#define BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
#include <stddef.h>
#include "base/base_export.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/threading/thread_collision_warner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#if DCHECK_IS_ON()
#include <set>
#endif
// Linux (including Android) support the MADV_REMOVE argument with madvise()
// which has the behavior of reliably causing zero-fill-on-demand pages to
// be returned after a call. Here we define
// DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE on Linux
// and Android to indicate that this type of behavior can be expected on
// those platforms. Note that madvise() will still be used on other POSIX
// platforms but doesn't provide the zero-fill-on-demand pages guarantee.
#if defined(OS_LINUX) || defined(OS_ANDROID)
#define DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE
#endif
namespace base {
// Platform abstraction for discardable shared memory.
//
// This class is not thread-safe. Clients are responsible for synchronizing
// access to an instance of this class.
class BASE_EXPORT DiscardableSharedMemory {
public:
enum LockResult { SUCCESS, PURGED, FAILED };
DiscardableSharedMemory();
// Create a new DiscardableSharedMemory object from an existing, open shared
// memory file. Memory must be locked.
explicit DiscardableSharedMemory(SharedMemoryHandle handle);
// Closes any open files.
virtual ~DiscardableSharedMemory();
// Creates and maps a locked DiscardableSharedMemory object with |size|.
// Returns true on success and false on failure.
bool CreateAndMap(size_t size);
// Maps the locked discardable memory into the caller's address space.
// Returns true on success, false otherwise.
bool Map(size_t size);
// Unmaps the discardable shared memory from the caller's address space.
// Returns true if successful; returns false on error or if the memory is
// not mapped.
bool Unmap();
// The actual size of the mapped memory (may be larger than requested).
size_t mapped_size() const { return mapped_size_; }
// Returns a shared memory handle for this DiscardableSharedMemory object.
SharedMemoryHandle handle() const { return shared_memory_.handle(); }
// Locks a range of memory so that it will not be purged by the system.
// The range of memory must be unlocked. The result of trying to lock an
// already locked range is undefined. |offset| and |length| must both be
// a multiple of the page size as returned by GetPageSize().
// Passing 0 for |length| means "everything onward".
// Returns SUCCESS if range was successfully locked and the memory is still
// resident, PURGED if range was successfully locked but has been purged
// since last time it was locked and FAILED if range could not be locked.
// Locking can fail for two reasons; object might have been purged, our
// last known usage timestamp might be out of date. Last known usage time
// is updated to the actual last usage timestamp if memory is still resident
// or 0 if not.
LockResult Lock(size_t offset, size_t length);
// Unlock a previously successfully locked range of memory. The range of
// memory must be locked. The result of trying to unlock a not
// previously locked range is undefined.
// |offset| and |length| must both be a multiple of the page size as returned
// by GetPageSize().
// Passing 0 for |length| means "everything onward".
void Unlock(size_t offset, size_t length);
// Gets a pointer to the opened discardable memory space. Discardable memory
// must have been mapped via Map().
void* memory() const;
// Returns the last known usage time for DiscardableSharedMemory object. This
// may be earlier than the "true" usage time when memory has been used by a
// different process. Returns NULL time if purged.
Time last_known_usage() const { return last_known_usage_; }
// This returns true and sets |last_known_usage_| to 0 if
// DiscardableSharedMemory object was successfully purged. Purging can fail
// for two reasons; object might be locked or our last known usage timestamp
// might be out of date. Last known usage time is updated to |current_time|
// if locked or the actual last usage timestamp if unlocked. It is often
// necessary to call this function twice for the object to successfully be
// purged. First call, updates |last_known_usage_|. Second call, successfully
// purges the object using the updated |last_known_usage_|.
// Note: there is no guarantee that multiple calls to this function will
// successfully purge object. DiscardableSharedMemory object might be locked
// or another thread/process might be able to lock and unlock it in between
// each call.
bool Purge(Time current_time);
// Returns true if memory is still resident.
bool IsMemoryResident() const;
// Returns true if memory is locked.
bool IsMemoryLocked() const;
// Closes the open discardable memory segment.
// It is safe to call Close repeatedly.
void Close();
// Shares the discardable memory segment to another process. Attempts to
// create a platform-specific |new_handle| which can be used in a remote
// process to access the discardable memory segment. |new_handle| is an
// output parameter to receive the handle for use in the remote process.
// Returns true on success, false otherwise.
bool ShareToProcess(ProcessHandle process_handle,
SharedMemoryHandle* new_handle) {
return shared_memory_.ShareToProcess(process_handle, new_handle);
}
private:
// Virtual for tests.
virtual Time Now() const;
SharedMemory shared_memory_;
size_t mapped_size_;
size_t locked_page_count_;
#if DCHECK_IS_ON()
std::set<size_t> locked_pages_;
#endif
// Implementation is not thread-safe but still usable if clients are
// synchronized somehow. Use a collision warner to detect incorrect usage.
DFAKE_MUTEX(thread_collision_warner_);
Time last_known_usage_;
DISALLOW_COPY_AND_ASSIGN(DiscardableSharedMemory);
};
} // namespace base
#endif // BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
|