1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// http://crbug.com/269623
6// http://openradar.appspot.com/14999594
7//
8// When the default version of close used on Mac OS X fails with EINTR, the
9// file descriptor is not in a deterministic state. It may have been closed,
10// or it may not have been. This makes it impossible to gracefully recover
11// from the error. If the close is retried after the FD has been closed, the
12// subsequent close can report EBADF, or worse, it can close an unrelated FD
13// opened by another thread. If the close is not retried after the FD has been
14// left open, the FD is leaked. Neither of these are good options.
15//
16// Mac OS X provides an alternate version of close, close$NOCANCEL. This
17// version will never fail with EINTR before the FD is actually closed. With
18// this version, it is thus safe to call close without checking for EINTR (as
19// the HANDLE_EINTR macro does) and not risk leaking the FD. In fact, mixing
20// this verison of close with HANDLE_EINTR is hazardous.
21//
22// The $NOCANCEL variants of various system calls are activated by compiling
23// with __DARWIN_NON_CANCELABLE, which prevents them from being pthread
24// cancellation points. Rather than taking such a heavy-handed approach, this
25// file implements an alternative: to use the $NOCANCEL variant of close (thus
26// preventing it from being a pthread cancellation point) without affecting
27// any other system calls.
28//
29// This file operates by providing a close function with the non-$NOCANCEL
30// symbol name expected for the compilation environment as set by <unistd.h>
31// and <sys/cdefs.h> (the DARWIN_ALIAS_C macro). That function calls the
32// $NOCANCEL variant, which is resolved from libsyscall. By linking with this
33// version of close prior to the libsyscall version, close's implementation is
34// overridden.
35
36#include <sys/cdefs.h>
37
38// If the non-cancelable variants of all system calls have already been
39// chosen, do nothing.
40#if !__DARWIN_NON_CANCELABLE
41
42extern "C" {
43
44#if __DARWIN_UNIX03 && !__DARWIN_ONLY_UNIX_CONFORMANCE
45
46// When there's a choice between UNIX2003 and pre-UNIX2003 and UNIX2003 has
47// been chosen:
48#define close_interface close$UNIX2003
49#define close_implementation close$NOCANCEL$UNIX2003
50
51#elif !__DARWIN_UNIX03 && !__DARWIN_ONLY_UNIX_CONFORMANCE
52
53// When there's a choice between UNIX2003 and pre-UNIX2003 and pre-UNIX2003
54// has been chosen. There's no close$NOCANCEL symbol in this case, so use
55// close$NOCANCEL$UNIX2003 as the implementation. It does the same thing
56// that close$NOCANCEL would do.
57#define close_interface close
58#define close_implementation close$NOCANCEL$UNIX2003
59
60#else  // __DARWIN_ONLY_UNIX_CONFORMANCE
61
62// When only UNIX2003 is supported:
63#define close_interface close
64#define close_implementation close$NOCANCEL
65
66#endif
67
68int close_implementation(int fd);
69
70int close_interface(int fd) {
71  return close_implementation(fd);
72}
73
74#undef close_interface
75#undef close_implementation
76
77}  // extern "C"
78
79#endif  // !__DARWIN_NON_CANCELABLE
80