From: Christopher Dykes Date: Wed, 11 May 2016 23:55:28 +0000 (-0700) Subject: Make the sys/uio.h portability header work for Windows X-Git-Tag: 2016.07.26~246 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=c6ad47b6d3a5d09477ab210916dfac0982104cd8;p=folly.git 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 --- diff --git a/folly/FileUtil.cpp b/folly/FileUtil.cpp index 26525deb..f814ddad 100644 --- a/folly/FileUtil.cpp +++ b/folly/FileUtil.cpp @@ -132,20 +132,16 @@ ssize_t readvFull(int fd, iovec* iov, int count) { return wrapvFull(readv, fd, iov, count); } -#if FOLLY_HAVE_PREADV ssize_t preadvFull(int fd, iovec* iov, int count, off_t offset) { return wrapvFull(preadv, fd, iov, count, offset); } -#endif ssize_t writevFull(int fd, iovec* iov, int count) { return wrapvFull(writev, fd, iov, count); } -#if FOLLY_HAVE_PWRITEV ssize_t pwritevFull(int fd, iovec* iov, int count, off_t offset) { return wrapvFull(pwritev, fd, iov, count, offset); } -#endif } // namespaces diff --git a/folly/FileUtil.h b/folly/FileUtil.h index a28b0477..de250aef 100644 --- a/folly/FileUtil.h +++ b/folly/FileUtil.h @@ -19,12 +19,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include @@ -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 preadFull(int fd, void* buf, size_t n, off_t offset); 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); -#endif /** * 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); 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 writevFull(int fd, iovec* iov, int count); -#if FOLLY_HAVE_PWRITEV 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 diff --git a/folly/Makefile.am b/folly/Makefile.am index b3b355f2..178d49fe 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -446,6 +446,7 @@ libfolly_la_SOURCES = \ portability/SysResource.cpp \ portability/SysStat.cpp \ portability/SysTime.cpp \ + portability/SysUio.cpp \ portability/Time.cpp \ portability/Unistd.cpp \ Random.cpp \ diff --git a/folly/Portability.h b/folly/Portability.h index c9616ea7..55c5dd5c 100644 --- a/folly/Portability.h +++ b/folly/Portability.h @@ -200,16 +200,6 @@ namespace std { typedef ::max_align_t max_align_t; } #undef FOLLY_TLS #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 // the 'std' namespace; the latter uses inline namespaces. Wrap this decision // up in a macro to make forward-declarations easier. diff --git a/folly/configure.ac b/folly/configure.ac index af1bbb4a..c2670fd0 100644 --- a/folly/configure.ac +++ b/folly/configure.ac @@ -478,7 +478,10 @@ AC_CHECK_FUNCS([getdelim \ malloc_size \ malloc_usable_size \ memrchr \ - pipe2]) + pipe2 \ + preadv \ + pwritev \ + ]) AC_CHECK_HEADER([lz4.h], AC_CHECK_LIB([lz4], [LZ4_decompress_safe])) AC_CHECK_HEADER([snappy.h], AC_CHECK_LIB([snappy], [main])) diff --git a/folly/portability/SysUio.cpp b/folly/portability/SysUio.cpp new file mode 100755 index 00000000..1a51728d --- /dev/null +++ b/folly/portability/SysUio.cpp @@ -0,0 +1,127 @@ +/* + * 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 + +#include +#include + +#include +#include +#include + +template +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 +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(fd, iov, count); +} + +extern "C" ssize_t writev(int fd, const iovec* iov, int count) { + return doVecOperation(fd, iov, count); +} +#endif diff --git a/folly/portability/SysUio.h b/folly/portability/SysUio.h index 9640f680..aa243d51 100644 --- a/folly/portability/SysUio.h +++ b/folly/portability/SysUio.h @@ -16,10 +16,23 @@ #pragma once -#include +#include +#include +#include -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 constexpr size_t kIovMax = IOV_MAX; #else diff --git a/folly/test/FileUtilTest.cpp b/folly/test/FileUtilTest.cpp index 6a7f5e2e..23a49f96 100644 --- a/folly/test/FileUtilTest.cpp +++ b/folly/test/FileUtilTest.cpp @@ -250,7 +250,6 @@ TEST(FileUtilTest2, wrapv) { EXPECT_EQ(sum, wrapvFull(writev, tempFile.fd(), iov.data(), iov.size())); } -#if FOLLY_HAVE_PREADV TEST_F(FileUtilTest, preadv) { for (auto& p : readers_) { IovecBuffers buf({12, 19, 31}); @@ -264,7 +263,6 @@ TEST_F(FileUtilTest, preadv) { } } } -#endif TEST(String, readFile) { srand(time(nullptr));