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