* 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:
Tezc 2020-11-29 19:37:24 +03:00 committed by GitHub
parent 46d77f2fe6
commit ef6c1983ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 954 additions and 2 deletions

View File

@ -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)

View File

@ -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

View File

@ -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
View 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
View 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
View 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
View File

@ -0,0 +1,7 @@
#include "sc_signal.h"
int main()
{
return 0;
}

280
signal/signal_test.c Normal file
View 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;
}

View File

@ -466,7 +466,7 @@ retry:
}
if (!sock->blocking && err == SC_EAGAIN) {
return 0;
return SC_SOCK_WANT_WRITE;
}
sc_sock_errstr(sock, 0);