blob: ea259b9d26fb53341c5980d9e3f73bfc7cd5fd37 [file] [log] [blame]
David 'Digit' Turner26aa4432014-02-11 17:08:33 +01001// 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