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 22namespace android { 23namespace 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)). 29using namespace ::android::base::testing; 30 31class EintrWrapperTest : public ::testing::Test, LogOutput { 32public: 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 51protected: 52 bool mFatal; 53 bool mLogged; 54 LogOutput* mPrevious; 55 jmp_buf mJumper; 56}; 57 58 59// Loop counter used by several functions below. 60static int gLoopCount = 0; 61 62// This function returns the first time it is called, or -1/EINVAL 63// otherwise. 64static int returnEinvalAfterFirstCall(void) { 65 if (++gLoopCount == 1) 66 return 0; 67 68 errno = EINVAL; 69 return -1; 70} 71 72TEST_F(EintrWrapperTest, NoLoopOnSuccess) { 73 gLoopCount = 0; 74 EXPECT_EQ(0, HANDLE_EINTR(returnEinvalAfterFirstCall())); 75 EXPECT_EQ(1, gLoopCount); 76} 77 78TEST_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 86static 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 97TEST_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. 107static int loopEintr10(void) { 108 if (++gLoopCount < 10) { 109 errno = EINTR; 110 return -1; 111 } 112 return 0; 113} 114 115TEST_F(EintrWrapperTest, LoopOnEintr) { 116 gLoopCount = 0; 117 EXPECT_EQ(0, HANDLE_EINTR(loopEintr10())); 118 EXPECT_EQ(10, gLoopCount); 119} 120 121static int loopEintr200(void) { 122 if (++gLoopCount < 200) { 123 errno = EINTR; 124 return -1; 125 } 126 return 0; 127} 128 129TEST_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