mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 748598 - Implement VolatileBuffer for OSX, Ashmem, and Windows, r=njn,glandium
This commit is contained in:
parent
3319661389
commit
19dba2c6c6
112
memory/mozalloc/VolatileBuffer.h
Normal file
112
memory/mozalloc/VolatileBuffer.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* 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 mozalloc_VolatileBuffer_h
|
||||
#define mozalloc_VolatileBuffer_h
|
||||
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
/* VolatileBuffer
|
||||
*
|
||||
* This class represents a piece of memory that can potentially be reclaimed
|
||||
* by the OS when not in use. As long as there are one or more
|
||||
* VolatileBufferPtrs holding on to a VolatileBuffer, the memory will remain
|
||||
* available. However, when there are no VolatileBufferPtrs holding a
|
||||
* VolatileBuffer, the OS can purge the pages if it wants to. The OS can make
|
||||
* better decisions about what pages to purge than we can.
|
||||
*
|
||||
* VolatileBuffers may not always be volatile - if the allocation is too small,
|
||||
* or if the OS doesn't support the feature, or if the OS doesn't want to,
|
||||
* the buffer will be allocated on heap.
|
||||
*
|
||||
* VolatileBuffer allocations are fallible. They are intended for uses where
|
||||
* one may allocate large buffers for caching data. Init() must be called
|
||||
* exactly once.
|
||||
*
|
||||
* After getting a reference to VolatileBuffer using VolatileBufferPtr,
|
||||
* WasPurged() can be used to check if the OS purged any pages in the buffer.
|
||||
* The OS cannot purge a buffer immediately after a VolatileBuffer is
|
||||
* initialized. At least one VolatileBufferPtr must be created before the
|
||||
* buffer can be purged, so the first use of VolatileBufferPtr does not need
|
||||
* to check WasPurged().
|
||||
*
|
||||
* When a buffer is purged, some or all of the buffer is zeroed out. This
|
||||
* API cannot tell which parts of the buffer were lost.
|
||||
*
|
||||
* VolatileBuffer is not thread safe. Do not use VolatileBufferPtrs on
|
||||
* different threads.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MOZALLOC_EXPORT VolatileBuffer : public RefCounted<VolatileBuffer>
|
||||
{
|
||||
friend class VolatileBufferPtr_base;
|
||||
public:
|
||||
VolatileBuffer();
|
||||
~VolatileBuffer();
|
||||
|
||||
/* aAlignment must be a multiple of the pointer size */
|
||||
bool Init(size_t aSize, size_t aAlignment = sizeof(void*));
|
||||
|
||||
size_t HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||
size_t NonHeapSizeOfExcludingThis() const;
|
||||
|
||||
protected:
|
||||
bool Lock(void** aBuf);
|
||||
void Unlock();
|
||||
bool OnHeap() const;
|
||||
|
||||
private:
|
||||
void* mBuf;
|
||||
size_t mSize;
|
||||
int mLockCount;
|
||||
#if defined(ANDROID)
|
||||
int mFd;
|
||||
#elif defined(XP_DARWIN)
|
||||
bool mHeap;
|
||||
#elif defined(XP_WIN)
|
||||
bool mHeap;
|
||||
bool mFirstLock;
|
||||
#endif
|
||||
};
|
||||
|
||||
class VolatileBufferPtr_base {
|
||||
public:
|
||||
VolatileBufferPtr_base(VolatileBuffer* vbuf) : mVBuf(vbuf) {
|
||||
mPurged = !vbuf->Lock(&mMapping);
|
||||
}
|
||||
|
||||
~VolatileBufferPtr_base() {
|
||||
mVBuf->Unlock();
|
||||
}
|
||||
|
||||
bool WasBufferPurged() const {
|
||||
return mPurged;
|
||||
}
|
||||
|
||||
protected:
|
||||
void* mMapping;
|
||||
|
||||
private:
|
||||
RefPtr<VolatileBuffer> mVBuf;
|
||||
bool mPurged;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class VolatileBufferPtr : public VolatileBufferPtr_base
|
||||
{
|
||||
public:
|
||||
VolatileBufferPtr(VolatileBuffer* vbuf) : VolatileBufferPtr_base(vbuf) {}
|
||||
|
||||
operator T*() const {
|
||||
return (T*) mMapping;
|
||||
}
|
||||
};
|
||||
|
||||
}; /* namespace mozilla */
|
||||
|
||||
#endif /* mozalloc_VolatileBuffer_h */
|
137
memory/mozalloc/VolatileBufferAshmem.cpp
Normal file
137
memory/mozalloc/VolatileBufferAshmem.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "VolatileBuffer.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
extern "C" int __wrap_posix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
#else
|
||||
extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MIN_VOLATILE_ALLOC_SIZE 8192
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
VolatileBuffer::VolatileBuffer()
|
||||
: mBuf(nullptr)
|
||||
, mSize(0)
|
||||
, mLockCount(0)
|
||||
, mFd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Init(size_t aSize, size_t aAlignment)
|
||||
{
|
||||
MOZ_ASSERT(!mSize && !mBuf, "Init called twice");
|
||||
MOZ_ASSERT(!(aAlignment % sizeof(void *)),
|
||||
"Alignment must be multiple of pointer size");
|
||||
|
||||
mSize = aSize;
|
||||
if (aSize < MIN_VOLATILE_ALLOC_SIZE) {
|
||||
goto heap_alloc;
|
||||
}
|
||||
|
||||
mFd = open("/" ASHMEM_NAME_DEF, O_RDWR);
|
||||
if (mFd < 0) {
|
||||
goto heap_alloc;
|
||||
}
|
||||
|
||||
if (ioctl(mFd, ASHMEM_SET_SIZE, mSize) < 0) {
|
||||
close(mFd);
|
||||
mFd = -1;
|
||||
goto heap_alloc;
|
||||
}
|
||||
|
||||
mBuf = mmap(nullptr, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mFd, 0);
|
||||
if (mBuf != MAP_FAILED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
heap_alloc:
|
||||
#ifdef MOZ_MEMORY
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
__wrap_posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#else
|
||||
posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#endif
|
||||
#else
|
||||
mBuf = memalign(aAlignment, aSize);
|
||||
#endif
|
||||
return !!mBuf;
|
||||
}
|
||||
|
||||
VolatileBuffer::~VolatileBuffer()
|
||||
{
|
||||
if (OnHeap()) {
|
||||
free(mBuf);
|
||||
} else {
|
||||
munmap(mBuf, mSize);
|
||||
close(mFd);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Lock(void** aBuf)
|
||||
{
|
||||
MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer");
|
||||
|
||||
*aBuf = mBuf;
|
||||
if (++mLockCount > 1 || OnHeap()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Zero offset and zero length means we want to pin/unpin the entire thing.
|
||||
struct ashmem_pin pin = { 0, 0 };
|
||||
return ioctl(mFd, ASHMEM_PIN, &pin) == ASHMEM_NOT_PURGED;
|
||||
}
|
||||
|
||||
void
|
||||
VolatileBuffer::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!");
|
||||
if (--mLockCount || OnHeap()) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct ashmem_pin pin = { 0, 0 };
|
||||
ioctl(mFd, ASHMEM_UNPIN, &pin);
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::OnHeap() const
|
||||
{
|
||||
return mFd < 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return OnHeap() ? aMallocSizeOf(mBuf) : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::NonHeapSizeOfExcludingThis() const
|
||||
{
|
||||
if (OnHeap()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (mSize + (PAGE_SIZE - 1)) & PAGE_MASK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
80
memory/mozalloc/VolatileBufferFallback.cpp
Normal file
80
memory/mozalloc/VolatileBufferFallback.cpp
Normal file
@ -0,0 +1,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/. */
|
||||
|
||||
#include "VolatileBuffer.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
int posix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
VolatileBuffer::VolatileBuffer()
|
||||
: mBuf(nullptr)
|
||||
, mSize(0)
|
||||
, mLockCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool VolatileBuffer::Init(size_t aSize, size_t aAlignment)
|
||||
{
|
||||
MOZ_ASSERT(!mSize && !mBuf, "Init called twice");
|
||||
MOZ_ASSERT(!(aAlignment % sizeof(void *)),
|
||||
"Alignment must be multiple of pointer size");
|
||||
|
||||
mSize = aSize;
|
||||
#if defined(MOZ_MEMORY)
|
||||
posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#elif defined(HAVE_POSIX_MEMALIGN)
|
||||
moz_posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#else
|
||||
#error "No memalign implementation found"
|
||||
#endif
|
||||
return !!mBuf;
|
||||
}
|
||||
|
||||
VolatileBuffer::~VolatileBuffer()
|
||||
{
|
||||
free(mBuf);
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Lock(void** aBuf)
|
||||
{
|
||||
MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer");
|
||||
|
||||
*aBuf = mBuf;
|
||||
mLockCount++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
VolatileBuffer::Unlock()
|
||||
{
|
||||
mLockCount--;
|
||||
MOZ_ASSERT(mLockCount >= 0, "VolatileBuffer unlocked too many times!");
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::OnHeap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return aMallocSizeOf(mBuf);
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::NonHeapSizeOfExcludingThis() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
122
memory/mozalloc/VolatileBufferOSX.cpp
Normal file
122
memory/mozalloc/VolatileBufferOSX.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "VolatileBuffer.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MIN_VOLATILE_ALLOC_SIZE 8192
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
VolatileBuffer::VolatileBuffer()
|
||||
: mBuf(nullptr)
|
||||
, mSize(0)
|
||||
, mLockCount(0)
|
||||
, mHeap(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Init(size_t aSize, size_t aAlignment)
|
||||
{
|
||||
MOZ_ASSERT(!mSize && !mBuf, "Init called twice");
|
||||
MOZ_ASSERT(!(aAlignment % sizeof(void *)),
|
||||
"Alignment must be multiple of pointer size");
|
||||
|
||||
mSize = aSize;
|
||||
|
||||
kern_return_t ret = 0;
|
||||
if (aSize < MIN_VOLATILE_ALLOC_SIZE) {
|
||||
goto heap_alloc;
|
||||
}
|
||||
|
||||
ret = vm_allocate(mach_task_self(),
|
||||
(vm_address_t*)&mBuf,
|
||||
mSize,
|
||||
VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE);
|
||||
if (ret == KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
heap_alloc:
|
||||
moz_posix_memalign(&mBuf, aAlignment, aSize);
|
||||
mHeap = true;
|
||||
return !!mBuf;
|
||||
}
|
||||
|
||||
VolatileBuffer::~VolatileBuffer()
|
||||
{
|
||||
if (OnHeap()) {
|
||||
free(mBuf);
|
||||
} else {
|
||||
vm_deallocate(mach_task_self(), (vm_address_t)mBuf, mSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Lock(void** aBuf)
|
||||
{
|
||||
MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer");
|
||||
|
||||
*aBuf = mBuf;
|
||||
if (++mLockCount > 1 || OnHeap()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int state = VM_PURGABLE_NONVOLATILE;
|
||||
kern_return_t ret =
|
||||
vm_purgable_control(mach_task_self(),
|
||||
(vm_address_t)mBuf,
|
||||
VM_PURGABLE_SET_STATE,
|
||||
&state);
|
||||
return ret == KERN_SUCCESS && !(state & VM_PURGABLE_EMPTY);
|
||||
}
|
||||
|
||||
void
|
||||
VolatileBuffer::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!");
|
||||
if (--mLockCount || OnHeap()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int state = VM_PURGABLE_VOLATILE | VM_VOLATILE_GROUP_DEFAULT;
|
||||
DebugOnly<kern_return_t> ret =
|
||||
vm_purgable_control(mach_task_self(),
|
||||
(vm_address_t)mBuf,
|
||||
VM_PURGABLE_SET_STATE,
|
||||
&state);
|
||||
MOZ_ASSERT(ret == KERN_SUCCESS, "Failed to set buffer as purgable");
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::OnHeap() const
|
||||
{
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return OnHeap() ? aMallocSizeOf(mBuf) : 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::NonHeapSizeOfExcludingThis() const
|
||||
{
|
||||
if (OnHeap()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long pagemask = getpagesize() - 1;
|
||||
return (mSize + pagemask) & ~pagemask;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
173
memory/mozalloc/VolatileBufferWindows.cpp
Normal file
173
memory/mozalloc/VolatileBufferWindows.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/* 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/. */
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_OS2)
|
||||
# define MOZALLOC_EXPORT __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
#include "VolatileBuffer.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#ifdef MOZ_MEMORY
|
||||
extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size);
|
||||
#endif
|
||||
|
||||
#ifndef MEM_RESET_UNDO
|
||||
#define MEM_RESET_UNDO 0x1000000
|
||||
#endif
|
||||
|
||||
#define MIN_VOLATILE_ALLOC_SIZE 8192
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
VolatileBuffer::VolatileBuffer()
|
||||
: mBuf(nullptr)
|
||||
, mSize(0)
|
||||
, mLockCount(0)
|
||||
, mHeap(false)
|
||||
, mFirstLock(true)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Init(size_t aSize, size_t aAlignment)
|
||||
{
|
||||
MOZ_ASSERT(!mSize && !mBuf, "Init called twice");
|
||||
MOZ_ASSERT(!(aAlignment % sizeof(void *)),
|
||||
"Alignment must be multiple of pointer size");
|
||||
|
||||
mSize = aSize;
|
||||
if (aSize < MIN_VOLATILE_ALLOC_SIZE) {
|
||||
goto heap_alloc;
|
||||
}
|
||||
|
||||
static bool sCheckedVersion = false;
|
||||
static bool sUndoSupported = false;
|
||||
if (!sCheckedVersion) {
|
||||
OSVERSIONINFOEX verinfo = { 0 };
|
||||
verinfo.dwOSVersionInfoSize = sizeof(verinfo);
|
||||
verinfo.dwMajorVersion = 6;
|
||||
verinfo.dwMinorVersion = 2;
|
||||
|
||||
DWORDLONG mask = 0;
|
||||
VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
|
||||
sUndoSupported = VerifyVersionInfo(&verinfo,
|
||||
VER_MAJORVERSION | VER_MINORVERSION,
|
||||
mask);
|
||||
sCheckedVersion = true;
|
||||
}
|
||||
|
||||
if (!sUndoSupported) {
|
||||
goto heap_alloc;
|
||||
}
|
||||
|
||||
mBuf = VirtualAllocEx(GetCurrentProcess(),
|
||||
nullptr,
|
||||
mSize,
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE);
|
||||
if (mBuf) {
|
||||
return true;
|
||||
}
|
||||
|
||||
heap_alloc:
|
||||
#ifdef MOZ_MEMORY
|
||||
posix_memalign(&mBuf, aAlignment, aSize);
|
||||
#else
|
||||
mBuf = _aligned_malloc(aSize, aAlignment);
|
||||
#endif
|
||||
mHeap = true;
|
||||
return !!mBuf;
|
||||
}
|
||||
|
||||
VolatileBuffer::~VolatileBuffer()
|
||||
{
|
||||
if (OnHeap()) {
|
||||
#ifdef MOZ_MEMORY
|
||||
free(mBuf);
|
||||
#else
|
||||
_aligned_free(mBuf);
|
||||
#endif
|
||||
} else {
|
||||
VirtualFreeEx(GetCurrentProcess(), mBuf, 0, MEM_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::Lock(void** aBuf)
|
||||
{
|
||||
MOZ_ASSERT(mBuf, "Attempting to lock an uninitialized VolatileBuffer");
|
||||
|
||||
*aBuf = mBuf;
|
||||
if (++mLockCount > 1 || OnHeap()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// MEM_RESET_UNDO's behavior is undefined when called on memory that
|
||||
// hasn't been MEM_RESET.
|
||||
if (mFirstLock) {
|
||||
mFirstLock = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void* addr = VirtualAllocEx(GetCurrentProcess(),
|
||||
mBuf,
|
||||
mSize,
|
||||
MEM_RESET_UNDO,
|
||||
PAGE_READWRITE);
|
||||
return !!addr;
|
||||
}
|
||||
|
||||
void
|
||||
VolatileBuffer::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mLockCount > 0, "VolatileBuffer unlocked too many times!");
|
||||
if (--mLockCount || OnHeap()) {
|
||||
return;
|
||||
}
|
||||
|
||||
void* addr = VirtualAllocEx(GetCurrentProcess(),
|
||||
mBuf,
|
||||
mSize,
|
||||
MEM_RESET,
|
||||
PAGE_READWRITE);
|
||||
MOZ_ASSERT(addr, "Failed to MEM_RESET");
|
||||
}
|
||||
|
||||
bool
|
||||
VolatileBuffer::OnHeap() const
|
||||
{
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
if (OnHeap()) {
|
||||
#ifdef MOZ_MEMORY
|
||||
return aMallocSizeOf(mBuf);
|
||||
#else
|
||||
return mSize;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
VolatileBuffer::NonHeapSizeOfExcludingThis() const
|
||||
{
|
||||
if (OnHeap()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (mSize + 4095) & ~4095;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -10,6 +10,7 @@ EXPORTS.mozilla += [
|
||||
'mozalloc.h',
|
||||
'mozalloc_abort.h',
|
||||
'mozalloc_oom.h',
|
||||
'VolatileBuffer.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_MSVC_STL_WRAP__RAISE'] or CONFIG['MOZ_MSVC_STL_WRAP__Throw']:
|
||||
@ -38,6 +39,23 @@ UNIFIED_SOURCES += [
|
||||
'mozalloc_oom.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'Android':
|
||||
UNIFIED_SOURCES += [
|
||||
'VolatileBufferAshmem.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] == 'Darwin':
|
||||
UNIFIED_SOURCES += [
|
||||
'VolatileBufferOSX.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] == 'WINNT':
|
||||
UNIFIED_SOURCES += [
|
||||
'VolatileBufferWindows.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'VolatileBufferFallback.cpp',
|
||||
]
|
||||
|
||||
LIBRARY_NAME = 'mozalloc'
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
@ -47,3 +65,5 @@ else:
|
||||
|
||||
# The strndup declaration in string.h is in an ifdef __USE_GNU section
|
||||
DEFINES['_GNU_SOURCE'] = True
|
||||
|
||||
TEST_TOOL_DIRS += ['tests']
|
||||
|
144
memory/mozalloc/tests/TestVolatileBuffer.cpp
Normal file
144
memory/mozalloc/tests/TestVolatileBuffer.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "TestHarness.h"
|
||||
#include "mozilla/VolatileBuffer.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include <string.h>
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include <fcntl.h>
|
||||
#include <linux/ashmem.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#elif defined(XP_DARWIN)
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ScopedXPCOM xpcom("VolatileBufferTests");
|
||||
if (xpcom.failed()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
RefPtr<VolatileBuffer> heapbuf = new VolatileBuffer();
|
||||
if (!heapbuf || !heapbuf->Init(512)) {
|
||||
fail("Failed to initialize VolatileBuffer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
VolatileBufferPtr<char> ptr(heapbuf);
|
||||
if (ptr.WasBufferPurged()) {
|
||||
fail("Buffer was immediately purged after initialization");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
fail("Didn't get a pointer");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<VolatileBuffer> buf = new VolatileBuffer();
|
||||
if (!buf || !buf->Init(16384)) {
|
||||
fail("Failed to initialize VolatileBuffer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char teststr[] = "foobar";
|
||||
|
||||
{
|
||||
VolatileBufferPtr<char> ptr(buf);
|
||||
if (ptr.WasBufferPurged()) {
|
||||
fail("Buffer should not be purged immediately after initialization");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ptr) {
|
||||
fail("Didn't get a pointer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
VolatileBufferPtr<char> ptr2(buf);
|
||||
if (ptr2.WasBufferPurged()) {
|
||||
fail("Failed to Lock buffer again while currently locked");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ptr2) {
|
||||
fail("Didn't get a pointer on the second lock");
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(ptr2, teststr);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
VolatileBufferPtr<char> ptr(buf);
|
||||
if (ptr.WasBufferPurged()) {
|
||||
fail("Buffer was immediately purged after unlock");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(ptr, teststr)) {
|
||||
fail("Buffer failed to retain data after unlock");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Test purging if we know how to
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
// This also works on Android, but we need root.
|
||||
int fd = open("/" ASHMEM_NAME_DEF, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fail("Failed to open ashmem device");
|
||||
return 1;
|
||||
}
|
||||
if (ioctl(fd, ASHMEM_PURGE_ALL_CACHES, NULL) < 0) {
|
||||
fail("Failed to purge ashmem caches");
|
||||
return 1;
|
||||
}
|
||||
#elif defined(XP_DARWIN)
|
||||
int state;
|
||||
vm_purgable_control(mach_task_self(), (vm_address_t)NULL,
|
||||
VM_PURGABLE_PURGE_ALL, &state);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!buf->NonHeapSizeOfExcludingThis()) {
|
||||
fail("Buffer should not be allocated on heap");
|
||||
return 1;
|
||||
}
|
||||
|
||||
{
|
||||
VolatileBufferPtr<char> ptr(buf);
|
||||
if (!ptr.WasBufferPurged()) {
|
||||
fail("Buffer should not be unpurged after forced purge");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(ptr, teststr)) {
|
||||
fail("Purge did not actually purge data");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
VolatileBufferPtr<char> ptr(buf);
|
||||
if (ptr.WasBufferPurged()) {
|
||||
fail("Buffer still purged after lock");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
9
memory/mozalloc/tests/moz.build
Normal file
9
memory/mozalloc/tests/moz.build
Normal file
@ -0,0 +1,9 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
CPP_UNIT_TESTS += [
|
||||
'TestVolatileBuffer.cpp',
|
||||
]
|
Loading…
Reference in New Issue
Block a user