Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,35 @@ if(Protobuf_VERSION VERSION_GREATER 4.21)
absl::variant
)
endif()

# Cacheline-aligned types such as ResourcePool<Socket> are created with plain
# `new'. C++17 uses the aligned operator new for them; C++14 does so only with
# -faligned-new, and otherwise glibc returns 16-byte aligned storage. Their
# headers are installed, so consumers need the flag too (see brpc.pc).
set(BRPC_PC_EXTRA_CFLAGS "")
if(BRPC_CXX_STANDARD LESS 17)
include(CheckCXXSourceCompiles)
set(_brpc_saved_required_flags "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS
"${CMAKE_REQUIRED_FLAGS} -std=c++${BRPC_CXX_STANDARD} -faligned-new")
# Link an over-aligned allocation so the C++ runtime is checked as well.
check_cxx_source_compiles("
struct alignas(64) BrpcAlignedNewProbe { char c; };
int main() {
BrpcAlignedNewProbe* p = new BrpcAlignedNewProbe;
delete p;
return 0;
}" BRPC_HAS_ALIGNED_NEW)
set(CMAKE_REQUIRED_FLAGS "${_brpc_saved_required_flags}")
if(NOT BRPC_HAS_ALIGNED_NEW)
message(FATAL_ERROR
"C++${BRPC_CXX_STANDARD} builds need -faligned-new and an aligned "
"operator new in the C++ runtime (GCC 7+, Clang 4+ or libc++). "
"Use a newer toolchain or build with C++17.")
endif()
list(APPEND BRPC_COMMON_COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:CXX>:-faligned-new>)
set(BRPC_PC_EXTRA_CFLAGS " -faligned-new")
endif()
find_package(Threads REQUIRED)

list(REMOVE_DUPLICATES BRPC_COMMON_INCLUDE_DIRS)
Expand Down
2 changes: 1 addition & 1 deletion cmake/brpc.pc.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
Name: brpc
Description: Apache bRPC is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "bRPC" means "better RPC".
Version: @BRPC_VERSION@
Cflags: -I${includedir}
Cflags: -I${includedir}@BRPC_PC_EXTRA_CFLAGS@
Libs: -L${libdir}/ -lbrpc
Libs.private: @BRPC_PRIVATE_LIBS@
19 changes: 19 additions & 0 deletions config_brpc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,25 @@ else
print_success "Found protobuf version $PROTOBUF_VERSION"
fi

# Cacheline-aligned types such as ResourcePool<Socket> are created with plain
# `new'. C++17 uses the aligned operator new for them; C++14 does so only with
# -faligned-new, and otherwise glibc returns 16-byte aligned storage. Link an
# over-aligned allocation so the C++ runtime is checked as well. config.mk
# carries the flag to code built against this tree.
if [ "$CXXFLAGS" = "-std=c++14" ]; then
ALIGNED_NEW_PROBE=$(mktemp "${TMPDIR:-/tmp}/brpc_aligned_new.XXXXXX")
if printf '%s\n' 'struct alignas(64) P { char c; };' \
'int main() { P* p = new P; delete p; return 0; }' | \
$CXX $CXXFLAGS -faligned-new -x c++ - -o "$ALIGNED_NEW_PROBE" >/dev/null 2>&1; then
CXXFLAGS="${CXXFLAGS} -faligned-new"
rm -f "$ALIGNED_NEW_PROBE"
else
rm -f "$ALIGNED_NEW_PROBE"
>&2 $ECHO "C++14 builds need -faligned-new and an aligned operator new in the C++ runtime (GCC 7+, Clang 4+ or libc++)"
exit 1
fi
fi

CPPFLAGS=

if [ $WITH_ASAN != 0 ]; then
Expand Down
30 changes: 30 additions & 0 deletions test/resource_pool_unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,34 @@ TEST_F(ResourcePoolTest, verify_get) {

clear_resources<int>();
}

struct BAIDU_CACHELINE_ALIGNMENT CachelineObject {
int value;
};

TEST_F(ResourcePoolTest, plain_new_honors_cacheline_alignment) {
// Pools, their per-thread LocalPool and brpc's SocketPool are
// cacheline-aligned and created with plain `new'. C++14 builds need
// -faligned-new for that; glibc malloc then returns 16-byte aligned
// storage. tcmalloc, linked into this test, may hide the problem, so
// also require the compiler to use aligned new.
#if !defined(__cpp_aligned_new)
FAIL() << "Build with C++17 or -faligned-new";
Comment on lines +470 to +471

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration now stops first on such toolchains, so this test only runs where aligned new is expected to be in effect, and it fails if it isn't.

#endif
std::vector<CachelineObject*> objects;
for (int i = 0; i < 256; ++i) {
objects.push_back(new CachelineObject);
}
size_t misaligned = 0;
for (size_t i = 0; i < objects.size(); ++i) {
// The compiler may assume `new' honored alignof and fold a direct
// check to false; reading through a volatile keeps the real address.
volatile uintptr_t addr = reinterpret_cast<uintptr_t>(objects[i]);
if (addr % alignof(CachelineObject)) {
++misaligned;
}
delete objects[i];
}
ASSERT_EQ(0u, misaligned);
}
} // namespace
Loading