• 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/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