1af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// Copyright 2014 The Android Open Source Project
2af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner//
3af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// This software is licensed under the terms of the GNU General Public
4af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// License version 2, as published by the Free Software Foundation, and
5af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// may be copied, distributed, and modified under those terms.
6af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner//
7af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// This program is distributed in the hope that it will be useful,
8af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// but WITHOUT ANY WARRANTY; without even the implied warranty of
9af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// GNU General Public License for more details.
11af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
12af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// Forces debug mode
13af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#define EINTR_WRAPPER_DEBUG 1
14af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
15af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/eintr_wrapper.h"
16af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
17af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include <stdarg.h>
18af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include <setjmp.h>
19af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
20af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/panic.h"
21af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
22af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include <gtest/gtest.h>
23af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
24af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// Loop counter used by several functions below.
25af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic int loop_count = 0;
26af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
27af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// This function returns the first time it is called, or -1/EINVAL
28af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// otherwise.
29af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic int return_einval_after_first_call(void) {
30af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    if (++loop_count == 1)
31af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        return 0;
32af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
33af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    errno = EINVAL;
34af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    return -1;
35af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
36af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
37af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' TurnerTEST(eintr_wrapper,NoLoopOnSuccess) {
38af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    loop_count = 0;
39af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
40af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(1, loop_count);
41af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
42af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
43af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' TurnerTEST(eintr_wrapper,NoLoopOnRegularError) {
44af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    loop_count = 0;
45af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(0, HANDLE_EINTR(return_einval_after_first_call()));
46af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(-1, HANDLE_EINTR(return_einval_after_first_call()));
47af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(EINVAL, errno);
48af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(2, loop_count);
49af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
50af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
51af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic int always_return_eintr(void) {
52af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    loop_count++;
53af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#ifdef _WIN32
54af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    // Win32 cannot generate EINTR.
55af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    return 0;
56af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#else
57af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    errno = EINTR;
58af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    return -1;
59af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#endif
60af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
61af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
62af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' TurnerTEST(eintr_wrapper,IgnoreEintr) {
63af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    loop_count = 0;
64af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(0, IGNORE_EINTR(always_return_eintr()));
65af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(1, loop_count);
66af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
67af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
68af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#ifndef _WIN32
69af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
70af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// This function loops 10 times around |loop_count|, while returning
71af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// -1/errno.
72af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic int loop_eintr_10(void) {
73af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    if (++loop_count < 10) {
74af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        errno = EINTR;
75af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        return -1;
76af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    }
77af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    return 0;
78af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
79af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
80af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' TurnerTEST(eintr_wrapper,LoopOnEintr) {
81af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    loop_count = 0;
82af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(0, HANDLE_EINTR(loop_eintr_10()));
83af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    EXPECT_EQ(10, loop_count);
84af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
85af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
86af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// Implementation of a custom panic function used to detect that
87af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// HANDLE_EINTR() called panic after too many loop iterations.
88af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// Uses setjmp()/longjmp() since the panic handler must be
89af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner// __attribute__((noreturn)).
90af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic jmp_buf panic_jumper;
91af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic bool panic_called = false;
92af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
93af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic void __attribute__((noreturn))
94af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        my_panic_handler(const char*, va_list);
95af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
96af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic void my_panic_handler(const char* fmt, va_list args) {
97af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    panic_called = true;
98af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    longjmp(panic_jumper, 1);
99af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
100af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
101af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turnerstatic int loop_eintr_200(void) {
102af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    if (++loop_count < 200) {
103af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        errno = EINTR;
104af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        return -1;
105af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    }
106af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    return 0;
107af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
108af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
109af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' TurnerTEST(eintr_wrapper,PanicOnTooManyLoops) {
110af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    loop_count = 0;
111af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    android_panic_registerHandler(my_panic_handler);
112af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    if (setjmp(panic_jumper) == 0) {
113af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        HANDLE_EINTR(loop_eintr_200());
114af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        ASSERT_TRUE(0) << "HANDLE_EINTR() didn't panic!";
115af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    } else {
116af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        EXPECT_EQ(true, panic_called);
117af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner        EXPECT_EQ(MAX_EINTR_LOOP_COUNT, loop_count);
118af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    }
119af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner}
120af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner
121af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#endif  // !_WIN32
122