• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Android Open Source Project
2 //
3 // 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
6 //
7 // 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.
14 
15 #pragma once
16 
17 #include <errno.h>
18 
19 #include "aemu/base/logging/CLog.h"
20 
21 namespace android {
22 namespace base {
23 
24 // Set EINTR_WRAPPER_DEBUG to 1 to force the debug version of HANDLE_EINTR
25 // which will call eintrWrapperFatal() is the system call loops
26 // too many times, or 0 to get it to loop indefinitly.
27 // Mostly used for unit testing.
28 // If the macro is undefined, auto-detect the value based on NDEBUG.
29 #if !defined(EINTR_WRAPPER_DEBUG)
30 #  ifdef NDEBUG
31 #    define EINTR_WRAPPER_DEBUG 0
32 #  else
33 #    define EINTR_WRAPPER_DEBUG 1
34 #  endif
35 #endif
36 
37 // HANDLE_EINTR() is a macro used to handle EINTR return values when
38 // calling system calls like open() or read() on Posix systems.
39 //
40 // By default, this will loop indefinitly, retrying the call until
41 // the result is no longer -1/EINTR, except in debug mode, where a
42 // loop counter is actually used and to provoke a fatal error if there
43 // are too many loops.
44 //
45 // Usage example:
46 //     int ret = HANDLE_EINTR(open("/some/file/path", O_RDONLY));
47 //
48 // IMPORTANT: Do not use with the close() system call (use IGNORE_EINTR()
49 // instead).
50 //
51 // - On Linux, the file descriptor is always already closed when this
52 //   function returns -1/EINTR, and calling it again with the same
53 //   parameters risks closing another file descriptor open by another
54 //   thread in parallel!
55 //
56 // - On OS X, whether the file descriptor is closed or not is pretty
57 //   much random! It's better to leave the descriptor open than risk
58 //   closing another one by mistake :(
59 //
60 #define MAX_EINTR_LOOP_COUNT  100
61 
62 #ifdef _WIN32
63 #  define HANDLE_EINTR(x)  (x)
64 #elif EINTR_WRAPPER_DEBUG == 0
65 #  define HANDLE_EINTR(x) \
66     __extension__ ({ \
67         __typeof__(x) eintr_wrapper_result; \
68         do { \
69             eintr_wrapper_result = (x); \
70         } while (eintr_wrapper_result < 0 && errno == EINTR); \
71         eintr_wrapper_result; \
72     })
73 #else  // !_WIN32 && EINTR_WRAPPER_DEBUG
74 
75 #  define HANDLE_EINTR(x) \
76     __extension__ ({ \
77         __typeof__(x) eintr_wrapper_result; \
78         int eintr_wrapper_loop_count = 0; \
79         for (;;) { \
80             eintr_wrapper_result = (x); \
81             if (eintr_wrapper_result != -1 || errno != EINTR) \
82                 break; \
83             ++eintr_wrapper_loop_count; \
84             if(eintr_wrapper_loop_count >= MAX_EINTR_LOOP_COUNT) \
85                 dfatal("Looping around EINTR too many times"); \
86         }; \
87         eintr_wrapper_result; \
88     })
89 #endif  // !_WIN32 && EINTR_WRAPPER_DEBUG
90 
91 // IGNORE_EINTR() is a macro used to perform a system call and ignore
92 // an EINTR result, i.e. it will return 0 instead of -1 if this occurs.
93 // This is mostly used with the close() system call, as described
94 // in the HANDLE_EINTR() documentation.
95 #ifdef _WIN32
96 #  define IGNORE_EINTR(x)  (x)
97 #else
98 #  define IGNORE_EINTR(x) \
99     __extension__ ({ \
100         __typeof__(x) eintr_wrapper_result = (x); \
101         if (eintr_wrapper_result == -1 && errno == EINTR) \
102             eintr_wrapper_result = 0; \
103         eintr_wrapper_result; \
104     })
105 #endif
106 
107 }  // namespace base
108 }  // namespace android
109