1 // Copyright 2014 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11
12 // Forces debug mode
13 #define EINTR_WRAPPER_DEBUG 1
14
15 #include "android/utils/eintr_wrapper.h"
16
17 #include <stdarg.h>
18 #include <setjmp.h>
19
20 #include "android/utils/panic.h"
21
22 #include <gtest/gtest.h>
23
24 // Loop counter used by several functions below.
25 static int loop_count = 0;
26
27 // This function returns the first time it is called, or -1/EINVAL
28 // otherwise.
return_einval_after_first_call(void)29 static int return_einval_after_first_call(void) {
30 if (++loop_count == 1)
31 return 0;
32
33 errno = EINVAL;
34 return -1;
35 }
36
TEST(eintr_wrapper,NoLoopOnSuccess)37 TEST(eintr_wrapper,NoLoopOnSuccess) {
38 loop_count = 0;
39 EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
40 EXPECT_EQ(1, loop_count);
41 }
42
TEST(eintr_wrapper,NoLoopOnRegularError)43 TEST(eintr_wrapper,NoLoopOnRegularError) {
44 loop_count = 0;
45 EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
46 EXPECT_EQ(-1, HANDLE_EINTR(return_einval_after_first_call()));
47 EXPECT_EQ(EINVAL, errno);
48 EXPECT_EQ(2, loop_count);
49 }
50
always_return_eintr(void)51 static int always_return_eintr(void) {
52 loop_count++;
53 #ifdef _WIN32
54 // Win32 cannot generate EINTR.
55 return 0;
56 #else
57 errno = EINTR;
58 return -1;
59 #endif
60 }
61
TEST(eintr_wrapper,IgnoreEintr)62 TEST(eintr_wrapper,IgnoreEintr) {
63 loop_count = 0;
64 EXPECT_EQ(0, IGNORE_EINTR(always_return_eintr()));
65 EXPECT_EQ(1, loop_count);
66 }
67
68 #ifndef _WIN32
69
70 // This function loops 10 times around |loop_count|, while returning
71 // -1/errno.
loop_eintr_10(void)72 static int loop_eintr_10(void) {
73 if (++loop_count < 10) {
74 errno = EINTR;
75 return -1;
76 }
77 return 0;
78 }
79
TEST(eintr_wrapper,LoopOnEintr)80 TEST(eintr_wrapper,LoopOnEintr) {
81 loop_count = 0;
82 EXPECT_EQ(0, HANDLE_EINTR(loop_eintr_10()));
83 EXPECT_EQ(10, loop_count);
84 }
85
86 // Implementation of a custom panic function used to detect that
87 // HANDLE_EINTR() called panic after too many loop iterations.
88 // Uses setjmp()/longjmp() since the panic handler must be
89 // __attribute__((noreturn)).
90 static jmp_buf panic_jumper;
91 static bool panic_called = false;
92
93 static void __attribute__((noreturn))
94 my_panic_handler(const char*, va_list);
95
my_panic_handler(const char * fmt,va_list args)96 static void my_panic_handler(const char* fmt, va_list args) {
97 panic_called = true;
98 longjmp(panic_jumper, 1);
99 }
100
loop_eintr_200(void)101 static int loop_eintr_200(void) {
102 if (++loop_count < 200) {
103 errno = EINTR;
104 return -1;
105 }
106 return 0;
107 }
108
TEST(eintr_wrapper,PanicOnTooManyLoops)109 TEST(eintr_wrapper,PanicOnTooManyLoops) {
110 loop_count = 0;
111 android_panic_registerHandler(my_panic_handler);
112 if (setjmp(panic_jumper) == 0) {
113 HANDLE_EINTR(loop_eintr_200());
114 ASSERT_TRUE(0) << "HANDLE_EINTR() didn't panic!";
115 } else {
116 EXPECT_EQ(true, panic_called);
117 EXPECT_EQ(MAX_EINTR_LOOP_COUNT, loop_count);
118 }
119 }
120
121 #endif // !_WIN32
122