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/base/EintrWrapper.h"
16
17 #include <stdarg.h>
18 #include <setjmp.h>
19
20 #include <gtest/gtest.h>
21
22 namespace android {
23 namespace base {
24
25 // Implementation of a custom panic function used to detect that
26 // HANDLE_EINTR() called panic after too many loop iterations.
27 // Uses setjmp()/longjmp() since the panic handler must be
28 // __attribute__((noreturn)).
29 using namespace ::android::base::testing;
30
31 class EintrWrapperTest : public ::testing::Test, LogOutput {
32 public:
EintrWrapperTest()33 EintrWrapperTest() :
34 mFatal(false),
35 mLogged(true),
36 mPrevious(LogOutput::setNewOutput(this)) {}
37
~EintrWrapperTest()38 ~EintrWrapperTest() {
39 LogOutput::setNewOutput(mPrevious);
40 }
41
logMessage(const android::base::LogParams & params,const char * message,size_t messageLen)42 virtual void logMessage(const android::base::LogParams& params,
43 const char* message,
44 size_t messageLen) {
45 mFatal = (params.severity == LOG_FATAL);
46 mLogged = true;
47 if (mFatal)
48 longjmp(mJumper, 1);
49 }
50
51 protected:
52 bool mFatal;
53 bool mLogged;
54 LogOutput* mPrevious;
55 jmp_buf mJumper;
56 };
57
58
59 // Loop counter used by several functions below.
60 static int gLoopCount = 0;
61
62 // This function returns the first time it is called, or -1/EINVAL
63 // otherwise.
returnEinvalAfterFirstCall(void)64 static int returnEinvalAfterFirstCall(void) {
65 if (++gLoopCount == 1)
66 return 0;
67
68 errno = EINVAL;
69 return -1;
70 }
71
TEST_F(EintrWrapperTest,NoLoopOnSuccess)72 TEST_F(EintrWrapperTest, NoLoopOnSuccess) {
73 gLoopCount = 0;
74 EXPECT_EQ(0, HANDLE_EINTR(returnEinvalAfterFirstCall()));
75 EXPECT_EQ(1, gLoopCount);
76 }
77
TEST_F(EintrWrapperTest,NoLoopOnRegularError)78 TEST_F(EintrWrapperTest, NoLoopOnRegularError) {
79 gLoopCount = 0;
80 EXPECT_EQ(0, HANDLE_EINTR(returnEinvalAfterFirstCall()));
81 EXPECT_EQ(-1, HANDLE_EINTR(returnEinvalAfterFirstCall()));
82 EXPECT_EQ(EINVAL, errno);
83 EXPECT_EQ(2, gLoopCount);
84 }
85
alwaysReturnEintr(void)86 static int alwaysReturnEintr(void) {
87 gLoopCount++;
88 #ifdef _WIN32
89 // Win32 cannot generate EINTR.
90 return 0;
91 #else
92 errno = EINTR;
93 return -1;
94 #endif
95 }
96
TEST_F(EintrWrapperTest,IgnoreEintr)97 TEST_F(EintrWrapperTest, IgnoreEintr) {
98 gLoopCount = 0;
99 EXPECT_EQ(0, IGNORE_EINTR(alwaysReturnEintr()));
100 EXPECT_EQ(1, gLoopCount);
101 }
102
103 #ifndef _WIN32
104
105 // This function loops 10 times around |gLoopCount|, while returning
106 // -1/errno.
loopEintr10(void)107 static int loopEintr10(void) {
108 if (++gLoopCount < 10) {
109 errno = EINTR;
110 return -1;
111 }
112 return 0;
113 }
114
TEST_F(EintrWrapperTest,LoopOnEintr)115 TEST_F(EintrWrapperTest, LoopOnEintr) {
116 gLoopCount = 0;
117 EXPECT_EQ(0, HANDLE_EINTR(loopEintr10()));
118 EXPECT_EQ(10, gLoopCount);
119 }
120
loopEintr200(void)121 static int loopEintr200(void) {
122 if (++gLoopCount < 200) {
123 errno = EINTR;
124 return -1;
125 }
126 return 0;
127 }
128
TEST_F(EintrWrapperTest,PanicOnTooManyLoops)129 TEST_F(EintrWrapperTest, PanicOnTooManyLoops) {
130 gLoopCount = 0;
131 if (setjmp(mJumper) == 0) {
132 HANDLE_EINTR(loopEintr200());
133 ASSERT_TRUE(0) << "HANDLE_EINTR() didn't panic!";
134 } else {
135 EXPECT_TRUE(mLogged);
136 EXPECT_TRUE(mFatal);
137 EXPECT_EQ(MAX_EINTR_LOOP_COUNT, gLoopCount);
138 }
139 }
140
141 #endif // !_WIN32
142
143 } // namespace base
144 } // namespace android
145