2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/PackedSyncPtr.h>
21 #include <unordered_map>
24 #include <folly/portability/GTest.h>
26 using folly::PackedSyncPtr;
30 // Compile time check for packability. This requires that
31 // PackedSyncPtr is a POD struct on gcc.
33 struct ignore { PackedSyncPtr<int> foo; char c; } FOLLY_PACK_ATTR;
35 static_assert(sizeof(ignore) == 9, "PackedSyncPtr wasn't packable");
39 TEST(PackedSyncPtr, Basic) {
40 PackedSyncPtr<std::pair<int,int>> sp;
41 sp.init(new std::pair<int,int>[2]);
42 EXPECT_EQ(sizeof(sp), 8);
44 EXPECT_EQ(sp[0].first, 5);
46 EXPECT_EQ(sp[1].second, 7);
48 EXPECT_EQ(sp[1].second, 7);
50 EXPECT_EQ(sp->first, 9);
52 EXPECT_EQ((sp.get() + 1)->second, 7);
55 EXPECT_EQ(sp.extra(), 0);
57 EXPECT_EQ(sp.extra(), 0x13);
58 EXPECT_EQ((sp.get() + 1)->second, 7);
60 auto newP = new std::pair<int,int>();
62 EXPECT_EQ(sp.extra(), 0x13);
63 EXPECT_EQ(sp.get(), newP);
68 // Here we use the PackedSyncPtr to lock the whole SyncVec (base, *base, and sz)
71 PackedSyncPtr<T> base;
72 SyncVec() { base.init(); }
73 ~SyncVec() { free(base.get()); }
74 void push_back(const T& t) {
75 base.set((T*) realloc(base.get(),
76 (base.extra() + 1) * sizeof(T)));
77 base[base.extra()] = t;
78 base.setExtra(base.extra() + 1);
87 T* begin() const { return base.get(); }
88 T* end() const { return base.get() + base.extra(); }
90 typedef SyncVec<intptr_t> VecT;
91 typedef std::unordered_map<int64_t, VecT> Map;
92 const int mapCap = 1317;
93 const int nthrs = 297;
94 static Map map(mapCap);
96 // Each app thread inserts it's ID into every vec in map
97 // map is read only, so doesn't need any additional locking
98 void appThread(intptr_t id) {
99 for (auto& kv : map) {
101 kv.second.push_back(id);
106 TEST(PackedSyncPtr, Application) {
107 for (int64_t i = 0; i < mapCap / 2; ++i) {
108 map.insert(std::make_pair(i, VecT()));
110 std::vector<std::thread> thrs;
111 for (intptr_t i = 0; i < nthrs; i++) {
112 thrs.push_back(std::thread(appThread, i));
114 for (auto& t : thrs) {
118 for (auto& kv : map) {
119 // Make sure every thread successfully inserted it's ID into every vec
120 std::set<intptr_t> idsFound;
121 for (auto& elem : kv.second) {
122 EXPECT_TRUE(idsFound.insert(elem).second); // check for dups
124 EXPECT_EQ(idsFound.size(), nthrs); // check they are all there
128 TEST(PackedSyncPtr, extraData) {
129 PackedSyncPtr<int> p;
131 int* unaligned = reinterpret_cast<int*>(0xf003);
134 uintptr_t* bytes = reinterpret_cast<uintptr_t*>(&p);
135 LOG(INFO) << "Bytes integer is: 0x" << std::hex << *bytes;
136 EXPECT_EQ(p.get(), unaligned);