Move ThreadLocal.h into the implementation
[folly.git] / folly / test / MemoryMappingTest.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <sys/mman.h>
18 #include <cstdlib>
19 #include <folly/FileUtil.h>
20 #include <folly/MemoryMapping.h>
21 #include <gtest/gtest.h>
22
23 namespace folly {
24
25 TEST(MemoryMapping, Basic) {
26   File f = File::temporary();
27   {
28     MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
29     double* d = m.asWritableRange<double>().data();
30     *d = 37 * M_PI;
31   }
32   {
33     MemoryMapping m(File(f.fd()), 0, 3);
34     EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
35   }
36   {
37     MemoryMapping m(File(f.fd()), 0, sizeof(double));
38     const double* d = m.asRange<double>().data();
39     EXPECT_EQ(*d, 37 * M_PI);
40   }
41 }
42
43 TEST(MemoryMapping, Move) {
44   File f = File::temporary();
45   {
46     MemoryMapping m(
47         File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
48     double* d = m.asWritableRange<double>().data();
49     d[0] = 37 * M_PI;
50     MemoryMapping m2(std::move(m));
51     double* d2 = m2.asWritableRange<double>().data();
52     d2[1] = 39 * M_PI;
53   }
54   {
55     MemoryMapping m(File(f.fd()), 0, sizeof(double));
56     const double* d = m.asRange<double>().data();
57     EXPECT_EQ(d[0], 37 * M_PI);
58     MemoryMapping m2(std::move(m));
59     const double* d2 = m2.asRange<double>().data();
60     EXPECT_EQ(d2[1], 39 * M_PI);
61   }
62 }
63
64 TEST(MemoryMapping, DoublyMapped) {
65   File f = File::temporary();
66   // two mappings of the same memory, different addresses.
67   MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
68   MemoryMapping mr(File(f.fd()), 0, sizeof(double));
69
70   double* dw = mw.asWritableRange<double>().data();
71   const double* dr = mr.asRange<double>().data();
72
73   // Show that it's truly the same value, even though the pointers differ
74   EXPECT_NE(dw, dr);
75   *dw = 42 * M_PI;
76   EXPECT_EQ(*dr, 42 * M_PI);
77   *dw = 43 * M_PI;
78   EXPECT_EQ(*dr, 43 * M_PI);
79 }
80
81 namespace {
82
83 void writeStringToFileOrDie(const std::string& str, int fd) {
84   const char* b = str.c_str();
85   size_t count = str.size();
86   ssize_t total_bytes = 0;
87   ssize_t r;
88   do {
89     r = write(fd, b, count);
90     if (r == -1) {
91       if (errno == EINTR) {
92         continue;
93       }
94       PCHECK(r) << "write";
95     }
96
97     total_bytes += r;
98     b += r;
99     count -= r;
100   } while (r != 0 && count);
101 }
102
103 }  // anonymous namespace
104
105 TEST(MemoryMapping, Simple) {
106   File f = File::temporary();
107   writeStringToFileOrDie("hello", f.fd());
108
109   {
110     MemoryMapping m(File(f.fd()));
111     EXPECT_EQ("hello", m.data());
112   }
113   {
114     MemoryMapping m(File(f.fd()), 1, 2);
115     EXPECT_EQ("el", m.data());
116   }
117 }
118
119 TEST(MemoryMapping, LargeFile) {
120   std::string fileData;
121   size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
122   fileData.reserve(fileSize);
123   for (size_t i = 0; i < fileSize; i++) {
124     fileData.push_back(0xff & random());
125   }
126
127   File f = File::temporary();
128   writeStringToFileOrDie(fileData, f.fd());
129
130   {
131     MemoryMapping m(File(f.fd()));
132     EXPECT_EQ(fileData, m.data());
133   }
134   {
135     size_t size = sysconf(_SC_PAGESIZE) * 2;
136     StringPiece s(fileData.data() + 9, size - 9);
137     MemoryMapping m(File(f.fd()), 9, size - 9);
138     EXPECT_EQ(s.toString(), m.data());
139   }
140 }
141
142 TEST(MemoryMapping, ZeroLength) {
143   File f = File::temporary();
144   MemoryMapping m(File(f.fd()));
145   EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
146   EXPECT_TRUE(m.mlocked());
147   EXPECT_EQ(0, m.data().size());
148 }
149
150 TEST(MemoryMapping, Advise) {
151   File f = File::temporary();
152   size_t kPageSize = 4096;
153   size_t size = kPageSize + 10;  // unaligned file size
154   PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
155
156   MemoryMapping m(File(f.fd()));
157
158   // NOTE: advise crashes on bad input.
159
160   m.advise(MADV_NORMAL, 0, kPageSize);
161   m.advise(MADV_NORMAL, 1, kPageSize);
162   m.advise(MADV_NORMAL, 0, 2);
163   m.advise(MADV_NORMAL, 1, 2);
164
165   m.advise(MADV_NORMAL, kPageSize, 0);
166   m.advise(MADV_NORMAL, kPageSize, 1);
167   m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
168
169   auto off = kPageSize + 1;
170   m.advise(MADV_NORMAL, off, size - off);
171
172   EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
173 }
174
175 } // namespace folly