Commit 82fce98f authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

Let assume be invocable anytime

Summary:
[Folly] Let `assume` be invocable anytime, including before and after `main` and in signal handlers, by switching from `CHECK` to `FOLLY_SAFE_CHECK`.

Requires further minimizing the deps of `FOLLY_SAFE_CHECK`.

Reviewed By: ot, Orvid, luciang

Differential Revision: D6636035

fbshipit-source-id: 026b15ea92ba37acf9b11d714d834b79da80936a
parent e5460d02
......@@ -22,6 +22,7 @@
#include <vector>
#include <folly/detail/FileUtilDetail.h>
#include <folly/detail/FileUtilVectorDetail.h>
#include <folly/net/NetOps.h>
#include <folly/portability/Fcntl.h>
#include <folly/portability/Sockets.h>
......
......@@ -16,19 +16,22 @@
#pragma once
#include <algorithm>
#include <cerrno>
#include <cstddef>
#include <type_traits>
#include <folly/portability/SysUio.h>
#include <folly/portability/Unistd.h>
// Private functions for wrapping file-io against interrupt and partial op
// completions.
//
// This header is intended to be extremely lightweight. In particular, the
// parallel private functions for wrapping vector file-io are in a separate
// header.
/**
* Helper functions and templates for FileUtil.cpp. Declared here so
* they can be unittested.
*/
namespace folly {
namespace fileutil_detail {
using ssize_t = std::make_signed_t<size_t>;
// Wrap call to f(args) in loop to retry on EINTR
template <class F, class... Args>
ssize_t wrapNoInt(F f, Args... args) {
......@@ -39,9 +42,10 @@ ssize_t wrapNoInt(F f, Args... args) {
return r;
}
inline void incr(ssize_t /* n */) {}
inline void incr(ssize_t n, off_t& offset) {
offset += off_t(n);
inline void incr(ssize_t) {}
template <typename Offset>
inline void incr(ssize_t n, Offset& offset) {
offset += static_cast<Offset>(n);
}
// Wrap call to read/pread/write/pwrite(fd, buf, count, offset?) to retry on
......@@ -72,52 +76,5 @@ ssize_t wrapFull(F f, int fd, void* buf, size_t count, Offset... offset) {
return totalBytes;
}
// Retry reading/writing iovec objects.
// On POSIX platforms this wraps readv/preadv/writev/pwritev to
// retry on incomplete reads / writes. On Windows this wraps
// read/pread/write/pwrite. Note that pread and pwrite are not native calls on
// Windows and are provided by folly/portability/Unistd.cpp
template <class F, class... Offset>
ssize_t wrapvFull(F f, int fd, iovec* iov, int count, Offset... offset) {
ssize_t totalBytes = 0;
ssize_t r;
do {
#ifndef _WIN32
r = f(fd, iov, std::min<int>(count, kIovMax), offset...);
#else // _WIN32
// On Windows the caller will pass in just the simple
// read/write/pread/pwrite function, since the OS does not provide *v()
// versions.
r = f(fd, iov->iov_base, iov->iov_len, offset...);
#endif // _WIN32
if (r == -1) {
if (errno == EINTR) {
continue;
}
return r;
}
if (r == 0) {
break; // EOF
}
totalBytes += r;
incr(r, offset...);
while (r != 0 && count != 0) {
if (r >= ssize_t(iov->iov_len)) {
r -= ssize_t(iov->iov_len);
++iov;
--count;
} else {
iov->iov_base = static_cast<char*>(iov->iov_base) + r;
iov->iov_len -= r;
r = 0;
}
}
} while (count);
return totalBytes;
}
} // namespace fileutil_detail
} // namespace folly
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 <algorithm>
#include <cerrno>
#include <folly/detail/FileUtilDetail.h>
#include <folly/portability/SysUio.h>
#include <folly/portability/Unistd.h>
/**
* Helper functions and templates for FileUtil.cpp. Declared here so
* they can be unittested.
*/
namespace folly {
namespace fileutil_detail {
// Retry reading/writing iovec objects.
// On POSIX platforms this wraps readv/preadv/writev/pwritev to
// retry on incomplete reads / writes. On Windows this wraps
// read/pread/write/pwrite. Note that pread and pwrite are not native calls on
// Windows and are provided by folly/portability/Unistd.cpp
template <class F, class... Offset>
ssize_t wrapvFull(F f, int fd, iovec* iov, int count, Offset... offset) {
ssize_t totalBytes = 0;
ssize_t r;
do {
#ifndef _WIN32
r = f(fd, iov, std::min<int>(count, kIovMax), offset...);
#else // _WIN32
// On Windows the caller will pass in just the simple
// read/write/pread/pwrite function, since the OS does not provide *v()
// versions.
r = f(fd, iov->iov_base, iov->iov_len, offset...);
#endif // _WIN32
if (r == -1) {
if (errno == EINTR) {
continue;
}
return r;
}
if (r == 0) {
break; // EOF
}
totalBytes += r;
incr(r, offset...);
while (r != 0 && count != 0) {
if (r >= ssize_t(iov->iov_len)) {
r -= ssize_t(iov->iov_len);
++iov;
--count;
} else {
iov->iov_base = static_cast<char*>(iov->iov_base) + r;
iov->iov_len -= r;
r = 0;
}
}
} while (count);
return totalBytes;
}
} // namespace fileutil_detail
} // namespace folly
......@@ -16,14 +16,14 @@
#include <folly/lang/Assume.h>
#include <glog/logging.h>
#include <folly/lang/SafeAssert.h>
namespace folly {
namespace detail {
void assume_check(bool cond) {
CHECK(cond) << "compiler-hint assumption fails at runtime";
FOLLY_SAFE_CHECK(cond, "compiler-hint assumption fails at runtime");
}
} // namespace detail
......
......@@ -22,7 +22,21 @@
#include <folly/detail/FileUtilDetail.h>
#include <folly/lang/ToAscii.h>
#include <folly/portability/Unistd.h>
#include <folly/portability/SysTypes.h>
#include <folly/portability/Windows.h>
#if defined(_WIN32)
#include <fileapi.h> // @manual
#else
// @lint-ignore CLANGTIDY
#include <unistd.h>
#endif
// This header takes care to have minimal dependencies.
namespace folly {
namespace detail {
......@@ -444,14 +458,54 @@ constexpr std::pair<int, const char*> errors[] = {
};
#undef FOLLY_DETAIL_ERROR
#if defined(_WIN32)
constexpr int stderr_fileno = 2;
ssize_t write(int fh, void const* buf, size_t count) {
auto r = _write(fh, buf, static_cast<unsigned int>(count));
if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) {
// Writing to a pipe with a full buffer doesn't generate
// any error type, unless it caused us to write exactly 0
// bytes, so we have to see if we have a pipe first. We
// don't touch the errno for anything else.
HANDLE h = (HANDLE)_get_osfhandle(fh);
if (GetFileType(h) == FILE_TYPE_PIPE) {
DWORD state = 0;
if (GetNamedPipeHandleState(
h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {
errno = EAGAIN;
return -1;
}
}
}
}
return r;
}
int fsync(int fh) {
HANDLE h = (HANDLE)_get_osfhandle(fh);
if (!FlushFileBuffers(h)) {
return -1;
}
return 0;
}
#else
constexpr int stderr_fileno = STDERR_FILENO;
#endif
void writeStderr(const char* s, size_t len) {
fileutil_detail::wrapFull(write, STDERR_FILENO, const_cast<char*>(s), len);
fileutil_detail::wrapFull(write, stderr_fileno, const_cast<char*>(s), len);
}
void writeStderr(const char* s) {
writeStderr(s, strlen(s));
}
void flushStderr() {
fileutil_detail::wrapNoInt(fsync, STDERR_FILENO);
fileutil_detail::wrapNoInt(fsync, stderr_fileno);
}
[[noreturn]] FOLLY_COLD void safe_assert_terminate_v(
......
......@@ -29,6 +29,7 @@
#include <folly/Range.h>
#include <folly/String.h>
#include <folly/detail/FileUtilDetail.h>
#include <folly/detail/FileUtilVectorDetail.h>
#include <folly/experimental/TestUtil.h>
#include <folly/portability/GTest.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment