Fix a pair of non-ascii quotes that made their way into AsyncSocket
[folly.git] / folly / test / MemoryMappingTest.cpp
1 /*
2  * Copyright 2016 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 <cstdlib>
18
19 #include <folly/FileUtil.h>
20 #include <folly/MemoryMapping.h>
21 #include <folly/portability/SysMman.h>
22
23 #include <gtest/gtest.h>
24
25 namespace folly {
26
27 TEST(MemoryMapping, Basic) {
28   File f = File::temporary();
29   {
30     MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
31     double* d = m.asWritableRange<double>().data();
32     *d = 37 * M_PI;
33   }
34   {
35     MemoryMapping m(File(f.fd()), 0, 3);
36     EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
37   }
38   {
39     MemoryMapping m(File(f.fd()), 0, sizeof(double));
40     const double* d = m.asRange<double>().data();
41     EXPECT_EQ(*d, 37 * M_PI);
42   }
43 }
44
45 TEST(MemoryMapping, Move) {
46   File f = File::temporary();
47   {
48     MemoryMapping m(
49         File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
50     double* d = m.asWritableRange<double>().data();
51     d[0] = 37 * M_PI;
52     MemoryMapping m2(std::move(m));
53     double* d2 = m2.asWritableRange<double>().data();
54     d2[1] = 39 * M_PI;
55   }
56   {
57     MemoryMapping m(File(f.fd()), 0, sizeof(double));
58     const double* d = m.asRange<double>().data();
59     EXPECT_EQ(d[0], 37 * M_PI);
60     MemoryMapping m2(std::move(m));
61     const double* d2 = m2.asRange<double>().data();
62     EXPECT_EQ(d2[1], 39 * M_PI);
63   }
64 }
65
66 TEST(MemoryMapping, DoublyMapped) {
67   File f = File::temporary();
68   // two mappings of the same memory, different addresses.
69   MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
70   MemoryMapping mr(File(f.fd()), 0, sizeof(double));
71
72   double* dw = mw.asWritableRange<double>().data();
73   const double* dr = mr.asRange<double>().data();
74
75   // Show that it's truly the same value, even though the pointers differ
76   EXPECT_NE(dw, dr);
77   *dw = 42 * M_PI;
78   EXPECT_EQ(*dr, 42 * M_PI);
79   *dw = 43 * M_PI;
80   EXPECT_EQ(*dr, 43 * M_PI);
81 }
82
83 namespace {
84
85 void writeStringToFileOrDie(const std::string& str, int fd) {
86   const char* b = str.c_str();
87   size_t count = str.size();
88   ssize_t total_bytes = 0;
89   ssize_t r;
90   do {
91     r = write(fd, b, count);
92     if (r == -1) {
93       if (errno == EINTR) {
94         continue;
95       }
96       PCHECK(r) << "write";
97     }
98
99     total_bytes += r;
100     b += r;
101     count -= r;
102   } while (r != 0 && count);
103 }
104
105 }  // anonymous namespace
106
107 TEST(MemoryMapping, Simple) {
108   File f = File::temporary();
109   writeStringToFileOrDie("hello", f.fd());
110
111   {
112     MemoryMapping m(File(f.fd()));
113     EXPECT_EQ("hello", m.data());
114   }
115   {
116     MemoryMapping m(File(f.fd()), 1, 2);
117     EXPECT_EQ("el", m.data());
118   }
119 }
120
121 TEST(MemoryMapping, LargeFile) {
122   std::string fileData;
123   size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
124   fileData.reserve(fileSize);
125   for (size_t i = 0; i < fileSize; i++) {
126     fileData.push_back(0xff & random());
127   }
128
129   File f = File::temporary();
130   writeStringToFileOrDie(fileData, f.fd());
131
132   {
133     MemoryMapping m(File(f.fd()));
134     EXPECT_EQ(fileData, m.data());
135   }
136   {
137     size_t size = sysconf(_SC_PAGESIZE) * 2;
138     StringPiece s(fileData.data() + 9, size - 9);
139     MemoryMapping m(File(f.fd()), 9, size - 9);
140     EXPECT_EQ(s.toString(), m.data());
141   }
142 }
143
144 TEST(MemoryMapping, ZeroLength) {
145   File f = File::temporary();
146   MemoryMapping m(File(f.fd()));
147   EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
148   EXPECT_TRUE(m.mlocked());
149   EXPECT_EQ(0, m.data().size());
150 }
151
152 TEST(MemoryMapping, Advise) {
153   File f = File::temporary();
154   size_t kPageSize = 4096;
155   size_t size = kPageSize + 10;  // unaligned file size
156   PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
157
158   MemoryMapping m(File(f.fd()));
159
160   // NOTE: advise crashes on bad input.
161
162   m.advise(MADV_NORMAL, 0, kPageSize);
163   m.advise(MADV_NORMAL, 1, kPageSize);
164   m.advise(MADV_NORMAL, 0, 2);
165   m.advise(MADV_NORMAL, 1, 2);
166
167   m.advise(MADV_NORMAL, kPageSize, 0);
168   m.advise(MADV_NORMAL, kPageSize, 1);
169   m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
170
171   auto off = kPageSize + 1;
172   m.advise(MADV_NORMAL, off, size - off);
173
174   EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
175 }
176
177 } // namespace folly