Files
sdk/runtime/bin/fdutils_macos.cc
T
ager@google.com c3f89c46ec Fix race condition between signal handler and main thread.
The signal handler could unblock the main thread. The main thread
could delete the Process object the signal handler is holding a
pointer to. The signal handler could then close a file descriptor
it got from the deleted memory.

The whole process exit handling infrastructure is pretty fragile.
We should attempt to come up with something simpler.

R=sgjesse@google.com
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com//9225019

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@3652 260f80e4-7a28-3924-810f-c04153c831b5
2012-01-27 13:01:16 +00:00

110 lines
2.9 KiB
C++

// 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 <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "bin/fdutils.h"
bool FDUtils::SetNonBlocking(intptr_t fd) {
intptr_t status;
status = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
if (status < 0) {
perror("fcntl F_GETFL failed");
return false;
}
status = (status | O_NONBLOCK);
if (TEMP_FAILURE_RETRY(fcntl(fd, F_SETFL, status)) < 0) {
perror("fcntl F_SETFL failed");
return false;
}
return true;
}
bool FDUtils::IsBlocking(intptr_t fd, bool* is_blocking) {
intptr_t status;
status = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
if (status < 0) {
perror("fcntl F_GETFL failed");
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 = TEMP_FAILURE_RETRY(ioctl(fd, FIONREAD, &available));
if (result < 0) {
perror("ioctl FIONREAD failed");
return result;
}
#ifdef DEBUG
ASSERT(available >= 0);
#endif
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;
}