diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-16 18:31:33 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-16 18:31:33 +0000 |
commit | 36424441697b957009738f609c0eae22cf5ded34 (patch) | |
tree | 260908a82ae907bfa5514c52b776638d09f655ff /base | |
parent | d899ee5ad954db46b7546b53f7ec91281951adbc (diff) | |
download | chromium_src-36424441697b957009738f609c0eae22cf5ded34.zip chromium_src-36424441697b957009738f609c0eae22cf5ded34.tar.gz chromium_src-36424441697b957009738f609c0eae22cf5ded34.tar.bz2 |
Use close$NOCANCEL on the Mac, so that it has deterministic behavior when
it fails with EINTR. Specifically, in this case, the FD will already have been
closed.
BUG=269623
R=thakis@chromium.org
Review URL: https://codereview.chromium.org/23455051
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@223369 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gypi | 1 | ||||
-rw-r--r-- | base/mac/close_nocancel.cc | 79 |
2 files changed, 80 insertions, 0 deletions
diff --git a/base/base.gypi b/base/base.gypi index ecb7563..d8be2bb 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -247,6 +247,7 @@ 'mac/bind_objc_block.h', 'mac/bundle_locations.h', 'mac/bundle_locations.mm', + 'mac/close_nocancel.cc', 'mac/cocoa_protocols.h', 'mac/foundation_util.h', 'mac/foundation_util.mm', diff --git a/base/mac/close_nocancel.cc b/base/mac/close_nocancel.cc new file mode 100644 index 0000000..134f7ac --- /dev/null +++ b/base/mac/close_nocancel.cc @@ -0,0 +1,79 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// http://crbug.com/269623 +// http://openradar.appspot.com/14999594 +// +// When the default version of close used on Mac OS X fails with EINTR, the +// file descriptor is not in a deterministic state. It may have been closed, +// or it may not have been. This makes it impossible to gracefully recover +// from the error. If the close is retried after the FD has been closed, the +// subsequent close can report EBADF, or worse, it can close an unrelated FD +// opened by another thread. If the close is not retried after the FD has been +// left open, the FD is leaked. Neither of these are good options. +// +// Mac OS X provides an alternate version of close, close$NOCANCEL. This +// version will never fail with EINTR before the FD is actually closed. With +// this version, it is thus safe to call close without checking for EINTR (as +// the HANDLE_EINTR macro does) and not risk leaking the FD. In fact, mixing +// this verison of close with HANDLE_EINTR is hazardous. +// +// The $NOCANCEL variants of various system calls are activated by compiling +// with __DARWIN_NON_CANCELABLE, which prevents them from being pthread +// cancellation points. Rather than taking such a heavy-handed approach, this +// file implements an alternative: to use the $NOCANCEL variant of close (thus +// preventing it from being a pthread cancellation point) without affecting +// any other system calls. +// +// This file operates by providing a close function with the non-$NOCANCEL +// symbol name expected for the compilation environment as set by <unistd.h> +// and <sys/cdefs.h> (the DARWIN_ALIAS_C macro). That function calls the +// $NOCANCEL variant, which is resolved from libsyscall. By linking with this +// version of close prior to the libsyscall version, close's implementation is +// overridden. + +#include <sys/cdefs.h> + +// If the non-cancelable variants of all system calls have already been +// chosen, do nothing. +#if !__DARWIN_NON_CANCELABLE + +extern "C" { + +#if __DARWIN_UNIX03 && !__DARWIN_ONLY_UNIX_CONFORMANCE + +// When there's a choice between UNIX2003 and pre-UNIX2003 and UNIX2003 has +// been chosen: +#define close_interface close$UNIX2003 +#define close_implementation close$NOCANCEL$UNIX2003 + +#elif !__DARWIN_UNIX03 && !__DARWIN_ONLY_UNIX_CONFORMANCE + +// When there's a choice between UNIX2003 and pre-UNIX2003 and pre-UNIX2003 +// has been chosen. There's no close$NOCANCEL symbol in this case, so use +// close$NOCANCEL$UNIX2003 as the implementation. It does the same thing +// that close$NOCANCEL would do. +#define close_interface close +#define close_implementation close$NOCANCEL$UNIX2003 + +#else // __DARWIN_ONLY_UNIX_CONFORMANCE + +// When only UNIX2003 is supported: +#define close_interface close +#define close_implementation close$NOCANCEL + +#endif + +int close_implementation(int fd); + +int close_interface(int fd) { + return close_implementation(fd); +} + +#undef close_interface +#undef close_implementation + +} // extern "C" + +#endif // !__DARWIN_NON_CANCELABLE |