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#include "courgette/memory_allocator.h"
6
7#include <map>
8
9#include "base/file_util.h"
10#include "base/strings/stringprintf.h"
11
12#if defined(OS_WIN)
13
14namespace {
15
16// The file is created in the %TEMP% folder.
17// NOTE: Since the file will be used as backing for a memory allocation,
18// it will never be so big that size_t cannot represent its size.
19base::File CreateTempFile() {
20  base::FilePath path;
21  if (!base::CreateTemporaryFile(&path))
22    return base::File();
23
24  int flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
25              base::File::FLAG_WRITE | base::File::FLAG_DELETE_ON_CLOSE |
26              base::File::FLAG_TEMPORARY;
27  return base::File(path, flags);
28}
29
30}  // namespace
31
32namespace courgette {
33
34// FileMapping
35
36FileMapping::FileMapping() : mapping_(NULL), view_(NULL) {
37}
38
39FileMapping::~FileMapping() {
40  Close();
41}
42
43bool FileMapping::InitializeView(size_t size) {
44  DCHECK(view_ == NULL);
45  DCHECK(mapping_ != NULL);
46  view_ = ::MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0, size);
47  if (!view_) {
48    Close();
49    return false;
50  }
51  return true;
52}
53
54bool FileMapping::Create(HANDLE file, size_t size) {
55  DCHECK(file != INVALID_HANDLE_VALUE);
56  DCHECK(!valid());
57  mapping_ = ::CreateFileMapping(file, NULL, PAGE_READWRITE, 0, 0, NULL);
58  if (!mapping_)
59    return false;
60
61  return InitializeView(size);
62}
63
64void FileMapping::Close() {
65  if (view_)
66    ::UnmapViewOfFile(view_);
67  if (mapping_)
68    ::CloseHandle(mapping_);
69  mapping_ = NULL;
70  view_ = NULL;
71}
72
73bool FileMapping::valid() const {
74  return view_ != NULL;
75}
76
77void* FileMapping::view() const {
78  return view_;
79}
80
81// TempMapping
82
83TempMapping::TempMapping() {
84}
85
86TempMapping::~TempMapping() {
87}
88
89bool TempMapping::Initialize(size_t size) {
90  file_ = CreateTempFile();
91  if (!file_.IsValid())
92    return false;
93
94  // TODO(tommi): The assumption here is that the alignment of pointers (this)
95  // is as strict or stricter than the alignment of the element type.  This is
96  // not always true, e.g. __m128 has 16-byte alignment.
97  size += sizeof(this);
98  if (!file_.SetLength(size) ||
99      !mapping_.Create(file_.GetPlatformFile(), size)) {
100    file_.Close();
101    return false;
102  }
103
104  TempMapping** write = reinterpret_cast<TempMapping**>(mapping_.view());
105  write[0] = this;
106
107  return true;
108}
109
110void* TempMapping::memory() const {
111  uint8* mem = reinterpret_cast<uint8*>(mapping_.view());
112  // The 'this' pointer is written at the start of mapping_.view(), so
113  // go past it. (See Initialize()).
114  if (mem)
115    mem += sizeof(this);
116  DCHECK(mem);
117  return mem;
118}
119
120bool TempMapping::valid() const {
121  return mapping_.valid();
122}
123
124// static
125TempMapping* TempMapping::GetMappingFromPtr(void* mem) {
126  TempMapping* ret = NULL;
127  if (mem) {
128    ret = reinterpret_cast<TempMapping**>(mem)[-1];
129  }
130  DCHECK(ret);
131  return ret;
132}
133
134}  // namespace courgette
135
136#endif  // OS_WIN
137