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: 33 EintrWrapperTest() : 34 mFatal(false), 35 mLogged(true), 36 mPrevious(LogOutput::setNewOutput(this)) {} 37 38 ~EintrWrapperTest() { 39 LogOutput::setNewOutput(mPrevious); 40 } 41 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. 64 static int returnEinvalAfterFirstCall(void) { 65 if (++gLoopCount == 1) 66 return 0; 67 68 errno = EINVAL; 69 return -1; 70 } 71 72 TEST_F(EintrWrapperTest, NoLoopOnSuccess) { 73 gLoopCount = 0; 74 EXPECT_EQ(0, HANDLE_EINTR(returnEinvalAfterFirstCall())); 75 EXPECT_EQ(1, gLoopCount); 76 } 77 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 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 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. 107 static int loopEintr10(void) { 108 if (++gLoopCount < 10) { 109 errno = EINTR; 110 return -1; 111 } 112 return 0; 113 } 114 115 TEST_F(EintrWrapperTest, LoopOnEintr) { 116 gLoopCount = 0; 117 EXPECT_EQ(0, HANDLE_EINTR(loopEintr10())); 118 EXPECT_EQ(10, gLoopCount); 119 } 120 121 static int loopEintr200(void) { 122 if (++gLoopCount < 200) { 123 errno = EINTR; 124 return -1; 125 } 126 return 0; 127 } 128 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