mirror of
https://github.com/tezc/sc.git
synced 2025-01-28 07:03:06 +08:00
Dev (#7)
* thread & url * fix cirrus * fix thread * fix thread * split actions * test * fix test * fix windows thread * cond & fail-fast * cond & fail-fast * cond & fail-fast * cond & fail-fast * buffer * fix swap * fix big endian * socket & poll * socket fix * kqueue fix * freebsd * socket & mmap init * kqueue * kqueue * valgrind * fix freebsd * kqueue * accept fix * accept fix * accept fix * accept fix * accept fix * accept fix * accept fix * accept fix * accept fix * accept fix * fix big endian fmt * fix big endian fmt * mmap * mmap * mmap * mmap * fix freebsd * fix 32 bit, mmap * fix 32 bit, mmap * test sock * fix 32 bit, mmap * signal * signal * signal * add test array * fix backtrace
This commit is contained in:
parent
46d77f2fe6
commit
ef6c1983ff
@ -25,6 +25,7 @@ add_subdirectory(memory-map)
|
||||
add_subdirectory(mutex)
|
||||
add_subdirectory(queue)
|
||||
add_subdirectory(perf)
|
||||
add_subdirectory(signal)
|
||||
add_subdirectory(socket)
|
||||
add_subdirectory(string)
|
||||
add_subdirectory(time)
|
||||
|
@ -90,6 +90,7 @@ void *__wrap_realloc(void *p, size_t n)
|
||||
|
||||
void fail_test()
|
||||
{
|
||||
int tmp;
|
||||
int *arr, total = 0;
|
||||
|
||||
assert(sc_array_create(arr, SIZE_MAX) == false);
|
||||
@ -160,6 +161,12 @@ void fail_test()
|
||||
assert(arr[i] == i);
|
||||
}
|
||||
|
||||
total = 0;
|
||||
sc_array_foreach(arr, tmp) {
|
||||
total += tmp;
|
||||
}
|
||||
assert(total == 10);
|
||||
|
||||
sc_array_destroy(arr);
|
||||
}
|
||||
#else
|
||||
|
@ -37,7 +37,7 @@
|
||||
#elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
|
||||
#define SIZE_T_BITS 64
|
||||
#else
|
||||
#error TBD code SIZE_T_BITS
|
||||
#error unknown size_t bits
|
||||
#endif
|
||||
|
||||
bool sc_math_is_pow2(size_t num)
|
||||
|
117
signal/CMakeLists.txt
Normal file
117
signal/CMakeLists.txt
Normal file
@ -0,0 +1,117 @@
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
project(sc_signal C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
add_executable(sc_signal signal_example.c sc_signal.h sc_signal.c)
|
||||
|
||||
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -pedantic -Werror -D_GNU_SOURCE")
|
||||
endif ()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# --------------------- Test Configuration Start ---------------------------- #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
include(CTest)
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_executable(${PROJECT_NAME}_test signal_test.c sc_signal.c)
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_SIZE_MAX=1400000ul)
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
void *array[10];
|
||||
size_t size = backtrace(array, 10);
|
||||
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
||||
return 0;
|
||||
}" HAVE_BACKTRACE)
|
||||
|
||||
FIND_LIBRARY(EXECINFO_LIBRARY NAMES execinfo)
|
||||
IF (EXECINFO_LIBRARY)
|
||||
SET(CMAKE_REQUIRED_LIBRARIES "${EXECINFO_LIBRARY}")
|
||||
ENDIF(EXECINFO_LIBRARY)
|
||||
|
||||
if (${HAVE_BACKTRACE})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_BACKTRACE")
|
||||
endif ()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-omit-frame-pointer)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -DSC_HAVE_WRAP)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-builtin)
|
||||
#target_link_options(${PROJECT_NAME}_test PRIVATE -Wl,--wrap=realloc)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang" OR
|
||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fno-omit-frame-pointer)
|
||||
|
||||
if (SANITIZER)
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE -fsanitize=${SANITIZER})
|
||||
target_link_options(${PROJECT_NAME}_test PRIVATE -fsanitize=${SANITIZER})
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
|
||||
|
||||
SET(MEMORYCHECK_COMMAND_OPTIONS
|
||||
"-q --log-fd=2 --trace-children=yes --track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--error-exitcode=255")
|
||||
|
||||
add_custom_target(valgrind_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
-E env CTEST_OUTPUT_ON_FAILURE=1
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG>
|
||||
--overwrite MemoryCheckCommandOptions=${MEMORYCHECK_COMMAND_OPTIONS}
|
||||
--verbose -T memcheck WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_custom_target(check_${PROJECT_NAME} ${CMAKE_COMMAND}
|
||||
-E env CTEST_OUTPUT_ON_FAILURE=1
|
||||
${CMAKE_CTEST_COMMAND} -C $<CONFIG> --verbose
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# ----------------------- - Code Coverage Start ----------------------------- #
|
||||
|
||||
if (${CMAKE_BUILD_TYPE} MATCHES "Coverage")
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
|
||||
target_compile_options(${PROJECT_NAME}_test PRIVATE --coverage)
|
||||
target_link_libraries(${PROJECT_NAME}_test gcov)
|
||||
else ()
|
||||
message(FATAL_ERROR "Only GCC is supported for coverage")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
add_custom_target(coverage_${PROJECT_NAME})
|
||||
add_custom_command(
|
||||
TARGET coverage_${PROJECT_NAME}
|
||||
COMMAND lcov --capture --directory ..
|
||||
--output-file coverage.info --rc lcov_branch_coverage=1
|
||||
COMMAND lcov --remove coverage.info '/usr/*' '*example*' '*test*'
|
||||
--output-file coverage.info --rc lcov_branch_coverage=1
|
||||
COMMAND lcov --list coverage.info --rc lcov_branch_coverage=1
|
||||
)
|
||||
|
||||
add_dependencies(coverage_${PROJECT_NAME} check_${PROJECT_NAME})
|
||||
|
||||
# -------------------------- Code Coverage End ------------------------------ #
|
||||
|
||||
|
||||
# ----------------------- Test Configuration End ---------------------------- #
|
||||
|
495
signal/sc_signal.c
Normal file
495
signal/sc_signal.c
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sc_signal.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define get_uint(va, size) \
|
||||
(size) == 3 ? va_arg(va, unsigned long long) : \
|
||||
(size) == 2 ? va_arg(va, unsigned long) : \
|
||||
(size) == 1 ? va_arg(va, unsigned int) : \
|
||||
0
|
||||
|
||||
#define get_int(va, size) \
|
||||
(size) == 3 ? va_arg(va, long long) : \
|
||||
(size) == 2 ? va_arg(va, long) : \
|
||||
(size) == 1 ? va_arg(va, int) : \
|
||||
0
|
||||
|
||||
int sc_signal_vsnprintf(char *buf, size_t size, const char *fmt, va_list va)
|
||||
{
|
||||
size_t len;
|
||||
size_t out_cap = size == 0 ? 0 : size - 1;
|
||||
char *str;
|
||||
char *out = buf;
|
||||
char *pos = (char *) fmt;
|
||||
char digits[32];
|
||||
|
||||
while (true) {
|
||||
char *orig = pos;
|
||||
|
||||
switch (*pos) {
|
||||
case '\0': {
|
||||
*out = '\0';
|
||||
return (int) (out - buf);
|
||||
}
|
||||
case '%': {
|
||||
pos++;
|
||||
switch (*pos) {
|
||||
case 's':
|
||||
str = (char *) va_arg(va, const char *);
|
||||
str = (str == NULL) ? "(null)" : str;
|
||||
len = strlen(str);
|
||||
break;
|
||||
case 'l':
|
||||
pos += (*(pos + 1) == 'l') ? 2 : 1;
|
||||
case 'd':
|
||||
case 'u':
|
||||
len = 0;
|
||||
|
||||
if (*pos == 'u') {
|
||||
uint64_t u64 = get_uint(va, pos - orig);
|
||||
|
||||
do {
|
||||
digits[31 - (len++)] = '0' + (u64 % 10);
|
||||
} while (u64 /= 10UL);
|
||||
|
||||
} else if (*pos == 'd') {
|
||||
int64_t i64 = get_int(va, pos - orig);
|
||||
uint64_t u64 = i64 < 0 ? -i64 : i64;
|
||||
|
||||
do {
|
||||
digits[31 - (len++)] = '0' + (u64 % 10);
|
||||
} while (u64 /= 10UL);
|
||||
|
||||
if (i64 < 0) {
|
||||
digits[31 - (len++)] = '-';
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
str = &digits[32 - len];
|
||||
break;
|
||||
case 'p': {
|
||||
char *arr = "0123456789abcdef";
|
||||
len = 0;
|
||||
int s = (sizeof(void *) == sizeof(unsigned long long)) ? 3 : 2;
|
||||
uint64_t u64 = get_uint(va, s);
|
||||
|
||||
do {
|
||||
digits[31 - (len++)] = arr[u64 % 16];
|
||||
} while (u64 /= 16UL);
|
||||
|
||||
digits[31 - (len++)] = 'x';
|
||||
digits[31 - (len++)] = '0';
|
||||
str = &digits[32 - len];
|
||||
} break;
|
||||
case '%':
|
||||
str = "%";
|
||||
len = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
} break;
|
||||
default: {
|
||||
while (*pos != '\0' && *pos != '%') {
|
||||
pos++;
|
||||
}
|
||||
str = orig;
|
||||
len = pos - orig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
len = len < out_cap ? len : out_cap;
|
||||
memcpy(out, str, len);
|
||||
|
||||
out += len;
|
||||
out_cap -= len;
|
||||
}
|
||||
}
|
||||
|
||||
int sc_signal_snprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = sc_signal_vsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#include <signal.h>
|
||||
#include <windows.h>
|
||||
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
static void sc_signal_log(int fd, char *buf, size_t len, char *fmt, ...)
|
||||
{
|
||||
int written;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
written = sc_signal_vsnprintf(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
write(fd, buf, written);
|
||||
}
|
||||
|
||||
BOOL WINAPI sc_console_handler(DWORD type)
|
||||
{
|
||||
int rc;
|
||||
char *err;
|
||||
char buf[128];
|
||||
int fd = sc_signal_log_fd != -1 ? sc_signal_log_fd : _fileno(stdout);
|
||||
|
||||
switch (type) {
|
||||
case CTRL_C_EVENT:
|
||||
err = "CTRL_C event";
|
||||
break;
|
||||
case CTRL_BREAK_EVENT:
|
||||
err = "CTRL_BREAK event";
|
||||
break;
|
||||
default:
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"Unknown console event [%d], shutting down! \n", type);
|
||||
_Exit(1);
|
||||
}
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Received : %s, (%d) \n", err, type);
|
||||
|
||||
if (sc_signal_will_shutdown != 0) {
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Forcing shut down! \n");
|
||||
_Exit(1);
|
||||
}
|
||||
|
||||
sc_signal_will_shutdown = 1;
|
||||
|
||||
if (sc_signal_shutdown_fd != INVALID_SOCKET) {
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Sending shutdown command. \n");
|
||||
rc = send(sc_signal_shutdown_fd, (void *) &(int){1}, 1, 0);
|
||||
if (rc != 1) {
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"Failed to send shutdown command, "
|
||||
"shutting down immediately! \n");
|
||||
_Exit(1);
|
||||
}
|
||||
} else {
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"No shutdown handler, shutting down! \n");
|
||||
_Exit(0);
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LONG WINAPI sc_signal_on_fatal(PEXCEPTION_POINTERS info)
|
||||
{
|
||||
char buf[128];
|
||||
int fd = sc_signal_log_fd != -1 ? sc_signal_log_fd : _fileno(stderr);
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Fatal signal : %d, shutting down! \n",
|
||||
info->ExceptionRecord->ExceptionCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sc_signal_std_on_fatal(int type)
|
||||
{
|
||||
char buf[128];
|
||||
int fd = sc_signal_log_fd != -1 ? sc_signal_log_fd : _fileno(stderr);
|
||||
const char *sig_str;
|
||||
|
||||
switch (type) {
|
||||
case SIGSEGV:
|
||||
sig_str = "SIGSEGV";
|
||||
break;
|
||||
case SIGABRT:
|
||||
sig_str = "SIGABRT";
|
||||
break;
|
||||
case SIGFPE:
|
||||
sig_str = "SIGFPE";
|
||||
break;
|
||||
case SIGILL:
|
||||
sig_str = "SIGILL";
|
||||
break;
|
||||
default:
|
||||
sig_str = "Unknown signal";
|
||||
break;
|
||||
}
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"Fatal signal : [%s][%d], shutting down! \n", sig_str, type);
|
||||
|
||||
_Exit(1);
|
||||
}
|
||||
|
||||
void sc_signal_std_on_shutdown(int type)
|
||||
{
|
||||
sc_console_handler(CTRL_C_EVENT);
|
||||
}
|
||||
int sc_signal_init()
|
||||
{
|
||||
BOOL b;
|
||||
sc_signal_log_fd = -1;
|
||||
sc_signal_shutdown_fd = -1;
|
||||
|
||||
b = SetConsoleCtrlHandler(sc_console_handler, TRUE);
|
||||
if (!b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetUnhandledExceptionFilter(sc_signal_on_fatal);
|
||||
signal(SIGABRT, sc_signal_std_on_fatal);
|
||||
signal(SIGINT, sc_signal_std_on_shutdown);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// clang-format off
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
|
||||
static void *sc_instruction(ucontext_t *uc)
|
||||
{
|
||||
void* insp = NULL;
|
||||
|
||||
#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||
insp = (void *) uc->uc_mcontext->__ss.__rip;
|
||||
#elif defined(__i386__)
|
||||
insp = (void *) uc->uc_mcontext->__ss.__eip;
|
||||
#else
|
||||
insp = (void *) arm_thread_state64_get_pc(uc->uc_mcontext->__ss);
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#if defined(__i386__) || ((defined(__x86_64__)) && defined(__ILP32__))
|
||||
insp = (void *) uc->uc_mcontext.gregs[REG_EIP];
|
||||
#elif defined(__x86_64__)
|
||||
insp = (void *) uc->uc_mcontext.gregs[REG_RIP];
|
||||
#elif defined(__ia64__)
|
||||
insp = (void *) uc->uc_mcontext.sc_ip;
|
||||
#elif defined(__arm__)
|
||||
insp = (void *) uc->uc_mcontext.arm_pc;
|
||||
#elif defined(__aarch64__)
|
||||
insp = (void *) uc->uc_mcontext.pc;
|
||||
#endif
|
||||
#elif defined(__FreeBSD__)
|
||||
#if defined(__i386__)
|
||||
insp = (void *) uc->uc_mcontext.mc_eip;
|
||||
#elif defined(__x86_64__)
|
||||
insp = (void *) uc->uc_mcontext.mc_rip;
|
||||
#endif
|
||||
#elif defined(__OpenBSD__)
|
||||
#if defined(__i386__)
|
||||
insp = (void *) uc->sc_eip;
|
||||
#elif defined(__x86_64__)
|
||||
insp = (void *) uc->sc_rip;
|
||||
#endif
|
||||
#elif defined(__NetBSD__)
|
||||
#if defined(__i386__)
|
||||
insp = (void *) uc->uc_mcontext.__gregs[_REG_EIP];
|
||||
#elif defined(__x86_64__)
|
||||
insp = (void *) uc->uc_mcontext.__gregs[_REG_RIP];
|
||||
#endif
|
||||
#elif defined(__DragonFly__)
|
||||
insp = (void *) uc->uc_mcontext.mc_rip;
|
||||
#endif
|
||||
|
||||
return insp;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
static void sc_signal_log(int fd, char *buf, size_t len, char *fmt, ...)
|
||||
{
|
||||
int written;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
written = sc_signal_vsnprintf(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
write(fd, buf, written);
|
||||
}
|
||||
|
||||
static void sc_signal_on_shutdown(int sig)
|
||||
{
|
||||
int rc;
|
||||
int fd = sc_signal_log_fd != -1 ? sc_signal_log_fd : STDOUT_FILENO;
|
||||
char buf[4096], *sig_str;
|
||||
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
sig_str = "SIGINT";
|
||||
break;
|
||||
case SIGTERM:
|
||||
sig_str = "SIGTERM";
|
||||
break;
|
||||
default:
|
||||
sig_str = "Shutdown signal";
|
||||
break;
|
||||
}
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Received : %s, (%d) \n", sig_str, sig);
|
||||
|
||||
if (sc_signal_will_shutdown != 0) {
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Forcing shut down! \n");
|
||||
_Exit(1);
|
||||
}
|
||||
|
||||
sc_signal_will_shutdown = 1;
|
||||
|
||||
if (sc_signal_shutdown_fd != -1) {
|
||||
sc_signal_log(fd, buf, sizeof(buf), "Sending shutdown command. \n");
|
||||
rc = write(sc_signal_shutdown_fd, (void *) &(int){1}, 1);
|
||||
if (rc != 1) {
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"Failed to send shutdown command, "
|
||||
"shutting down immediately! \n");
|
||||
_Exit(1);
|
||||
}
|
||||
} else {
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"No shutdown handler, shutting down! \n");
|
||||
_Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void sc_signal_on_fatal(int sig, siginfo_t *info, void *context)
|
||||
{
|
||||
int fd = sc_signal_log_fd != -1 ? sc_signal_log_fd : STDERR_FILENO;
|
||||
|
||||
char buf[4096], *sig_str;
|
||||
struct sigaction act;
|
||||
|
||||
switch (sig) {
|
||||
case SIGSEGV:
|
||||
sig_str = "SIGSEGV";
|
||||
break;
|
||||
case SIGABRT:
|
||||
sig_str = "SIGABRT";
|
||||
break;
|
||||
case SIGBUS:
|
||||
sig_str = "SIGBUS";
|
||||
break;
|
||||
case SIGFPE:
|
||||
sig_str = "SIGFPE";
|
||||
break;
|
||||
case SIGILL:
|
||||
sig_str = "SIGILL";
|
||||
break;
|
||||
default:
|
||||
sig_str = "Unknown signal";
|
||||
break;
|
||||
}
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf), "\nSignal received : [%d][%s] \n", sig,
|
||||
sig_str);
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"\n----------------- CRASH REPORT ---------------- \n");
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
void *caller = sc_instruction((ucontext_t *) context);
|
||||
int trace_size;
|
||||
void *trace[100];
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf), "\n Caller [%p] \n\n", caller);
|
||||
|
||||
trace_size = backtrace(trace, 100);
|
||||
backtrace_symbols_fd(trace, trace_size, fd);
|
||||
#endif
|
||||
sc_signal_log(fd, buf, sizeof(buf),
|
||||
"\n--------------- CRASH REPORT END -------------- \n");
|
||||
|
||||
sc_signal_log(fd, buf, sizeof(buf), "\nSignal handler completed! \n");
|
||||
close(fd);
|
||||
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction(sig, &act, NULL);
|
||||
|
||||
kill(getpid(), sig);
|
||||
}
|
||||
|
||||
int sc_signal_init()
|
||||
{
|
||||
bool rc = true;
|
||||
struct sigaction action;
|
||||
|
||||
sc_signal_log_fd = -1;
|
||||
sc_signal_shutdown_fd = -1;
|
||||
|
||||
rc &= (signal(SIGHUP, SIG_IGN) != SIG_ERR);
|
||||
rc &= (signal(SIGPIPE, SIG_IGN) != SIG_ERR);
|
||||
rc &= (sigemptyset(&action.sa_mask) == 0);
|
||||
|
||||
action.sa_flags = 0;
|
||||
action.sa_handler = sc_signal_on_shutdown;
|
||||
|
||||
rc &= (sigaction(SIGTERM, &action, NULL) == 0);
|
||||
rc &= (sigaction(SIGINT, &action, NULL) == 0);
|
||||
|
||||
rc &= (sigemptyset(&action.sa_mask) == 0);
|
||||
action.sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
|
||||
action.sa_sigaction = sc_signal_on_fatal;
|
||||
|
||||
rc &= (sigaction(SIGABRT, &action, NULL) == 0);
|
||||
rc &= (sigaction(SIGSEGV, &action, NULL) == 0);
|
||||
rc &= (sigaction(SIGBUS, &action, NULL) == 0);
|
||||
rc &= (sigaction(SIGFPE, &action, NULL) == 0);
|
||||
rc &= (sigaction(SIGILL, &action, NULL) == 0);
|
||||
|
||||
return rc ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
45
signal/sc_signal.h
Normal file
45
signal/sc_signal.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 Ozan Tezcan
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SC_SIGNAL_H
|
||||
#define SC_SIGNAL_H
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
volatile SOCKET sc_signal_shutdown_fd;
|
||||
#else
|
||||
volatile sig_atomic_t sc_signal_shutdown_fd;
|
||||
#endif
|
||||
|
||||
volatile sig_atomic_t sc_signal_log_fd;
|
||||
volatile sig_atomic_t sc_signal_will_shutdown;
|
||||
|
||||
int sc_signal_init();
|
||||
int sc_signal_vsnprintf(char *buf, size_t size, const char *fmt, va_list va);
|
||||
int sc_signal_snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
|
||||
#endif
|
7
signal/signal_example.c
Normal file
7
signal/signal_example.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include "sc_signal.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
280
signal/signal_test.c
Normal file
280
signal/signal_test.c
Normal file
@ -0,0 +1,280 @@
|
||||
#include "sc_signal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
typedef SOCKET sc_sock_int;
|
||||
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
typedef int sc_sock_int;
|
||||
#endif
|
||||
|
||||
enum sc_sock_ev
|
||||
{
|
||||
SC_SOCK_NONE = 0u,
|
||||
SC_SOCK_READ = 1u,
|
||||
SC_SOCK_WRITE = 2u,
|
||||
};
|
||||
|
||||
enum sc_sock_family
|
||||
{
|
||||
SC_SOCK_INET = AF_INET,
|
||||
SC_SOCK_INET6 = AF_INET6,
|
||||
SC_SOCK_UNIX = AF_UNIX
|
||||
};
|
||||
|
||||
struct sc_sock_fd
|
||||
{
|
||||
sc_sock_int fd;
|
||||
enum sc_sock_ev op;
|
||||
int type;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct sc_sock_pipe
|
||||
{
|
||||
struct sc_sock_fd fdt;
|
||||
sc_sock_int fds[2];
|
||||
};
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
int sc_sock_pipe_init(struct sc_sock_pipe *p, int type)
|
||||
{
|
||||
SOCKET listener;
|
||||
int rc;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
int val = 1;
|
||||
BOOL nodelay = 1;
|
||||
|
||||
p->fdt.type = type;
|
||||
p->fds[0] = INVALID_SOCKET;
|
||||
p->fds[1] = INVALID_SOCKET;
|
||||
|
||||
/* Create listening socket. */
|
||||
listener = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listener == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &val,
|
||||
sizeof(val));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
addr.sin_port = 0;
|
||||
|
||||
rc = bind(listener, (const struct sockaddr *) &addr, sizeof(addr));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = getsockname(listener, (struct sockaddr *) &addr, &addrlen);
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = listen(listener, 1);
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
p->fds[1] = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (p->fds[1] == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = setsockopt(p->fds[1], IPPROTO_TCP, TCP_NODELAY, (char *) &nodelay,
|
||||
sizeof(nodelay));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
rc = connect(p->fds[1], (struct sockaddr *) &addr, sizeof(addr));
|
||||
if (rc == SOCKET_ERROR) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
p->fds[0] = accept(listener, (struct sockaddr *) &addr, &addrlen);
|
||||
if (p->fds[0] == INVALID_SOCKET) {
|
||||
goto wsafail;
|
||||
}
|
||||
|
||||
closesocket(listener);
|
||||
|
||||
return 0;
|
||||
|
||||
wsafail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sc_sock_pipe_term(struct sc_sock_pipe *p)
|
||||
{
|
||||
int rc = 0, rv;
|
||||
|
||||
rv = closesocket(p->fds[0]);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
rv = closesocket(p->fds[1]);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_sock_pipe_write(struct sc_sock_pipe *p, void *data, int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = send(p->fds[1], data, len, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_sock_pipe_read(struct sc_sock_pipe *p, void *data, int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = recv(p->fds[0], (char *) data, len, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int sc_sock_pipe_init(struct sc_sock_pipe *p, int type)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pipe(p->fds);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->fdt.type = type;
|
||||
p->fdt.op = 0;
|
||||
p->fdt.fd = p->fds[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_sock_pipe_term(struct sc_sock_pipe *p)
|
||||
{
|
||||
int rc = 0, rv;
|
||||
|
||||
rv = close(p->fds[0]);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
rv = close(p->fds[1]);
|
||||
if (rv != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sc_sock_pipe_write(struct sc_sock_pipe *p, void *data, int len)
|
||||
{
|
||||
ssize_t n;
|
||||
char *b = data;
|
||||
|
||||
retry:
|
||||
n = write(p->fds[1], b, len);
|
||||
if (n == -1 && errno == EINTR) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (n > 0 && n != len) {
|
||||
len -= n;
|
||||
b += n;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int sc_sock_pipe_read(struct sc_sock_pipe *p, void *data, int len)
|
||||
{
|
||||
ssize_t n;
|
||||
char *b = data;
|
||||
|
||||
retry:
|
||||
n = read(p->fds[0], b, len);
|
||||
if (n == -1 && errno == EINTR) {
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (n > 0 && n != len) {
|
||||
len -= n;
|
||||
b += n;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
void test1()
|
||||
{
|
||||
int rc;
|
||||
char buf[32];
|
||||
struct sc_sock_pipe pipe;
|
||||
|
||||
rc = sc_signal_init();
|
||||
assert(rc == 0);
|
||||
|
||||
rc = sc_sock_pipe_init(&pipe, 0);
|
||||
assert(rc == 0);
|
||||
|
||||
sc_signal_shutdown_fd = pipe.fds[1];
|
||||
raise(SIGINT);
|
||||
|
||||
rc = sc_sock_pipe_read(&pipe, buf, 1);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = sc_sock_pipe_term(&pipe);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSADATA data;
|
||||
|
||||
int rc = WSAStartup(MAKEWORD(2, 2), &data);
|
||||
assert(rc == 0);
|
||||
assert(LOBYTE(data.wVersion) == 2 && HIBYTE(data.wVersion) == 2);
|
||||
#endif
|
||||
|
||||
test1();
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
rc = WSACleanup();
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@ -466,7 +466,7 @@ retry:
|
||||
}
|
||||
|
||||
if (!sock->blocking && err == SC_EAGAIN) {
|
||||
return 0;
|
||||
return SC_SOCK_WANT_WRITE;
|
||||
}
|
||||
|
||||
sc_sock_errstr(sock, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user