• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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