Home | History | Annotate | Download | only in base
      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