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/utils/eintr_wrapper.h"
16
17#include <stdarg.h>
18#include <setjmp.h>
19
20#include "android/utils/panic.h"
21
22#include <gtest/gtest.h>
23
24// Loop counter used by several functions below.
25static int loop_count = 0;
26
27// This function returns the first time it is called, or -1/EINVAL
28// otherwise.
29static int return_einval_after_first_call(void) {
30    if (++loop_count == 1)
31        return 0;
32
33    errno = EINVAL;
34    return -1;
35}
36
37TEST(eintr_wrapper,NoLoopOnSuccess) {
38    loop_count = 0;
39    EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
40    EXPECT_EQ(1, loop_count);
41}
42
43TEST(eintr_wrapper,NoLoopOnRegularError) {
44    loop_count = 0;
45    EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
46    EXPECT_EQ(-1, HANDLE_EINTR(return_einval_after_first_call()));
47    EXPECT_EQ(EINVAL, errno);
48    EXPECT_EQ(2, loop_count);
49}
50
51static int always_return_eintr(void) {
52    loop_count++;
53#ifdef _WIN32
54    // Win32 cannot generate EINTR.
55    return 0;
56#else
57    errno = EINTR;
58    return -1;
59#endif
60}
61
62TEST(eintr_wrapper,IgnoreEintr) {
63    loop_count = 0;
64    EXPECT_EQ(0, IGNORE_EINTR(always_return_eintr()));
65    EXPECT_EQ(1, loop_count);
66}
67
68#ifndef _WIN32
69
70// This function loops 10 times around |loop_count|, while returning
71// -1/errno.
72static int loop_eintr_10(void) {
73    if (++loop_count < 10) {
74        errno = EINTR;
75        return -1;
76    }
77    return 0;
78}
79
80TEST(eintr_wrapper,LoopOnEintr) {
81    loop_count = 0;
82    EXPECT_EQ(0, HANDLE_EINTR(loop_eintr_10()));
83    EXPECT_EQ(10, loop_count);
84}
85
86// Implementation of a custom panic function used to detect that
87// HANDLE_EINTR() called panic after too many loop iterations.
88// Uses setjmp()/longjmp() since the panic handler must be
89// __attribute__((noreturn)).
90static jmp_buf panic_jumper;
91static bool panic_called = false;
92
93static void __attribute__((noreturn))
94        my_panic_handler(const char*, va_list);
95
96static void my_panic_handler(const char* fmt, va_list args) {
97    panic_called = true;
98    longjmp(panic_jumper, 1);
99}
100
101static int loop_eintr_200(void) {
102    if (++loop_count < 200) {
103        errno = EINTR;
104        return -1;
105    }
106    return 0;
107}
108
109TEST(eintr_wrapper,PanicOnTooManyLoops) {
110    loop_count = 0;
111    android_panic_registerHandler(my_panic_handler);
112    if (setjmp(panic_jumper) == 0) {
113        HANDLE_EINTR(loop_eintr_200());
114        ASSERT_TRUE(0) << "HANDLE_EINTR() didn't panic!";
115    } else {
116        EXPECT_EQ(true, panic_called);
117        EXPECT_EQ(MAX_EINTR_LOOP_COUNT, loop_count);
118    }
119}
120
121#endif  // !_WIN32
122