Commit c6ad47b6 authored by Christopher Dykes's avatar Christopher Dykes Committed by Facebook Github Bot 0

Make the sys/uio.h portability header work for Windows

Summary: Windows doesn't have sys/uio.h, so implement it. This doesn't adjust any includes of it yet, I'll leave that for a separate diff.

Reviewed By: yfeldblum

Differential Revision: D2978042

fbshipit-source-id: 16d398a856de50b6c662f739eb11dfb851096592
parent bd52f502
...@@ -132,20 +132,16 @@ ssize_t readvFull(int fd, iovec* iov, int count) { ...@@ -132,20 +132,16 @@ ssize_t readvFull(int fd, iovec* iov, int count) {
return wrapvFull(readv, fd, iov, count); return wrapvFull(readv, fd, iov, count);
} }
#if FOLLY_HAVE_PREADV
ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset) { ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset) {
return wrapvFull(preadv, fd, iov, count, offset); return wrapvFull(preadv, fd, iov, count, offset);
} }
#endif
ssize_t writevFull(int fd, iovec* iov, int count) { ssize_t writevFull(int fd, iovec* iov, int count) {
return wrapvFull(writev, fd, iov, count); return wrapvFull(writev, fd, iov, count);
} }
#if FOLLY_HAVE_PWRITEV
ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset) { ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset) {
return wrapvFull(pwritev, fd, iov, count, offset); return wrapvFull(pwritev, fd, iov, count, offset);
} }
#endif
} // namespaces } // namespaces
...@@ -19,12 +19,12 @@ ...@@ -19,12 +19,12 @@
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/ScopeGuard.h> #include <folly/ScopeGuard.h>
#include <folly/portability/SysUio.h>
#include <cassert> #include <cassert>
#include <limits> #include <limits>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
...@@ -80,9 +80,7 @@ ssize_t writevNoInt(int fd, const iovec* iov, int count); ...@@ -80,9 +80,7 @@ ssize_t writevNoInt(int fd, const iovec* iov, int count);
ssize_t readFull(int fd, void* buf, size_t n); ssize_t readFull(int fd, void* buf, size_t n);
ssize_t preadFull(int fd, void* buf, size_t n, off_t offset); ssize_t preadFull(int fd, void* buf, size_t n, off_t offset);
ssize_t readvFull(int fd, iovec* iov, int count); ssize_t readvFull(int fd, iovec* iov, int count);
#if FOLLY_HAVE_PREADV
ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset); ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
#endif
/** /**
* Similar to readFull and preadFull above, wrappers around write() and * Similar to readFull and preadFull above, wrappers around write() and
...@@ -101,9 +99,7 @@ ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset); ...@@ -101,9 +99,7 @@ ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset);
ssize_t writeFull(int fd, const void* buf, size_t n); ssize_t writeFull(int fd, const void* buf, size_t n);
ssize_t pwriteFull(int fd, const void* buf, size_t n, off_t offset); ssize_t pwriteFull(int fd, const void* buf, size_t n, off_t offset);
ssize_t writevFull(int fd, iovec* iov, int count); ssize_t writevFull(int fd, iovec* iov, int count);
#if FOLLY_HAVE_PWRITEV
ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset); ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset);
#endif
/** /**
* Read entire file (if num_bytes is defaulted) or no more than * Read entire file (if num_bytes is defaulted) or no more than
......
...@@ -446,6 +446,7 @@ libfolly_la_SOURCES = \ ...@@ -446,6 +446,7 @@ libfolly_la_SOURCES = \
portability/SysResource.cpp \ portability/SysResource.cpp \
portability/SysStat.cpp \ portability/SysStat.cpp \
portability/SysTime.cpp \ portability/SysTime.cpp \
portability/SysUio.cpp \
portability/Time.cpp \ portability/Time.cpp \
portability/Unistd.cpp \ portability/Unistd.cpp \
Random.cpp \ Random.cpp \
......
...@@ -200,16 +200,6 @@ namespace std { typedef ::max_align_t max_align_t; } ...@@ -200,16 +200,6 @@ namespace std { typedef ::max_align_t max_align_t; }
#undef FOLLY_TLS #undef FOLLY_TLS
#endif #endif
// Define to 1 if you have the `preadv' and `pwritev' functions, respectively
#if !defined(FOLLY_HAVE_PREADV) && !defined(FOLLY_HAVE_PWRITEV)
# if defined(__GLIBC_PREREQ)
# if __GLIBC_PREREQ(2, 10)
# define FOLLY_HAVE_PREADV 1
# define FOLLY_HAVE_PWRITEV 1
# endif
# endif
#endif
// It turns out that GNU libstdc++ and LLVM libc++ differ on how they implement // It turns out that GNU libstdc++ and LLVM libc++ differ on how they implement
// the 'std' namespace; the latter uses inline namespaces. Wrap this decision // the 'std' namespace; the latter uses inline namespaces. Wrap this decision
// up in a macro to make forward-declarations easier. // up in a macro to make forward-declarations easier.
......
...@@ -478,7 +478,10 @@ AC_CHECK_FUNCS([getdelim \ ...@@ -478,7 +478,10 @@ AC_CHECK_FUNCS([getdelim \
malloc_size \ malloc_size \
malloc_usable_size \ malloc_usable_size \
memrchr \ memrchr \
pipe2]) pipe2 \
preadv \
pwritev \
])
AC_CHECK_HEADER([lz4.h], AC_CHECK_LIB([lz4], [LZ4_decompress_safe])) AC_CHECK_HEADER([lz4.h], AC_CHECK_LIB([lz4], [LZ4_decompress_safe]))
AC_CHECK_HEADER([snappy.h], AC_CHECK_LIB([snappy], [main])) AC_CHECK_HEADER([snappy.h], AC_CHECK_LIB([snappy], [main]))
......
/*
* Copyright 2016 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/portability/SysUio.h>
#include <errno.h>
#include <stdio.h>
#include <folly/ScopeGuard.h>
#include <folly/portability/SysFile.h>
#include <folly/portability/Unistd.h>
template <class F, class... Args>
static int wrapPositional(F f, int fd, off_t offset, Args... args) {
off_t origLoc = lseek(fd, 0, SEEK_CUR);
if (origLoc == off_t(-1)) {
return -1;
}
if (lseek(fd, offset, SEEK_SET) == off_t(-1)) {
return -1;
}
int res = (int)f(fd, args...);
int curErrNo = errno;
if (lseek(fd, origLoc, SEEK_SET) == off_t(-1)) {
if (res == -1) {
errno = curErrNo;
}
return -1;
}
errno = curErrNo;
return res;
}
#if defined(FOLLY_HAVE_PREADV) && !FOLLY_HAVE_PREADV
extern "C" ssize_t preadv(int fd, const iovec* iov, int count, off_t offset) {
return wrapPositional(readv, fd, offset, iov, count);
}
#endif
#if defined(FOLLY_HAVE_PWRITEV) && !FOLLY_HAVE_PWRITEV
extern "C" ssize_t pwritev(int fd, const iovec* iov, int count, off_t offset) {
return wrapPositional(writev, fd, offset, iov, count);
}
#endif
#ifdef _WIN32
template <bool isRead>
static ssize_t doVecOperation(int fd, const iovec* iov, int count) {
if (!count) {
return 0;
}
if (count < 0 || count > folly::kIovMax) {
errno = EINVAL;
return -1;
}
if (lockf(fd, F_LOCK, 0) == -1) {
return -1;
}
SCOPE_EXIT { lockf(fd, F_ULOCK, 0); };
ssize_t bytesProcessed = 0;
int curIov = 0;
void* curBase = iov[0].iov_base;
size_t curLen = iov[0].iov_len;
while (curIov < count) {
int res = 0;
if (isRead) {
res = read(fd, curBase, (unsigned int)curLen);
if (res == 0 && curLen != 0) {
break; // End of File
}
} else {
res = write(fd, curBase, (unsigned int)curLen);
// Write of zero bytes is fine.
}
if (res == -1) {
return -1;
}
if (res == curLen) {
curIov++;
if (curIov < count) {
curBase = iov[curIov].iov_base;
curLen = iov[curIov].iov_len;
}
} else {
curBase += (void*)((char*)curBase + res);
curLen -= res;
}
if (bytesProcessed + res < 0) {
// Overflow
errno = EINVAL;
return -1;
}
bytesProcessed += res;
}
return bytesProcessed;
}
extern "C" ssize_t readv(int fd, const iovec* iov, int count) {
return doVecOperation<true>(fd, iov, count);
}
extern "C" ssize_t writev(int fd, const iovec* iov, int count) {
return doVecOperation<false>(fd, iov, count);
}
#endif
...@@ -16,10 +16,23 @@ ...@@ -16,10 +16,23 @@
#pragma once #pragma once
#include <sys/uio.h> #include <folly/portability/Config.h>
#include <folly/portability/IOVec.h>
#include <folly/portability/SysTypes.h>
namespace folly { #if defined(FOLLY_HAVE_PREADV) && !FOLLY_HAVE_PREADV
extern "C" ssize_t preadv(int fd, const iovec* iov, int count, off_t offset);
#endif
#if defined(FOLLY_HAVE_PWRITEV) && !FOLLY_HAVE_PWRITEV
extern "C" ssize_t pwritev(int fd, const iovec* iov, int count, off_t offset);
#endif
#ifdef _WIN32
extern "C" ssize_t readv(int fd, const iovec* iov, int count);
extern "C" ssize_t writev(int fd, const iovec* iov, int count);
#endif
namespace folly {
#ifdef IOV_MAX // not defined on Android #ifdef IOV_MAX // not defined on Android
constexpr size_t kIovMax = IOV_MAX; constexpr size_t kIovMax = IOV_MAX;
#else #else
......
...@@ -250,7 +250,6 @@ TEST(FileUtilTest2, wrapv) { ...@@ -250,7 +250,6 @@ TEST(FileUtilTest2, wrapv) {
EXPECT_EQ(sum, wrapvFull(writev, tempFile.fd(), iov.data(), iov.size())); EXPECT_EQ(sum, wrapvFull(writev, tempFile.fd(), iov.data(), iov.size()));
} }
#if FOLLY_HAVE_PREADV
TEST_F(FileUtilTest, preadv) { TEST_F(FileUtilTest, preadv) {
for (auto& p : readers_) { for (auto& p : readers_) {
IovecBuffers buf({12, 19, 31}); IovecBuffers buf({12, 19, 31});
...@@ -264,7 +263,6 @@ TEST_F(FileUtilTest, preadv) { ...@@ -264,7 +263,6 @@ TEST_F(FileUtilTest, preadv) {
} }
} }
} }
#endif
TEST(String, readFile) { TEST(String, readFile) {
srand(time(nullptr)); srand(time(nullptr));
......
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