| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #include "platform/globals.h" | |
| #if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) | |
| #include "bin/fdutils.h" | |
| #include <errno.h> // NOLINT | |
| #include <fcntl.h> // NOLINT | |
| #include <sys/ioctl.h> // NOLINT | |
| #include <unistd.h> // NOLINT | |
| #include "platform/signal_blocker.h" | |
| namespace dart { | |
| namespace bin { | |
| bool FDUtils::SetCloseOnExec(intptr_t fd) { | |
| FATAL("Use O_CLOEXEC instead"); | |
| return false; | |
| } | |
| static bool SetBlockingHelper(intptr_t fd, bool blocking) { | |
| intptr_t status; | |
| status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFL)); | |
| if (status < 0) { | |
| perror("fcntl(F_GETFL) failed"); | |
| return false; | |
| } | |
| status = blocking ? (status & ~O_NONBLOCK) : (status | O_NONBLOCK); | |
| if (NO_RETRY_EXPECTED(fcntl(fd, F_SETFL, status)) < 0) { | |
| perror("fcntl(F_SETFL, O_NONBLOCK) failed"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool FDUtils::SetNonBlocking(intptr_t fd) { | |
| return SetBlockingHelper(fd, false); | |
| } | |
| bool FDUtils::SetBlocking(intptr_t fd) { | |
| return SetBlockingHelper(fd, true); | |
| } | |
| bool FDUtils::IsBlocking(intptr_t fd, bool* is_blocking) { | |
| intptr_t status; | |
| status = NO_RETRY_EXPECTED(fcntl(fd, F_GETFL)); | |
| if (status < 0) { | |
| return false; | |
| } | |
| *is_blocking = (status & O_NONBLOCK) == 0; | |
| return true; | |
| } | |
| intptr_t FDUtils::AvailableBytes(intptr_t fd) { | |
| int available; // ioctl for FIONREAD expects an 'int*' argument. | |
| int result = NO_RETRY_EXPECTED(ioctl(fd, FIONREAD, &available)); | |
| if (result < 0) { | |
| return result; | |
| } | |
| ASSERT(available >= 0); | |
| return static_cast<intptr_t>(available); | |
| } | |
| ssize_t FDUtils::ReadFromBlocking(int fd, void* buffer, size_t count) { | |
| #ifdef DEBUG | |
| bool is_blocking = false; | |
| ASSERT(FDUtils::IsBlocking(fd, &is_blocking)); | |
| ASSERT(is_blocking); | |
| #endif | |
| size_t remaining = count; | |
| char* buffer_pos = reinterpret_cast<char*>(buffer); | |
| while (remaining > 0) { | |
| ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer_pos, remaining)); | |
| if (bytes_read == 0) { | |
| return count - remaining; | |
| } else if (bytes_read == -1) { | |
| ASSERT(EAGAIN == EWOULDBLOCK); | |
| // Error code EWOULDBLOCK should only happen for non blocking | |
| // file descriptors. | |
| ASSERT(errno != EWOULDBLOCK); | |
| return -1; | |
| } else { | |
| ASSERT(bytes_read > 0); | |
| remaining -= bytes_read; | |
| buffer_pos += bytes_read; | |
| } | |
| } | |
| return count; | |
| } | |
| ssize_t FDUtils::WriteToBlocking(int fd, const void* buffer, size_t count) { | |
| #ifdef DEBUG | |
| bool is_blocking = false; | |
| ASSERT(FDUtils::IsBlocking(fd, &is_blocking)); | |
| ASSERT(is_blocking); | |
| #endif | |
| size_t remaining = count; | |
| char* buffer_pos = const_cast<char*>(reinterpret_cast<const char*>(buffer)); | |
| while (remaining > 0) { | |
| ssize_t bytes_written = | |
| TEMP_FAILURE_RETRY(write(fd, buffer_pos, remaining)); | |
| if (bytes_written == 0) { | |
| return count - remaining; | |
| } else if (bytes_written == -1) { | |
| ASSERT(EAGAIN == EWOULDBLOCK); | |
| // Error code EWOULDBLOCK should only happen for non blocking | |
| // file descriptors. | |
| ASSERT(errno != EWOULDBLOCK); | |
| return -1; | |
| } else { | |
| ASSERT(bytes_written > 0); | |
| remaining -= bytes_written; | |
| buffer_pos += bytes_written; | |
| } | |
| } | |
| return count; | |
| } | |
| void FDUtils::SaveErrorAndClose(intptr_t fd) { | |
| int err = errno; | |
| close(fd); | |
| errno = err; | |
| } | |
| } // namespace bin | |
| } // namespace dart | |
| #endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID) |