blob: da7b0b3d194d51809391dbe77fd9a34a2f7ecd1e [file] [log] [blame]
Lingfeng Yang43459932020-10-31 01:34:58 -07001// Copyright 2020 The Android Open Source Project
Lingfeng Yang3c944902020-10-28 11:56:43 -07002//
Lingfeng Yang43459932020-10-31 01:34:58 -07003// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
Lingfeng Yang3c944902020-10-28 11:56:43 -07006//
Lingfeng Yang43459932020-10-31 01:34:58 -07007// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
Lingfeng Yang3c944902020-10-28 11:56:43 -070014
15#pragma once
16
17#include <errno.h>
18
19namespace android {
20namespace base {
21
22// Set EINTR_WRAPPER_DEBUG to 1 to force the debug version of HANDLE_EINTR
23// which will call eintrWrapperFatal() is the system call loops
24// too many times, or 0 to get it to loop indefinitly.
25// Mostly used for unit testing.
26// If the macro is undefined, auto-detect the value based on NDEBUG.
27#if !defined(EINTR_WRAPPER_DEBUG)
28# ifdef NDEBUG
29# define EINTR_WRAPPER_DEBUG 0
30# else
31# define EINTR_WRAPPER_DEBUG 1
32# endif
33#endif
34
35// HANDLE_EINTR() is a macro used to handle EINTR return values when
36// calling system calls like open() or read() on Posix systems.
37//
38// By default, this will loop indefinitly, retrying the call until
39// the result is no longer -1/EINTR, except in debug mode, where a
40// loop counter is actually used and to provoke a fatal error if there
41// are too many loops.
42//
43// Usage example:
44// int ret = HANDLE_EINTR(open("/some/file/path", O_RDONLY));
45//
46// IMPORTANT: Do not use with the close() system call (use IGNORE_EINTR()
47// instead).
48//
49// - On Linux, the file descriptor is always already closed when this
50// function returns -1/EINTR, and calling it again with the same
51// parameters risks closing another file descriptor open by another
52// thread in parallel!
53//
54// - On OS X, whether the file descriptor is closed or not is pretty
55// much random! It's better to leave the descriptor open than risk
56// closing another one by mistake :(
57//
58#define MAX_EINTR_LOOP_COUNT 100
59
60#ifdef _WIN32
61# define HANDLE_EINTR(x) (x)
62#elif EINTR_WRAPPER_DEBUG == 0
63# define HANDLE_EINTR(x) \
64 __extension__ ({ \
65 __typeof__(x) eintr_wrapper_result; \
66 do { \
67 eintr_wrapper_result = (x); \
68 } while (eintr_wrapper_result < 0 && errno == EINTR); \
69 eintr_wrapper_result; \
70 })
71#else // !_WIN32 && EINTR_WRAPPER_DEBUG
72
73# define HANDLE_EINTR(x) \
74 __extension__ ({ \
75 __typeof__(x) eintr_wrapper_result; \
76 int eintr_wrapper_loop_count = 0; \
77 for (;;) { \
78 eintr_wrapper_result = (x); \
79 if (eintr_wrapper_result != -1 || errno != EINTR) \
80 break; \
81 ++eintr_wrapper_loop_count; \
82 if(eintr_wrapper_loop_count >= MAX_EINTR_LOOP_COUNT) \
83 fprintf(stderr, "Looping around EINTR too many times\n"); \
84 }; \
85 eintr_wrapper_result; \
86 })
87#endif // !_WIN32 && EINTR_WRAPPER_DEBUG
88
89// IGNORE_EINTR() is a macro used to perform a system call and ignore
90// an EINTR result, i.e. it will return 0 instead of -1 if this occurs.
91// This is mostly used with the close() system call, as described
92// in the HANDLE_EINTR() documentation.
93#ifdef _WIN32
94# define IGNORE_EINTR(x) (x)
95#else
96# define IGNORE_EINTR(x) \
97 __extension__ ({ \
98 __typeof__(x) eintr_wrapper_result = (x); \
99 if (eintr_wrapper_result == -1 && errno == EINTR) \
100 eintr_wrapper_result = 0; \
101 eintr_wrapper_result; \
102 })
103#endif
104
105} // namespace base
106} // namespace android