DIRECTORY synchronization/test/
TEST call_once_test SOURCES CallOnceTest.cpp
+ DIRECTORY system/test/
+ TEST memory_mapping_test SOURCES MemoryMappingTest.cpp
+ TEST shell_test SOURCES ShellTest.cpp
+ #TEST subprocess_test SOURCES SubprocessTest.cpp
+ TEST thread_id_test SOURCES ThreadIdTest.cpp
+ TEST thread_name_test SOURCES ThreadNameTest.cpp
+
DIRECTORY test/
TEST ahm_int_stress_test SOURCES AHMIntStressTest.cpp
TEST arena_test SOURCES ArenaTest.cpp
TEST map_util_test SOURCES MapUtilTest.cpp
TEST memcpy_test SOURCES MemcpyTest.cpp
TEST memory_idler_test SOURCES MemoryIdlerTest.cpp
- TEST memory_mapping_test SOURCES MemoryMappingTest.cpp
TEST memory_test SOURCES MemoryTest.cpp
TEST merge SOURCES MergeTest.cpp
TEST move_wrapper_test SOURCES MoveWrapperTest.cpp
TEST scope_guard_test SOURCES ScopeGuardTest.cpp
# Heavily dependent on drand and srand48
#TEST shared_mutex_test SOURCES SharedMutexTest.cpp
- TEST shell_test SOURCES ShellTest.cpp
TEST singleton_test SOURCES SingletonTest.cpp
TEST singleton_test_global SOURCES SingletonTestGlobal.cpp
TEST singleton_thread_local_test SOURCES SingletonThreadLocalTest.cpp
TEST sorted_vector_types_test SOURCES sorted_vector_test.cpp
TEST sparse_byte_set_test SOURCES SparseByteSetTest.cpp
TEST string_test SOURCES StringTest.cpp
- #TEST subprocess_test SOURCES SubprocessTest.cpp
TEST synchronized_test SOURCES SynchronizedTest.cpp
TEST thread_cached_arena_test SOURCES ThreadCachedArenaTest.cpp
TEST thread_cached_int_test SOURCES ThreadCachedIntTest.cpp
- TEST thread_id_test SOURCES ThreadIdTest.cpp
TEST thread_local_test SOURCES ThreadLocalTest.cpp
- TEST thread_name_test SOURCES ThreadNameTest.cpp
TEST timeout_queue_test SOURCES TimeoutQueueTest.cpp
TEST token_bucket_test SOURCES TokenBucketTest.cpp
TEST traits_test SOURCES TraitsTest.cpp
MapUtil.h \
Math.h \
Memory.h \
- MemoryMapping.h \
memory/MallctlHelper.h \
memory/UninitializedMemoryHacks.h \
MicroSpinLock.h \
SafeAssert.h \
ScopeGuard.h \
SharedMutex.h \
- Shell.h \
Singleton.h \
Singleton-inl.h \
SingletonThreadLocal.h \
stats/TimeseriesHistogram-defs.h \
stats/TimeseriesHistogram.h \
synchronization/CallOnce.h \
+ system/MemoryMapping.h \
+ system/Shell.h \
+ system/ThreadId.h \
+ system/ThreadName.h \
+ system/VersionCheck.h \
stop_watch.h \
String.h \
String-inl.h \
test/TestUtils.h \
ThreadCachedArena.h \
ThreadCachedInt.h \
- ThreadId.h \
ThreadLocal.h \
- ThreadName.h \
TimeoutQueue.h \
TokenBucket.h \
tracing/StaticTracepoint.h \
Uri.h \
Uri-inl.h \
Utility.h \
- Varint.h \
- VersionCheck.h
+ Varint.h
FormatTables.cpp: build/generate_format_tables.py
$(PYTHON) build/generate_format_tables.py
detail/MemoryIdler.cpp \
detail/SocketFastOpen.cpp \
MacAddress.cpp \
- MemoryMapping.cpp \
portability/Dirent.cpp \
portability/Fcntl.cpp \
portability/Libgen.cpp \
SafeAssert.cpp \
ScopeGuard.cpp \
SharedMutex.cpp \
- Shell.cpp \
MicroLock.cpp \
Optional.cpp \
Singleton.cpp \
stats/Histogram.cpp \
stats/MultiLevelTimeSeries.cpp \
stats/TimeseriesHistogram.cpp \
+ system/MemoryMapping.cpp \
+ system/Shell.cpp \
+ system/ThreadName.cpp \
+ system/VersionCheck.cpp \
Subprocess.cpp \
ThreadCachedArena.cpp \
- ThreadName.cpp \
TimeoutQueue.cpp \
Try.cpp \
Uri.cpp \
- Version.cpp \
experimental/AsymmetricMemoryBarrier.cpp \
experimental/ThreadedRepeatingFunctionRunner.cpp \
experimental/bser/Dump.cpp \
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/MemoryMapping.h>
-
-#include <algorithm>
-#include <functional>
-#include <utility>
-
-#include <folly/Format.h>
-#include <folly/portability/GFlags.h>
-#include <folly/portability/SysMman.h>
-
-#ifdef __linux__
-#include <folly/experimental/io/HugePages.h>
-#endif
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <system_error>
-
-static constexpr ssize_t kDefaultMlockChunkSize =
-#ifndef _MSC_VER
- // Linux implementations of unmap/mlock/munlock take a kernel
- // semaphore and block other threads from doing other memory
- // operations. Split the operations in chunks.
- (1 << 20) // 1MB
-#else // _MSC_VER
- // MSVC doesn't have this problem, and calling munmap many times
- // with the same address is a bad idea with the windows implementation.
- (-1)
-#endif // _MSC_VER
- ;
-
-DEFINE_int64(mlock_chunk_size, kDefaultMlockChunkSize,
- "Maximum bytes to mlock/munlock/munmap at once "
- "(will be rounded up to PAGESIZE). Ignored if negative.");
-
-#ifndef MAP_POPULATE
-#define MAP_POPULATE 0
-#endif
-
-namespace folly {
-
-MemoryMapping::MemoryMapping(MemoryMapping&& other) noexcept {
- swap(other);
-}
-
-MemoryMapping::MemoryMapping(File file, off_t offset, off_t length,
- Options options)
- : file_(std::move(file)),
- options_(std::move(options)) {
- CHECK(file_);
- init(offset, length);
-}
-
-MemoryMapping::MemoryMapping(const char* name, off_t offset, off_t length,
- Options options)
- : MemoryMapping(File(name, options.writable ? O_RDWR : O_RDONLY),
- offset,
- length,
- options) { }
-
-MemoryMapping::MemoryMapping(int fd, off_t offset, off_t length,
- Options options)
- : MemoryMapping(File(fd), offset, length, options) { }
-
-MemoryMapping::MemoryMapping(AnonymousType, off_t length, Options options)
- : options_(std::move(options)) {
- init(0, length);
-}
-
-namespace {
-
-#ifdef __linux__
-void getDeviceOptions(dev_t device, off_t& pageSize, bool& autoExtend) {
- auto ps = getHugePageSizeForDevice(device);
- if (ps) {
- pageSize = ps->size;
- autoExtend = true;
- }
-}
-#else
-inline void getDeviceOptions(dev_t, off_t&, bool&) {}
-#endif
-
-} // namespace
-
-void MemoryMapping::init(off_t offset, off_t length) {
- const bool grow = options_.grow;
- const bool anon = !file_;
- CHECK(!(grow && anon));
-
- off_t& pageSize = options_.pageSize;
-
- struct stat st;
-
- // On Linux, hugetlbfs file systems don't require ftruncate() to grow the
- // file, and (on kernels before 2.6.24) don't even allow it. Also, the file
- // size is always a multiple of the page size.
- bool autoExtend = false;
-
- if (!anon) {
- // Stat the file
- CHECK_ERR(fstat(file_.fd(), &st));
-
- if (pageSize == 0) {
- getDeviceOptions(st.st_dev, pageSize, autoExtend);
- }
- } else {
- DCHECK(!file_);
- DCHECK_EQ(offset, 0);
- CHECK_EQ(pageSize, 0);
- CHECK_GE(length, 0);
- }
-
- if (pageSize == 0) {
- pageSize = off_t(sysconf(_SC_PAGESIZE));
- }
-
- CHECK_GT(pageSize, 0);
- CHECK_EQ(pageSize & (pageSize - 1), 0); // power of two
- CHECK_GE(offset, 0);
-
- // Round down the start of the mapped region
- off_t skipStart = offset % pageSize;
- offset -= skipStart;
-
- mapLength_ = length;
- if (mapLength_ != -1) {
- mapLength_ += skipStart;
-
- // Round up the end of the mapped region
- mapLength_ = (mapLength_ + pageSize - 1) / pageSize * pageSize;
- }
-
- off_t remaining = anon ? length : st.st_size - offset;
-
- if (mapLength_ == -1) {
- length = mapLength_ = remaining;
- } else {
- if (length > remaining) {
- if (grow) {
- if (!autoExtend) {
- PCHECK(0 == ftruncate(file_.fd(), offset + length))
- << "ftruncate() failed, couldn't grow file to "
- << offset + length;
- remaining = length;
- } else {
- // Extend mapping to multiple of page size, don't use ftruncate
- remaining = mapLength_;
- }
- } else {
- length = remaining;
- }
- }
- if (mapLength_ > remaining) {
- mapLength_ = remaining;
- }
- }
-
- if (length == 0) {
- mapLength_ = 0;
- mapStart_ = nullptr;
- } else {
- int flags = options_.shared ? MAP_SHARED : MAP_PRIVATE;
- if (anon) {
- flags |= MAP_ANONYMOUS;
- }
- if (options_.prefault) {
- flags |= MAP_POPULATE;
- }
-
- // The standard doesn't actually require PROT_NONE to be zero...
- int prot = PROT_NONE;
- if (options_.readable || options_.writable) {
- prot = ((options_.readable ? PROT_READ : 0) |
- (options_.writable ? PROT_WRITE : 0));
- }
-
- unsigned char* start = static_cast<unsigned char*>(mmap(
- options_.address, size_t(mapLength_), prot, flags, file_.fd(), offset));
- PCHECK(start != MAP_FAILED)
- << " offset=" << offset
- << " length=" << mapLength_;
- mapStart_ = start;
- data_.reset(start + skipStart, size_t(length));
- }
-}
-
-namespace {
-
-off_t memOpChunkSize(off_t length, off_t pageSize) {
- off_t chunkSize = length;
- if (FLAGS_mlock_chunk_size <= 0) {
- return chunkSize;
- }
-
- chunkSize = off_t(FLAGS_mlock_chunk_size);
- off_t r = chunkSize % pageSize;
- if (r) {
- chunkSize += (pageSize - r);
- }
- return chunkSize;
-}
-
-/**
- * Run @op in chunks over the buffer @mem of @bufSize length.
- *
- * Return:
- * - success: true + amountSucceeded == bufSize (op success on whole buffer)
- * - failure: false + amountSucceeded == nr bytes on which op succeeded.
- */
-bool memOpInChunks(std::function<int(void*, size_t)> op,
- void* mem, size_t bufSize, off_t pageSize,
- size_t& amountSucceeded) {
- // Linux' unmap/mlock/munlock take a kernel semaphore and block other threads
- // from doing other memory operations. If the size of the buffer is big the
- // semaphore can be down for seconds (for benchmarks see
- // http://kostja-osipov.livejournal.com/42963.html). Doing the operations in
- // chunks breaks the locking into intervals and lets other threads do memory
- // operations of their own.
-
- size_t chunkSize = size_t(memOpChunkSize(off_t(bufSize), pageSize));
-
- char* addr = static_cast<char*>(mem);
- amountSucceeded = 0;
-
- while (amountSucceeded < bufSize) {
- size_t size = std::min(chunkSize, bufSize - amountSucceeded);
- if (op(addr + amountSucceeded, size) != 0) {
- return false;
- }
- amountSucceeded += size;
- }
-
- return true;
-}
-
-} // namespace
-
-bool MemoryMapping::mlock(LockMode lock) {
- size_t amountSucceeded = 0;
- locked_ = memOpInChunks(
- ::mlock,
- mapStart_,
- size_t(mapLength_),
- options_.pageSize,
- amountSucceeded);
- if (locked_) {
- return true;
- }
-
- auto msg =
- folly::format("mlock({}) failed at {}", mapLength_, amountSucceeded);
- if (lock == LockMode::TRY_LOCK && errno == EPERM) {
- PLOG(WARNING) << msg;
- } else if (lock == LockMode::TRY_LOCK && errno == ENOMEM) {
- VLOG(1) << msg;
- } else {
- PLOG(FATAL) << msg;
- }
-
- // only part of the buffer was mlocked, unlock it back
- if (!memOpInChunks(::munlock, mapStart_, amountSucceeded, options_.pageSize,
- amountSucceeded)) {
- PLOG(WARNING) << "munlock()";
- }
-
- return false;
-}
-
-void MemoryMapping::munlock(bool dontneed) {
- if (!locked_) {
- return;
- }
-
- size_t amountSucceeded = 0;
- if (!memOpInChunks(
- ::munlock,
- mapStart_,
- size_t(mapLength_),
- options_.pageSize,
- amountSucceeded)) {
- PLOG(WARNING) << "munlock()";
- }
- if (mapLength_ && dontneed &&
- ::madvise(mapStart_, size_t(mapLength_), MADV_DONTNEED)) {
- PLOG(WARNING) << "madvise()";
- }
- locked_ = false;
-}
-
-void MemoryMapping::hintLinearScan() {
- advise(MADV_SEQUENTIAL);
-}
-
-MemoryMapping::~MemoryMapping() {
- if (mapLength_) {
- size_t amountSucceeded = 0;
- if (!memOpInChunks(
- ::munmap,
- mapStart_,
- size_t(mapLength_),
- options_.pageSize,
- amountSucceeded)) {
- PLOG(FATAL) << folly::format("munmap({}) failed at {}",
- mapLength_, amountSucceeded);
- }
- }
-}
-
-void MemoryMapping::advise(int advice) const {
- advise(advice, 0, size_t(mapLength_));
-}
-
-void MemoryMapping::advise(int advice, size_t offset, size_t length) const {
- CHECK_LE(offset + length, size_t(mapLength_))
- << " offset: " << offset
- << " length: " << length
- << " mapLength_: " << mapLength_;
-
- // Include the entire start page: round down to page boundary.
- const auto offMisalign = offset % options_.pageSize;
- offset -= offMisalign;
- length += offMisalign;
-
- // Round the last page down to page boundary.
- if (offset + length != size_t(mapLength_)) {
- length -= length % options_.pageSize;
- }
-
- if (length == 0) {
- return;
- }
-
- char* mapStart = static_cast<char*>(mapStart_) + offset;
- PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise";
-}
-
-MemoryMapping& MemoryMapping::operator=(MemoryMapping other) {
- swap(other);
- return *this;
-}
-
-void MemoryMapping::swap(MemoryMapping& other) noexcept {
- using std::swap;
- swap(this->file_, other.file_);
- swap(this->mapStart_, other.mapStart_);
- swap(this->mapLength_, other.mapLength_);
- swap(this->options_, other.options_);
- swap(this->locked_, other.locked_);
- swap(this->data_, other.data_);
-}
-
-void swap(MemoryMapping& a, MemoryMapping& b) noexcept { a.swap(b); }
-
-void alignedForwardMemcpy(void* dst, const void* src, size_t size) {
- assert(reinterpret_cast<uintptr_t>(src) % alignof(unsigned long) == 0);
- assert(reinterpret_cast<uintptr_t>(dst) % alignof(unsigned long) == 0);
-
- auto srcl = static_cast<const unsigned long*>(src);
- auto dstl = static_cast<unsigned long*>(dst);
-
- while (size >= sizeof(unsigned long)) {
- *dstl++ = *srcl++;
- size -= sizeof(unsigned long);
- }
-
- auto srcc = reinterpret_cast<const unsigned char*>(srcl);
- auto dstc = reinterpret_cast<unsigned char*>(dstl);
-
- while (size != 0) {
- *dstc++ = *srcc++;
- --size;
- }
-}
-
-void mmapFileCopy(const char* src, const char* dest, mode_t mode) {
- MemoryMapping srcMap(src);
- srcMap.hintLinearScan();
-
- MemoryMapping destMap(
- File(dest, O_RDWR | O_CREAT | O_TRUNC, mode),
- 0,
- off_t(srcMap.range().size()),
- MemoryMapping::writable());
-
- alignedForwardMemcpy(destMap.writableRange().data(),
- srcMap.range().data(),
- srcMap.range().size());
-}
-
-} // namespace folly
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <boost/noncopyable.hpp>
-#include <glog/logging.h>
-
-#include <folly/File.h>
-#include <folly/Range.h>
-
-namespace folly {
-
-/**
- * Maps files in memory (read-only).
- *
- * @author Tudor Bosman (tudorb@fb.com)
- */
-class MemoryMapping : boost::noncopyable {
- public:
- /**
- * Lock the pages in memory?
- * TRY_LOCK = try to lock, log warning if permission denied
- * MUST_LOCK = lock, fail assertion if permission denied.
- */
- enum class LockMode {
- TRY_LOCK,
- MUST_LOCK
- };
- /**
- * Map a portion of the file indicated by filename in memory, causing a CHECK
- * failure on error.
- *
- * By default, map the whole file. length=-1: map from offset to EOF.
- * Unlike the mmap() system call, offset and length don't need to be
- * page-aligned. length is clipped to the end of the file if it's too large.
- *
- * The mapping will be destroyed (and the memory pointed-to by data() will
- * likely become inaccessible) when the MemoryMapping object is destroyed.
- */
- struct Options {
- Options() {}
-
- // Convenience methods; return *this for chaining.
- Options& setPageSize(off_t v) { pageSize = v; return *this; }
- Options& setShared(bool v) { shared = v; return *this; }
- Options& setPrefault(bool v) { prefault = v; return *this; }
- Options& setReadable(bool v) { readable = v; return *this; }
- Options& setWritable(bool v) { writable = v; return *this; }
- Options& setGrow(bool v) { grow = v; return *this; }
-
- // Page size. 0 = use appropriate page size.
- // (On Linux, we use a huge page size if the file is on a hugetlbfs
- // file system, and the default page size otherwise)
- off_t pageSize = 0;
-
- // If shared (default), the memory mapping is shared with other processes
- // mapping the same file (or children); if not shared (private), each
- // process has its own mapping. Changes in writable, private mappings are
- // not reflected to the underlying file. See the discussion of
- // MAP_PRIVATE vs MAP_SHARED in the mmap(2) manual page.
- bool shared = true;
-
- // Populate page tables; subsequent accesses should not be blocked
- // by page faults. This is a hint, as it may not be supported.
- bool prefault = false;
-
- // Map the pages readable. Note that mapping pages without read permissions
- // is not universally supported (not supported on hugetlbfs on Linux, for
- // example)
- bool readable = true;
-
- // Map the pages writable.
- bool writable = false;
-
- // When mapping a file in writable mode, grow the file to the requested
- // length (using ftruncate()) before mapping; if false, truncate the
- // mapping to the actual file size instead.
- bool grow = false;
-
- // Fix map at this address, if not nullptr. Must be aligned to a multiple
- // of the appropriate page size.
- void* address = nullptr;
- };
-
- // Options to emulate the old WritableMemoryMapping: readable and writable,
- // allow growing the file if mapping past EOF.
- static Options writable() {
- return Options().setWritable(true).setGrow(true);
- }
-
- enum AnonymousType {
- kAnonymous
- };
-
- /**
- * Create an anonymous mapping.
- */
- MemoryMapping(AnonymousType, off_t length, Options options=Options());
-
- explicit MemoryMapping(File file,
- off_t offset=0,
- off_t length=-1,
- Options options=Options());
-
- explicit MemoryMapping(const char* name,
- off_t offset=0,
- off_t length=-1,
- Options options=Options());
-
- explicit MemoryMapping(int fd,
- off_t offset=0,
- off_t length=-1,
- Options options=Options());
-
- MemoryMapping(MemoryMapping&&) noexcept;
-
- ~MemoryMapping();
-
- MemoryMapping& operator=(MemoryMapping);
-
- void swap(MemoryMapping& other) noexcept;
-
- /**
- * Lock the pages in memory
- */
- bool mlock(LockMode lock);
-
- /**
- * Unlock the pages.
- * If dontneed is true, the kernel is instructed to release these pages
- * (per madvise(MADV_DONTNEED)).
- */
- void munlock(bool dontneed = false);
-
- /**
- * Hint that these pages will be scanned linearly.
- * madvise(MADV_SEQUENTIAL)
- */
- void hintLinearScan();
-
- /**
- * Advise the kernel about memory access.
- */
- void advise(int advice) const;
- void advise(int advice, size_t offset, size_t length) const;
-
- /**
- * A bitwise cast of the mapped bytes as range of values. Only intended for
- * use with POD or in-place usable types.
- */
- template <class T>
- Range<const T*> asRange() const {
- size_t count = data_.size() / sizeof(T);
- return Range<const T*>(static_cast<const T*>(
- static_cast<const void*>(data_.data())),
- count);
- }
-
- /**
- * A range of bytes mapped by this mapping.
- */
- ByteRange range() const {
- return data_;
- }
-
- /**
- * A bitwise cast of the mapped bytes as range of mutable values. Only
- * intended for use with POD or in-place usable types.
- */
- template <class T>
- Range<T*> asWritableRange() const {
- DCHECK(options_.writable); // you'll segfault anyway...
- size_t count = data_.size() / sizeof(T);
- return Range<T*>(static_cast<T*>(
- static_cast<void*>(data_.data())),
- count);
- }
-
- /**
- * A range of mutable bytes mapped by this mapping.
- */
- MutableByteRange writableRange() const {
- DCHECK(options_.writable); // you'll segfault anyway...
- return data_;
- }
-
- /**
- * Return the memory area where the file was mapped.
- * Deprecated; use range() instead.
- */
- StringPiece data() const {
- return asRange<const char>();
- }
-
- bool mlocked() const {
- return locked_;
- }
-
- int fd() const { return file_.fd(); }
-
- private:
- MemoryMapping();
-
- enum InitFlags {
- kGrow = 1 << 0,
- kAnon = 1 << 1,
- };
- void init(off_t offset, off_t length);
-
- File file_;
- void* mapStart_ = nullptr;
- off_t mapLength_ = 0;
- Options options_;
- bool locked_ = false;
- MutableByteRange data_;
-};
-
-void swap(MemoryMapping&, MemoryMapping&) noexcept;
-
-/**
- * A special case of memcpy() that always copies memory forwards.
- * (libc's memcpy() is allowed to copy memory backwards, and will do so
- * when using SSSE3 instructions).
- *
- * Assumes src and dest are aligned to alignof(unsigned long).
- *
- * Useful when copying from/to memory mappings after hintLinearScan();
- * copying backwards renders any prefetching useless (even harmful).
- */
-void alignedForwardMemcpy(void* dest, const void* src, size_t size);
-
-/**
- * Copy a file using mmap(). Overwrites dest.
- */
-void mmapFileCopy(const char* src, const char* dest, mode_t mode = 0666);
-
-} // namespace folly
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/Shell.h>
-
-namespace folly {
-
-std::string shellQuote(StringPiece argument) {
- std::string quoted = "'";
- for (auto c : argument) {
- if (c == '\'') {
- quoted += "'\\''";
- } else {
- quoted += c;
- }
- }
- return quoted + "'";
-}
-
-} // namespace folly
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * `Shell` provides a collection of functions to use with `Subprocess` that make
- * it easier to safely run processes in a unix shell.
- *
- * Note: use this rarely and carefully. By default you should use `Subprocess`
- * with a vector of arguments.
- */
-
-#pragma once
-
-#include <string>
-#include <vector>
-
-#include <folly/Conv.h>
-#include <folly/Format.h>
-#include <folly/Range.h>
-
-namespace folly {
-
-/**
- * Quotes an argument to make it suitable for use as shell command arguments.
- */
-std::string shellQuote(StringPiece argument);
-
-namespace detail {
-template <typename... Arguments>
-std::vector<std::string> shellify(
- StringPiece format,
- Arguments&&... arguments) {
- auto command = sformat(
- format,
- shellQuote(to<std::string>(std::forward<Arguments>(arguments)))...);
- return {"/bin/sh", "-c", command};
-}
-
-struct ShellCmdFormat {
- StringPiece format;
- template <typename... Arguments>
- std::vector<std::string> operator()(Arguments&&... arguments) const {
- return ::folly::detail::shellify(
- format, std::forward<Arguments>(arguments)...);
- }
-};
-
-} // namespace detail
-
-inline namespace literals {
-inline namespace shell_literals {
-constexpr detail::ShellCmdFormat operator"" _shellify(
- char const* name,
- std::size_t length) {
- return {folly::StringPiece(name, length)};
-}
-} // inline namespace shell_literals
-} // inline namespace literals
-
-/**
- * Create argument array for `Subprocess()` for a process running in a
- * shell.
- *
- * The shell to use is always going to be `/bin/sh`.
- *
- * This is deprecated in favour of the user-defined-literal `_shellify`
- * from namespace `folly::shell_literals` because that requires that the format
- * string is a compile-time constant which can be inspected during code reviews
- */
-template <typename... Arguments>
-FOLLY_DEPRECATED(
- "Use `\"command {} {} ...\"_shellify(argument1, argument2 ...)` from "
- "namespace `folly::literals::shell_literals`")
-std::vector<std::string> shellify(
- StringPiece format,
- Arguments&&... arguments) {
- return detail::shellify(format, std::forward<Arguments>(arguments)...);
-}
-
-} // namespace folly
#include <folly/Conv.h>
#include <folly/Exception.h>
#include <folly/ScopeGuard.h>
-#include <folly/Shell.h>
#include <folly/String.h>
#include <folly/io/Cursor.h>
#include <folly/portability/Sockets.h>
#include <folly/portability/Stdlib.h>
#include <folly/portability/SysSyscall.h>
#include <folly/portability/Unistd.h>
+#include <folly/system/Shell.h>
constexpr int kExecFailure = 127;
constexpr int kChildFailure = 126;
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include <folly/portability/PThread.h>
-#include <folly/portability/SysSyscall.h>
-#include <folly/portability/Unistd.h>
-#include <folly/portability/Windows.h>
-
-namespace folly {
-
-/**
- * Get a process-specific identifier for the current thread.
- *
- * The return value will uniquely identify the thread within the current
- * process.
- *
- * Note that the return value does not necessarily correspond to an operating
- * system thread ID. The return value is also only unique within the current
- * process: getCurrentThreadID() may return the same value for two concurrently
- * running threads in separate processes.
- *
- * The thread ID may be reused once the thread it corresponds to has been
- * joined.
- */
-inline uint64_t getCurrentThreadID() {
-#if __APPLE__
- return uint64_t(pthread_mach_thread_np(pthread_self()));
-#elif _WIN32
- return uint64_t(GetCurrentThreadId());
-#else
- return uint64_t(pthread_self());
-#endif
-}
-
-/**
- * Get the operating-system level thread ID for the current thread.
- *
- * The returned value will uniquely identify this thread on the system.
- *
- * This makes it more suitable for logging or displaying in user interfaces
- * than the result of getCurrentThreadID().
- *
- * There are some potential caveats about this API, however:
- *
- * - In theory there is no guarantee that application threads map one-to-one to
- * kernel threads. An application threading implementation could potentially
- * share one OS thread across multiple application threads, and/or it could
- * potentially move application threads between different OS threads over
- * time. However, in practice all of the platforms we currently support have
- * a one-to-one mapping between userspace threads and operating system
- * threads.
- *
- * - This API may also be slightly slower than getCurrentThreadID() on some
- * platforms. This API may require a system call, where getCurrentThreadID()
- * may only need to read thread-local memory.
- *
- * On Linux the returned value is a pid_t, and can be used in contexts
- * requiring a thread pid_t.
- *
- * The thread ID may be reused once the thread it corresponds to has been
- * joined.
- */
-inline uint64_t getOSThreadID() {
-#if __APPLE__
- uint64_t tid;
- pthread_threadid_np(nullptr, &tid);
- return tid;
-#elif _WIN32
- return uint64_t(GetCurrentThreadId());
-#else
- return uint64_t(syscall(FOLLY_SYS_gettid));
-#endif
-}
-}
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/ThreadName.h>
-
-#include <type_traits>
-
-#include <folly/Portability.h>
-#include <folly/Traits.h>
-#include <folly/portability/PThread.h>
-
-namespace folly {
-
-// This looks a bit weird, but it's necessary to avoid
-// having an undefined compiler function called.
-#if defined(__GLIBC__) && !defined(__APPLE__) && !defined(__ANDROID__)
-#if __GLIBC_PREREQ(2, 12)
-// has pthread_setname_np(pthread_t, const char*) (2 params)
-#define FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME 1
-#endif
-#endif
-
-#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
-// has pthread_setname_np(const char*) (1 param)
-#define FOLLY_HAS_PTHREAD_SETNAME_NP_NAME 1
-#endif
-#endif
-
-namespace {
-
-#if FOLLY_HAVE_PTHREAD && !_WIN32
-pthread_t stdTidToPthreadId(std::thread::id tid) {
- static_assert(
- std::is_same<pthread_t, std::thread::native_handle_type>::value,
- "This assumes that the native handle type is pthread_t");
- static_assert(
- sizeof(std::thread::native_handle_type) == sizeof(std::thread::id),
- "This assumes std::thread::id is a thin wrapper around "
- "std::thread::native_handle_type, but that doesn't appear to be true.");
- // In most implementations, std::thread::id is a thin wrapper around
- // std::thread::native_handle_type, which means we can do unsafe things to
- // extract it.
- pthread_t id;
- std::memcpy(&id, &tid, sizeof(id));
- return id;
-}
-#endif
-
-} // namespace
-
-bool canSetCurrentThreadName() {
-#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
- FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
- return true;
-#else
- return false;
-#endif
-}
-
-bool canSetOtherThreadName() {
-#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME
- return true;
-#else
- return false;
-#endif
-}
-
-static constexpr size_t kMaxThreadNameLength = 16;
-
-Optional<std::string> getThreadName(std::thread::id id) {
-#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
- FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
- std::array<char, kMaxThreadNameLength> buf;
- if (pthread_getname_np(stdTidToPthreadId(id), buf.data(), buf.size()) != 0) {
- return Optional<std::string>();
- }
- return make_optional(std::string(buf.data()));
-#else
- return Optional<std::string>();
-#endif
-}
-
-Optional<std::string> getCurrentThreadName() {
- return getThreadName(std::this_thread::get_id());
-}
-
-bool setThreadName(std::thread::id tid, StringPiece name) {
-#if !FOLLY_HAVE_PTHREAD || _WIN32
- return false;
-#else
- name = name.subpiece(0, kMaxThreadNameLength - 1);
- char buf[kMaxThreadNameLength] = {};
- std::memcpy(buf, name.data(), name.size());
- auto id = stdTidToPthreadId(tid);
-#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME
- return 0 == pthread_setname_np(id, buf);
-#elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
- // Since OS X 10.6 it is possible for a thread to set its own name,
- // but not that of some other thread.
- if (pthread_equal(pthread_self(), id)) {
- return 0 == pthread_setname_np(buf);
- }
- return false;
-#else
- (void)id;
- return false;
-#endif
-#endif
-}
-
-#if FOLLY_HAVE_PTHREAD
-bool setThreadName(pthread_t pid, StringPiece name) {
-#if _WIN32
- // Not currently supported on Windows.
- return false;
-#else
- static_assert(
- std::is_same<pthread_t, std::thread::native_handle_type>::value,
- "This assumes that the native handle type is pthread_t");
- static_assert(
- sizeof(std::thread::native_handle_type) == sizeof(std::thread::id),
- "This assumes std::thread::id is a thin wrapper around "
- "std::thread::native_handle_type, but that doesn't appear to be true.");
- // In most implementations, std::thread::id is a thin wrapper around
- // std::thread::native_handle_type, which means we can do unsafe things to
- // extract it.
- std::thread::id id;
- std::memcpy(&id, &pid, sizeof(id));
- return setThreadName(id, name);
-#endif
-}
-#endif
-
-bool setThreadName(StringPiece name) {
- return setThreadName(std::this_thread::get_id(), name);
-}
-}
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-#include <thread>
-
-#include <folly/Optional.h>
-#include <folly/Range.h>
-#include <folly/portability/Config.h>
-#include <folly/portability/PThread.h>
-
-namespace folly {
-
-/**
- * This returns true if the current platform supports setting the name of the
- * current thread.
- */
-bool canSetCurrentThreadName();
-
-/**
- * This returns true if the current platform supports setting the name of
- * threads other than the one currently executing.
- */
-bool canSetOtherThreadName();
-
-/**
- * Get the name of the given thread, or nothing if an error occurs
- * or the functionality is not available.
- */
-Optional<std::string> getThreadName(std::thread::id tid);
-
-/**
- * Equivalent to getThreadName(std::this_thread::get_id());
- */
-Optional<std::string> getCurrentThreadName();
-
-/**
- * Set the name of the given thread.
- * Returns false on failure, if an error occurs or the functionality
- * is not available.
- */
-bool setThreadName(std::thread::id tid, StringPiece name);
-#if FOLLY_HAVE_PTHREAD
-bool setThreadName(pthread_t pid, StringPiece name);
-#endif
-
-/**
- * Equivalent to setThreadName(std::this_thread::get_id(), name);
- */
-bool setThreadName(StringPiece name);
-}
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/VersionCheck.h>
-
-namespace folly { namespace detail {
-
-FOLLY_VERSION_CHECK(folly, FOLLY_VERSION)
-
-}} // namespaces
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-#include <folly/Portability.h>
-#include <folly/Preprocessor.h>
-
-/**
- * Check if the currently loaded version of a library is what you expect.
- *
- * It is possible for multiple versions of the same shared library to end up
- * being loaded simultaneously in the same address space, usually with
- * disastrous results.
- *
- * For example, let's say you have a shared library (foo) that doesn't keep
- * binary compatbility between releases, and so each version is distributed as
- * a SO with different SONAME. Let's say you build another shared library, bar
- * that depends on version 1 of foo: libbar.so depends on libfoo1.so.
- * Your main executable now (baz) depends on version 2 of foo, and also
- * depends on bar: baz depends on libfoo2.so and libbar.so.
- *
- * At load time, baz loads libfoo2.so first, then libbar.so; libbar.so will
- * load libfoo1.so, but, as this is normal dynamic loading (and not explicit
- * dlopen calls with RTLD_DEEPBIND), any symbols from libfoo1.so that are
- * also present in libfoo2.so will be satisfied from the (already loaded)
- * libfoo2.so.
- *
- * But foo does not preserve binary compatibility between versions, so all
- * hell breaks loose (the symbols from libfoo2.so are not necessarily direct
- * replacements of the identically-named symbols in libfoo1.so).
- *
- * It is better to crash with a helpful error message instead, which is what
- * this macro provides. FOLLY_VERSION_CHECK verifies at load time that
- * the compiled-in version is the same as the currently loaded version.
- *
- * Usage: use this macro at namespace scope in a .cpp file (IMPORTANT: NOT
- * in the unnamed namespace):
- *
- * FOLLY_VERSION_CHECK(mylib, "1")
- *
- * The first argument identifies your library; the second argument is a
- * string literal containing the desired version string.
- *
- * In order to avoid changing the file for each version, the version string
- * could be provided on the compiler command line with -D:
- *
- * FOLLY_VERSION_CHECK(mylib, MYLIB_VERSION)
- *
- * ... and then commpile your file with -DMYLIB_VERSION=\"1\"
- */
-
-#if defined(_MSC_VER)
-// MSVC doesn't support constructor priorities. Just pray it works, I guess.
-// We could implement a link-time mechanism for MSVC,
-// via #pragma detect_mismatch but that would only handle
-// static library linking.
-# define FOLLY_VERSION_CHECK_PRIORITY(Ret, name) \
- __pragma(section(".CRT$XCU",read)) \
- static Ret __cdecl name(void); \
- __declspec(allocate(".CRT$XCU")) \
- Ret (__cdecl*name##_)(void) = name; \
- Ret __cdecl name()
-
-#elif defined(__APPLE__)
-// OS X doesn't support constructor priorities. Just pray it works, I guess.
-# define FOLLY_VERSION_CHECK_PRIORITY(Ret, name) \
- __attribute__((__constructor__)) Ret name()
-
-#else
-# define FOLLY_VERSION_CHECK_PRIORITY(Ret, name) \
- __attribute__((__constructor__(101))) Ret name()
-#endif
-
-// Note that this is carefully crafted: PRODUCT##Version must have external
-// linkage (so it collides among versions), versionCheck must have internal
-// linkage (so it does NOT collide between versions); if we're trying to have
-// multiple versions loaded at the same time, they must each run their copy
-// of versionCheck, but share the PRODUCT##Version variable.
-#define FOLLY_VERSION_CHECK(PRODUCT, VERSION) \
- const char* PRODUCT##Version = VERSION; \
- namespace { \
- FOLLY_VERSION_CHECK_PRIORITY(void, versionCheck) { \
- if (strcmp(PRODUCT##Version, VERSION)) { \
- fprintf(stderr, \
- "Invalid %s version: desired [%s], currently loaded [%s]\n", \
- FB_STRINGIZE(PRODUCT), PRODUCT##Version, VERSION); \
- abort(); \
- } \
- } \
- }
#include <folly/Likely.h>
#include <folly/Memory.h>
#include <folly/Portability.h>
-#include <folly/ThreadId.h>
#include <folly/portability/BitsFunctexcept.h>
#include <folly/portability/Memory.h>
+#include <folly/system/ThreadId.h>
namespace folly {
#include <folly/AtomicStruct.h>
#include <folly/Hash.h>
-#include <folly/ThreadId.h>
#include <folly/Traits.h>
#include <folly/detail/Futex.h>
+#include <folly/system/ThreadId.h>
namespace folly {
#include <glog/logging.h>
-#include <folly/ThreadName.h>
#include <folly/executors/thread_factory/NamedThreadFactory.h>
+#include <folly/system/ThreadName.h>
namespace folly {
#include <folly/Conv.h>
#include <folly/Range.h>
-#include <folly/ThreadName.h>
#include <folly/executors/thread_factory/ThreadFactory.h>
+#include <folly/system/ThreadName.h>
namespace folly {
#include <folly/Conv.h>
#include <folly/Random.h>
#include <folly/String.h>
-#include <folly/ThreadName.h>
+#include <folly/system/ThreadName.h>
using std::chrono::milliseconds;
using std::chrono::steady_clock;
*/
#include "folly/experimental/ThreadedRepeatingFunctionRunner.h"
-#include <folly/ThreadName.h>
+#include <folly/system/ThreadName.h>
#include <glog/logging.h>
#include <iostream>
#include <stdexcept>
#include <folly/Format.h>
-#include <folly/MemoryMapping.h>
#include <folly/Range.h>
#include <folly/experimental/io/HugePages.h>
#include <folly/portability/GFlags.h>
+#include <folly/system/MemoryMapping.h>
DEFINE_bool(cp, false, "Copy file");
*/
#include <folly/experimental/logging/LogMessage.h>
-#include <folly/ThreadId.h>
+#include <folly/system/ThreadId.h>
using std::chrono::system_clock;
#include <folly/MPMCQueue.h>
#include <folly/Range.h>
#include <folly/Singleton.h>
-#include <folly/ThreadName.h>
#include <folly/portability/GFlags.h>
+#include <folly/system/ThreadName.h>
namespace folly {
namespace observer_detail {
#include <mutex>
#include <folly/File.h>
-#include <folly/MemoryMapping.h>
#include <folly/Range.h>
#include <folly/io/IOBuf.h>
+#include <folly/system/MemoryMapping.h>
namespace folly {
#include <folly/Baton.h>
#include <folly/Memory.h>
-#include <folly/ThreadName.h>
#include <folly/io/async/NotificationQueue.h>
#include <folly/io/async/VirtualEventBase.h>
#include <folly/portability/Unistd.h>
+#include <folly/system/ThreadName.h>
namespace folly {
#include <folly/Random.h>
#include <folly/SharedMutex.h>
#include <folly/SpinLock.h>
-#include <folly/ThreadId.h>
#include <folly/ssl/Init.h>
+#include <folly/system/ThreadId.h>
// ---------------------------------------------------------------------
// SSLContext implementation
#include <folly/Function.h>
#include <folly/Range.h>
-#include <folly/ThreadName.h>
#include <folly/io/async/EventBaseManager.h>
+#include <folly/system/ThreadName.h>
using namespace std;
#include <chrono>
#include <folly/Baton.h>
-#include <folly/ThreadName.h>
#include <folly/io/async/EventBaseManager.h>
#include <folly/portability/GTest.h>
+#include <folly/system/ThreadName.h>
using namespace std;
using namespace std::chrono;
#include <folly/Baton.h>
#include <folly/Optional.h>
-#include <folly/ThreadName.h>
#include <folly/io/async/EventBaseManager.h>
#include <folly/portability/GTest.h>
+#include <folly/system/ThreadName.h>
using namespace std;
using namespace std::chrono;
#include <folly/Conv.h>
#include <folly/ScopeGuard.h>
-#include <folly/ThreadId.h>
#include <folly/portability/Unistd.h>
+#include <folly/system/ThreadId.h>
#include <glog/logging.h>
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/system/MemoryMapping.h>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include <folly/Format.h>
+#include <folly/portability/GFlags.h>
+#include <folly/portability/SysMman.h>
+
+#ifdef __linux__
+#include <folly/experimental/io/HugePages.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <system_error>
+
+static constexpr ssize_t kDefaultMlockChunkSize =
+#ifndef _MSC_VER
+ // Linux implementations of unmap/mlock/munlock take a kernel
+ // semaphore and block other threads from doing other memory
+ // operations. Split the operations in chunks.
+ (1 << 20) // 1MB
+#else // _MSC_VER
+ // MSVC doesn't have this problem, and calling munmap many times
+ // with the same address is a bad idea with the windows implementation.
+ (-1)
+#endif // _MSC_VER
+ ;
+
+DEFINE_int64(mlock_chunk_size, kDefaultMlockChunkSize,
+ "Maximum bytes to mlock/munlock/munmap at once "
+ "(will be rounded up to PAGESIZE). Ignored if negative.");
+
+#ifndef MAP_POPULATE
+#define MAP_POPULATE 0
+#endif
+
+namespace folly {
+
+MemoryMapping::MemoryMapping(MemoryMapping&& other) noexcept {
+ swap(other);
+}
+
+MemoryMapping::MemoryMapping(File file, off_t offset, off_t length,
+ Options options)
+ : file_(std::move(file)),
+ options_(std::move(options)) {
+ CHECK(file_);
+ init(offset, length);
+}
+
+MemoryMapping::MemoryMapping(const char* name, off_t offset, off_t length,
+ Options options)
+ : MemoryMapping(File(name, options.writable ? O_RDWR : O_RDONLY),
+ offset,
+ length,
+ options) { }
+
+MemoryMapping::MemoryMapping(int fd, off_t offset, off_t length,
+ Options options)
+ : MemoryMapping(File(fd), offset, length, options) { }
+
+MemoryMapping::MemoryMapping(AnonymousType, off_t length, Options options)
+ : options_(std::move(options)) {
+ init(0, length);
+}
+
+namespace {
+
+#ifdef __linux__
+void getDeviceOptions(dev_t device, off_t& pageSize, bool& autoExtend) {
+ auto ps = getHugePageSizeForDevice(device);
+ if (ps) {
+ pageSize = ps->size;
+ autoExtend = true;
+ }
+}
+#else
+inline void getDeviceOptions(dev_t, off_t&, bool&) {}
+#endif
+
+} // namespace
+
+void MemoryMapping::init(off_t offset, off_t length) {
+ const bool grow = options_.grow;
+ const bool anon = !file_;
+ CHECK(!(grow && anon));
+
+ off_t& pageSize = options_.pageSize;
+
+ struct stat st;
+
+ // On Linux, hugetlbfs file systems don't require ftruncate() to grow the
+ // file, and (on kernels before 2.6.24) don't even allow it. Also, the file
+ // size is always a multiple of the page size.
+ bool autoExtend = false;
+
+ if (!anon) {
+ // Stat the file
+ CHECK_ERR(fstat(file_.fd(), &st));
+
+ if (pageSize == 0) {
+ getDeviceOptions(st.st_dev, pageSize, autoExtend);
+ }
+ } else {
+ DCHECK(!file_);
+ DCHECK_EQ(offset, 0);
+ CHECK_EQ(pageSize, 0);
+ CHECK_GE(length, 0);
+ }
+
+ if (pageSize == 0) {
+ pageSize = off_t(sysconf(_SC_PAGESIZE));
+ }
+
+ CHECK_GT(pageSize, 0);
+ CHECK_EQ(pageSize & (pageSize - 1), 0); // power of two
+ CHECK_GE(offset, 0);
+
+ // Round down the start of the mapped region
+ off_t skipStart = offset % pageSize;
+ offset -= skipStart;
+
+ mapLength_ = length;
+ if (mapLength_ != -1) {
+ mapLength_ += skipStart;
+
+ // Round up the end of the mapped region
+ mapLength_ = (mapLength_ + pageSize - 1) / pageSize * pageSize;
+ }
+
+ off_t remaining = anon ? length : st.st_size - offset;
+
+ if (mapLength_ == -1) {
+ length = mapLength_ = remaining;
+ } else {
+ if (length > remaining) {
+ if (grow) {
+ if (!autoExtend) {
+ PCHECK(0 == ftruncate(file_.fd(), offset + length))
+ << "ftruncate() failed, couldn't grow file to "
+ << offset + length;
+ remaining = length;
+ } else {
+ // Extend mapping to multiple of page size, don't use ftruncate
+ remaining = mapLength_;
+ }
+ } else {
+ length = remaining;
+ }
+ }
+ if (mapLength_ > remaining) {
+ mapLength_ = remaining;
+ }
+ }
+
+ if (length == 0) {
+ mapLength_ = 0;
+ mapStart_ = nullptr;
+ } else {
+ int flags = options_.shared ? MAP_SHARED : MAP_PRIVATE;
+ if (anon) {
+ flags |= MAP_ANONYMOUS;
+ }
+ if (options_.prefault) {
+ flags |= MAP_POPULATE;
+ }
+
+ // The standard doesn't actually require PROT_NONE to be zero...
+ int prot = PROT_NONE;
+ if (options_.readable || options_.writable) {
+ prot = ((options_.readable ? PROT_READ : 0) |
+ (options_.writable ? PROT_WRITE : 0));
+ }
+
+ unsigned char* start = static_cast<unsigned char*>(mmap(
+ options_.address, size_t(mapLength_), prot, flags, file_.fd(), offset));
+ PCHECK(start != MAP_FAILED)
+ << " offset=" << offset
+ << " length=" << mapLength_;
+ mapStart_ = start;
+ data_.reset(start + skipStart, size_t(length));
+ }
+}
+
+namespace {
+
+off_t memOpChunkSize(off_t length, off_t pageSize) {
+ off_t chunkSize = length;
+ if (FLAGS_mlock_chunk_size <= 0) {
+ return chunkSize;
+ }
+
+ chunkSize = off_t(FLAGS_mlock_chunk_size);
+ off_t r = chunkSize % pageSize;
+ if (r) {
+ chunkSize += (pageSize - r);
+ }
+ return chunkSize;
+}
+
+/**
+ * Run @op in chunks over the buffer @mem of @bufSize length.
+ *
+ * Return:
+ * - success: true + amountSucceeded == bufSize (op success on whole buffer)
+ * - failure: false + amountSucceeded == nr bytes on which op succeeded.
+ */
+bool memOpInChunks(std::function<int(void*, size_t)> op,
+ void* mem, size_t bufSize, off_t pageSize,
+ size_t& amountSucceeded) {
+ // Linux' unmap/mlock/munlock take a kernel semaphore and block other threads
+ // from doing other memory operations. If the size of the buffer is big the
+ // semaphore can be down for seconds (for benchmarks see
+ // http://kostja-osipov.livejournal.com/42963.html). Doing the operations in
+ // chunks breaks the locking into intervals and lets other threads do memory
+ // operations of their own.
+
+ size_t chunkSize = size_t(memOpChunkSize(off_t(bufSize), pageSize));
+
+ char* addr = static_cast<char*>(mem);
+ amountSucceeded = 0;
+
+ while (amountSucceeded < bufSize) {
+ size_t size = std::min(chunkSize, bufSize - amountSucceeded);
+ if (op(addr + amountSucceeded, size) != 0) {
+ return false;
+ }
+ amountSucceeded += size;
+ }
+
+ return true;
+}
+
+} // namespace
+
+bool MemoryMapping::mlock(LockMode lock) {
+ size_t amountSucceeded = 0;
+ locked_ = memOpInChunks(
+ ::mlock,
+ mapStart_,
+ size_t(mapLength_),
+ options_.pageSize,
+ amountSucceeded);
+ if (locked_) {
+ return true;
+ }
+
+ auto msg =
+ folly::format("mlock({}) failed at {}", mapLength_, amountSucceeded);
+ if (lock == LockMode::TRY_LOCK && errno == EPERM) {
+ PLOG(WARNING) << msg;
+ } else if (lock == LockMode::TRY_LOCK && errno == ENOMEM) {
+ VLOG(1) << msg;
+ } else {
+ PLOG(FATAL) << msg;
+ }
+
+ // only part of the buffer was mlocked, unlock it back
+ if (!memOpInChunks(::munlock, mapStart_, amountSucceeded, options_.pageSize,
+ amountSucceeded)) {
+ PLOG(WARNING) << "munlock()";
+ }
+
+ return false;
+}
+
+void MemoryMapping::munlock(bool dontneed) {
+ if (!locked_) {
+ return;
+ }
+
+ size_t amountSucceeded = 0;
+ if (!memOpInChunks(
+ ::munlock,
+ mapStart_,
+ size_t(mapLength_),
+ options_.pageSize,
+ amountSucceeded)) {
+ PLOG(WARNING) << "munlock()";
+ }
+ if (mapLength_ && dontneed &&
+ ::madvise(mapStart_, size_t(mapLength_), MADV_DONTNEED)) {
+ PLOG(WARNING) << "madvise()";
+ }
+ locked_ = false;
+}
+
+void MemoryMapping::hintLinearScan() {
+ advise(MADV_SEQUENTIAL);
+}
+
+MemoryMapping::~MemoryMapping() {
+ if (mapLength_) {
+ size_t amountSucceeded = 0;
+ if (!memOpInChunks(
+ ::munmap,
+ mapStart_,
+ size_t(mapLength_),
+ options_.pageSize,
+ amountSucceeded)) {
+ PLOG(FATAL) << folly::format("munmap({}) failed at {}",
+ mapLength_, amountSucceeded);
+ }
+ }
+}
+
+void MemoryMapping::advise(int advice) const {
+ advise(advice, 0, size_t(mapLength_));
+}
+
+void MemoryMapping::advise(int advice, size_t offset, size_t length) const {
+ CHECK_LE(offset + length, size_t(mapLength_))
+ << " offset: " << offset
+ << " length: " << length
+ << " mapLength_: " << mapLength_;
+
+ // Include the entire start page: round down to page boundary.
+ const auto offMisalign = offset % options_.pageSize;
+ offset -= offMisalign;
+ length += offMisalign;
+
+ // Round the last page down to page boundary.
+ if (offset + length != size_t(mapLength_)) {
+ length -= length % options_.pageSize;
+ }
+
+ if (length == 0) {
+ return;
+ }
+
+ char* mapStart = static_cast<char*>(mapStart_) + offset;
+ PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise";
+}
+
+MemoryMapping& MemoryMapping::operator=(MemoryMapping other) {
+ swap(other);
+ return *this;
+}
+
+void MemoryMapping::swap(MemoryMapping& other) noexcept {
+ using std::swap;
+ swap(this->file_, other.file_);
+ swap(this->mapStart_, other.mapStart_);
+ swap(this->mapLength_, other.mapLength_);
+ swap(this->options_, other.options_);
+ swap(this->locked_, other.locked_);
+ swap(this->data_, other.data_);
+}
+
+void swap(MemoryMapping& a, MemoryMapping& b) noexcept { a.swap(b); }
+
+void alignedForwardMemcpy(void* dst, const void* src, size_t size) {
+ assert(reinterpret_cast<uintptr_t>(src) % alignof(unsigned long) == 0);
+ assert(reinterpret_cast<uintptr_t>(dst) % alignof(unsigned long) == 0);
+
+ auto srcl = static_cast<const unsigned long*>(src);
+ auto dstl = static_cast<unsigned long*>(dst);
+
+ while (size >= sizeof(unsigned long)) {
+ *dstl++ = *srcl++;
+ size -= sizeof(unsigned long);
+ }
+
+ auto srcc = reinterpret_cast<const unsigned char*>(srcl);
+ auto dstc = reinterpret_cast<unsigned char*>(dstl);
+
+ while (size != 0) {
+ *dstc++ = *srcc++;
+ --size;
+ }
+}
+
+void mmapFileCopy(const char* src, const char* dest, mode_t mode) {
+ MemoryMapping srcMap(src);
+ srcMap.hintLinearScan();
+
+ MemoryMapping destMap(
+ File(dest, O_RDWR | O_CREAT | O_TRUNC, mode),
+ 0,
+ off_t(srcMap.range().size()),
+ MemoryMapping::writable());
+
+ alignedForwardMemcpy(destMap.writableRange().data(),
+ srcMap.range().data(),
+ srcMap.range().size());
+}
+
+} // namespace folly
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <boost/noncopyable.hpp>
+#include <glog/logging.h>
+
+#include <folly/File.h>
+#include <folly/Range.h>
+
+namespace folly {
+
+/**
+ * Maps files in memory (read-only).
+ *
+ * @author Tudor Bosman (tudorb@fb.com)
+ */
+class MemoryMapping : boost::noncopyable {
+ public:
+ /**
+ * Lock the pages in memory?
+ * TRY_LOCK = try to lock, log warning if permission denied
+ * MUST_LOCK = lock, fail assertion if permission denied.
+ */
+ enum class LockMode {
+ TRY_LOCK,
+ MUST_LOCK
+ };
+ /**
+ * Map a portion of the file indicated by filename in memory, causing a CHECK
+ * failure on error.
+ *
+ * By default, map the whole file. length=-1: map from offset to EOF.
+ * Unlike the mmap() system call, offset and length don't need to be
+ * page-aligned. length is clipped to the end of the file if it's too large.
+ *
+ * The mapping will be destroyed (and the memory pointed-to by data() will
+ * likely become inaccessible) when the MemoryMapping object is destroyed.
+ */
+ struct Options {
+ Options() {}
+
+ // Convenience methods; return *this for chaining.
+ Options& setPageSize(off_t v) { pageSize = v; return *this; }
+ Options& setShared(bool v) { shared = v; return *this; }
+ Options& setPrefault(bool v) { prefault = v; return *this; }
+ Options& setReadable(bool v) { readable = v; return *this; }
+ Options& setWritable(bool v) { writable = v; return *this; }
+ Options& setGrow(bool v) { grow = v; return *this; }
+
+ // Page size. 0 = use appropriate page size.
+ // (On Linux, we use a huge page size if the file is on a hugetlbfs
+ // file system, and the default page size otherwise)
+ off_t pageSize = 0;
+
+ // If shared (default), the memory mapping is shared with other processes
+ // mapping the same file (or children); if not shared (private), each
+ // process has its own mapping. Changes in writable, private mappings are
+ // not reflected to the underlying file. See the discussion of
+ // MAP_PRIVATE vs MAP_SHARED in the mmap(2) manual page.
+ bool shared = true;
+
+ // Populate page tables; subsequent accesses should not be blocked
+ // by page faults. This is a hint, as it may not be supported.
+ bool prefault = false;
+
+ // Map the pages readable. Note that mapping pages without read permissions
+ // is not universally supported (not supported on hugetlbfs on Linux, for
+ // example)
+ bool readable = true;
+
+ // Map the pages writable.
+ bool writable = false;
+
+ // When mapping a file in writable mode, grow the file to the requested
+ // length (using ftruncate()) before mapping; if false, truncate the
+ // mapping to the actual file size instead.
+ bool grow = false;
+
+ // Fix map at this address, if not nullptr. Must be aligned to a multiple
+ // of the appropriate page size.
+ void* address = nullptr;
+ };
+
+ // Options to emulate the old WritableMemoryMapping: readable and writable,
+ // allow growing the file if mapping past EOF.
+ static Options writable() {
+ return Options().setWritable(true).setGrow(true);
+ }
+
+ enum AnonymousType {
+ kAnonymous
+ };
+
+ /**
+ * Create an anonymous mapping.
+ */
+ MemoryMapping(AnonymousType, off_t length, Options options=Options());
+
+ explicit MemoryMapping(File file,
+ off_t offset=0,
+ off_t length=-1,
+ Options options=Options());
+
+ explicit MemoryMapping(const char* name,
+ off_t offset=0,
+ off_t length=-1,
+ Options options=Options());
+
+ explicit MemoryMapping(int fd,
+ off_t offset=0,
+ off_t length=-1,
+ Options options=Options());
+
+ MemoryMapping(MemoryMapping&&) noexcept;
+
+ ~MemoryMapping();
+
+ MemoryMapping& operator=(MemoryMapping);
+
+ void swap(MemoryMapping& other) noexcept;
+
+ /**
+ * Lock the pages in memory
+ */
+ bool mlock(LockMode lock);
+
+ /**
+ * Unlock the pages.
+ * If dontneed is true, the kernel is instructed to release these pages
+ * (per madvise(MADV_DONTNEED)).
+ */
+ void munlock(bool dontneed = false);
+
+ /**
+ * Hint that these pages will be scanned linearly.
+ * madvise(MADV_SEQUENTIAL)
+ */
+ void hintLinearScan();
+
+ /**
+ * Advise the kernel about memory access.
+ */
+ void advise(int advice) const;
+ void advise(int advice, size_t offset, size_t length) const;
+
+ /**
+ * A bitwise cast of the mapped bytes as range of values. Only intended for
+ * use with POD or in-place usable types.
+ */
+ template <class T>
+ Range<const T*> asRange() const {
+ size_t count = data_.size() / sizeof(T);
+ return Range<const T*>(static_cast<const T*>(
+ static_cast<const void*>(data_.data())),
+ count);
+ }
+
+ /**
+ * A range of bytes mapped by this mapping.
+ */
+ ByteRange range() const {
+ return data_;
+ }
+
+ /**
+ * A bitwise cast of the mapped bytes as range of mutable values. Only
+ * intended for use with POD or in-place usable types.
+ */
+ template <class T>
+ Range<T*> asWritableRange() const {
+ DCHECK(options_.writable); // you'll segfault anyway...
+ size_t count = data_.size() / sizeof(T);
+ return Range<T*>(static_cast<T*>(
+ static_cast<void*>(data_.data())),
+ count);
+ }
+
+ /**
+ * A range of mutable bytes mapped by this mapping.
+ */
+ MutableByteRange writableRange() const {
+ DCHECK(options_.writable); // you'll segfault anyway...
+ return data_;
+ }
+
+ /**
+ * Return the memory area where the file was mapped.
+ * Deprecated; use range() instead.
+ */
+ StringPiece data() const {
+ return asRange<const char>();
+ }
+
+ bool mlocked() const {
+ return locked_;
+ }
+
+ int fd() const { return file_.fd(); }
+
+ private:
+ MemoryMapping();
+
+ enum InitFlags {
+ kGrow = 1 << 0,
+ kAnon = 1 << 1,
+ };
+ void init(off_t offset, off_t length);
+
+ File file_;
+ void* mapStart_ = nullptr;
+ off_t mapLength_ = 0;
+ Options options_;
+ bool locked_ = false;
+ MutableByteRange data_;
+};
+
+void swap(MemoryMapping&, MemoryMapping&) noexcept;
+
+/**
+ * A special case of memcpy() that always copies memory forwards.
+ * (libc's memcpy() is allowed to copy memory backwards, and will do so
+ * when using SSSE3 instructions).
+ *
+ * Assumes src and dest are aligned to alignof(unsigned long).
+ *
+ * Useful when copying from/to memory mappings after hintLinearScan();
+ * copying backwards renders any prefetching useless (even harmful).
+ */
+void alignedForwardMemcpy(void* dest, const void* src, size_t size);
+
+/**
+ * Copy a file using mmap(). Overwrites dest.
+ */
+void mmapFileCopy(const char* src, const char* dest, mode_t mode = 0666);
+
+} // namespace folly
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/system/Shell.h>
+
+namespace folly {
+
+std::string shellQuote(StringPiece argument) {
+ std::string quoted = "'";
+ for (auto c : argument) {
+ if (c == '\'') {
+ quoted += "'\\''";
+ } else {
+ quoted += c;
+ }
+ }
+ return quoted + "'";
+}
+
+} // namespace folly
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * `Shell` provides a collection of functions to use with `Subprocess` that make
+ * it easier to safely run processes in a unix shell.
+ *
+ * Note: use this rarely and carefully. By default you should use `Subprocess`
+ * with a vector of arguments.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <folly/Conv.h>
+#include <folly/Format.h>
+#include <folly/Range.h>
+
+namespace folly {
+
+/**
+ * Quotes an argument to make it suitable for use as shell command arguments.
+ */
+std::string shellQuote(StringPiece argument);
+
+namespace detail {
+template <typename... Arguments>
+std::vector<std::string> shellify(
+ StringPiece format,
+ Arguments&&... arguments) {
+ auto command = sformat(
+ format,
+ shellQuote(to<std::string>(std::forward<Arguments>(arguments)))...);
+ return {"/bin/sh", "-c", command};
+}
+
+struct ShellCmdFormat {
+ StringPiece format;
+ template <typename... Arguments>
+ std::vector<std::string> operator()(Arguments&&... arguments) const {
+ return ::folly::detail::shellify(
+ format, std::forward<Arguments>(arguments)...);
+ }
+};
+
+} // namespace detail
+
+inline namespace literals {
+inline namespace shell_literals {
+constexpr detail::ShellCmdFormat operator"" _shellify(
+ char const* name,
+ std::size_t length) {
+ return {folly::StringPiece(name, length)};
+}
+} // inline namespace shell_literals
+} // inline namespace literals
+
+/**
+ * Create argument array for `Subprocess()` for a process running in a
+ * shell.
+ *
+ * The shell to use is always going to be `/bin/sh`.
+ *
+ * This is deprecated in favour of the user-defined-literal `_shellify`
+ * from namespace `folly::shell_literals` because that requires that the format
+ * string is a compile-time constant which can be inspected during code reviews
+ */
+template <typename... Arguments>
+FOLLY_DEPRECATED(
+ "Use `\"command {} {} ...\"_shellify(argument1, argument2 ...)` from "
+ "namespace `folly::literals::shell_literals`")
+std::vector<std::string> shellify(
+ StringPiece format,
+ Arguments&&... arguments) {
+ return detail::shellify(format, std::forward<Arguments>(arguments)...);
+}
+
+} // namespace folly
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <folly/portability/PThread.h>
+#include <folly/portability/SysSyscall.h>
+#include <folly/portability/Unistd.h>
+#include <folly/portability/Windows.h>
+
+namespace folly {
+
+/**
+ * Get a process-specific identifier for the current thread.
+ *
+ * The return value will uniquely identify the thread within the current
+ * process.
+ *
+ * Note that the return value does not necessarily correspond to an operating
+ * system thread ID. The return value is also only unique within the current
+ * process: getCurrentThreadID() may return the same value for two concurrently
+ * running threads in separate processes.
+ *
+ * The thread ID may be reused once the thread it corresponds to has been
+ * joined.
+ */
+inline uint64_t getCurrentThreadID() {
+#if __APPLE__
+ return uint64_t(pthread_mach_thread_np(pthread_self()));
+#elif _WIN32
+ return uint64_t(GetCurrentThreadId());
+#else
+ return uint64_t(pthread_self());
+#endif
+}
+
+/**
+ * Get the operating-system level thread ID for the current thread.
+ *
+ * The returned value will uniquely identify this thread on the system.
+ *
+ * This makes it more suitable for logging or displaying in user interfaces
+ * than the result of getCurrentThreadID().
+ *
+ * There are some potential caveats about this API, however:
+ *
+ * - In theory there is no guarantee that application threads map one-to-one to
+ * kernel threads. An application threading implementation could potentially
+ * share one OS thread across multiple application threads, and/or it could
+ * potentially move application threads between different OS threads over
+ * time. However, in practice all of the platforms we currently support have
+ * a one-to-one mapping between userspace threads and operating system
+ * threads.
+ *
+ * - This API may also be slightly slower than getCurrentThreadID() on some
+ * platforms. This API may require a system call, where getCurrentThreadID()
+ * may only need to read thread-local memory.
+ *
+ * On Linux the returned value is a pid_t, and can be used in contexts
+ * requiring a thread pid_t.
+ *
+ * The thread ID may be reused once the thread it corresponds to has been
+ * joined.
+ */
+inline uint64_t getOSThreadID() {
+#if __APPLE__
+ uint64_t tid;
+ pthread_threadid_np(nullptr, &tid);
+ return tid;
+#elif _WIN32
+ return uint64_t(GetCurrentThreadId());
+#else
+ return uint64_t(syscall(FOLLY_SYS_gettid));
+#endif
+}
+}
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/system/ThreadName.h>
+
+#include <type_traits>
+
+#include <folly/Portability.h>
+#include <folly/Traits.h>
+#include <folly/portability/PThread.h>
+
+namespace folly {
+
+// This looks a bit weird, but it's necessary to avoid
+// having an undefined compiler function called.
+#if defined(__GLIBC__) && !defined(__APPLE__) && !defined(__ANDROID__)
+#if __GLIBC_PREREQ(2, 12)
+// has pthread_setname_np(pthread_t, const char*) (2 params)
+#define FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME 1
+#endif
+#endif
+
+#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+// has pthread_setname_np(const char*) (1 param)
+#define FOLLY_HAS_PTHREAD_SETNAME_NP_NAME 1
+#endif
+#endif
+
+namespace {
+
+#if FOLLY_HAVE_PTHREAD && !_WIN32
+pthread_t stdTidToPthreadId(std::thread::id tid) {
+ static_assert(
+ std::is_same<pthread_t, std::thread::native_handle_type>::value,
+ "This assumes that the native handle type is pthread_t");
+ static_assert(
+ sizeof(std::thread::native_handle_type) == sizeof(std::thread::id),
+ "This assumes std::thread::id is a thin wrapper around "
+ "std::thread::native_handle_type, but that doesn't appear to be true.");
+ // In most implementations, std::thread::id is a thin wrapper around
+ // std::thread::native_handle_type, which means we can do unsafe things to
+ // extract it.
+ pthread_t id;
+ std::memcpy(&id, &tid, sizeof(id));
+ return id;
+}
+#endif
+
+} // namespace
+
+bool canSetCurrentThreadName() {
+#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
+ FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool canSetOtherThreadName() {
+#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME
+ return true;
+#else
+ return false;
+#endif
+}
+
+static constexpr size_t kMaxThreadNameLength = 16;
+
+Optional<std::string> getThreadName(std::thread::id id) {
+#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
+ FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
+ std::array<char, kMaxThreadNameLength> buf;
+ if (pthread_getname_np(stdTidToPthreadId(id), buf.data(), buf.size()) != 0) {
+ return Optional<std::string>();
+ }
+ return make_optional(std::string(buf.data()));
+#else
+ return Optional<std::string>();
+#endif
+}
+
+Optional<std::string> getCurrentThreadName() {
+ return getThreadName(std::this_thread::get_id());
+}
+
+bool setThreadName(std::thread::id tid, StringPiece name) {
+#if !FOLLY_HAVE_PTHREAD || _WIN32
+ return false;
+#else
+ name = name.subpiece(0, kMaxThreadNameLength - 1);
+ char buf[kMaxThreadNameLength] = {};
+ std::memcpy(buf, name.data(), name.size());
+ auto id = stdTidToPthreadId(tid);
+#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME
+ return 0 == pthread_setname_np(id, buf);
+#elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
+ // Since OS X 10.6 it is possible for a thread to set its own name,
+ // but not that of some other thread.
+ if (pthread_equal(pthread_self(), id)) {
+ return 0 == pthread_setname_np(buf);
+ }
+ return false;
+#else
+ (void)id;
+ return false;
+#endif
+#endif
+}
+
+#if FOLLY_HAVE_PTHREAD
+bool setThreadName(pthread_t pid, StringPiece name) {
+#if _WIN32
+ // Not currently supported on Windows.
+ return false;
+#else
+ static_assert(
+ std::is_same<pthread_t, std::thread::native_handle_type>::value,
+ "This assumes that the native handle type is pthread_t");
+ static_assert(
+ sizeof(std::thread::native_handle_type) == sizeof(std::thread::id),
+ "This assumes std::thread::id is a thin wrapper around "
+ "std::thread::native_handle_type, but that doesn't appear to be true.");
+ // In most implementations, std::thread::id is a thin wrapper around
+ // std::thread::native_handle_type, which means we can do unsafe things to
+ // extract it.
+ std::thread::id id;
+ std::memcpy(&id, &pid, sizeof(id));
+ return setThreadName(id, name);
+#endif
+}
+#endif
+
+bool setThreadName(StringPiece name) {
+ return setThreadName(std::this_thread::get_id(), name);
+}
+}
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <thread>
+
+#include <folly/Optional.h>
+#include <folly/Range.h>
+#include <folly/portability/Config.h>
+#include <folly/portability/PThread.h>
+
+namespace folly {
+
+/**
+ * This returns true if the current platform supports setting the name of the
+ * current thread.
+ */
+bool canSetCurrentThreadName();
+
+/**
+ * This returns true if the current platform supports setting the name of
+ * threads other than the one currently executing.
+ */
+bool canSetOtherThreadName();
+
+/**
+ * Get the name of the given thread, or nothing if an error occurs
+ * or the functionality is not available.
+ */
+Optional<std::string> getThreadName(std::thread::id tid);
+
+/**
+ * Equivalent to getThreadName(std::this_thread::get_id());
+ */
+Optional<std::string> getCurrentThreadName();
+
+/**
+ * Set the name of the given thread.
+ * Returns false on failure, if an error occurs or the functionality
+ * is not available.
+ */
+bool setThreadName(std::thread::id tid, StringPiece name);
+#if FOLLY_HAVE_PTHREAD
+bool setThreadName(pthread_t pid, StringPiece name);
+#endif
+
+/**
+ * Equivalent to setThreadName(std::this_thread::get_id(), name);
+ */
+bool setThreadName(StringPiece name);
+}
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/system/VersionCheck.h>
+
+namespace folly { namespace detail {
+
+FOLLY_VERSION_CHECK(folly, FOLLY_VERSION)
+
+}} // namespaces
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include <folly/Portability.h>
+#include <folly/Preprocessor.h>
+
+/**
+ * Check if the currently loaded version of a library is what you expect.
+ *
+ * It is possible for multiple versions of the same shared library to end up
+ * being loaded simultaneously in the same address space, usually with
+ * disastrous results.
+ *
+ * For example, let's say you have a shared library (foo) that doesn't keep
+ * binary compatbility between releases, and so each version is distributed as
+ * a SO with different SONAME. Let's say you build another shared library, bar
+ * that depends on version 1 of foo: libbar.so depends on libfoo1.so.
+ * Your main executable now (baz) depends on version 2 of foo, and also
+ * depends on bar: baz depends on libfoo2.so and libbar.so.
+ *
+ * At load time, baz loads libfoo2.so first, then libbar.so; libbar.so will
+ * load libfoo1.so, but, as this is normal dynamic loading (and not explicit
+ * dlopen calls with RTLD_DEEPBIND), any symbols from libfoo1.so that are
+ * also present in libfoo2.so will be satisfied from the (already loaded)
+ * libfoo2.so.
+ *
+ * But foo does not preserve binary compatibility between versions, so all
+ * hell breaks loose (the symbols from libfoo2.so are not necessarily direct
+ * replacements of the identically-named symbols in libfoo1.so).
+ *
+ * It is better to crash with a helpful error message instead, which is what
+ * this macro provides. FOLLY_VERSION_CHECK verifies at load time that
+ * the compiled-in version is the same as the currently loaded version.
+ *
+ * Usage: use this macro at namespace scope in a .cpp file (IMPORTANT: NOT
+ * in the unnamed namespace):
+ *
+ * FOLLY_VERSION_CHECK(mylib, "1")
+ *
+ * The first argument identifies your library; the second argument is a
+ * string literal containing the desired version string.
+ *
+ * In order to avoid changing the file for each version, the version string
+ * could be provided on the compiler command line with -D:
+ *
+ * FOLLY_VERSION_CHECK(mylib, MYLIB_VERSION)
+ *
+ * ... and then commpile your file with -DMYLIB_VERSION=\"1\"
+ */
+
+#if defined(_MSC_VER)
+// MSVC doesn't support constructor priorities. Just pray it works, I guess.
+// We could implement a link-time mechanism for MSVC,
+// via #pragma detect_mismatch but that would only handle
+// static library linking.
+# define FOLLY_VERSION_CHECK_PRIORITY(Ret, name) \
+ __pragma(section(".CRT$XCU",read)) \
+ static Ret __cdecl name(void); \
+ __declspec(allocate(".CRT$XCU")) \
+ Ret (__cdecl*name##_)(void) = name; \
+ Ret __cdecl name()
+
+#elif defined(__APPLE__)
+// OS X doesn't support constructor priorities. Just pray it works, I guess.
+# define FOLLY_VERSION_CHECK_PRIORITY(Ret, name) \
+ __attribute__((__constructor__)) Ret name()
+
+#else
+# define FOLLY_VERSION_CHECK_PRIORITY(Ret, name) \
+ __attribute__((__constructor__(101))) Ret name()
+#endif
+
+// Note that this is carefully crafted: PRODUCT##Version must have external
+// linkage (so it collides among versions), versionCheck must have internal
+// linkage (so it does NOT collide between versions); if we're trying to have
+// multiple versions loaded at the same time, they must each run their copy
+// of versionCheck, but share the PRODUCT##Version variable.
+#define FOLLY_VERSION_CHECK(PRODUCT, VERSION) \
+ const char* PRODUCT##Version = VERSION; \
+ namespace { \
+ FOLLY_VERSION_CHECK_PRIORITY(void, versionCheck) { \
+ if (strcmp(PRODUCT##Version, VERSION)) { \
+ fprintf(stderr, \
+ "Invalid %s version: desired [%s], currently loaded [%s]\n", \
+ FB_STRINGIZE(PRODUCT), PRODUCT##Version, VERSION); \
+ abort(); \
+ } \
+ } \
+ }
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+
+#include <folly/FileUtil.h>
+#include <folly/Random.h>
+#include <folly/portability/GTest.h>
+#include <folly/portability/SysMman.h>
+#include <folly/system/MemoryMapping.h>
+
+static constexpr double kSomeDouble = 3.14;
+
+namespace folly {
+
+TEST(MemoryMapping, Basic) {
+ File f = File::temporary();
+ {
+ MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
+ double* d = m.asWritableRange<double>().data();
+ *d = 37 * kSomeDouble;
+ }
+ {
+ MemoryMapping m(File(f.fd()), 0, 3);
+ EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
+ }
+ {
+ MemoryMapping m(File(f.fd()), 0, sizeof(double));
+ const double* d = m.asRange<double>().data();
+ EXPECT_EQ(*d, 37 * kSomeDouble);
+ }
+}
+
+TEST(MemoryMapping, Move) {
+ File f = File::temporary();
+ {
+ MemoryMapping m(
+ File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
+ double* d = m.asWritableRange<double>().data();
+ d[0] = 37 * kSomeDouble;
+ MemoryMapping m2(std::move(m));
+ double* d2 = m2.asWritableRange<double>().data();
+ d2[1] = 39 * kSomeDouble;
+ }
+ {
+ MemoryMapping m(File(f.fd()), 0, sizeof(double));
+ const double* d = m.asRange<double>().data();
+ EXPECT_EQ(d[0], 37 * kSomeDouble);
+ MemoryMapping m2(std::move(m));
+ const double* d2 = m2.asRange<double>().data();
+ EXPECT_EQ(d2[1], 39 * kSomeDouble);
+ }
+}
+
+TEST(MemoryMapping, DoublyMapped) {
+ File f = File::temporary();
+ // two mappings of the same memory, different addresses.
+ MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
+ MemoryMapping mr(File(f.fd()), 0, sizeof(double));
+
+ double* dw = mw.asWritableRange<double>().data();
+ const double* dr = mr.asRange<double>().data();
+
+ // Show that it's truly the same value, even though the pointers differ
+ EXPECT_NE(dw, dr);
+ *dw = 42 * kSomeDouble;
+ EXPECT_EQ(*dr, 42 * kSomeDouble);
+ *dw = 43 * kSomeDouble;
+ EXPECT_EQ(*dr, 43 * kSomeDouble);
+}
+
+namespace {
+
+void writeStringToFileOrDie(const std::string& str, int fd) {
+ const char* b = str.c_str();
+ size_t count = str.size();
+ ssize_t total_bytes = 0;
+ ssize_t r;
+ do {
+ r = write(fd, b, count);
+ if (r == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ PCHECK(r) << "write";
+ }
+
+ total_bytes += r;
+ b += r;
+ count -= r;
+ } while (r != 0 && count);
+}
+
+} // namespace
+
+TEST(MemoryMapping, Simple) {
+ File f = File::temporary();
+ writeStringToFileOrDie("hello", f.fd());
+
+ {
+ MemoryMapping m(File(f.fd()));
+ EXPECT_EQ("hello", m.data());
+ }
+ {
+ MemoryMapping m(File(f.fd()), 1, 2);
+ EXPECT_EQ("el", m.data());
+ }
+}
+
+TEST(MemoryMapping, LargeFile) {
+ std::string fileData;
+ size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
+ fileData.reserve(fileSize);
+ for (size_t i = 0; i < fileSize; i++) {
+ fileData.push_back(0xff & Random::rand32());
+ }
+
+ File f = File::temporary();
+ writeStringToFileOrDie(fileData, f.fd());
+
+ {
+ MemoryMapping m(File(f.fd()));
+ EXPECT_EQ(fileData, m.data());
+ }
+ {
+ size_t size = sysconf(_SC_PAGESIZE) * 2;
+ StringPiece s(fileData.data() + 9, size - 9);
+ MemoryMapping m(File(f.fd()), 9, size - 9);
+ EXPECT_EQ(s.toString(), m.data());
+ }
+}
+
+TEST(MemoryMapping, ZeroLength) {
+ File f = File::temporary();
+ MemoryMapping m(File(f.fd()));
+ EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
+ EXPECT_TRUE(m.mlocked());
+ EXPECT_EQ(0, m.data().size());
+}
+
+TEST(MemoryMapping, Advise) {
+ File f = File::temporary();
+ size_t kPageSize = 4096;
+ size_t size = kPageSize + 10; // unaligned file size
+ PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
+
+ MemoryMapping m(File(f.fd()));
+
+ // NOTE: advise crashes on bad input.
+
+ m.advise(MADV_NORMAL, 0, kPageSize);
+ m.advise(MADV_NORMAL, 1, kPageSize);
+ m.advise(MADV_NORMAL, 0, 2);
+ m.advise(MADV_NORMAL, 1, 2);
+
+ m.advise(MADV_NORMAL, kPageSize, 0);
+ m.advise(MADV_NORMAL, kPageSize, 1);
+ m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
+
+ auto off = kPageSize + 1;
+ m.advise(MADV_NORMAL, off, size - off);
+
+ EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
+}
+
+} // namespace folly
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glog/logging.h>
+
+#include <folly/portability/GTest.h>
+#include <folly/system/Shell.h>
+
+using namespace folly;
+
+TEST(Shell, ShellQuote) {
+ EXPECT_EQ(shellQuote("a"), "'a'");
+ EXPECT_EQ(shellQuote("a'b"), "'a'\\''b'");
+ EXPECT_EQ(shellQuote("a\"b"), "'a\"b'");
+}
+
+TEST(Shell, Shellify) {
+ auto command = "rm -rf /"_shellify();
+ EXPECT_EQ(command[0], "/bin/sh");
+ EXPECT_EQ(command[1], "-c");
+ EXPECT_EQ(command[2], "rm -rf /");
+
+ command = "rm -rf {}"_shellify("someFile.txt");
+ EXPECT_EQ(command[2], "rm -rf 'someFile.txt'");
+
+ command = "rm -rf {}"_shellify(5);
+ EXPECT_EQ(command[2], "rm -rf '5'");
+
+ command = "ls {}"_shellify("blah'; rm -rf /");
+ EXPECT_EQ(command[2], "ls 'blah'\\''; rm -rf /'");
+}
+
+TEST(Shell, Shellify_deprecated) {
+ auto command = shellify("rm -rf /");
+ EXPECT_EQ(command[0], "/bin/sh");
+ EXPECT_EQ(command[1], "-c");
+ EXPECT_EQ(command[2], "rm -rf /");
+
+ command = shellify("rm -rf {}", "someFile.txt");
+ EXPECT_EQ(command[2], "rm -rf 'someFile.txt'");
+
+ command = shellify("rm -rf {}", 5);
+ EXPECT_EQ(command[2], "rm -rf '5'");
+
+ command = shellify("ls {}", "blah'; rm -rf /");
+ EXPECT_EQ(command[2], "ls 'blah'\\''; rm -rf /'");
+}
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Make sure we include ThreadId.h before anything else.
+// There is no ThreadId.cpp file, so this test is the only thing that verifies
+// that ThreadId.h compiles by itself when included first.
+#include <folly/system/ThreadId.h>
+
+#include <thread>
+
+#include <folly/portability/GTest.h>
+
+TEST(ThreadId, getCurrentID) {
+ auto thisThreadID = folly::getCurrentThreadID();
+ uint64_t otherThreadID;
+ std::thread otherThread{[&] { otherThreadID = folly::getCurrentThreadID(); }};
+ otherThread.join();
+ EXPECT_NE(thisThreadID, otherThreadID);
+}
+
+TEST(ThreadId, getOSThreadID) {
+ auto thisThreadID = folly::getOSThreadID();
+ uint64_t otherThreadID;
+ std::thread otherThread{[&] { otherThreadID = folly::getOSThreadID(); }};
+ otherThread.join();
+ EXPECT_NE(thisThreadID, otherThreadID);
+}
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <folly/Baton.h>
+#include <folly/ScopeGuard.h>
+#include <folly/portability/GTest.h>
+#include <folly/system/ThreadName.h>
+
+using namespace std;
+using namespace folly;
+
+namespace {
+
+const bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName();
+const bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName();
+constexpr StringPiece kThreadName{"rockin-thread"};
+
+} // namespace
+
+TEST(ThreadName, getCurrentThreadName) {
+ thread th([] {
+ EXPECT_EQ(expectedSetSelfThreadNameResult, setThreadName(kThreadName));
+ if (expectedSetSelfThreadNameResult) {
+ EXPECT_EQ(kThreadName.toString(), *getCurrentThreadName());
+ }
+ });
+ SCOPE_EXIT { th.join(); };
+}
+
+TEST(ThreadName, setThreadName_other_pthread) {
+ Baton<> handle_set;
+ Baton<> let_thread_end;
+ pthread_t handle;
+ thread th([&] {
+ handle = pthread_self();
+ handle_set.post();
+ let_thread_end.wait();
+ });
+ SCOPE_EXIT { th.join(); };
+ handle_set.wait();
+ SCOPE_EXIT { let_thread_end.post(); };
+ EXPECT_EQ(
+ expectedSetOtherThreadNameResult, setThreadName(handle, kThreadName));
+}
+
+TEST(ThreadName, setThreadName_other_id) {
+ Baton<> let_thread_end;
+ thread th([&] {
+ let_thread_end.wait();
+ });
+ SCOPE_EXIT { th.join(); };
+ SCOPE_EXIT { let_thread_end.post(); };
+ EXPECT_EQ(
+ expectedSetOtherThreadNameResult,
+ setThreadName(th.get_id(), kThreadName));
+ if (expectedSetOtherThreadNameResult) {
+ EXPECT_EQ(*getThreadName(th.get_id()), kThreadName);
+ }
+}
thread_cached_int_test_SOURCES = ThreadCachedIntTest.cpp
thread_cached_int_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
-thread_id_test_SOURCES = ThreadIdTest.cpp
+thread_id_test_SOURCES = system/test/ThreadIdTest.cpp
thread_id_test_LDADD = libfollytestmain.la
TESTS += thread_id_test
token_bucket_test_LDADD = libfollytestmain.la $(top_builddir)/libfollybenchmark.la
TESTS += token_bucket_test
-thread_name_test_SOURCES = ThreadNameTest.cpp
+thread_name_test_SOURCES = system/ThreadNameTest.cpp
thread_name_test_LDADD = libfollytestmain.la
TESTS += thread_name_test
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cstdlib>
-
-#include <folly/FileUtil.h>
-#include <folly/MemoryMapping.h>
-#include <folly/Random.h>
-#include <folly/portability/GTest.h>
-#include <folly/portability/SysMman.h>
-
-static constexpr double kSomeDouble = 3.14;
-
-namespace folly {
-
-TEST(MemoryMapping, Basic) {
- File f = File::temporary();
- {
- MemoryMapping m(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
- double* d = m.asWritableRange<double>().data();
- *d = 37 * kSomeDouble;
- }
- {
- MemoryMapping m(File(f.fd()), 0, 3);
- EXPECT_EQ(0, m.asRange<int>().size()); // not big enough
- }
- {
- MemoryMapping m(File(f.fd()), 0, sizeof(double));
- const double* d = m.asRange<double>().data();
- EXPECT_EQ(*d, 37 * kSomeDouble);
- }
-}
-
-TEST(MemoryMapping, Move) {
- File f = File::temporary();
- {
- MemoryMapping m(
- File(f.fd()), 0, sizeof(double) * 2, MemoryMapping::writable());
- double* d = m.asWritableRange<double>().data();
- d[0] = 37 * kSomeDouble;
- MemoryMapping m2(std::move(m));
- double* d2 = m2.asWritableRange<double>().data();
- d2[1] = 39 * kSomeDouble;
- }
- {
- MemoryMapping m(File(f.fd()), 0, sizeof(double));
- const double* d = m.asRange<double>().data();
- EXPECT_EQ(d[0], 37 * kSomeDouble);
- MemoryMapping m2(std::move(m));
- const double* d2 = m2.asRange<double>().data();
- EXPECT_EQ(d2[1], 39 * kSomeDouble);
- }
-}
-
-TEST(MemoryMapping, DoublyMapped) {
- File f = File::temporary();
- // two mappings of the same memory, different addresses.
- MemoryMapping mw(File(f.fd()), 0, sizeof(double), MemoryMapping::writable());
- MemoryMapping mr(File(f.fd()), 0, sizeof(double));
-
- double* dw = mw.asWritableRange<double>().data();
- const double* dr = mr.asRange<double>().data();
-
- // Show that it's truly the same value, even though the pointers differ
- EXPECT_NE(dw, dr);
- *dw = 42 * kSomeDouble;
- EXPECT_EQ(*dr, 42 * kSomeDouble);
- *dw = 43 * kSomeDouble;
- EXPECT_EQ(*dr, 43 * kSomeDouble);
-}
-
-namespace {
-
-void writeStringToFileOrDie(const std::string& str, int fd) {
- const char* b = str.c_str();
- size_t count = str.size();
- ssize_t total_bytes = 0;
- ssize_t r;
- do {
- r = write(fd, b, count);
- if (r == -1) {
- if (errno == EINTR) {
- continue;
- }
- PCHECK(r) << "write";
- }
-
- total_bytes += r;
- b += r;
- count -= r;
- } while (r != 0 && count);
-}
-
-} // namespace
-
-TEST(MemoryMapping, Simple) {
- File f = File::temporary();
- writeStringToFileOrDie("hello", f.fd());
-
- {
- MemoryMapping m(File(f.fd()));
- EXPECT_EQ("hello", m.data());
- }
- {
- MemoryMapping m(File(f.fd()), 1, 2);
- EXPECT_EQ("el", m.data());
- }
-}
-
-TEST(MemoryMapping, LargeFile) {
- std::string fileData;
- size_t fileSize = sysconf(_SC_PAGESIZE) * 3 + 10;
- fileData.reserve(fileSize);
- for (size_t i = 0; i < fileSize; i++) {
- fileData.push_back(0xff & Random::rand32());
- }
-
- File f = File::temporary();
- writeStringToFileOrDie(fileData, f.fd());
-
- {
- MemoryMapping m(File(f.fd()));
- EXPECT_EQ(fileData, m.data());
- }
- {
- size_t size = sysconf(_SC_PAGESIZE) * 2;
- StringPiece s(fileData.data() + 9, size - 9);
- MemoryMapping m(File(f.fd()), 9, size - 9);
- EXPECT_EQ(s.toString(), m.data());
- }
-}
-
-TEST(MemoryMapping, ZeroLength) {
- File f = File::temporary();
- MemoryMapping m(File(f.fd()));
- EXPECT_TRUE(m.mlock(MemoryMapping::LockMode::MUST_LOCK));
- EXPECT_TRUE(m.mlocked());
- EXPECT_EQ(0, m.data().size());
-}
-
-TEST(MemoryMapping, Advise) {
- File f = File::temporary();
- size_t kPageSize = 4096;
- size_t size = kPageSize + 10; // unaligned file size
- PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
-
- MemoryMapping m(File(f.fd()));
-
- // NOTE: advise crashes on bad input.
-
- m.advise(MADV_NORMAL, 0, kPageSize);
- m.advise(MADV_NORMAL, 1, kPageSize);
- m.advise(MADV_NORMAL, 0, 2);
- m.advise(MADV_NORMAL, 1, 2);
-
- m.advise(MADV_NORMAL, kPageSize, 0);
- m.advise(MADV_NORMAL, kPageSize, 1);
- m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
-
- auto off = kPageSize + 1;
- m.advise(MADV_NORMAL, off, size - off);
-
- EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
-}
-
-} // namespace folly
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <glog/logging.h>
-
-#include <folly/Shell.h>
-#include <folly/portability/GTest.h>
-
-using namespace folly;
-
-TEST(Shell, ShellQuote) {
- EXPECT_EQ(shellQuote("a"), "'a'");
- EXPECT_EQ(shellQuote("a'b"), "'a'\\''b'");
- EXPECT_EQ(shellQuote("a\"b"), "'a\"b'");
-}
-
-TEST(Shell, Shellify) {
- auto command = "rm -rf /"_shellify();
- EXPECT_EQ(command[0], "/bin/sh");
- EXPECT_EQ(command[1], "-c");
- EXPECT_EQ(command[2], "rm -rf /");
-
- command = "rm -rf {}"_shellify("someFile.txt");
- EXPECT_EQ(command[2], "rm -rf 'someFile.txt'");
-
- command = "rm -rf {}"_shellify(5);
- EXPECT_EQ(command[2], "rm -rf '5'");
-
- command = "ls {}"_shellify("blah'; rm -rf /");
- EXPECT_EQ(command[2], "ls 'blah'\\''; rm -rf /'");
-}
-
-TEST(Shell, Shellify_deprecated) {
- auto command = shellify("rm -rf /");
- EXPECT_EQ(command[0], "/bin/sh");
- EXPECT_EQ(command[1], "-c");
- EXPECT_EQ(command[2], "rm -rf /");
-
- command = shellify("rm -rf {}", "someFile.txt");
- EXPECT_EQ(command[2], "rm -rf 'someFile.txt'");
-
- command = shellify("rm -rf {}", 5);
- EXPECT_EQ(command[2], "rm -rf '5'");
-
- command = shellify("ls {}", "blah'; rm -rf /");
- EXPECT_EQ(command[2], "ls 'blah'\\''; rm -rf /'");
-}
#include <folly/Benchmark.h>
#include <folly/Hash.h>
-#include <folly/ThreadId.h>
#include <folly/portability/GFlags.h>
#include <folly/portability/GTest.h>
+#include <folly/system/ThreadId.h>
using namespace folly;
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Make sure we include ThreadId.h before anything else.
-// There is no ThreadId.cpp file, so this test is the only thing that verifies
-// that ThreadId.h compiles by itself when included first.
-#include <folly/ThreadId.h>
-
-#include <thread>
-
-#include <folly/portability/GTest.h>
-
-TEST(ThreadId, getCurrentID) {
- auto thisThreadID = folly::getCurrentThreadID();
- uint64_t otherThreadID;
- std::thread otherThread{[&] { otherThreadID = folly::getCurrentThreadID(); }};
- otherThread.join();
- EXPECT_NE(thisThreadID, otherThreadID);
-}
-
-TEST(ThreadId, getOSThreadID) {
- auto thisThreadID = folly::getOSThreadID();
- uint64_t otherThreadID;
- std::thread otherThread{[&] { otherThreadID = folly::getOSThreadID(); }};
- otherThread.join();
- EXPECT_NE(thisThreadID, otherThreadID);
-}
#include <folly/Baton.h>
#include <folly/Memory.h>
-#include <folly/ThreadId.h>
#include <folly/experimental/io/FsUtil.h>
#include <folly/portability/GTest.h>
#include <folly/portability/Unistd.h>
+#include <folly/system/ThreadId.h>
using namespace folly;
+++ /dev/null
-/*
- * Copyright 2017 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <thread>
-
-#include <folly/Baton.h>
-#include <folly/ScopeGuard.h>
-#include <folly/ThreadName.h>
-#include <folly/portability/GTest.h>
-
-using namespace std;
-using namespace folly;
-
-namespace {
-
-const bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName();
-const bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName();
-constexpr StringPiece kThreadName{"rockin-thread"};
-
-} // namespace
-
-TEST(ThreadName, getCurrentThreadName) {
- thread th([] {
- EXPECT_EQ(expectedSetSelfThreadNameResult, setThreadName(kThreadName));
- if (expectedSetSelfThreadNameResult) {
- EXPECT_EQ(kThreadName.toString(), *getCurrentThreadName());
- }
- });
- SCOPE_EXIT { th.join(); };
-}
-
-TEST(ThreadName, setThreadName_other_pthread) {
- Baton<> handle_set;
- Baton<> let_thread_end;
- pthread_t handle;
- thread th([&] {
- handle = pthread_self();
- handle_set.post();
- let_thread_end.wait();
- });
- SCOPE_EXIT { th.join(); };
- handle_set.wait();
- SCOPE_EXIT { let_thread_end.post(); };
- EXPECT_EQ(
- expectedSetOtherThreadNameResult, setThreadName(handle, kThreadName));
-}
-
-TEST(ThreadName, setThreadName_other_id) {
- Baton<> let_thread_end;
- thread th([&] {
- let_thread_end.wait();
- });
- SCOPE_EXIT { th.join(); };
- SCOPE_EXIT { let_thread_end.post(); };
- EXPECT_EQ(
- expectedSetOtherThreadNameResult,
- setThreadName(th.get_id(), kThreadName));
- if (expectedSetOtherThreadNameResult) {
- EXPECT_EQ(*getThreadName(th.get_id()), kThreadName);
- }
-}