diff --git a/CMakeLists.txt b/CMakeLists.txt index a13428204..abc6f1581 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,8 +121,26 @@ set(ev_src_lua "src/lua/udp.lua.c" ) +############################################################################### +# Support functions +############################################################################### +function(ev_setup_target_wall name) + if (CMAKE_C_COMPILER_ID STREQUAL "MSVC") + target_compile_options(${name} PRIVATE /W4 /WX) + else () + target_compile_options(${name} PRIVATE -Wall -Wextra -Werror) + endif () +endfunction() + +############################################################################### +# Dependency +############################################################################### include(third_party/lua54.cmake) +include(tool/CMakeLists.txt) +############################################################################### +# Build libev +############################################################################### string(REPLACE ";" "," escaped_ev_src "${ev_src}") string(REPLACE ";" "," escaped_ev_src_os_win "${ev_src_os_win}") string(REPLACE ";" "," escaped_ev_src_os_unix "${ev_src_os_unix}") @@ -130,7 +148,7 @@ string(REPLACE ";" "," escaped_ev_src_lua "${ev_src_lua}") add_custom_command( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ev.h - COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/amalgamate.lua + COMMAND $ --no_line --out ${CMAKE_CURRENT_SOURCE_DIR}/ev.h --commit ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE @@ -147,8 +165,7 @@ add_custom_command( --source "include/ev.h" --source "include/ev/lua.h" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/amalgamate.lua - ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/CHANGELOG.md ${CMAKE_CURRENT_SOURCE_DIR}/include/ev/expose.h ${CMAKE_CURRENT_SOURCE_DIR}/include/ev/version.h @@ -163,7 +180,7 @@ add_custom_command( add_custom_command( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ev.c - COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/amalgamate.lua + COMMAND $ --no_line --out ${CMAKE_CURRENT_SOURCE_DIR}/ev.c --commit ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE @@ -183,8 +200,7 @@ add_custom_command( --source ${escaped_ev_src_lua} --string "#endif /* FEATURE: EV_HAVE_LUA_BINDING (2/2) */" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/amalgamate.lua - ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/ev.h ${ev_src} ${ev_src_os_win} @@ -216,14 +232,6 @@ else() target_link_libraries(${PROJECT_NAME} PRIVATE rt) endif() -function(ev_setup_target_wall name) - if (CMAKE_C_COMPILER_ID STREQUAL "MSVC") - target_compile_options(${name} PRIVATE /W4 /WX) - else () - target_compile_options(${name} PRIVATE -Wall -Wextra -Werror) - endif () -endfunction() - # add warning check ev_setup_target_wall(${PROJECT_NAME}) @@ -233,10 +241,14 @@ if (EV_ENABLE_COVERAGE AND CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang)") set(EV_HAVE_COVERAGE true) endif () -# build examples +############################################################################### +# Build examples +############################################################################### add_subdirectory(example) -# build test +############################################################################### +# Build test +############################################################################### if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) include(CTest) endif() diff --git a/amalgamate.lua b/amalgamate.lua deleted file mode 100644 index 431442830..000000000 --- a/amalgamate.lua +++ /dev/null @@ -1,92 +0,0 @@ - -local opt = { - no_line = false -} - -local out_path = nil -local out_data = "" - -local function split_string (inputstr) - local sep = "," - local t={} - for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do - table.insert(t, str) - end - return t -end - --- Read file and return content -local function read_file(path) - local file = io.open(path) - local data = file:read("a") - file:close() - return data -end - --- Write content into file -local function write_file(path, content) - local f = io.open(path, "w") - f:write(content) - f:close() -end - -local function append_source(paths) - local path_list = split_string(paths) - for _,v in ipairs(path_list) do - local content = read_file(v) - local pattern = "#%s*include%s+\"([-_%w%./]+)%.h\"" - local replace = "/* AMALGAMATE: %0 */" - - content = string.gsub(content, pattern, replace) - - if opt.no_line == false then - out_data = out_data .. "#line 1 \"" .. v .. "\"\n" - end - out_data = out_data .. content .. "\n" - end -end - -local function append_commit(path) - out_data = out_data .. "/**\n" - local f = io.open(path) - while true do - local d = f:read() - if d == nil then - break - end - out_data = out_data .. " * " .. d .. "\n" - end - f:close() - out_data = out_data .. " */\n" -end - -local function append_string(str) - out_data = out_data .. str .. "\n" -end - -for i,v in ipairs(arg) do - if v == "--no_line" then - opt.no_line = true - end - - if v == "--out" then - out_path = arg[i+1] - end - - if v == "--commit" then - append_commit(arg[i+1]) - end - - if v == "--source" then - append_source(arg[i+1]) - end - - if v == "--string" then - append_string(arg[i+1]) - end -end - -assert(out_path ~= nil) - --- Write file -write_file(out_path, out_data) diff --git a/ev.c b/ev.c index 59e30dc21..541e66258 100644 --- a/ev.c +++ b/ev.c @@ -1,30 +1,30 @@ -/** - * MIT License - * - * Copyright (c) 2021 qgymib - * - * 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. - */ -#define EV_AMALGAMATE_BUILD -#define EV_EXPOSE_SYMBOLS -#define _GNU_SOURCE -#include "ev.h" +/** + * MIT License + * + * Copyright (c) 2021 qgymib + * + * 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. + */ +#define EV_AMALGAMATE_BUILD +#define EV_EXPOSE_SYMBOLS +#define _GNU_SOURCE +#include "ev.h" #ifndef __EV_DEFINES_INTERNAL_H__ #define __EV_DEFINES_INTERNAL_H__ @@ -182,27 +182,27 @@ extern "C" { } #endif #endif - -#ifndef __EV_ALLOCATOR_INTERNAL_H__ -#define __EV_ALLOCATOR_INTERNAL_H__ - -/* AMALGAMATE: #include "defs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Same as [strdup(3)](https://man7.org/linux/man-pages/man3/strdup.3.html) - */ -EV_LOCAL char* ev__strdup(const char* str); - -#ifdef __cplusplus -} -#endif - -#endif - + +#ifndef __EV_ALLOCATOR_INTERNAL_H__ +#define __EV_ALLOCATOR_INTERNAL_H__ + +/* AMALGAMATE: #include "defs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Same as [strdup(3)](https://man7.org/linux/man-pages/man3/strdup.3.html) + */ +EV_LOCAL char* ev__strdup(const char* str); + +#ifdef __cplusplus +} +#endif + +#endif + #ifndef __EV_ASYNC_COMMON_H__ #define __EV_ASYNC_COMMON_H__ @@ -223,126 +223,126 @@ EV_LOCAL void ev__async_exit_force(ev_async_t* handle); } #endif #endif - -#ifndef __EV_HANDLE_INTERNAL_H__ -#define __EV_HANDLE_INTERNAL_H__ - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "defs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum ev_handle_flag -{ - /* Used by all handles. Bit 0-7. */ - EV_HANDLE_CLOSING = 0x01 << 0x00, /**< 1. Handle is going to close */ - EV_HANDLE_CLOSED = 0x01 << 0x01, /**< 2. Handle is closed */ - EV_HANDLE_ACTIVE = 0x01 << 0x02, /**< 4. Handle is busy */ - - /* #EV_ROLE_EV_TCP */ - EV_HANDLE_TCP_LISTING = 0x01 << 0x08, /**< 256. This is a listen socket and is listening */ - EV_HANDLE_TCP_ACCEPTING = 0x01 << 0x09, /**< 512. This is a socket waiting for accept */ - EV_HANDLE_TCP_STREAMING = 0x01 << 0x0A, /**< 1024. This is a socket waiting for read or write */ - EV_HANDLE_TCP_CONNECTING = 0x01 << 0x0B, /**< 2048. This is a connect and waiting for connect complete */ - EV_HABDLE_TCP_BOUND = 0x01 << 0x0C, /**< 4096. Socket is bond to address */ - - /* #EV_ROLE_EV_UDP */ - EV_HANDLE_UDP_IPV6 = 0x01 << 0x08, /**< 256. This socket have IPv6 ability */ - EV_HANDLE_UDP_CONNECTED = 0x01 << 0x09, /**< 512. This socket is connected */ - EV_HANDLE_UDP_BOUND = 0x01 << 0x0A, /**< 1024. Socket is bond to address */ - EV_HANDLE_UDP_BYPASS_IOCP = 0x01 << 0x0B, /**< 2048. FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS */ - - /* #EV_ROLE_EV_PIPE */ - EV_HANDLE_PIPE_IPC = 0x01 << 0x08, /**< 256. This pipe is support IPC */ - EV_HANDLE_PIPE_STREAMING = 0x01 << 0x09, /**< 512. This pipe is initialized by #ev_stream_t */ -} ev_handle_flag_t; - -/** - * @brief Initialize a handle. - * - * A initialized handle will be linked with \p loop. By default the \p handle - * is in #ev_loop_t::handles::idle_list. If the \p handle is active (The event - * counter is non-zero), the handle is moved into #ev_loop_t::handles::active_list. - * - * @note Once a handle is initialized, it must call #ev__handle_exit() when no - * longer needed. - * @param[in] loop The loop own the handle - * @param[out] handle A pointer to the structure - * @param[in] role Who we are - */ -EV_LOCAL void ev__handle_init(ev_loop_t* loop, ev_handle_t* handle, ev_role_t role); - -/** - * @brief Close the handle - * @note The handle will not closed until close_cb was called, which was given - * by #ev__handle_init() - * @note #ev__handle_exit() never reset active_events counter for you. You always - * need to balance active_events counter yourself. - * @param[in] handle handler - * @param[in] close_cb Close callback. If non-null, the \p close_cb will be - * called in next event loop. If null, the handle will be closed synchronously. - */ -EV_LOCAL void ev__handle_exit(ev_handle_t* handle, ev_handle_cb close_cb); - -/** - * @brief Add active event counter. If active event counter is non-zero, - * #EV_HANDLE_ACTIVE is appended. - * @param[in] handle Handler. - */ -EV_LOCAL void ev__handle_event_add(ev_handle_t* handle); - -/** - * @brief Decrease active event counter. If active event counter is zero, - * #EV_HANDLE_ACTIVE is removed. - * @param[in] handle Handler. - */ -EV_LOCAL void ev__handle_event_dec(ev_handle_t* handle); - -/** - * @brief Check if the handle is in active state - * @param[in] handle handler - * @return bool - */ -EV_LOCAL int ev__handle_is_active(ev_handle_t* handle); - -/** - * @brief Check if the handle is in closing or closed state - * @param[in] handle handler - * @return bool - */ -EV_LOCAL int ev__handle_is_closing(ev_handle_t* handle); - -/** - * @brief Queue a task. - * This task will be execute in next loop. - * @param[in] handle handler. - * @param[in] callback Task callback - * @return #ev_errno_t - */ -EV_LOCAL int ev__backlog_submit(ev_handle_t* handle, ev_handle_cb callback); - -/** - * @brief Process backlog events. - * @param[in] loop Event loop. - * @return Active count. - */ -EV_LOCAL size_t ev__process_backlog(ev_loop_t* loop); - -/** - * @brief Process endgame events. - * @param[in] loop Event loop. - * @return Active count. - */ -EV_LOCAL size_t ev__process_endgame(ev_loop_t* loop); - -#ifdef __cplusplus -} -#endif - -#endif - + +#ifndef __EV_HANDLE_INTERNAL_H__ +#define __EV_HANDLE_INTERNAL_H__ + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "defs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum ev_handle_flag +{ + /* Used by all handles. Bit 0-7. */ + EV_HANDLE_CLOSING = 0x01 << 0x00, /**< 1. Handle is going to close */ + EV_HANDLE_CLOSED = 0x01 << 0x01, /**< 2. Handle is closed */ + EV_HANDLE_ACTIVE = 0x01 << 0x02, /**< 4. Handle is busy */ + + /* #EV_ROLE_EV_TCP */ + EV_HANDLE_TCP_LISTING = 0x01 << 0x08, /**< 256. This is a listen socket and is listening */ + EV_HANDLE_TCP_ACCEPTING = 0x01 << 0x09, /**< 512. This is a socket waiting for accept */ + EV_HANDLE_TCP_STREAMING = 0x01 << 0x0A, /**< 1024. This is a socket waiting for read or write */ + EV_HANDLE_TCP_CONNECTING = 0x01 << 0x0B, /**< 2048. This is a connect and waiting for connect complete */ + EV_HABDLE_TCP_BOUND = 0x01 << 0x0C, /**< 4096. Socket is bond to address */ + + /* #EV_ROLE_EV_UDP */ + EV_HANDLE_UDP_IPV6 = 0x01 << 0x08, /**< 256. This socket have IPv6 ability */ + EV_HANDLE_UDP_CONNECTED = 0x01 << 0x09, /**< 512. This socket is connected */ + EV_HANDLE_UDP_BOUND = 0x01 << 0x0A, /**< 1024. Socket is bond to address */ + EV_HANDLE_UDP_BYPASS_IOCP = 0x01 << 0x0B, /**< 2048. FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS */ + + /* #EV_ROLE_EV_PIPE */ + EV_HANDLE_PIPE_IPC = 0x01 << 0x08, /**< 256. This pipe is support IPC */ + EV_HANDLE_PIPE_STREAMING = 0x01 << 0x09, /**< 512. This pipe is initialized by #ev_stream_t */ +} ev_handle_flag_t; + +/** + * @brief Initialize a handle. + * + * A initialized handle will be linked with \p loop. By default the \p handle + * is in #ev_loop_t::handles::idle_list. If the \p handle is active (The event + * counter is non-zero), the handle is moved into #ev_loop_t::handles::active_list. + * + * @note Once a handle is initialized, it must call #ev__handle_exit() when no + * longer needed. + * @param[in] loop The loop own the handle + * @param[out] handle A pointer to the structure + * @param[in] role Who we are + */ +EV_LOCAL void ev__handle_init(ev_loop_t* loop, ev_handle_t* handle, ev_role_t role); + +/** + * @brief Close the handle + * @note The handle will not closed until close_cb was called, which was given + * by #ev__handle_init() + * @note #ev__handle_exit() never reset active_events counter for you. You always + * need to balance active_events counter yourself. + * @param[in] handle handler + * @param[in] close_cb Close callback. If non-null, the \p close_cb will be + * called in next event loop. If null, the handle will be closed synchronously. + */ +EV_LOCAL void ev__handle_exit(ev_handle_t* handle, ev_handle_cb close_cb); + +/** + * @brief Add active event counter. If active event counter is non-zero, + * #EV_HANDLE_ACTIVE is appended. + * @param[in] handle Handler. + */ +EV_LOCAL void ev__handle_event_add(ev_handle_t* handle); + +/** + * @brief Decrease active event counter. If active event counter is zero, + * #EV_HANDLE_ACTIVE is removed. + * @param[in] handle Handler. + */ +EV_LOCAL void ev__handle_event_dec(ev_handle_t* handle); + +/** + * @brief Check if the handle is in active state + * @param[in] handle handler + * @return bool + */ +EV_LOCAL int ev__handle_is_active(ev_handle_t* handle); + +/** + * @brief Check if the handle is in closing or closed state + * @param[in] handle handler + * @return bool + */ +EV_LOCAL int ev__handle_is_closing(ev_handle_t* handle); + +/** + * @brief Queue a task. + * This task will be execute in next loop. + * @param[in] handle handler. + * @param[in] callback Task callback + * @return #ev_errno_t + */ +EV_LOCAL int ev__backlog_submit(ev_handle_t* handle, ev_handle_cb callback); + +/** + * @brief Process backlog events. + * @param[in] loop Event loop. + * @return Active count. + */ +EV_LOCAL size_t ev__process_backlog(ev_loop_t* loop); + +/** + * @brief Process endgame events. + * @param[in] loop Event loop. + * @return Active count. + */ +EV_LOCAL size_t ev__process_endgame(ev_loop_t* loop); + +#ifdef __cplusplus +} +#endif + +#endif + #ifndef __EV_LOOP_INTERNAL_H__ #define __EV_LOOP_INTERNAL_H__ #ifdef __cplusplus @@ -449,7 +449,7 @@ EV_LOCAL void ev__poll(ev_loop_t* loop, uint32_t timeout); } #endif #endif - + #ifndef __EV_FILE_INTERNAL_H__ #define __EV_FILE_INTERNAL_H__ @@ -576,32 +576,32 @@ EV_LOCAL int ev__fs_remove(const char* path, int recursive); } #endif #endif - -#ifndef __EV_MISC_INTERNAL_H__ -#define __EV_MISC_INTERNAL_H__ - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "defs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Translate system error into #ev_errno_t - * @param[in] syserr System error - * @return #ev_errno_t - */ -EV_LOCAL int ev__translate_sys_error(int syserr); - -EV_LOCAL int ev__translate_posix_sys_error(int syserr); - -#ifdef __cplusplus -} -#endif - -#endif - + +#ifndef __EV_MISC_INTERNAL_H__ +#define __EV_MISC_INTERNAL_H__ + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "defs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Translate system error into #ev_errno_t + * @param[in] syserr System error + * @return #ev_errno_t + */ +EV_LOCAL int ev__translate_sys_error(int syserr); + +EV_LOCAL int ev__translate_posix_sys_error(int syserr); + +#ifdef __cplusplus +} +#endif + +#endif + #ifndef __EV_PIPE_COMMON_INTERNAL_H__ #define __EV_PIPE_COMMON_INTERNAL_H__ @@ -667,7 +667,7 @@ EV_LOCAL int ev__pipe_write_init_ext(ev_pipe_write_req_t* req, ev_pipe_write_cb } #endif #endif - + #ifndef __EV_RINGBUFFER_INTERNAL_H__ #define __EV_RINGBUFFER_INTERNAL_H__ @@ -875,7 +875,7 @@ EV_LOCAL ring_buffer_token_t* ring_buffer_next(const ring_buffer_t* handler, } #endif #endif - + #ifndef __EV_THREADPOOL_INTERNAL_H__ #define __EV_THREADPOOL_INTERNAL_H__ @@ -1021,36 +1021,36 @@ EV_LOCAL void ev__threadpool_wakeup(ev_loop_t* loop); #endif #endif - -#ifndef __EV_TIMER_INTERNAL_H__ -#define __EV_TIMER_INTERNAL_H__ - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "defs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Initialize timer context. - * @param[out] loop Event loop - */ -EV_LOCAL void ev__init_timer(ev_loop_t* loop); - -/** - * @brief Process timer. - * @param[in] loop Event loop - * @return Active counter - */ -EV_LOCAL size_t ev__process_timer(ev_loop_t* loop); - -#ifdef __cplusplus -} -#endif - -#endif - + +#ifndef __EV_TIMER_INTERNAL_H__ +#define __EV_TIMER_INTERNAL_H__ + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "defs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize timer context. + * @param[out] loop Event loop + */ +EV_LOCAL void ev__init_timer(ev_loop_t* loop); + +/** + * @brief Process timer. + * @param[in] loop Event loop + * @return Active counter + */ +EV_LOCAL size_t ev__process_timer(ev_loop_t* loop); + +#ifdef __cplusplus +} +#endif + +#endif + #ifndef __EV_LOG_INTERNAL_H__ #define __EV_LOG_INTERNAL_H__ @@ -1104,7 +1104,7 @@ EV_LOCAL void ev__dump_hex(const void* data, size_t size, size_t width); } #endif #endif - + #ifndef __EV_UDP_COMMON_INTERNAL_H__ #define __EV_UDP_COMMON_INTERNAL_H__ @@ -1146,94 +1146,94 @@ EV_LOCAL int ev__udp_send(ev_udp_t* udp, ev_udp_write_t* req, } #endif #endif - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "allocator.h" */ -#include -#include - -typedef struct ev_allocator -{ - ev_malloc_fn malloc_func; /**< malloc */ - ev_calloc_fn calloc_func; /**< calloc */ - ev_realloc_fn realloc_func; /**< realloc */ - ev_free_fn free_func; /**< free */ -}ev_allocator_t; - -static void* _ev_malloc(size_t size) -{ - return malloc(size); -} - -static void* _ev_calloc(size_t nmemb, size_t size) -{ - return calloc(nmemb, size); -} - -static void* _ev_realloc(void* ptr, size_t size) -{ - return realloc(ptr, size); -} - -static void _ev_free(void* ptr) -{ - free(ptr); -} - -static ev_allocator_t ev__allocator = { - _ev_malloc, /* .malloc_func */ - _ev_calloc, /* .calloc_func */ - _ev_realloc, /* .realloc_func */ - _ev_free, /* ._ev_free */ -}; - -int ev_replace_allocator(ev_malloc_fn malloc_func, ev_calloc_fn calloc_func, - ev_realloc_fn realloc_func, ev_free_fn free_func) -{ - if (malloc_func == NULL || calloc_func == NULL || realloc_func == NULL || free_func == NULL) - { - return EV_EINVAL; - } - - ev__allocator.malloc_func = malloc_func; - ev__allocator.calloc_func = calloc_func; - ev__allocator.realloc_func = realloc_func; - ev__allocator.free_func = free_func; - - return 0; -} - -void* ev_calloc(size_t nmemb, size_t size) -{ - return ev__allocator.calloc_func(nmemb, size); -} - -void* ev_malloc(size_t size) -{ - return ev__allocator.malloc_func(size); -} - -void* ev_realloc(void* ptr, size_t size) -{ - return ev__allocator.realloc_func(ptr, size); -} - -void ev_free(void* ptr) -{ - ev__allocator.free_func(ptr); -} - -EV_LOCAL char* ev__strdup(const char* s) -{ - size_t len = strlen(s) + 1; - char* m = ev_malloc(len); - if (m == NULL) - { - return NULL; - } - return memcpy(m, s, len); -} - + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "allocator.h" */ +#include +#include + +typedef struct ev_allocator +{ + ev_malloc_fn malloc_func; /**< malloc */ + ev_calloc_fn calloc_func; /**< calloc */ + ev_realloc_fn realloc_func; /**< realloc */ + ev_free_fn free_func; /**< free */ +}ev_allocator_t; + +static void* _ev_malloc(size_t size) +{ + return malloc(size); +} + +static void* _ev_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + +static void* _ev_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + +static void _ev_free(void* ptr) +{ + free(ptr); +} + +static ev_allocator_t ev__allocator = { + _ev_malloc, /* .malloc_func */ + _ev_calloc, /* .calloc_func */ + _ev_realloc, /* .realloc_func */ + _ev_free, /* ._ev_free */ +}; + +int ev_replace_allocator(ev_malloc_fn malloc_func, ev_calloc_fn calloc_func, + ev_realloc_fn realloc_func, ev_free_fn free_func) +{ + if (malloc_func == NULL || calloc_func == NULL || realloc_func == NULL || free_func == NULL) + { + return EV_EINVAL; + } + + ev__allocator.malloc_func = malloc_func; + ev__allocator.calloc_func = calloc_func; + ev__allocator.realloc_func = realloc_func; + ev__allocator.free_func = free_func; + + return 0; +} + +void* ev_calloc(size_t nmemb, size_t size) +{ + return ev__allocator.calloc_func(nmemb, size); +} + +void* ev_malloc(size_t size) +{ + return ev__allocator.malloc_func(size); +} + +void* ev_realloc(void* ptr, size_t size) +{ + return ev__allocator.realloc_func(ptr, size); +} + +void ev_free(void* ptr) +{ + ev__allocator.free_func(ptr); +} + +EV_LOCAL char* ev__strdup(const char* s) +{ + size_t len = strlen(s) + 1; + char* m = ev_malloc(len); + if (m == NULL) + { + return NULL; + } + return memcpy(m, s, len); +} + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ /* AMALGAMATE: #include "fs.h" */ @@ -2186,264 +2186,264 @@ EV_LOCAL int ev__fs_remove(const char* path, int recursive) finish: return _ev_fs_remove(path); } - + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "loop.h" */ +/* AMALGAMATE: #include "handle.h" */ +#include + +/** + * @brief Set handle as inactive + * @see ev__handle_event_dec() + * @param[in] handle handler + */ +static void ev__handle_deactive(ev_handle_t* handle) +{ + if (!(handle->data.flags & EV_HANDLE_ACTIVE)) + { + return; + } + handle->data.flags &= ~EV_HANDLE_ACTIVE; + + ev_loop_t* loop = handle->loop; + ev_list_erase(&loop->handles.active_list, &handle->handle_queue); + ev_list_push_back(&loop->handles.idle_list, &handle->handle_queue); +} + +/** + * @brief Force set handle as active, regardless the active event counter. + * @see ev__handle_event_add() + * @param[in] handle handler + */ +static void ev__handle_active(ev_handle_t* handle) +{ + if (handle->data.flags & EV_HANDLE_ACTIVE) + { + return; + } + handle->data.flags |= EV_HANDLE_ACTIVE; + + ev_loop_t* loop = handle->loop; + ev_list_erase(&loop->handles.idle_list, &handle->handle_queue); + ev_list_push_back(&loop->handles.active_list, &handle->handle_queue); +} + +static void _ev_to_close_handle(ev_handle_t* handle) +{ + ev__handle_event_dec(handle); + + /** + * Deactive but not reset #ev_handle_t::data::active_events, for debug + * purpose. + * The #ev_handle_t::data::active_events should be zero by now. + */ + ev__handle_deactive(handle); + + handle->data.flags |= EV_HANDLE_CLOSED; + ev_list_erase(&handle->loop->handles.idle_list, &handle->handle_queue); + + handle->endgame.close_cb(handle); +} + +EV_LOCAL void ev__handle_init(ev_loop_t* loop, ev_handle_t* handle, ev_role_t role) +{ + handle->loop = loop; + ev_list_push_back(&loop->handles.idle_list, &handle->handle_queue); + + handle->data.role = role; + handle->data.flags = 0; + handle->data.active_events = 0; + + handle->backlog.status = EV_ENOENT; + handle->backlog.cb = NULL; + handle->backlog.node = (ev_list_node_t)EV_LIST_NODE_INIT; + + handle->endgame.close_cb = NULL; + handle->endgame.node = (ev_list_node_t)EV_LIST_NODE_INIT; +} + +EV_LOCAL void ev__handle_exit(ev_handle_t* handle, ev_handle_cb close_cb) +{ + assert(!ev__handle_is_closing(handle)); + + handle->data.flags |= EV_HANDLE_CLOSING; + handle->endgame.close_cb = close_cb; + + if (close_cb != NULL) + { + ev__handle_event_add(handle); + ev_list_push_back(&handle->loop->endgame_queue, &handle->endgame.node); + } + else + { + ev__handle_deactive(handle); + handle->data.flags |= EV_HANDLE_CLOSED; + ev_list_erase(&handle->loop->handles.idle_list, &handle->handle_queue); + } +} + +EV_LOCAL void ev__handle_event_add(ev_handle_t* handle) +{ + handle->data.active_events++; + + if (handle->data.active_events != 0) + { + ev__handle_active(handle); + } +} + +EV_LOCAL void ev__handle_event_dec(ev_handle_t* handle) +{ + assert(handle->data.active_events != 0); + + handle->data.active_events--; + + if (handle->data.active_events == 0) + { + ev__handle_deactive(handle); + } +} + +EV_LOCAL int ev__handle_is_active(ev_handle_t* handle) +{ + return handle->data.flags & EV_HANDLE_ACTIVE; +} + +EV_LOCAL int ev__handle_is_closing(ev_handle_t* handle) +{ + return handle->data.flags & (EV_HANDLE_CLOSING | EV_HANDLE_CLOSED); +} + +EV_LOCAL int ev__backlog_submit(ev_handle_t* handle, ev_handle_cb callback) +{ + if (handle->backlog.status != EV_ENOENT) + { + return EV_EEXIST; + } + + handle->backlog.status = EV_EEXIST; + handle->backlog.cb = callback; + ev__handle_event_add(handle); + + ev_list_push_back(&handle->loop->backlog_queue, &handle->backlog.node); + + return 0; +} + +EV_LOCAL size_t ev__process_backlog(ev_loop_t* loop) +{ + ev_list_node_t* it; + size_t active_count = 0; + + while ((it = ev_list_pop_front(&loop->backlog_queue)) != NULL) + { + ev_handle_t* handle = EV_CONTAINER_OF(it, ev_handle_t, backlog.node); + + ev__handle_event_dec(handle); + handle->backlog.status = EV_ENOENT; + + handle->backlog.cb(handle); + active_count++; + } + + return active_count; +} + +EV_LOCAL size_t ev__process_endgame(ev_loop_t* loop) +{ + ev_list_node_t* it; + size_t active_count = 0; + + while ((it = ev_list_pop_front(&loop->endgame_queue)) != NULL) + { + ev_handle_t* handle = EV_CONTAINER_OF(it, ev_handle_t, endgame.node); + _ev_to_close_handle(handle); + active_count++; + } + + return active_count; +} + +#include /* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "loop.h" */ -/* AMALGAMATE: #include "handle.h" */ -#include -/** - * @brief Set handle as inactive - * @see ev__handle_event_dec() - * @param[in] handle handler - */ -static void ev__handle_deactive(ev_handle_t* handle) +static void _list_lite_set_once(ev_list_t* handler, ev_list_node_t* node) { - if (!(handle->data.flags & EV_HANDLE_ACTIVE)) - { - return; - } - handle->data.flags &= ~EV_HANDLE_ACTIVE; + handler->head = node; + handler->tail = node; + node->p_after = NULL; + node->p_before = NULL; + handler->size = 1; +} - ev_loop_t* loop = handle->loop; - ev_list_erase(&loop->handles.active_list, &handle->handle_queue); - ev_list_push_back(&loop->handles.idle_list, &handle->handle_queue); +void ev_list_init(ev_list_t* handler) +{ + memset(handler, 0, sizeof(*handler)); } -/** - * @brief Force set handle as active, regardless the active event counter. - * @see ev__handle_event_add() - * @param[in] handle handler - */ -static void ev__handle_active(ev_handle_t* handle) +void ev_list_push_back(ev_list_t* handler, ev_list_node_t* node) { - if (handle->data.flags & EV_HANDLE_ACTIVE) + if (handler->head == NULL) { + _list_lite_set_once(handler, node); return; } - handle->data.flags |= EV_HANDLE_ACTIVE; - ev_loop_t* loop = handle->loop; - ev_list_erase(&loop->handles.idle_list, &handle->handle_queue); - ev_list_push_back(&loop->handles.active_list, &handle->handle_queue); + node->p_after = NULL; + node->p_before = handler->tail; + handler->tail->p_after = node; + handler->tail = node; + handler->size++; } -static void _ev_to_close_handle(ev_handle_t* handle) +void ev_list_insert_before(ev_list_t* handler, ev_list_node_t* pos, ev_list_node_t* node) { - ev__handle_event_dec(handle); - - /** - * Deactive but not reset #ev_handle_t::data::active_events, for debug - * purpose. - * The #ev_handle_t::data::active_events should be zero by now. - */ - ev__handle_deactive(handle); - - handle->data.flags |= EV_HANDLE_CLOSED; - ev_list_erase(&handle->loop->handles.idle_list, &handle->handle_queue); + if (handler->head == pos) + { + ev_list_push_front(handler, node); + return; + } - handle->endgame.close_cb(handle); + node->p_before = pos->p_before; + node->p_after = pos; + pos->p_before->p_after = node; + pos->p_before = node; + handler->size++; } -EV_LOCAL void ev__handle_init(ev_loop_t* loop, ev_handle_t* handle, ev_role_t role) +void ev_list_insert_after(ev_list_t* handler, ev_list_node_t* pos, ev_list_node_t* node) { - handle->loop = loop; - ev_list_push_back(&loop->handles.idle_list, &handle->handle_queue); - - handle->data.role = role; - handle->data.flags = 0; - handle->data.active_events = 0; - - handle->backlog.status = EV_ENOENT; - handle->backlog.cb = NULL; - handle->backlog.node = (ev_list_node_t)EV_LIST_NODE_INIT; + if (handler->tail == pos) + { + ev_list_push_back(handler, node); + return; + } - handle->endgame.close_cb = NULL; - handle->endgame.node = (ev_list_node_t)EV_LIST_NODE_INIT; + node->p_before = pos; + node->p_after = pos->p_after; + pos->p_after->p_before = node; + pos->p_after = node; + handler->size++; } -EV_LOCAL void ev__handle_exit(ev_handle_t* handle, ev_handle_cb close_cb) +void ev_list_push_front(ev_list_t* handler, ev_list_node_t* node) { - assert(!ev__handle_is_closing(handle)); - - handle->data.flags |= EV_HANDLE_CLOSING; - handle->endgame.close_cb = close_cb; - - if (close_cb != NULL) - { - ev__handle_event_add(handle); - ev_list_push_back(&handle->loop->endgame_queue, &handle->endgame.node); - } - else + if (handler->head == NULL) { - ev__handle_deactive(handle); - handle->data.flags |= EV_HANDLE_CLOSED; - ev_list_erase(&handle->loop->handles.idle_list, &handle->handle_queue); + _list_lite_set_once(handler, node); + return; } + + node->p_before = NULL; + node->p_after = handler->head; + handler->head->p_before = node; + handler->head = node; + handler->size++; } -EV_LOCAL void ev__handle_event_add(ev_handle_t* handle) +ev_list_node_t* ev_list_begin(const ev_list_t* handler) { - handle->data.active_events++; - - if (handle->data.active_events != 0) - { - ev__handle_active(handle); - } -} - -EV_LOCAL void ev__handle_event_dec(ev_handle_t* handle) -{ - assert(handle->data.active_events != 0); - - handle->data.active_events--; - - if (handle->data.active_events == 0) - { - ev__handle_deactive(handle); - } -} - -EV_LOCAL int ev__handle_is_active(ev_handle_t* handle) -{ - return handle->data.flags & EV_HANDLE_ACTIVE; -} - -EV_LOCAL int ev__handle_is_closing(ev_handle_t* handle) -{ - return handle->data.flags & (EV_HANDLE_CLOSING | EV_HANDLE_CLOSED); -} - -EV_LOCAL int ev__backlog_submit(ev_handle_t* handle, ev_handle_cb callback) -{ - if (handle->backlog.status != EV_ENOENT) - { - return EV_EEXIST; - } - - handle->backlog.status = EV_EEXIST; - handle->backlog.cb = callback; - ev__handle_event_add(handle); - - ev_list_push_back(&handle->loop->backlog_queue, &handle->backlog.node); - - return 0; -} - -EV_LOCAL size_t ev__process_backlog(ev_loop_t* loop) -{ - ev_list_node_t* it; - size_t active_count = 0; - - while ((it = ev_list_pop_front(&loop->backlog_queue)) != NULL) - { - ev_handle_t* handle = EV_CONTAINER_OF(it, ev_handle_t, backlog.node); - - ev__handle_event_dec(handle); - handle->backlog.status = EV_ENOENT; - - handle->backlog.cb(handle); - active_count++; - } - - return active_count; -} - -EV_LOCAL size_t ev__process_endgame(ev_loop_t* loop) -{ - ev_list_node_t* it; - size_t active_count = 0; - - while ((it = ev_list_pop_front(&loop->endgame_queue)) != NULL) - { - ev_handle_t* handle = EV_CONTAINER_OF(it, ev_handle_t, endgame.node); - _ev_to_close_handle(handle); - active_count++; - } - - return active_count; -} - -#include -/* AMALGAMATE: #include "ev.h" */ - -static void _list_lite_set_once(ev_list_t* handler, ev_list_node_t* node) -{ - handler->head = node; - handler->tail = node; - node->p_after = NULL; - node->p_before = NULL; - handler->size = 1; -} - -void ev_list_init(ev_list_t* handler) -{ - memset(handler, 0, sizeof(*handler)); -} - -void ev_list_push_back(ev_list_t* handler, ev_list_node_t* node) -{ - if (handler->head == NULL) - { - _list_lite_set_once(handler, node); - return; - } - - node->p_after = NULL; - node->p_before = handler->tail; - handler->tail->p_after = node; - handler->tail = node; - handler->size++; -} - -void ev_list_insert_before(ev_list_t* handler, ev_list_node_t* pos, ev_list_node_t* node) -{ - if (handler->head == pos) - { - ev_list_push_front(handler, node); - return; - } - - node->p_before = pos->p_before; - node->p_after = pos; - pos->p_before->p_after = node; - pos->p_before = node; - handler->size++; -} - -void ev_list_insert_after(ev_list_t* handler, ev_list_node_t* pos, ev_list_node_t* node) -{ - if (handler->tail == pos) - { - ev_list_push_back(handler, node); - return; - } - - node->p_before = pos; - node->p_after = pos->p_after; - pos->p_after->p_before = node; - pos->p_after = node; - handler->size++; -} - -void ev_list_push_front(ev_list_t* handler, ev_list_node_t* node) -{ - if (handler->head == NULL) - { - _list_lite_set_once(handler, node); - return; - } - - node->p_before = NULL; - node->p_after = handler->head; - handler->head->p_before = node; - handler->head = node; - handler->size++; -} - -ev_list_node_t* ev_list_begin(const ev_list_t* handler) -{ - return handler->head; + return handler->head; } ev_list_node_t* ev_list_end(const ev_list_t* handler) @@ -2547,97 +2547,97 @@ void ev_list_migrate(ev_list_t* dst, ev_list_t* src) src->tail = NULL; src->size = 0; } - -/* AMALGAMATE: #include "log.h" */ -#include -#include - -static const char* _ev_filename(const char* file) -{ - const char* pos = file; - - for (; *file; ++file) - { - if (*file == '\\' || *file == '/') - { - pos = file + 1; - } - } - return pos; -} - -static char _ev_ascii_to_char(unsigned char c) -{ - if (c >= 32 && c <= 126) - { - return c; - } - return '.'; -} - -EV_LOCAL void ev__log(ev_log_level_t level, const char* file, const char* func, - int line, const char* fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - const char* prefix; - switch (level) - { - case EV_LOG_INFO: - prefix = "I"; - break; - case EV_LOG_ERROR: - prefix = "E"; - break; - case EV_LOG_FATAL: - prefix = "F"; - break; - default: - prefix = "T"; - break; - } - - printf("[%s %s:%d %s] ", prefix, _ev_filename(file), line, func); - vprintf(fmt, ap); - printf("\n"); - - va_end(ap); -} - -EV_LOCAL void ev__dump_hex(const void* data, size_t size, size_t width) -{ - const unsigned char* pdat = (unsigned char*)data; - - size_t idx_line; - for (idx_line = 0; idx_line < size; idx_line += width) - { - size_t idx_colume; - /* printf hex */ - for (idx_colume = 0; idx_colume < width; idx_colume++) - { - const char* postfix = (idx_colume < width - 1) ? "" : "|"; - - if (idx_colume + idx_line < size) - { - fprintf(stdout, "%02x %s", pdat[idx_colume + idx_line], postfix); - } - else - { - fprintf(stdout, " %s", postfix); - } - } - fprintf(stdout, " "); - /* printf char */ - for (idx_colume = 0; (idx_colume < width) && (idx_colume + idx_line < size); idx_colume++) - { - fprintf(stdout, "%c", _ev_ascii_to_char(pdat[idx_colume + idx_line])); - } - fprintf(stdout, "\n"); - } - -} - + +/* AMALGAMATE: #include "log.h" */ +#include +#include + +static const char* _ev_filename(const char* file) +{ + const char* pos = file; + + for (; *file; ++file) + { + if (*file == '\\' || *file == '/') + { + pos = file + 1; + } + } + return pos; +} + +static char _ev_ascii_to_char(unsigned char c) +{ + if (c >= 32 && c <= 126) + { + return c; + } + return '.'; +} + +EV_LOCAL void ev__log(ev_log_level_t level, const char* file, const char* func, + int line, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + const char* prefix; + switch (level) + { + case EV_LOG_INFO: + prefix = "I"; + break; + case EV_LOG_ERROR: + prefix = "E"; + break; + case EV_LOG_FATAL: + prefix = "F"; + break; + default: + prefix = "T"; + break; + } + + printf("[%s %s:%d %s] ", prefix, _ev_filename(file), line, func); + vprintf(fmt, ap); + printf("\n"); + + va_end(ap); +} + +EV_LOCAL void ev__dump_hex(const void* data, size_t size, size_t width) +{ + const unsigned char* pdat = (unsigned char*)data; + + size_t idx_line; + for (idx_line = 0; idx_line < size; idx_line += width) + { + size_t idx_colume; + /* printf hex */ + for (idx_colume = 0; idx_colume < width; idx_colume++) + { + const char* postfix = (idx_colume < width - 1) ? "" : "|"; + + if (idx_colume + idx_line < size) + { + fprintf(stdout, "%02x %s", pdat[idx_colume + idx_line], postfix); + } + else + { + fprintf(stdout, " %s", postfix); + } + } + fprintf(stdout, " "); + /* printf char */ + for (idx_colume = 0; (idx_colume < width) && (idx_colume + idx_line < size); idx_colume++) + { + fprintf(stdout, "%c", _ev_ascii_to_char(pdat[idx_colume + idx_line])); + } + fprintf(stdout, "\n"); + } + +} + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ /* AMALGAMATE: #include "allocator.h" */ @@ -3037,7 +3037,7 @@ void ev_loop_walk(ev_loop_t* loop, ev_walk_cb cb, void* arg) } } } - + /* AMALGAMATE: #include "ev.h" */ #include #include @@ -3812,7 +3812,7 @@ ev_map_node_t* ev_map_prev(const ev_map_node_t* node) { return _ev_map_low_prev(node); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "misc.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -3992,7 +3992,7 @@ void ev_library_shutdown(void) { ev_threadpool_default_cleanup(); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ /* AMALGAMATE: #include "pipe.h" */ @@ -4037,650 +4037,650 @@ EV_LOCAL int ev__pipe_write_init_ext(ev_pipe_write_req_t* req, ev_pipe_write_cb { /* no handle need to send */ case EV_ROLE_UNKNOWN: - break; - - case EV_ROLE_EV_TCP: - if (handle_size != sizeof(ev_tcp_t)) - { - return EV_EINVAL; - } - req->handle.u.os_socket = ((ev_tcp_t*)handle_addr)->sock; - break; - - /* not support other type */ - default: - return EV_EINVAL; - } - - return 0; -} - -/* AMALGAMATE: #include "ev.h" */ -#include - -#define EV_QUEUE_NEXT(node) ((node)->p_next) -#define EV_QUEUE_PREV(node) ((node)->p_prev) -#define EV_QUEUE_PREV_NEXT(node) (EV_QUEUE_NEXT(EV_QUEUE_PREV(node))) -#define EV_QUEUE_NEXT_PREV(node) (EV_QUEUE_PREV(EV_QUEUE_NEXT(node))) - -void ev_queue_init(ev_queue_node_t* head) -{ - EV_QUEUE_NEXT(head) = head; - EV_QUEUE_PREV(head) = head; -} - -void ev_queue_push_back(ev_queue_node_t* head, ev_queue_node_t* node) -{ - EV_QUEUE_NEXT(node) = head; - EV_QUEUE_PREV(node) = EV_QUEUE_PREV(head); - EV_QUEUE_PREV_NEXT(node) = node; - EV_QUEUE_PREV(head) = node; -} - -void ev_queue_push_front(ev_queue_node_t* head, ev_queue_node_t* node) -{ - EV_QUEUE_NEXT(node) = EV_QUEUE_NEXT(head); - EV_QUEUE_PREV(node) = head; - EV_QUEUE_NEXT_PREV(node) = node; - EV_QUEUE_NEXT(head) = node; -} - -void ev_queue_erase(ev_queue_node_t* node) -{ - EV_QUEUE_PREV_NEXT(node) = EV_QUEUE_NEXT(node); - EV_QUEUE_NEXT_PREV(node) = EV_QUEUE_PREV(node); -} - -ev_queue_node_t* ev_queue_pop_front(ev_queue_node_t* head) -{ - ev_queue_node_t* node = ev_queue_head(head); - if (node == NULL) - { - return NULL; - } - - ev_queue_erase(node); - return node; -} - -ev_queue_node_t* ev_queue_pop_back(ev_queue_node_t* head) -{ - ev_queue_node_t* node = EV_QUEUE_PREV(head); - if (node == head) - { - return NULL; - } - - ev_queue_erase(node); - return node; -} - -ev_queue_node_t* ev_queue_head(ev_queue_node_t* head) -{ - ev_queue_node_t* node = EV_QUEUE_NEXT(head); - return node == head ? NULL : node; -} - -ev_queue_node_t* ev_queue_next(ev_queue_node_t* head, ev_queue_node_t* node) -{ - ev_queue_node_t* next = EV_QUEUE_NEXT(node); - return next == head ? NULL : next; -} - -int ev_queue_empty(const ev_queue_node_t* node) -{ - return EV_QUEUE_NEXT(node) == node; -} - -/* AMALGAMATE: #include "ringbuffer.h" */ - -#define EV_RB_BEG_POS(rb) \ - sizeof((rb)->basis) - -#define EV_RB_BEG_NODE(rb) \ - EV_RB_NODE(rb, EV_RB_BEG_POS(rb)) - -#define EV_RB_NODE(rb, pos) \ - ((ring_buffer_node_t*)((uintptr_t)&((rb)->basis) + (pos))) - -#define EV_RB_BASIS_DIFF(rb, ptr) \ - ((uintptr_t)(ptr) - (uintptr_t)&((rb)->basis)) - -static void _ring_buffer_reinit(ring_buffer_t* rb) -{ - rb->counter.writing = 0; - rb->counter.committed = 0; - rb->counter.reading = 0; - - rb->node.off_reserve = 0; - rb->node.off_HEAD = 0; - rb->node.off_TAIL = 0; -} - -/** - * @brief Create the first node in empty ring buffer. - * @param rb ring buffer - * @param data_len length of user data - * @param node_size size of node - * @return token - */ -static ring_buffer_token_t* _ring_buffer_reserve_empty(ring_buffer_t* rb, - size_t data_len, size_t node_size) -{ - /* check capacity */ - if (node_size > rb->config.capacity) - { - return NULL; - } - - /* The value of ring_buffer_t::basis MUST be 0 */ - rb->node.off_HEAD = EV_RB_BEG_POS(rb); - - /* Initialize node */ - { - ring_buffer_node_t* head = EV_RB_NODE(rb, rb->node.off_HEAD); - head->state = RINGBUFFER_STAT_WRITING; - head->token.size.size = data_len; - - /* Initialize position chain */ - head->chain_pos.off_next = rb->node.off_HEAD; - head->chain_pos.off_prev = rb->node.off_HEAD; - - /* Initialize time chain */ - head->chain_time.off_newer = 0; - head->chain_time.off_older = 0; - } - - /* Initialize other resources */ - rb->node.off_TAIL = rb->node.off_HEAD; - rb->node.off_reserve = rb->node.off_HEAD; - rb->counter.writing++; - - ring_buffer_node_t* rb_oldest_reserve = EV_RB_NODE(rb, rb->node.off_reserve); - return &rb_oldest_reserve->token; -} - -/** - * @brief Update time chain for \p new_node - * @param rb RingBuffer - * @param new_node New node - */ -static void _ring_buffer_update_time_for_new_node(ring_buffer_t* rb, - ring_buffer_node_t* new_node) -{ - /* update chain_time */ - new_node->chain_time.off_newer = 0; - new_node->chain_time.off_older = rb->node.off_HEAD; - EV_RB_NODE(rb, new_node->chain_time.off_older)->chain_time.off_newer = EV_RB_BASIS_DIFF(rb, new_node); - - /* update HEAD */ - rb->node.off_HEAD = EV_RB_BASIS_DIFF(rb, new_node); -} - -/** - * @brief Perform overwrite - */ -static ring_buffer_token_t* _ring_buffer_perform_overwrite( - ring_buffer_t* rb, uint8_t* start_point, ring_buffer_node_t* node_start, - ring_buffer_node_t* node_end, size_t counter_lost_nodes, - size_t data_len) -{ - ring_buffer_node_t* rb_tail = EV_RB_NODE(rb, rb->node.off_TAIL); - ring_buffer_node_t* newer_node = EV_RB_NODE(rb, node_end->chain_time.off_newer); - - /* - * here [node_start, node_end] will be overwrite, - * so off_reserve need to move forward. - * if TAIL was overwrite, then move TAIL too. - */ - if (rb_tail == EV_RB_NODE(rb, rb->node.off_reserve)) - { - rb->node.off_TAIL = EV_RB_BASIS_DIFF(rb, newer_node); - } - rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, newer_node); - - /* generate new node */ - ring_buffer_node_t* new_node = (ring_buffer_node_t*)start_point; - - /* Update position chain */ - new_node->chain_pos.off_next = node_end->chain_pos.off_next; - EV_RB_NODE(rb, new_node->chain_pos.off_next)->chain_pos.off_prev = EV_RB_BASIS_DIFF(rb, new_node); - new_node->chain_pos.off_prev = node_start->chain_pos.off_prev; - EV_RB_NODE(rb, new_node->chain_pos.off_prev)->chain_pos.off_next = EV_RB_BASIS_DIFF(rb, new_node); - - /* Update time chain */ - if (node_start->chain_time.off_older != 0) - { - EV_RB_NODE(rb, node_start->chain_time.off_older)->chain_time.off_newer = - node_end->chain_time.off_newer; - } - if (node_end->chain_time.off_newer != 0) - { - EV_RB_NODE(rb, node_end->chain_time.off_newer)->chain_time.off_older = - node_start->chain_time.off_older; - } - _ring_buffer_update_time_for_new_node(rb, new_node); - - /* Update counter */ - rb->counter.committed -= counter_lost_nodes; - rb->counter.writing += 1; - - /* Update data length */ - new_node->token.size.size = data_len; - - /* Update node status */ - new_node->state = RINGBUFFER_STAT_WRITING; - - return &new_node->token; -} - -/** - * @brief Try to overwrite - */ -static ring_buffer_token_t* _ring_buffer_reserve_try_overwrite( - ring_buffer_t* rb, size_t data_len, size_t node_size) -{ - ring_buffer_node_t* rb_oldest_reserve = EV_RB_NODE(rb, rb->node.off_reserve); - /* Overwrite only works for committed nodes */ - if (rb->node.off_reserve == 0 - || rb_oldest_reserve->state != RINGBUFFER_STAT_COMMITTED) - { - return NULL; - } - - /* Short cut: if only exists one node, check whether whole ring buffer can hold this data */ - if (rb_oldest_reserve->chain_pos.off_next == rb->node.off_reserve) - { - if (rb->config.capacity < node_size) - { - return NULL; - } - - /* If we can, re-initialize and add this node */ - _ring_buffer_reinit(rb); - return _ring_buffer_reserve_empty(rb, data_len, node_size); - } - - /* Step 1. Calculate where overwrite start */ - const ring_buffer_node_t* backward_node = EV_RB_NODE(rb, rb_oldest_reserve->chain_pos.off_prev); - uint8_t* start_point = (backward_node < rb_oldest_reserve) ? - ((uint8_t*)backward_node + ring_buffer_node_cost(backward_node->token.size.size)) : - (uint8_t*)EV_RB_BEG_NODE(rb); - - /* Step 2. Calculate whether continuous committed nodes could hold needed data */ - size_t sum_size = 0; - size_t counter_lost_nodes = 1; - ring_buffer_node_t* node_end = rb_oldest_reserve; - - while (1) - { - sum_size = (uint8_t*)node_end + ring_buffer_node_cost(node_end->token.size.size) - (uint8_t*)start_point; - - ring_buffer_node_t* forward_of_node_end = EV_RB_NODE(rb, node_end->chain_pos.off_next); - if (!(sum_size < node_size /* overwrite minimum nodes */ - && forward_of_node_end->state == RINGBUFFER_STAT_COMMITTED /* only overwrite committed node */ - && node_end->chain_pos.off_next == node_end->chain_time.off_newer /* node must both physical and time continuous */ - && forward_of_node_end > node_end /* cannot interrupt by array boundary */ - )) - { - break; - } - node_end = EV_RB_NODE(rb, node_end->chain_pos.off_next); - counter_lost_nodes++; - } - - /* Step 3. check if condition allow to overwrite */ - if (sum_size < node_size) - { - return NULL; - } - - /* Step 4. perform overwrite */ - return _ring_buffer_perform_overwrite(rb, start_point, rb_oldest_reserve, - node_end, counter_lost_nodes, data_len); -} - -inline static void _ring_buffer_insert_new_node(ring_buffer_t* rb, - ring_buffer_node_t* new_node, size_t data_len) -{ - ring_buffer_node_t* rb_head = EV_RB_NODE(rb, rb->node.off_HEAD); - - /* initialize token */ - new_node->state = RINGBUFFER_STAT_WRITING; - new_node->token.size.size = data_len; - - /* update chain_pos */ - new_node->chain_pos.off_next = rb_head->chain_pos.off_next; - new_node->chain_pos.off_prev = rb->node.off_HEAD; - EV_RB_NODE(rb, new_node->chain_pos.off_next)->chain_pos.off_prev = EV_RB_BASIS_DIFF(rb, new_node); - EV_RB_NODE(rb, new_node->chain_pos.off_prev)->chain_pos.off_next = EV_RB_BASIS_DIFF(rb, new_node); - - _ring_buffer_update_time_for_new_node(rb, new_node); -} - -/** - * @brief Update off_reserve - */ -static void _ring_buffer_reserve_update_oldest_reserve(ring_buffer_t* rb, - ring_buffer_node_t* node) -{ - if (rb->node.off_reserve == 0) - { - rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, node); - } -} - -static ring_buffer_token_t* _ring_buffer_reserve_none_empty( - ring_buffer_t* rb, size_t data_len, size_t node_size, int flags) -{ - ring_buffer_node_t* rb_head = EV_RB_NODE(rb, rb->node.off_HEAD); - - /** - * Get next possible node in right side of HEAD - * If there is a node exists, the address of that node is larger or equal to calculated address. - */ - size_t next_possible_pos = rb->node.off_HEAD + ring_buffer_node_cost(rb_head->token.size.size); - ring_buffer_node_t* next_possible_node = EV_RB_NODE(rb, next_possible_pos); - - /* If have a existing node on right side of HEAD, we can use that space */ - if (rb_head->chain_pos.off_next > rb->node.off_HEAD) - { - /* If space is enough, generate token */ - if (rb_head->chain_pos.off_next - next_possible_pos >= node_size) - { - rb->counter.writing++; - _ring_buffer_insert_new_node(rb, next_possible_node, data_len); - _ring_buffer_reserve_update_oldest_reserve(rb, next_possible_node); - return &next_possible_node->token; - } - - /* Otherwise overwrite */ - return (flags & RINGBUFFER_FLAG_OVERWRITE) ? - _ring_buffer_reserve_try_overwrite(rb, data_len, node_size) : - NULL; - } - - /* If no existing node on right side, try to create token */ - if ((rb->config.capacity - (next_possible_pos - EV_RB_BEG_POS(rb))) >= node_size) - { - rb->counter.writing++; - _ring_buffer_insert_new_node(rb, next_possible_node, data_len); - _ring_buffer_reserve_update_oldest_reserve(rb, next_possible_node); - return &next_possible_node->token; - } - - /* if area on the most left cache is enough, make token */ - if (rb_head->chain_pos.off_next - EV_RB_BEG_POS(rb) >= node_size) - { - next_possible_node = EV_RB_BEG_NODE(rb); - rb->counter.writing++; - _ring_buffer_insert_new_node(rb, next_possible_node, data_len); - _ring_buffer_reserve_update_oldest_reserve(rb, next_possible_node); - return &next_possible_node->token; - } - - /* in other condition, overwrite if needed */ - return (flags & RINGBUFFER_FLAG_OVERWRITE) ? - _ring_buffer_reserve_try_overwrite(rb, data_len, node_size) : NULL; -} - -inline static int _ring_buffer_commit_for_write_confirm(ring_buffer_t* rb, - ring_buffer_node_t* node) -{ - (void)rb; - - /* Update counter */ - rb->counter.writing--; - rb->counter.committed++; - - /* Update node status */ - node->state = RINGBUFFER_STAT_COMMITTED; - - return 0; -} - -/** - * @brief Update position chain and time chain after delete node. - * @param node The node to delete - */ -static void _ring_buffer_delete_node_update_chain(ring_buffer_t* rb, - ring_buffer_node_t* node) -{ - /* Update position chain */ - EV_RB_NODE(rb, node->chain_pos.off_prev)->chain_pos.off_next = node->chain_pos.off_next; - EV_RB_NODE(rb, node->chain_pos.off_next)->chain_pos.off_prev = node->chain_pos.off_prev; - - /* Update time chain */ - if (node->chain_time.off_older != 0) - { - EV_RB_NODE(rb, node->chain_time.off_older)->chain_time.off_newer = node->chain_time.off_newer; - } - if (node->chain_time.off_newer != 0) - { - EV_RB_NODE(rb, node->chain_time.off_newer)->chain_time.off_older = node->chain_time.off_older; - } -} - -/** - * @brief Completely remove a node from ring buffer - * @param rb ring buffer - * @param node node to be delete - */ -static void _ring_buffer_delete_node(ring_buffer_t* rb, - ring_buffer_node_t* node) -{ - /** - * Short cut: If only one node in ring buffer, re-initialize. - * Here use `p_forward` to check if it meets the condition: - * 1. `chain_pos.off_next` always point to next node. If it point to self, there is only one node. - * 2. Access to `node` means `node` is in CPU cache line. By access `p_forward` can avoid cache miss. - */ - if (node->chain_pos.off_next == EV_RB_BASIS_DIFF(rb, node)) - { - _ring_buffer_reinit(rb); - return; - } - - /* Delete node and update chains */ - _ring_buffer_delete_node_update_chain(rb, node); - - /* Update off_reserve */ - if (rb->node.off_reserve == EV_RB_BASIS_DIFF(rb, node)) - { - rb->node.off_reserve = node->chain_time.off_newer; - } - - /* Update TAIL if necessary */ - if (node->chain_time.off_older == 0) - { - rb->node.off_TAIL = node->chain_time.off_newer; - return; - } - - /* Update HEAD if necessary */ - if (node->chain_time.off_newer == 0) - { - rb->node.off_HEAD = node->chain_time.off_older; - return; - } - - return; -} - -static int _ring_buffer_commit_for_write_discard(ring_buffer_t* rb, - ring_buffer_node_t* node) -{ - rb->counter.writing--; - _ring_buffer_delete_node(rb, node); - return 0; -} - -static int _ring_buffer_commit_for_write(ring_buffer_t* rb, - ring_buffer_node_t* node, int flags) -{ - return (flags & RINGBUFFER_FLAG_DISCARD) ? - _ring_buffer_commit_for_write_discard(rb, node) : - _ring_buffer_commit_for_write_confirm(rb, node); -} - -static int _ring_buffer_commit_for_consume_confirm(ring_buffer_t* rb, - ring_buffer_node_t* node) -{ - rb->counter.reading--; - _ring_buffer_delete_node(rb, node); - return 0; -} - -/** - * @brief Discard a consumed token. - * the only condition a consumed token can be discard is no one consume newer token - */ -static int _ring_buffer_commit_for_consume_discard(ring_buffer_t* rb, - ring_buffer_node_t* node, int flags) -{ - /* If existing a newer consumer, should fail. */ - if (node->chain_time.off_newer != 0 - && EV_RB_NODE(rb, node->chain_time.off_newer)->state == RINGBUFFER_STAT_READING) - { - return (flags & RINGBUFFER_FLAG_ABANDON) ? - _ring_buffer_commit_for_consume_confirm(rb, node) : -1; - } - - /* Update counter and status */ - rb->counter.reading--; - rb->counter.committed++; - node->state = RINGBUFFER_STAT_COMMITTED; + break; - /* if no newer node, then off_reserve should point to this node */ - if (node->chain_time.off_newer == 0) - { - rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, node); - return 0; - } + case EV_ROLE_EV_TCP: + if (handle_size != sizeof(ev_tcp_t)) + { + return EV_EINVAL; + } + req->handle.u.os_socket = ((ev_tcp_t*)handle_addr)->sock; + break; - /* if node is just older than off_reserve, then off_reserve should move back */ - if (rb->node.off_reserve != 0 - && EV_RB_NODE(rb, rb->node.off_reserve)->chain_time.off_older == EV_RB_BASIS_DIFF(rb, node)) - { - rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, node); - return 0; + /* not support other type */ + default: + return EV_EINVAL; } return 0; } + +/* AMALGAMATE: #include "ev.h" */ +#include + +#define EV_QUEUE_NEXT(node) ((node)->p_next) +#define EV_QUEUE_PREV(node) ((node)->p_prev) +#define EV_QUEUE_PREV_NEXT(node) (EV_QUEUE_NEXT(EV_QUEUE_PREV(node))) +#define EV_QUEUE_NEXT_PREV(node) (EV_QUEUE_PREV(EV_QUEUE_NEXT(node))) -static int _ring_buffer_commit_for_consume(ring_buffer_t* rb, - ring_buffer_node_t* node, int flags) +void ev_queue_init(ev_queue_node_t* head) { - return (flags & RINGBUFFER_FLAG_DISCARD) ? - _ring_buffer_commit_for_consume_discard(rb, node, flags) : - _ring_buffer_commit_for_consume_confirm(rb, node); + EV_QUEUE_NEXT(head) = head; + EV_QUEUE_PREV(head) = head; } -EV_LOCAL size_t ring_buffer_heap_cost(void) +void ev_queue_push_back(ev_queue_node_t* head, ev_queue_node_t* node) { - /* need to align with machine size */ - return ALIGN_SIZE(sizeof(struct ring_buffer), sizeof(void*)); + EV_QUEUE_NEXT(node) = head; + EV_QUEUE_PREV(node) = EV_QUEUE_PREV(head); + EV_QUEUE_PREV_NEXT(node) = node; + EV_QUEUE_PREV(head) = node; } -EV_LOCAL size_t ring_buffer_node_cost(size_t size) +void ev_queue_push_front(ev_queue_node_t* head, ev_queue_node_t* node) { - return ALIGN_SIZE(sizeof(ring_buffer_node_t) + size, sizeof(void*)); + EV_QUEUE_NEXT(node) = EV_QUEUE_NEXT(head); + EV_QUEUE_PREV(node) = head; + EV_QUEUE_NEXT_PREV(node) = node; + EV_QUEUE_NEXT(head) = node; } -EV_LOCAL ring_buffer_t* ring_buffer_init(void* buffer, size_t size) +void ev_queue_erase(ev_queue_node_t* node) { - /* Calculate start address */ - ring_buffer_t* handler = buffer; - - /* Check space size */ - if (ring_buffer_heap_cost() + ring_buffer_node_cost(0) >= size) - { - return NULL; - } - - /* setup necessary field */ - handler->config.capacity = size - ring_buffer_heap_cost(); - handler->basis = NULL; - - /* initialize */ - _ring_buffer_reinit(handler); - - return handler; + EV_QUEUE_PREV_NEXT(node) = EV_QUEUE_NEXT(node); + EV_QUEUE_NEXT_PREV(node) = EV_QUEUE_PREV(node); } -EV_LOCAL ring_buffer_token_t* ring_buffer_reserve(ring_buffer_t* handler, size_t len, - int flags) +ev_queue_node_t* ev_queue_pop_front(ev_queue_node_t* head) { - /* node must aligned */ - const size_t node_size = ring_buffer_node_cost(len); - - /* empty ring buffer */ - if (handler->node.off_TAIL == 0) + ev_queue_node_t* node = ev_queue_head(head); + if (node == NULL) { - return _ring_buffer_reserve_empty(handler, len, node_size); + return NULL; } - /* non empty ring buffer */ - return _ring_buffer_reserve_none_empty(handler, len, node_size, flags); + ev_queue_erase(node); + return node; } -EV_LOCAL ring_buffer_token_t* ring_buffer_consume(ring_buffer_t* handler) +ev_queue_node_t* ev_queue_pop_back(ev_queue_node_t* head) { - ring_buffer_node_t* rb_oldest_reserve = EV_RB_NODE(handler, handler->node.off_reserve); - if (handler->node.off_reserve == 0 - || rb_oldest_reserve->state != RINGBUFFER_STAT_COMMITTED) + ev_queue_node_t* node = EV_QUEUE_PREV(head); + if (node == head) { return NULL; } - handler->counter.committed--; - handler->counter.reading++; - - ring_buffer_node_t* token_node = rb_oldest_reserve; - handler->node.off_reserve = rb_oldest_reserve->chain_time.off_newer; - token_node->state = RINGBUFFER_STAT_READING; - - return &token_node->token; -} - -EV_LOCAL int ring_buffer_commit(ring_buffer_t* handler, ring_buffer_token_t* token, int flags) -{ - ring_buffer_node_t* node = EV_CONTAINER_OF(token, ring_buffer_node_t, token); - - return node->state == RINGBUFFER_STAT_WRITING ? - _ring_buffer_commit_for_write(handler, node, flags) : - _ring_buffer_commit_for_consume(handler, node, flags); + ev_queue_erase(node); + return node; } -EV_LOCAL size_t ring_buffer_count(ring_buffer_t* handler, ring_buffer_counter_t* counter) +ev_queue_node_t* ev_queue_head(ev_queue_node_t* head) { - if (counter != NULL) - { - *counter = handler->counter; - } - - return handler->counter.committed + handler->counter.reading + handler->counter.writing; + ev_queue_node_t* node = EV_QUEUE_NEXT(head); + return node == head ? NULL : node; } -EV_LOCAL ring_buffer_token_t* ring_buffer_begin(const ring_buffer_t* handler) +ev_queue_node_t* ev_queue_next(ev_queue_node_t* head, ev_queue_node_t* node) { - ring_buffer_node_t* rb_tail = EV_RB_NODE(handler, handler->node.off_TAIL); - return &(rb_tail->token); + ev_queue_node_t* next = EV_QUEUE_NEXT(node); + return next == head ? NULL : next; } -EV_LOCAL ring_buffer_token_t* ring_buffer_next(const ring_buffer_t* handler, const ring_buffer_token_t* token) +int ev_queue_empty(const ev_queue_node_t* node) { - ring_buffer_node_t* node = EV_CONTAINER_OF(token, ring_buffer_node_t, token); - if (node->chain_time.off_newer == 0) - { - return NULL; - } - - node = EV_RB_NODE(handler, node->chain_time.off_newer); - return &(node->token); + return EV_QUEUE_NEXT(node) == node; } - + +/* AMALGAMATE: #include "ringbuffer.h" */ + +#define EV_RB_BEG_POS(rb) \ + sizeof((rb)->basis) + +#define EV_RB_BEG_NODE(rb) \ + EV_RB_NODE(rb, EV_RB_BEG_POS(rb)) + +#define EV_RB_NODE(rb, pos) \ + ((ring_buffer_node_t*)((uintptr_t)&((rb)->basis) + (pos))) + +#define EV_RB_BASIS_DIFF(rb, ptr) \ + ((uintptr_t)(ptr) - (uintptr_t)&((rb)->basis)) + +static void _ring_buffer_reinit(ring_buffer_t* rb) +{ + rb->counter.writing = 0; + rb->counter.committed = 0; + rb->counter.reading = 0; + + rb->node.off_reserve = 0; + rb->node.off_HEAD = 0; + rb->node.off_TAIL = 0; +} + +/** + * @brief Create the first node in empty ring buffer. + * @param rb ring buffer + * @param data_len length of user data + * @param node_size size of node + * @return token + */ +static ring_buffer_token_t* _ring_buffer_reserve_empty(ring_buffer_t* rb, + size_t data_len, size_t node_size) +{ + /* check capacity */ + if (node_size > rb->config.capacity) + { + return NULL; + } + + /* The value of ring_buffer_t::basis MUST be 0 */ + rb->node.off_HEAD = EV_RB_BEG_POS(rb); + + /* Initialize node */ + { + ring_buffer_node_t* head = EV_RB_NODE(rb, rb->node.off_HEAD); + head->state = RINGBUFFER_STAT_WRITING; + head->token.size.size = data_len; + + /* Initialize position chain */ + head->chain_pos.off_next = rb->node.off_HEAD; + head->chain_pos.off_prev = rb->node.off_HEAD; + + /* Initialize time chain */ + head->chain_time.off_newer = 0; + head->chain_time.off_older = 0; + } + + /* Initialize other resources */ + rb->node.off_TAIL = rb->node.off_HEAD; + rb->node.off_reserve = rb->node.off_HEAD; + rb->counter.writing++; + + ring_buffer_node_t* rb_oldest_reserve = EV_RB_NODE(rb, rb->node.off_reserve); + return &rb_oldest_reserve->token; +} + +/** + * @brief Update time chain for \p new_node + * @param rb RingBuffer + * @param new_node New node + */ +static void _ring_buffer_update_time_for_new_node(ring_buffer_t* rb, + ring_buffer_node_t* new_node) +{ + /* update chain_time */ + new_node->chain_time.off_newer = 0; + new_node->chain_time.off_older = rb->node.off_HEAD; + EV_RB_NODE(rb, new_node->chain_time.off_older)->chain_time.off_newer = EV_RB_BASIS_DIFF(rb, new_node); + + /* update HEAD */ + rb->node.off_HEAD = EV_RB_BASIS_DIFF(rb, new_node); +} + +/** + * @brief Perform overwrite + */ +static ring_buffer_token_t* _ring_buffer_perform_overwrite( + ring_buffer_t* rb, uint8_t* start_point, ring_buffer_node_t* node_start, + ring_buffer_node_t* node_end, size_t counter_lost_nodes, + size_t data_len) +{ + ring_buffer_node_t* rb_tail = EV_RB_NODE(rb, rb->node.off_TAIL); + ring_buffer_node_t* newer_node = EV_RB_NODE(rb, node_end->chain_time.off_newer); + + /* + * here [node_start, node_end] will be overwrite, + * so off_reserve need to move forward. + * if TAIL was overwrite, then move TAIL too. + */ + if (rb_tail == EV_RB_NODE(rb, rb->node.off_reserve)) + { + rb->node.off_TAIL = EV_RB_BASIS_DIFF(rb, newer_node); + } + rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, newer_node); + + /* generate new node */ + ring_buffer_node_t* new_node = (ring_buffer_node_t*)start_point; + + /* Update position chain */ + new_node->chain_pos.off_next = node_end->chain_pos.off_next; + EV_RB_NODE(rb, new_node->chain_pos.off_next)->chain_pos.off_prev = EV_RB_BASIS_DIFF(rb, new_node); + new_node->chain_pos.off_prev = node_start->chain_pos.off_prev; + EV_RB_NODE(rb, new_node->chain_pos.off_prev)->chain_pos.off_next = EV_RB_BASIS_DIFF(rb, new_node); + + /* Update time chain */ + if (node_start->chain_time.off_older != 0) + { + EV_RB_NODE(rb, node_start->chain_time.off_older)->chain_time.off_newer = + node_end->chain_time.off_newer; + } + if (node_end->chain_time.off_newer != 0) + { + EV_RB_NODE(rb, node_end->chain_time.off_newer)->chain_time.off_older = + node_start->chain_time.off_older; + } + _ring_buffer_update_time_for_new_node(rb, new_node); + + /* Update counter */ + rb->counter.committed -= counter_lost_nodes; + rb->counter.writing += 1; + + /* Update data length */ + new_node->token.size.size = data_len; + + /* Update node status */ + new_node->state = RINGBUFFER_STAT_WRITING; + + return &new_node->token; +} + +/** + * @brief Try to overwrite + */ +static ring_buffer_token_t* _ring_buffer_reserve_try_overwrite( + ring_buffer_t* rb, size_t data_len, size_t node_size) +{ + ring_buffer_node_t* rb_oldest_reserve = EV_RB_NODE(rb, rb->node.off_reserve); + /* Overwrite only works for committed nodes */ + if (rb->node.off_reserve == 0 + || rb_oldest_reserve->state != RINGBUFFER_STAT_COMMITTED) + { + return NULL; + } + + /* Short cut: if only exists one node, check whether whole ring buffer can hold this data */ + if (rb_oldest_reserve->chain_pos.off_next == rb->node.off_reserve) + { + if (rb->config.capacity < node_size) + { + return NULL; + } + + /* If we can, re-initialize and add this node */ + _ring_buffer_reinit(rb); + return _ring_buffer_reserve_empty(rb, data_len, node_size); + } + + /* Step 1. Calculate where overwrite start */ + const ring_buffer_node_t* backward_node = EV_RB_NODE(rb, rb_oldest_reserve->chain_pos.off_prev); + uint8_t* start_point = (backward_node < rb_oldest_reserve) ? + ((uint8_t*)backward_node + ring_buffer_node_cost(backward_node->token.size.size)) : + (uint8_t*)EV_RB_BEG_NODE(rb); + + /* Step 2. Calculate whether continuous committed nodes could hold needed data */ + size_t sum_size = 0; + size_t counter_lost_nodes = 1; + ring_buffer_node_t* node_end = rb_oldest_reserve; + + while (1) + { + sum_size = (uint8_t*)node_end + ring_buffer_node_cost(node_end->token.size.size) - (uint8_t*)start_point; + + ring_buffer_node_t* forward_of_node_end = EV_RB_NODE(rb, node_end->chain_pos.off_next); + if (!(sum_size < node_size /* overwrite minimum nodes */ + && forward_of_node_end->state == RINGBUFFER_STAT_COMMITTED /* only overwrite committed node */ + && node_end->chain_pos.off_next == node_end->chain_time.off_newer /* node must both physical and time continuous */ + && forward_of_node_end > node_end /* cannot interrupt by array boundary */ + )) + { + break; + } + node_end = EV_RB_NODE(rb, node_end->chain_pos.off_next); + counter_lost_nodes++; + } + + /* Step 3. check if condition allow to overwrite */ + if (sum_size < node_size) + { + return NULL; + } + + /* Step 4. perform overwrite */ + return _ring_buffer_perform_overwrite(rb, start_point, rb_oldest_reserve, + node_end, counter_lost_nodes, data_len); +} + +inline static void _ring_buffer_insert_new_node(ring_buffer_t* rb, + ring_buffer_node_t* new_node, size_t data_len) +{ + ring_buffer_node_t* rb_head = EV_RB_NODE(rb, rb->node.off_HEAD); + + /* initialize token */ + new_node->state = RINGBUFFER_STAT_WRITING; + new_node->token.size.size = data_len; + + /* update chain_pos */ + new_node->chain_pos.off_next = rb_head->chain_pos.off_next; + new_node->chain_pos.off_prev = rb->node.off_HEAD; + EV_RB_NODE(rb, new_node->chain_pos.off_next)->chain_pos.off_prev = EV_RB_BASIS_DIFF(rb, new_node); + EV_RB_NODE(rb, new_node->chain_pos.off_prev)->chain_pos.off_next = EV_RB_BASIS_DIFF(rb, new_node); + + _ring_buffer_update_time_for_new_node(rb, new_node); +} + +/** + * @brief Update off_reserve + */ +static void _ring_buffer_reserve_update_oldest_reserve(ring_buffer_t* rb, + ring_buffer_node_t* node) +{ + if (rb->node.off_reserve == 0) + { + rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, node); + } +} + +static ring_buffer_token_t* _ring_buffer_reserve_none_empty( + ring_buffer_t* rb, size_t data_len, size_t node_size, int flags) +{ + ring_buffer_node_t* rb_head = EV_RB_NODE(rb, rb->node.off_HEAD); + + /** + * Get next possible node in right side of HEAD + * If there is a node exists, the address of that node is larger or equal to calculated address. + */ + size_t next_possible_pos = rb->node.off_HEAD + ring_buffer_node_cost(rb_head->token.size.size); + ring_buffer_node_t* next_possible_node = EV_RB_NODE(rb, next_possible_pos); + + /* If have a existing node on right side of HEAD, we can use that space */ + if (rb_head->chain_pos.off_next > rb->node.off_HEAD) + { + /* If space is enough, generate token */ + if (rb_head->chain_pos.off_next - next_possible_pos >= node_size) + { + rb->counter.writing++; + _ring_buffer_insert_new_node(rb, next_possible_node, data_len); + _ring_buffer_reserve_update_oldest_reserve(rb, next_possible_node); + return &next_possible_node->token; + } + + /* Otherwise overwrite */ + return (flags & RINGBUFFER_FLAG_OVERWRITE) ? + _ring_buffer_reserve_try_overwrite(rb, data_len, node_size) : + NULL; + } + + /* If no existing node on right side, try to create token */ + if ((rb->config.capacity - (next_possible_pos - EV_RB_BEG_POS(rb))) >= node_size) + { + rb->counter.writing++; + _ring_buffer_insert_new_node(rb, next_possible_node, data_len); + _ring_buffer_reserve_update_oldest_reserve(rb, next_possible_node); + return &next_possible_node->token; + } + + /* if area on the most left cache is enough, make token */ + if (rb_head->chain_pos.off_next - EV_RB_BEG_POS(rb) >= node_size) + { + next_possible_node = EV_RB_BEG_NODE(rb); + rb->counter.writing++; + _ring_buffer_insert_new_node(rb, next_possible_node, data_len); + _ring_buffer_reserve_update_oldest_reserve(rb, next_possible_node); + return &next_possible_node->token; + } + + /* in other condition, overwrite if needed */ + return (flags & RINGBUFFER_FLAG_OVERWRITE) ? + _ring_buffer_reserve_try_overwrite(rb, data_len, node_size) : NULL; +} + +inline static int _ring_buffer_commit_for_write_confirm(ring_buffer_t* rb, + ring_buffer_node_t* node) +{ + (void)rb; + + /* Update counter */ + rb->counter.writing--; + rb->counter.committed++; + + /* Update node status */ + node->state = RINGBUFFER_STAT_COMMITTED; + + return 0; +} + +/** + * @brief Update position chain and time chain after delete node. + * @param node The node to delete + */ +static void _ring_buffer_delete_node_update_chain(ring_buffer_t* rb, + ring_buffer_node_t* node) +{ + /* Update position chain */ + EV_RB_NODE(rb, node->chain_pos.off_prev)->chain_pos.off_next = node->chain_pos.off_next; + EV_RB_NODE(rb, node->chain_pos.off_next)->chain_pos.off_prev = node->chain_pos.off_prev; + + /* Update time chain */ + if (node->chain_time.off_older != 0) + { + EV_RB_NODE(rb, node->chain_time.off_older)->chain_time.off_newer = node->chain_time.off_newer; + } + if (node->chain_time.off_newer != 0) + { + EV_RB_NODE(rb, node->chain_time.off_newer)->chain_time.off_older = node->chain_time.off_older; + } +} + +/** + * @brief Completely remove a node from ring buffer + * @param rb ring buffer + * @param node node to be delete + */ +static void _ring_buffer_delete_node(ring_buffer_t* rb, + ring_buffer_node_t* node) +{ + /** + * Short cut: If only one node in ring buffer, re-initialize. + * Here use `p_forward` to check if it meets the condition: + * 1. `chain_pos.off_next` always point to next node. If it point to self, there is only one node. + * 2. Access to `node` means `node` is in CPU cache line. By access `p_forward` can avoid cache miss. + */ + if (node->chain_pos.off_next == EV_RB_BASIS_DIFF(rb, node)) + { + _ring_buffer_reinit(rb); + return; + } + + /* Delete node and update chains */ + _ring_buffer_delete_node_update_chain(rb, node); + + /* Update off_reserve */ + if (rb->node.off_reserve == EV_RB_BASIS_DIFF(rb, node)) + { + rb->node.off_reserve = node->chain_time.off_newer; + } + + /* Update TAIL if necessary */ + if (node->chain_time.off_older == 0) + { + rb->node.off_TAIL = node->chain_time.off_newer; + return; + } + + /* Update HEAD if necessary */ + if (node->chain_time.off_newer == 0) + { + rb->node.off_HEAD = node->chain_time.off_older; + return; + } + + return; +} + +static int _ring_buffer_commit_for_write_discard(ring_buffer_t* rb, + ring_buffer_node_t* node) +{ + rb->counter.writing--; + _ring_buffer_delete_node(rb, node); + return 0; +} + +static int _ring_buffer_commit_for_write(ring_buffer_t* rb, + ring_buffer_node_t* node, int flags) +{ + return (flags & RINGBUFFER_FLAG_DISCARD) ? + _ring_buffer_commit_for_write_discard(rb, node) : + _ring_buffer_commit_for_write_confirm(rb, node); +} + +static int _ring_buffer_commit_for_consume_confirm(ring_buffer_t* rb, + ring_buffer_node_t* node) +{ + rb->counter.reading--; + _ring_buffer_delete_node(rb, node); + return 0; +} + +/** + * @brief Discard a consumed token. + * the only condition a consumed token can be discard is no one consume newer token + */ +static int _ring_buffer_commit_for_consume_discard(ring_buffer_t* rb, + ring_buffer_node_t* node, int flags) +{ + /* If existing a newer consumer, should fail. */ + if (node->chain_time.off_newer != 0 + && EV_RB_NODE(rb, node->chain_time.off_newer)->state == RINGBUFFER_STAT_READING) + { + return (flags & RINGBUFFER_FLAG_ABANDON) ? + _ring_buffer_commit_for_consume_confirm(rb, node) : -1; + } + + /* Update counter and status */ + rb->counter.reading--; + rb->counter.committed++; + node->state = RINGBUFFER_STAT_COMMITTED; + + /* if no newer node, then off_reserve should point to this node */ + if (node->chain_time.off_newer == 0) + { + rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, node); + return 0; + } + + /* if node is just older than off_reserve, then off_reserve should move back */ + if (rb->node.off_reserve != 0 + && EV_RB_NODE(rb, rb->node.off_reserve)->chain_time.off_older == EV_RB_BASIS_DIFF(rb, node)) + { + rb->node.off_reserve = EV_RB_BASIS_DIFF(rb, node); + return 0; + } + + return 0; +} + +static int _ring_buffer_commit_for_consume(ring_buffer_t* rb, + ring_buffer_node_t* node, int flags) +{ + return (flags & RINGBUFFER_FLAG_DISCARD) ? + _ring_buffer_commit_for_consume_discard(rb, node, flags) : + _ring_buffer_commit_for_consume_confirm(rb, node); +} + +EV_LOCAL size_t ring_buffer_heap_cost(void) +{ + /* need to align with machine size */ + return ALIGN_SIZE(sizeof(struct ring_buffer), sizeof(void*)); +} + +EV_LOCAL size_t ring_buffer_node_cost(size_t size) +{ + return ALIGN_SIZE(sizeof(ring_buffer_node_t) + size, sizeof(void*)); +} + +EV_LOCAL ring_buffer_t* ring_buffer_init(void* buffer, size_t size) +{ + /* Calculate start address */ + ring_buffer_t* handler = buffer; + + /* Check space size */ + if (ring_buffer_heap_cost() + ring_buffer_node_cost(0) >= size) + { + return NULL; + } + + /* setup necessary field */ + handler->config.capacity = size - ring_buffer_heap_cost(); + handler->basis = NULL; + + /* initialize */ + _ring_buffer_reinit(handler); + + return handler; +} + +EV_LOCAL ring_buffer_token_t* ring_buffer_reserve(ring_buffer_t* handler, size_t len, + int flags) +{ + /* node must aligned */ + const size_t node_size = ring_buffer_node_cost(len); + + /* empty ring buffer */ + if (handler->node.off_TAIL == 0) + { + return _ring_buffer_reserve_empty(handler, len, node_size); + } + + /* non empty ring buffer */ + return _ring_buffer_reserve_none_empty(handler, len, node_size, flags); +} + +EV_LOCAL ring_buffer_token_t* ring_buffer_consume(ring_buffer_t* handler) +{ + ring_buffer_node_t* rb_oldest_reserve = EV_RB_NODE(handler, handler->node.off_reserve); + if (handler->node.off_reserve == 0 + || rb_oldest_reserve->state != RINGBUFFER_STAT_COMMITTED) + { + return NULL; + } + + handler->counter.committed--; + handler->counter.reading++; + + ring_buffer_node_t* token_node = rb_oldest_reserve; + handler->node.off_reserve = rb_oldest_reserve->chain_time.off_newer; + token_node->state = RINGBUFFER_STAT_READING; + + return &token_node->token; +} + +EV_LOCAL int ring_buffer_commit(ring_buffer_t* handler, ring_buffer_token_t* token, int flags) +{ + ring_buffer_node_t* node = EV_CONTAINER_OF(token, ring_buffer_node_t, token); + + return node->state == RINGBUFFER_STAT_WRITING ? + _ring_buffer_commit_for_write(handler, node, flags) : + _ring_buffer_commit_for_consume(handler, node, flags); +} + +EV_LOCAL size_t ring_buffer_count(ring_buffer_t* handler, ring_buffer_counter_t* counter) +{ + if (counter != NULL) + { + *counter = handler->counter; + } + + return handler->counter.committed + handler->counter.reading + handler->counter.writing; +} + +EV_LOCAL ring_buffer_token_t* ring_buffer_begin(const ring_buffer_t* handler) +{ + ring_buffer_node_t* rb_tail = EV_RB_NODE(handler, handler->node.off_TAIL); + return &(rb_tail->token); +} + +EV_LOCAL ring_buffer_token_t* ring_buffer_next(const ring_buffer_t* handler, const ring_buffer_token_t* token) +{ + ring_buffer_node_t* node = EV_CONTAINER_OF(token, ring_buffer_node_t, token); + if (node->chain_time.off_newer == 0) + { + return NULL; + } + + node = EV_RB_NODE(handler, node->chain_time.off_newer); + return &(node->token); +} + /* AMALGAMATE: #include "shmem.h" */ void* ev_shm_addr(ev_shm_t* shm) @@ -4692,7 +4692,7 @@ size_t ev_shm_size(ev_shm_t* shm) { return shm->size; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ /* AMALGAMATE: #include "handle.h" */ @@ -5077,7 +5077,7 @@ EV_LOCAL void ev__threadpool_process(ev_loop_t* loop) handle->backlog.cb(handle); } } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "timer.h" */ /* AMALGAMATE: #include "handle.h" */ @@ -5189,7 +5189,7 @@ void ev_timer_stop(ev_timer_t* handle) ev__handle_event_dec(&handle->base); ev_map_erase(&handle->base.loop->timer.heap, &handle->node); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ /* AMALGAMATE: #include "handle.h" */ @@ -5303,7 +5303,7 @@ int ev_udp_send(ev_udp_t* udp, ev_udp_write_t* req, ev_buf_t* bufs, size_t nbuf, ev__handle_exit(&req->handle, NULL); return ret; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -5327,8 +5327,8 @@ unsigned ev_version_code(void) { return EV_VERSION_CODE; } - -#if defined(_WIN32) /* AMALGAMATE: ev.c (1/3) */ + +#if defined(_WIN32) /* AMALGAMATE: ev.c (1/3) */ #ifndef __EV_WINAPI_INTERNAL_H__ #define __EV_WINAPI_INTERNAL_H__ #ifdef __cplusplus @@ -5835,7 +5835,7 @@ EV_LOCAL void ev__winapi_init(void); } #endif #endif - + #ifndef __EV_WINSOCK_INTERNAL_H__ #define __EV_WINSOCK_INTERNAL_H__ @@ -5916,59 +5916,59 @@ EV_LOCAL int ev__ntstatus_to_winsock_error(NTSTATUS status); } #endif #endif - -#ifndef __EV_ASYNC_WIN_INTERNAL_H__ -#define __EV_ASYNC_WIN_INTERNAL_H__ - -/* AMALGAMATE: #include "async.h" */ - -#endif - -#ifndef __EV_FS_WIN_INTERNAL_H__ -#define __EV_FS_WIN_INTERNAL_H__ - -/* AMALGAMATE: #include "fs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ev_dirent_w_s -{ - WCHAR* name; /**< Entry name */ - ev_dirent_type_t type; /**< Entry type */ -}ev_dirent_w_t; - -/** - * @brief Directory information callback. - * @param[in] info Directory information. - * @param[in] arg User defined argument. - * @return non-zero to stop. - */ -typedef int (*ev_readdir_w_cb)(ev_dirent_w_t* info, void* arg); - -/** - * @brief Same as [readdir(3)](https://man7.org/linux/man-pages/man3/readdir.3.html) - * @param[in] path Directory path. The path can be end with or without '/'. - * @param[in] cb Dirent callback. - * @param[in] arg User defined data. - * @return #ev_errno_t - */ -EV_LOCAL int ev__fs_readdir_w(const WCHAR* path, ev_readdir_w_cb cb, void* arg); - -#ifdef __cplusplus -} -#endif - -#endif - -#ifndef __EV_UDP_WIN_INTERNAL_H__ -#define __EV_UDP_WIN_INTERNAL_H__ - -/* AMALGAMATE: #include "udp.h" */ - -#endif - + +#ifndef __EV_ASYNC_WIN_INTERNAL_H__ +#define __EV_ASYNC_WIN_INTERNAL_H__ + +/* AMALGAMATE: #include "async.h" */ + +#endif + +#ifndef __EV_FS_WIN_INTERNAL_H__ +#define __EV_FS_WIN_INTERNAL_H__ + +/* AMALGAMATE: #include "fs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ev_dirent_w_s +{ + WCHAR* name; /**< Entry name */ + ev_dirent_type_t type; /**< Entry type */ +}ev_dirent_w_t; + +/** + * @brief Directory information callback. + * @param[in] info Directory information. + * @param[in] arg User defined argument. + * @return non-zero to stop. + */ +typedef int (*ev_readdir_w_cb)(ev_dirent_w_t* info, void* arg); + +/** + * @brief Same as [readdir(3)](https://man7.org/linux/man-pages/man3/readdir.3.html) + * @param[in] path Directory path. The path can be end with or without '/'. + * @param[in] cb Dirent callback. + * @param[in] arg User defined data. + * @return #ev_errno_t + */ +EV_LOCAL int ev__fs_readdir_w(const WCHAR* path, ev_readdir_w_cb cb, void* arg); + +#ifdef __cplusplus +} +#endif + +#endif + +#ifndef __EV_UDP_WIN_INTERNAL_H__ +#define __EV_UDP_WIN_INTERNAL_H__ + +/* AMALGAMATE: #include "udp.h" */ + +#endif + #ifndef __EV_LOOP_WIN_INTERNAL_H__ #define __EV_LOOP_WIN_INTERNAL_H__ #ifdef __cplusplus @@ -6040,58 +6040,58 @@ EV_LOCAL int ev__ipv6only_win(SOCKET sock, int opt); } #endif #endif - -#ifndef __EV_PROCESS_WIN_INTERNAL_H__ -#define __EV_PROCESS_WIN_INTERNAL_H__ - -/* AMALGAMATE: #include "ev.h" */ - -#endif - -#ifndef __EV_PIPE_WIN_INTERNAL_H__ -#define __EV_PIPE_WIN_INTERNAL_H__ - -/* AMALGAMATE: #include "pipe.h" */ - -#endif - -#ifndef __EV_MISC_WIN_INTERNAL_H__ -#define __EV_MISC_WIN_INTERNAL_H__ - -/* AMALGAMATE: #include "misc.h" */ - -#define EV_FATAL_SYSCALL(errcode, syscall) \ - ev__fatal_syscall(__FILE__, __LINE__, errcode, syscall) - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Maps a character string to a UTF-16 (wide character) string. - * @param[out] dst Pointer to store wide string. Use #ev_free() to release it. - * @param[in] src Source string. - * @return The number of characters (not bytes) of \p dst, or #ev_errno_t if error. - */ -EV_LOCAL ssize_t ev__utf8_to_wide(WCHAR** dst, const char* src); - -/** - * @brief Maps a UTF-16 (wide character) string to a character string. - * @param[out] dst Pointer to store wide string. Use #ev_free() to release it. - * @param[in] src Source string. - * @return The number of characters (not bytes) of \p dst, or #ev_errno_t if error. - */ -EV_LOCAL ssize_t ev__wide_to_utf8(char** dst, const WCHAR* src); - -EV_LOCAL void ev__fatal_syscall(const char* file, int line, - DWORD errcode, const char* syscall); - -#ifdef __cplusplus -} -#endif - -#endif - + +#ifndef __EV_PROCESS_WIN_INTERNAL_H__ +#define __EV_PROCESS_WIN_INTERNAL_H__ + +/* AMALGAMATE: #include "ev.h" */ + +#endif + +#ifndef __EV_PIPE_WIN_INTERNAL_H__ +#define __EV_PIPE_WIN_INTERNAL_H__ + +/* AMALGAMATE: #include "pipe.h" */ + +#endif + +#ifndef __EV_MISC_WIN_INTERNAL_H__ +#define __EV_MISC_WIN_INTERNAL_H__ + +/* AMALGAMATE: #include "misc.h" */ + +#define EV_FATAL_SYSCALL(errcode, syscall) \ + ev__fatal_syscall(__FILE__, __LINE__, errcode, syscall) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maps a character string to a UTF-16 (wide character) string. + * @param[out] dst Pointer to store wide string. Use #ev_free() to release it. + * @param[in] src Source string. + * @return The number of characters (not bytes) of \p dst, or #ev_errno_t if error. + */ +EV_LOCAL ssize_t ev__utf8_to_wide(WCHAR** dst, const char* src); + +/** + * @brief Maps a UTF-16 (wide character) string to a character string. + * @param[out] dst Pointer to store wide string. Use #ev_free() to release it. + * @param[in] src Source string. + * @return The number of characters (not bytes) of \p dst, or #ev_errno_t if error. + */ +EV_LOCAL ssize_t ev__wide_to_utf8(char** dst, const WCHAR* src); + +EV_LOCAL void ev__fatal_syscall(const char* file, int line, + DWORD errcode, const char* syscall); + +#ifdef __cplusplus +} +#endif + +#endif + #ifndef __EV_THREAD_WIN_INTERNAL_H__ #define __EV_THREAD_WIN_INTERNAL_H__ @@ -6111,7 +6111,7 @@ EV_LOCAL void ev__thread_init_win(void); } #endif #endif - + #ifndef __EV_THREADPOOL_WIN_INTERNAL_H__ #define __EV_THREADPOOL_WIN_INTERNAL_H__ @@ -6129,7 +6129,7 @@ EV_LOCAL void ev__threadpool_exit_win(ev_loop_t* loop); #endif #endif - + #ifndef __EV_TCP_WIN_INTERNAL_H__ #define __EV_TCP_WIN_INTERNAL_H__ @@ -6152,70 +6152,70 @@ EV_LOCAL int ev__tcp_open_win(ev_tcp_t* tcp, SOCKET fd); } #endif #endif - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "async_win.h" */ -/* AMALGAMATE: #include "handle.h" */ -/* AMALGAMATE: #include "loop_win.h" */ -#include - -static void _async_on_iocp_win(ev_iocp_t* iocp, size_t transferred, void* arg) -{ - (void)transferred; (void)arg; - ev_async_t* handle = EV_CONTAINER_OF(iocp, ev_async_t, backend.io); - - handle->backend.async_sent = 0; - handle->active_cb(handle); -} - -static void _ev_async_on_close_win(ev_handle_t* handle) -{ - ev_async_t* async = EV_CONTAINER_OF(handle, ev_async_t, base); - - if (async->close_cb != NULL) - { - async->close_cb(async); - } -} - -static void _ev_asyc_exit_win(ev_async_t* handle, ev_async_cb close_cb) -{ - handle->close_cb = close_cb; - ev__handle_event_dec(&handle->base); - ev__handle_exit(&handle->base, close_cb != NULL ? _ev_async_on_close_win : NULL); -} - -EV_LOCAL void ev__async_exit_force(ev_async_t* handle) -{ - _ev_asyc_exit_win(handle, NULL); -} - -int ev_async_init(ev_loop_t* loop, ev_async_t* handle, ev_async_cb cb) -{ - handle->active_cb = cb; - handle->close_cb = NULL; - handle->backend.async_sent = 0; - - ev__iocp_init(&handle->backend.io, _async_on_iocp_win, NULL); - ev__handle_init(loop, &handle->base, EV_ROLE_EV_ASYNC); - ev__handle_event_add(&handle->base); - - return 0; -} - -void ev_async_exit(ev_async_t* handle, ev_async_cb close_cb) -{ - _ev_asyc_exit_win(handle, close_cb); -} - -void ev_async_wakeup(ev_async_t* handle) -{ - if (!InterlockedOr(&handle->backend.async_sent, 1)) - { - ev__iocp_post(handle->base.loop, &handle->backend.io); - } -} - + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "async_win.h" */ +/* AMALGAMATE: #include "handle.h" */ +/* AMALGAMATE: #include "loop_win.h" */ +#include + +static void _async_on_iocp_win(ev_iocp_t* iocp, size_t transferred, void* arg) +{ + (void)transferred; (void)arg; + ev_async_t* handle = EV_CONTAINER_OF(iocp, ev_async_t, backend.io); + + handle->backend.async_sent = 0; + handle->active_cb(handle); +} + +static void _ev_async_on_close_win(ev_handle_t* handle) +{ + ev_async_t* async = EV_CONTAINER_OF(handle, ev_async_t, base); + + if (async->close_cb != NULL) + { + async->close_cb(async); + } +} + +static void _ev_asyc_exit_win(ev_async_t* handle, ev_async_cb close_cb) +{ + handle->close_cb = close_cb; + ev__handle_event_dec(&handle->base); + ev__handle_exit(&handle->base, close_cb != NULL ? _ev_async_on_close_win : NULL); +} + +EV_LOCAL void ev__async_exit_force(ev_async_t* handle) +{ + _ev_asyc_exit_win(handle, NULL); +} + +int ev_async_init(ev_loop_t* loop, ev_async_t* handle, ev_async_cb cb) +{ + handle->active_cb = cb; + handle->close_cb = NULL; + handle->backend.async_sent = 0; + + ev__iocp_init(&handle->backend.io, _async_on_iocp_win, NULL); + ev__handle_init(loop, &handle->base, EV_ROLE_EV_ASYNC); + ev__handle_event_add(&handle->base); + + return 0; +} + +void ev_async_exit(ev_async_t* handle, ev_async_cb close_cb) +{ + _ev_asyc_exit_win(handle, close_cb); +} + +void ev_async_wakeup(ev_async_t* handle) +{ + if (!InterlockedOr(&handle->backend.async_sent, 1)) + { + ev__iocp_post(handle->base.loop, &handle->backend.io); + } +} + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ /* AMALGAMATE: #include "allocator.h" */ @@ -7075,7 +7075,7 @@ EV_LOCAL int ev__fs_mkdir(const char* path, int mode) return (int)ret; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "misc.h" */ /* AMALGAMATE: #include "allocator.h" */ @@ -7264,229 +7264,229 @@ EV_LOCAL void ev__iocp_post(ev_loop_t* loop, ev_iocp_t* req) } } -EV_LOCAL int ev__reuse_win(SOCKET sock, int opt) -{ - DWORD optval = !!opt; - int optlen = sizeof(optval); - - int err; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, optlen) != 0) - { - err = WSAGetLastError(); - return ev__translate_sys_error(err); - } - - return 0; -} - -EV_LOCAL int ev__ipv6only_win(SOCKET sock, int opt) -{ - DWORD optval = !!opt; - int optlen = sizeof(optval); - - if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&optval, optlen) != 0) - { - int err = WSAGetLastError(); - return ev__translate_sys_error(err); - } - - return 0; -} - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "allocator.h" */ -/* AMALGAMATE: #include "winapi.h" */ -/* AMALGAMATE: #include "misc_win.h" */ -#include - -EV_LOCAL ssize_t ev__utf8_to_wide(WCHAR** dst, const char* src) -{ - int errcode; - int pathw_len = MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0); - if (pathw_len == 0) - { - errcode = GetLastError(); - return ev__translate_sys_error(errcode); - } - - size_t buf_sz = pathw_len * sizeof(WCHAR); - WCHAR* buf = ev_malloc(buf_sz); - if (buf == NULL) - { - return EV_ENOMEM; - } - - int r = MultiByteToWideChar(CP_UTF8, 0, src, -1, buf, pathw_len); - assert(r == pathw_len); - - *dst = buf; - - return r; -} - -EV_LOCAL ssize_t ev__wide_to_utf8(char** dst, const WCHAR* src) -{ - int errcode; - int target_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, - NULL, NULL); - if (target_len == 0) - { - errcode = GetLastError(); - return ev__translate_sys_error(errcode); - } - - char* buf = ev_malloc(target_len); - if (buf == NULL) +EV_LOCAL int ev__reuse_win(SOCKET sock, int opt) +{ + DWORD optval = !!opt; + int optlen = sizeof(optval); + + int err; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, optlen) != 0) { - return EV_ENOMEM; + err = WSAGetLastError(); + return ev__translate_sys_error(err); } - int ret = WideCharToMultiByte(CP_UTF8, 0, src, -1, buf, target_len, NULL, - NULL); - assert(ret == target_len); - *dst = buf; - - return (ssize_t)ret; + return 0; } -EV_LOCAL int ev__translate_sys_error(int err) +EV_LOCAL int ev__ipv6only_win(SOCKET sock, int opt) { - switch (err) - { - case 0: return 0; - case ERROR_NOACCESS: return EV_EACCES; - case WSAEACCES: return EV_EACCES; - case ERROR_ELEVATION_REQUIRED: return EV_EACCES; - case ERROR_CANT_ACCESS_FILE: return EV_EACCES; - case ERROR_ADDRESS_ALREADY_ASSOCIATED: return EV_EADDRINUSE; - case WSAEADDRINUSE: return EV_EADDRINUSE; - case WSAEADDRNOTAVAIL: return EV_EADDRNOTAVAIL; - case WSAEAFNOSUPPORT: return EV_EAFNOSUPPORT; - case WSAEWOULDBLOCK: return EV_EAGAIN; - case WSAEALREADY: return EV_EALREADY; - case ERROR_INVALID_FLAGS: return EV_EBADF; - case ERROR_INVALID_HANDLE: return EV_EBADF; - case ERROR_LOCK_VIOLATION: return EV_EBUSY; - case ERROR_PIPE_BUSY: return EV_EBUSY; - case ERROR_SHARING_VIOLATION: return EV_EBUSY; - case ERROR_OPERATION_ABORTED: return EV_ECANCELED; - case WSAEINTR: return EV_ECANCELED; - case ERROR_CONNECTION_ABORTED: return EV_ECONNABORTED; - case WSAECONNABORTED: return EV_ECONNABORTED; - case ERROR_CONNECTION_REFUSED: return EV_ECONNREFUSED; - case WSAECONNREFUSED: return EV_ECONNREFUSED; - case ERROR_NETNAME_DELETED: return EV_ECONNRESET; - case WSAECONNRESET: return EV_ECONNRESET; - case ERROR_ALREADY_EXISTS: return EV_EEXIST; - case ERROR_FILE_EXISTS: return EV_EEXIST; - case ERROR_BUFFER_OVERFLOW: return EV_EFAULT; - case WSAEFAULT: return EV_EFAULT; - case ERROR_HOST_UNREACHABLE: return EV_EHOSTUNREACH; - case WSAEHOSTUNREACH: return EV_EHOSTUNREACH; - case ERROR_INSUFFICIENT_BUFFER: return EV_EINVAL; - case ERROR_INVALID_DATA: return EV_EINVAL; - case ERROR_INVALID_PARAMETER: return EV_EINVAL; - case ERROR_SYMLINK_NOT_SUPPORTED: return EV_EINVAL; - case WSAEINVAL: return EV_EINVAL; - case WSAEPFNOSUPPORT: return EV_EINVAL; - case WSAESOCKTNOSUPPORT: return EV_EINVAL; - case ERROR_BEGINNING_OF_MEDIA: return EV_EIO; - case ERROR_BUS_RESET: return EV_EIO; - case ERROR_CRC: return EV_EIO; - case ERROR_DEVICE_DOOR_OPEN: return EV_EIO; - case ERROR_DEVICE_REQUIRES_CLEANING: return EV_EIO; - case ERROR_DISK_CORRUPT: return EV_EIO; - case ERROR_EOM_OVERFLOW: return EV_EIO; - case ERROR_FILEMARK_DETECTED: return EV_EIO; - case ERROR_GEN_FAILURE: return EV_EIO; - case ERROR_INVALID_BLOCK_LENGTH: return EV_EIO; - case ERROR_IO_DEVICE: return EV_EIO; - case ERROR_NO_DATA_DETECTED: return EV_EIO; - case ERROR_NO_SIGNAL_SENT: return EV_EIO; - case ERROR_OPEN_FAILED: return EV_EIO; - case ERROR_SETMARK_DETECTED: return EV_EIO; - case ERROR_SIGNAL_REFUSED: return EV_EIO; - case WSAEISCONN: return EV_EISCONN; - case ERROR_CANT_RESOLVE_FILENAME: return EV_ELOOP; - case ERROR_TOO_MANY_OPEN_FILES: return EV_EMFILE; - case WSAEMFILE: return EV_EMFILE; - case WSAEMSGSIZE: return EV_EMSGSIZE; - case ERROR_FILENAME_EXCED_RANGE: return EV_ENAMETOOLONG; - case ERROR_NETWORK_UNREACHABLE: return EV_ENETUNREACH; - case WSAENETUNREACH: return EV_ENETUNREACH; - case WSAENOBUFS: return EV_ENOBUFS; - case ERROR_BAD_PATHNAME: return EV_ENOENT; - case ERROR_DIRECTORY: return EV_ENOENT; - case ERROR_ENVVAR_NOT_FOUND: return EV_ENOENT; - case ERROR_FILE_NOT_FOUND: return EV_ENOENT; - case ERROR_INVALID_NAME: return EV_ENOENT; - case ERROR_INVALID_DRIVE: return EV_ENOENT; - case ERROR_INVALID_REPARSE_DATA: return EV_ENOENT; - case ERROR_MOD_NOT_FOUND: return EV_ENOENT; - case ERROR_PATH_NOT_FOUND: return EV_ENOENT; - case WSAHOST_NOT_FOUND: return EV_ENOENT; - case WSANO_DATA: return EV_ENOENT; - case ERROR_NOT_ENOUGH_MEMORY: return EV_ENOMEM; - case ERROR_OUTOFMEMORY: return EV_ENOMEM; - case ERROR_CANNOT_MAKE: return EV_ENOSPC; - case ERROR_DISK_FULL: return EV_ENOSPC; - case ERROR_EA_TABLE_FULL: return EV_ENOSPC; - case ERROR_END_OF_MEDIA: return EV_ENOSPC; - case ERROR_HANDLE_DISK_FULL: return EV_ENOSPC; - case ERROR_NOT_CONNECTED: return EV_ENOTCONN; - case WSAENOTCONN: return EV_ENOTCONN; - case ERROR_DIR_NOT_EMPTY: return EV_ENOTEMPTY; - case WSAENOTSOCK: return EV_ENOTSOCK; - case ERROR_NOT_SUPPORTED: return EV_ENOTSUP; - case ERROR_BROKEN_PIPE: return EV_EOF; - case ERROR_ACCESS_DENIED: return EV_EPERM; - case ERROR_PRIVILEGE_NOT_HELD: return EV_EPERM; - case ERROR_BAD_PIPE: return EV_EPIPE; - case ERROR_NO_DATA: return EV_EPIPE; - case ERROR_PIPE_NOT_CONNECTED: return EV_EPIPE; - case WSAESHUTDOWN: return EV_EPIPE; - case WSAEPROTONOSUPPORT: return EV_EPROTONOSUPPORT; - case ERROR_WRITE_PROTECT: return EV_EROFS; - case ERROR_SEM_TIMEOUT: return EV_ETIMEDOUT; - case WSAETIMEDOUT: return EV_ETIMEDOUT; - case ERROR_NOT_SAME_DEVICE: return EV_EXDEV; - case ERROR_INVALID_FUNCTION: return EV_EISDIR; - case ERROR_META_EXPANSION_TOO_LONG: return EV_E2BIG; - default: return ev__translate_posix_sys_error(err); - } -} - -EV_LOCAL void ev__fatal_syscall(const char* file, int line, - DWORD errcode, const char* syscall) -{ - const char* errmsg = "Unknown error"; - char* buf = NULL; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); - if (buf) - { - errmsg = buf; - } - - if (syscall != NULL) - { - fprintf(stderr, "%s:%d: [%s] %s(%d)\n", file, line, syscall, errmsg, (int)errcode); - } - else - { - fprintf(stderr, "%s:%d: %s(%d)\n", file, line, errmsg, (int)errcode); - } + DWORD optval = !!opt; + int optlen = sizeof(optval); - if (buf) + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&optval, optlen) != 0) { - LocalFree(buf); - buf = NULL; + int err = WSAGetLastError(); + return ev__translate_sys_error(err); } - __debugbreak(); - abort(); + return 0; } - + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "allocator.h" */ +/* AMALGAMATE: #include "winapi.h" */ +/* AMALGAMATE: #include "misc_win.h" */ +#include + +EV_LOCAL ssize_t ev__utf8_to_wide(WCHAR** dst, const char* src) +{ + int errcode; + int pathw_len = MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0); + if (pathw_len == 0) + { + errcode = GetLastError(); + return ev__translate_sys_error(errcode); + } + + size_t buf_sz = pathw_len * sizeof(WCHAR); + WCHAR* buf = ev_malloc(buf_sz); + if (buf == NULL) + { + return EV_ENOMEM; + } + + int r = MultiByteToWideChar(CP_UTF8, 0, src, -1, buf, pathw_len); + assert(r == pathw_len); + + *dst = buf; + + return r; +} + +EV_LOCAL ssize_t ev__wide_to_utf8(char** dst, const WCHAR* src) +{ + int errcode; + int target_len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, + NULL, NULL); + if (target_len == 0) + { + errcode = GetLastError(); + return ev__translate_sys_error(errcode); + } + + char* buf = ev_malloc(target_len); + if (buf == NULL) + { + return EV_ENOMEM; + } + + int ret = WideCharToMultiByte(CP_UTF8, 0, src, -1, buf, target_len, NULL, + NULL); + assert(ret == target_len); + *dst = buf; + + return (ssize_t)ret; +} + +EV_LOCAL int ev__translate_sys_error(int err) +{ + switch (err) + { + case 0: return 0; + case ERROR_NOACCESS: return EV_EACCES; + case WSAEACCES: return EV_EACCES; + case ERROR_ELEVATION_REQUIRED: return EV_EACCES; + case ERROR_CANT_ACCESS_FILE: return EV_EACCES; + case ERROR_ADDRESS_ALREADY_ASSOCIATED: return EV_EADDRINUSE; + case WSAEADDRINUSE: return EV_EADDRINUSE; + case WSAEADDRNOTAVAIL: return EV_EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: return EV_EAFNOSUPPORT; + case WSAEWOULDBLOCK: return EV_EAGAIN; + case WSAEALREADY: return EV_EALREADY; + case ERROR_INVALID_FLAGS: return EV_EBADF; + case ERROR_INVALID_HANDLE: return EV_EBADF; + case ERROR_LOCK_VIOLATION: return EV_EBUSY; + case ERROR_PIPE_BUSY: return EV_EBUSY; + case ERROR_SHARING_VIOLATION: return EV_EBUSY; + case ERROR_OPERATION_ABORTED: return EV_ECANCELED; + case WSAEINTR: return EV_ECANCELED; + case ERROR_CONNECTION_ABORTED: return EV_ECONNABORTED; + case WSAECONNABORTED: return EV_ECONNABORTED; + case ERROR_CONNECTION_REFUSED: return EV_ECONNREFUSED; + case WSAECONNREFUSED: return EV_ECONNREFUSED; + case ERROR_NETNAME_DELETED: return EV_ECONNRESET; + case WSAECONNRESET: return EV_ECONNRESET; + case ERROR_ALREADY_EXISTS: return EV_EEXIST; + case ERROR_FILE_EXISTS: return EV_EEXIST; + case ERROR_BUFFER_OVERFLOW: return EV_EFAULT; + case WSAEFAULT: return EV_EFAULT; + case ERROR_HOST_UNREACHABLE: return EV_EHOSTUNREACH; + case WSAEHOSTUNREACH: return EV_EHOSTUNREACH; + case ERROR_INSUFFICIENT_BUFFER: return EV_EINVAL; + case ERROR_INVALID_DATA: return EV_EINVAL; + case ERROR_INVALID_PARAMETER: return EV_EINVAL; + case ERROR_SYMLINK_NOT_SUPPORTED: return EV_EINVAL; + case WSAEINVAL: return EV_EINVAL; + case WSAEPFNOSUPPORT: return EV_EINVAL; + case WSAESOCKTNOSUPPORT: return EV_EINVAL; + case ERROR_BEGINNING_OF_MEDIA: return EV_EIO; + case ERROR_BUS_RESET: return EV_EIO; + case ERROR_CRC: return EV_EIO; + case ERROR_DEVICE_DOOR_OPEN: return EV_EIO; + case ERROR_DEVICE_REQUIRES_CLEANING: return EV_EIO; + case ERROR_DISK_CORRUPT: return EV_EIO; + case ERROR_EOM_OVERFLOW: return EV_EIO; + case ERROR_FILEMARK_DETECTED: return EV_EIO; + case ERROR_GEN_FAILURE: return EV_EIO; + case ERROR_INVALID_BLOCK_LENGTH: return EV_EIO; + case ERROR_IO_DEVICE: return EV_EIO; + case ERROR_NO_DATA_DETECTED: return EV_EIO; + case ERROR_NO_SIGNAL_SENT: return EV_EIO; + case ERROR_OPEN_FAILED: return EV_EIO; + case ERROR_SETMARK_DETECTED: return EV_EIO; + case ERROR_SIGNAL_REFUSED: return EV_EIO; + case WSAEISCONN: return EV_EISCONN; + case ERROR_CANT_RESOLVE_FILENAME: return EV_ELOOP; + case ERROR_TOO_MANY_OPEN_FILES: return EV_EMFILE; + case WSAEMFILE: return EV_EMFILE; + case WSAEMSGSIZE: return EV_EMSGSIZE; + case ERROR_FILENAME_EXCED_RANGE: return EV_ENAMETOOLONG; + case ERROR_NETWORK_UNREACHABLE: return EV_ENETUNREACH; + case WSAENETUNREACH: return EV_ENETUNREACH; + case WSAENOBUFS: return EV_ENOBUFS; + case ERROR_BAD_PATHNAME: return EV_ENOENT; + case ERROR_DIRECTORY: return EV_ENOENT; + case ERROR_ENVVAR_NOT_FOUND: return EV_ENOENT; + case ERROR_FILE_NOT_FOUND: return EV_ENOENT; + case ERROR_INVALID_NAME: return EV_ENOENT; + case ERROR_INVALID_DRIVE: return EV_ENOENT; + case ERROR_INVALID_REPARSE_DATA: return EV_ENOENT; + case ERROR_MOD_NOT_FOUND: return EV_ENOENT; + case ERROR_PATH_NOT_FOUND: return EV_ENOENT; + case WSAHOST_NOT_FOUND: return EV_ENOENT; + case WSANO_DATA: return EV_ENOENT; + case ERROR_NOT_ENOUGH_MEMORY: return EV_ENOMEM; + case ERROR_OUTOFMEMORY: return EV_ENOMEM; + case ERROR_CANNOT_MAKE: return EV_ENOSPC; + case ERROR_DISK_FULL: return EV_ENOSPC; + case ERROR_EA_TABLE_FULL: return EV_ENOSPC; + case ERROR_END_OF_MEDIA: return EV_ENOSPC; + case ERROR_HANDLE_DISK_FULL: return EV_ENOSPC; + case ERROR_NOT_CONNECTED: return EV_ENOTCONN; + case WSAENOTCONN: return EV_ENOTCONN; + case ERROR_DIR_NOT_EMPTY: return EV_ENOTEMPTY; + case WSAENOTSOCK: return EV_ENOTSOCK; + case ERROR_NOT_SUPPORTED: return EV_ENOTSUP; + case ERROR_BROKEN_PIPE: return EV_EOF; + case ERROR_ACCESS_DENIED: return EV_EPERM; + case ERROR_PRIVILEGE_NOT_HELD: return EV_EPERM; + case ERROR_BAD_PIPE: return EV_EPIPE; + case ERROR_NO_DATA: return EV_EPIPE; + case ERROR_PIPE_NOT_CONNECTED: return EV_EPIPE; + case WSAESHUTDOWN: return EV_EPIPE; + case WSAEPROTONOSUPPORT: return EV_EPROTONOSUPPORT; + case ERROR_WRITE_PROTECT: return EV_EROFS; + case ERROR_SEM_TIMEOUT: return EV_ETIMEDOUT; + case WSAETIMEDOUT: return EV_ETIMEDOUT; + case ERROR_NOT_SAME_DEVICE: return EV_EXDEV; + case ERROR_INVALID_FUNCTION: return EV_EISDIR; + case ERROR_META_EXPANSION_TOO_LONG: return EV_E2BIG; + default: return ev__translate_posix_sys_error(err); + } +} + +EV_LOCAL void ev__fatal_syscall(const char* file, int line, + DWORD errcode, const char* syscall) +{ + const char* errmsg = "Unknown error"; + char* buf = NULL; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errcode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL); + if (buf) + { + errmsg = buf; + } + + if (syscall != NULL) + { + fprintf(stderr, "%s:%d: [%s] %s(%d)\n", file, line, syscall, errmsg, (int)errcode); + } + else + { + fprintf(stderr, "%s:%d: %s(%d)\n", file, line, errmsg, (int)errcode); + } + + if (buf) + { + LocalFree(buf); + buf = NULL; + } + + __debugbreak(); + abort(); +} + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -7520,7 +7520,7 @@ int ev_mutex_try_enter(ev_mutex_t* handle) return EV_EBUSY; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop_win.h" */ @@ -7541,7 +7541,7 @@ void ev_once_execute(ev_once_t* guard, ev_once_cb cb) EV_ABORT("GetLastError:%lu", (unsigned long)errcode); } } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "handle.h" */ /* AMALGAMATE: #include "loop_win.h" */ @@ -8998,7 +8998,7 @@ void ev_pipe_close(ev_os_pipe_t fd) { CloseHandle(fd); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "async.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -9647,7 +9647,7 @@ ssize_t ev_exepath(char* buffer, size_t size) ev_free(utf16_buffer); return ev__translate_sys_error(err); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -9709,7 +9709,7 @@ int ev_sem_try_wait(ev_sem_t* sem) DWORD errcode = GetLastError(); EV_ABORT("ret:%lu, GetLastError:%lu", ret, errcode); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "misc_win.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -9792,7 +9792,7 @@ void ev_shm_exit(ev_shm_t* shm) EV_ABORT("GetLastError:%lu", (unsigned long)GetLastError()); } } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "handle.h" */ /* AMALGAMATE: #include "loop_win.h" */ @@ -10556,7 +10556,7 @@ EV_LOCAL int ev__tcp_open_win(ev_tcp_t* tcp, SOCKET fd) return 0; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop_win.h" */ /* AMALGAMATE: #include "misc_win.h" */ @@ -10742,7 +10742,7 @@ void* ev_tls_get(ev_tls_t* tls) } return val; } - + /* AMALGAMATE: #include "threadpool_win.h" */ /* AMALGAMATE: #include "loop_win.h" */ @@ -10769,7 +10769,7 @@ EV_LOCAL void ev__threadpool_exit_win(ev_loop_t* loop) { (void)loop; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "misc.h" */ /* AMALGAMATE: #include "loop_win.h" */ @@ -11705,7 +11705,7 @@ int ev_udp_set_ttl(ev_udp_t* udp, int ttl) return 0; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "winapi.h" */ #include @@ -11734,7 +11734,7 @@ EV_LOCAL void ev__winapi_init(void) #undef GET_NTDLL_FUNC } - + /* AMALGAMATE: #include "winsock.h" */ /* AMALGAMATE: #include "misc_win.h" */ @@ -12115,41 +12115,41 @@ EV_LOCAL int ev__ntstatus_to_winsock_error(NTSTATUS status) } } } - -#else /* AMALGAMATE: ev.c (2/3) */ -#ifndef __EV_ASYNC_UNIX_INTERNAL_H__ -#define __EV_ASYNC_UNIX_INTERNAL_H__ - -/* AMALGAMATE: #include "async.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Create a pair of eventfd. - * Index 0 for read, index 1 for write. - */ -EV_LOCAL int ev__asyc_eventfd(int evtfd[2]); - -EV_LOCAL void ev__async_eventfd_close(int fd); - -/** - * @brief Post event to eventfd. - */ -EV_LOCAL void ev__async_post(int wfd); - -/** - * @brief Pend event from eventfd. - */ -EV_LOCAL void ev__async_pend(int rfd); - -#ifdef __cplusplus -} -#endif - -#endif - + +#else /* AMALGAMATE: ev.c (2/3) */ +#ifndef __EV_ASYNC_UNIX_INTERNAL_H__ +#define __EV_ASYNC_UNIX_INTERNAL_H__ + +/* AMALGAMATE: #include "async.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create a pair of eventfd. + * Index 0 for read, index 1 for write. + */ +EV_LOCAL int ev__asyc_eventfd(int evtfd[2]); + +EV_LOCAL void ev__async_eventfd_close(int fd); + +/** + * @brief Post event to eventfd. + */ +EV_LOCAL void ev__async_post(int wfd); + +/** + * @brief Pend event from eventfd. + */ +EV_LOCAL void ev__async_pend(int rfd); + +#ifdef __cplusplus +} +#endif + +#endif + #ifndef __EV_IO_UNIX_H__ #define __EV_IO_UNIX_H__ @@ -12259,33 +12259,33 @@ EV_LOCAL int ev__send_unix(int fd, ev_write_t* req, } #endif #endif - -#ifndef __EV_PROCESS_UNIX_H__ -#define __EV_PROCESS_UNIX_H__ - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "defs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ev_process_ctx_s -{ - ev_list_t wait_queue; /**< #ev_process_t::node */ - ev_mutex_t wait_queue_mutex; /**< Mutex for wait_queue */ -} ev_process_ctx_t; - -/** - * @brief Initialize process context. - */ -EV_LOCAL void ev__init_process_unix(void); - -#ifdef __cplusplus -} -#endif -#endif - + +#ifndef __EV_PROCESS_UNIX_H__ +#define __EV_PROCESS_UNIX_H__ + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "defs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ev_process_ctx_s +{ + ev_list_t wait_queue; /**< #ev_process_t::node */ + ev_mutex_t wait_queue_mutex; /**< Mutex for wait_queue */ +} ev_process_ctx_t; + +/** + * @brief Initialize process context. + */ +EV_LOCAL void ev__init_process_unix(void); + +#ifdef __cplusplus +} +#endif +#endif + #ifndef __EV_TCP_UNIX_H__ #define __EV_TCP_UNIX_H__ @@ -12308,7 +12308,7 @@ EV_LOCAL int ev__tcp_open(ev_tcp_t* tcp, int fd); } #endif #endif - + #ifndef __EV_LOOP_UNIX_H__ #define __EV_LOOP_UNIX_H__ @@ -12340,14 +12340,14 @@ EV_LOCAL void ev__init_once_unix(void); } #endif #endif - -#ifndef __EV_MISC_UNIX_INTERNAL_H__ -#define __EV_MISC_UNIX_INTERNAL_H__ - -/* AMALGAMATE: #include "misc.h" */ - -#endif - + +#ifndef __EV_MISC_UNIX_INTERNAL_H__ +#define __EV_MISC_UNIX_INTERNAL_H__ + +/* AMALGAMATE: #include "misc.h" */ + +#endif + #ifndef __EV_STREAM_UNIX_H__ #define __EV_STREAM_UNIX_H__ @@ -12416,190 +12416,190 @@ EV_LOCAL void ev__nonblock_stream_cleanup(ev_nonblock_stream_t* stream, unsigned } #endif #endif - -#ifndef __EV_WORK_INTERNAL_H__ -#define __EV_WORK_INTERNAL_H__ - -/* AMALGAMATE: #include "defs.h" */ - -#ifdef __cplusplus -extern "C" { -#endif - -EV_LOCAL void ev__init_work(ev_loop_t* loop); - -EV_LOCAL void ev__exit_work(ev_loop_t* loop); - -#ifdef __cplusplus -} -#endif - -#endif - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "io_unix.h" */ -/* AMALGAMATE: #include "loop.h" */ -/* AMALGAMATE: #include "handle.h" */ -/* AMALGAMATE: #include "misc_unix.h" */ -/* AMALGAMATE: #include "async_unix.h" */ -#include -#include -#include - -static void _async_on_wakeup_unix(ev_nonblock_io_t* io, unsigned evts, void* arg) -{ - (void)evts; (void)arg; - ev_async_t* handle = EV_CONTAINER_OF(io, ev_async_t, backend.io); - - ev__async_pend(handle->backend.pipfd[0]); - handle->active_cb(handle); -} - -static void _ev_async_on_close(ev_handle_t* handle) -{ - ev_async_t* async = EV_CONTAINER_OF(handle, ev_async_t, base); - - if (async->close_cb != NULL) - { - async->close_cb(async); - } -} - -static void _async_close_pipe(ev_async_t* handle) -{ - if (handle->backend.pipfd[0] != -1) - { - close(handle->backend.pipfd[0]); - handle->backend.pipfd[0] = -1; - } - if (handle->backend.pipfd[1] != -1) - { - close(handle->backend.pipfd[1]); - handle->backend.pipfd[1] = -1; - } -} - -static void _ev_async_exit(ev_async_t* handle, ev_async_cb close_cb) -{ - assert(!ev__handle_is_closing(&handle->base)); - - handle->close_cb = close_cb; - _async_close_pipe(handle); - - ev__handle_event_dec(&handle->base); - ev__handle_exit(&handle->base, close_cb != NULL ? _ev_async_on_close : NULL); -} - -EV_LOCAL void ev__async_exit_force(ev_async_t* handle) -{ - _ev_async_exit(handle, NULL); -} - -EV_LOCAL int ev__asyc_eventfd(int evtfd[2]) -{ - int errcode; - -#if defined(__linux__) - if ((evtfd[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) < 0) - { - errcode = errno; - return ev__translate_sys_error(errcode); - } - - if ((evtfd[1] = dup(evtfd[0])) < 0) - { - errcode = errno; - close(evtfd[0]); - return ev__translate_sys_error(errcode); - } -#else - errcode = ev_pipe_make(evtfd, EV_PIPE_NONBLOCK, EV_PIPE_NONBLOCK); - if (errcode != 0) - { - return errcode; - } -#endif - - return 0; -} - -EV_LOCAL void ev__async_eventfd_close(int fd) -{ - close(fd); -} - -EV_LOCAL void ev__async_post(int wfd) -{ - uint64_t val = 1; - - ssize_t write_size; - int errcode; - - do - { - write_size = write(wfd, &val, sizeof(val)); - }while(write_size == -1 && (errcode = errno) == EINTR); - - if (write_size < 0) - { - EV_ABORT(); - } -} - -EV_LOCAL void ev__async_pend(int rfd) -{ - uint64_t val; - int errcode; - ssize_t read_size; - - do - { - read_size = read(rfd, &val, sizeof(val)); - }while(read_size == -1 && (errcode = errno) == EINTR); - - if (read_size < 0) - { - EV_ABORT(); - } -} - -int ev_async_init(ev_loop_t* loop, ev_async_t* handle, ev_async_cb cb) -{ - int errcode; - - handle->active_cb = cb; - handle->close_cb = NULL; - ev__handle_init(loop, &handle->base, EV_ROLE_EV_ASYNC); - - errcode = ev__asyc_eventfd(handle->backend.pipfd); - if (errcode != 0) - { - goto err_close_handle; - } - - ev__nonblock_io_init(&handle->backend.io, handle->backend.pipfd[0], - _async_on_wakeup_unix, NULL); - ev__nonblock_io_add(loop, &handle->backend.io, EV_IO_IN); - ev__handle_event_add(&handle->base); - - return 0; - -err_close_handle: - _async_close_pipe(handle); - ev__handle_exit(&handle->base, NULL); - return errcode; -} - -void ev_async_exit(ev_async_t* handle, ev_async_cb close_cb) -{ - _ev_async_exit(handle, close_cb); -} - -void ev_async_wakeup(ev_async_t* handle) -{ - ev__async_post(handle->backend.pipfd[1]); -} - + +#ifndef __EV_WORK_INTERNAL_H__ +#define __EV_WORK_INTERNAL_H__ + +/* AMALGAMATE: #include "defs.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +EV_LOCAL void ev__init_work(ev_loop_t* loop); + +EV_LOCAL void ev__exit_work(ev_loop_t* loop); + +#ifdef __cplusplus +} +#endif + +#endif + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "io_unix.h" */ +/* AMALGAMATE: #include "loop.h" */ +/* AMALGAMATE: #include "handle.h" */ +/* AMALGAMATE: #include "misc_unix.h" */ +/* AMALGAMATE: #include "async_unix.h" */ +#include +#include +#include + +static void _async_on_wakeup_unix(ev_nonblock_io_t* io, unsigned evts, void* arg) +{ + (void)evts; (void)arg; + ev_async_t* handle = EV_CONTAINER_OF(io, ev_async_t, backend.io); + + ev__async_pend(handle->backend.pipfd[0]); + handle->active_cb(handle); +} + +static void _ev_async_on_close(ev_handle_t* handle) +{ + ev_async_t* async = EV_CONTAINER_OF(handle, ev_async_t, base); + + if (async->close_cb != NULL) + { + async->close_cb(async); + } +} + +static void _async_close_pipe(ev_async_t* handle) +{ + if (handle->backend.pipfd[0] != -1) + { + close(handle->backend.pipfd[0]); + handle->backend.pipfd[0] = -1; + } + if (handle->backend.pipfd[1] != -1) + { + close(handle->backend.pipfd[1]); + handle->backend.pipfd[1] = -1; + } +} + +static void _ev_async_exit(ev_async_t* handle, ev_async_cb close_cb) +{ + assert(!ev__handle_is_closing(&handle->base)); + + handle->close_cb = close_cb; + _async_close_pipe(handle); + + ev__handle_event_dec(&handle->base); + ev__handle_exit(&handle->base, close_cb != NULL ? _ev_async_on_close : NULL); +} + +EV_LOCAL void ev__async_exit_force(ev_async_t* handle) +{ + _ev_async_exit(handle, NULL); +} + +EV_LOCAL int ev__asyc_eventfd(int evtfd[2]) +{ + int errcode; + +#if defined(__linux__) + if ((evtfd[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) < 0) + { + errcode = errno; + return ev__translate_sys_error(errcode); + } + + if ((evtfd[1] = dup(evtfd[0])) < 0) + { + errcode = errno; + close(evtfd[0]); + return ev__translate_sys_error(errcode); + } +#else + errcode = ev_pipe_make(evtfd, EV_PIPE_NONBLOCK, EV_PIPE_NONBLOCK); + if (errcode != 0) + { + return errcode; + } +#endif + + return 0; +} + +EV_LOCAL void ev__async_eventfd_close(int fd) +{ + close(fd); +} + +EV_LOCAL void ev__async_post(int wfd) +{ + uint64_t val = 1; + + ssize_t write_size; + int errcode; + + do + { + write_size = write(wfd, &val, sizeof(val)); + }while(write_size == -1 && (errcode = errno) == EINTR); + + if (write_size < 0) + { + EV_ABORT(); + } +} + +EV_LOCAL void ev__async_pend(int rfd) +{ + uint64_t val; + int errcode; + ssize_t read_size; + + do + { + read_size = read(rfd, &val, sizeof(val)); + }while(read_size == -1 && (errcode = errno) == EINTR); + + if (read_size < 0) + { + EV_ABORT(); + } +} + +int ev_async_init(ev_loop_t* loop, ev_async_t* handle, ev_async_cb cb) +{ + int errcode; + + handle->active_cb = cb; + handle->close_cb = NULL; + ev__handle_init(loop, &handle->base, EV_ROLE_EV_ASYNC); + + errcode = ev__asyc_eventfd(handle->backend.pipfd); + if (errcode != 0) + { + goto err_close_handle; + } + + ev__nonblock_io_init(&handle->backend.io, handle->backend.pipfd[0], + _async_on_wakeup_unix, NULL); + ev__nonblock_io_add(loop, &handle->backend.io, EV_IO_IN); + ev__handle_event_add(&handle->base); + + return 0; + +err_close_handle: + _async_close_pipe(handle); + ev__handle_exit(&handle->base, NULL); + return errcode; +} + +void ev_async_exit(ev_async_t* handle, ev_async_cb close_cb) +{ + _ev_async_exit(handle, close_cb); +} + +void ev_async_wakeup(ev_async_t* handle) +{ + ev__async_post(handle->backend.pipfd[1]); +} + #define _GNU_SOURCE /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -12953,7 +12953,7 @@ EV_LOCAL int ev__fs_mkdir(const char* path, int mode) return ret; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "misc_unix.h" */ /* AMALGAMATE: #include "io_unix.h" */ @@ -13384,7 +13384,7 @@ EV_LOCAL int ev__send_unix(int fd, ev_write_t* req, return _ev_io_finalize_send_req_unix(req, (size_t)write_size); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop_unix.h" */ /* AMALGAMATE: #include "io_unix.h" */ @@ -13575,16 +13575,16 @@ EV_LOCAL void ev__poll(ev_loop_t* loop, uint32_t timeout) timeout = user_timeout - pass_time; } } - -/* AMALGAMATE: #include "ev.h" */ -/* AMALGAMATE: #include "misc_unix.h" */ -#include - -EV_LOCAL int ev__translate_sys_error(int syserr) -{ - return ev__translate_posix_sys_error(syserr); -} - + +/* AMALGAMATE: #include "ev.h" */ +/* AMALGAMATE: #include "misc_unix.h" */ +#include + +EV_LOCAL int ev__translate_sys_error(int syserr) +{ + return ev__translate_posix_sys_error(syserr); +} + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -13696,7 +13696,7 @@ int ev_mutex_try_enter(ev_mutex_t* handle) return EV_EBUSY; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ #include @@ -13708,7 +13708,7 @@ void ev_once_execute(ev_once_t* guard, ev_once_cb cb) EV_ABORT(); } } - + #define _GNU_SOURCE /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop_unix.h" */ @@ -14631,7 +14631,7 @@ void ev_pipe_close(ev_os_pipe_t fd) close(fd); } } - + #define _GNU_SOURCE /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "allocator.h" */ @@ -15333,7 +15333,7 @@ ssize_t ev_exepath(char* buffer, size_t size) ev_free(tmp_buffer); return errcode; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -15395,7 +15395,7 @@ int ev_sem_try_wait(ev_sem_t* sem) return 0; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "shmem.h" */ /* AMALGAMATE: #include "loop.h" */ @@ -15501,7 +15501,7 @@ void ev_shm_exit(ev_shm_t* shm) close(shm->backend.map_file); } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "stream_unix.h" */ @@ -15744,7 +15744,7 @@ EV_LOCAL void ev__nonblock_stream_cleanup(ev_nonblock_stream_t* stream, unsigned _ev_stream_cleanup_r(stream, EV_ECANCELED); } } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "loop_unix.h" */ /* AMALGAMATE: #include "stream_unix.h" */ @@ -16222,7 +16222,7 @@ EV_LOCAL int ev__tcp_open(ev_tcp_t* tcp, int fd) return 0; } - + #define _GNU_SOURCE /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "misc_unix.h" */ @@ -16408,7 +16408,7 @@ void* ev_tls_get(ev_tls_t* tls) { return pthread_getspecific(tls->tls); } - + /* AMALGAMATE: #include "threadpool.h" */ /* AMALGAMATE: #include "loop_unix.h" */ /* AMALGAMATE: #include "async_unix.h" */ @@ -16445,7 +16445,7 @@ EV_LOCAL void ev__exit_work(ev_loop_t* loop) ev__async_eventfd_close(loop->backend.threadpool.evtfd[1]); loop->backend.threadpool.evtfd[1] = -1; } - + /* AMALGAMATE: #include "ev.h" */ /* AMALGAMATE: #include "io_unix.h" */ /* AMALGAMATE: #include "misc_unix.h" */ @@ -17396,11 +17396,11 @@ int ev_udp_set_ttl(ev_udp_t* udp, int ttl) return _ev_udp_set_ttl_unix(udp, ttl, IP_TTL, IPV6_UNICAST_HOPS); } - -#endif /* AMALGAMATE: ev.c (3/3) */ -#if defined(EV_HAVE_LUA_BINDING) /* FEATURE: EV_HAVE_LUA_BINDING (1/2) */ -#include "lua.h" -#include "lauxlib.h" + +#endif /* AMALGAMATE: ev.c (3/3) */ +#if defined(EV_HAVE_LUA_BINDING) /* FEATURE: EV_HAVE_LUA_BINDING (1/2) */ +#include "lua.h" +#include "lauxlib.h" #ifndef __EV_LUA_INTERNAL_H__ #define __EV_LUA_INTERNAL_H__ @@ -17471,7 +17471,7 @@ int lev_error_ex(const char* file, int line, lua_State* L, ev_loop_t* loop, int #endif #endif - + #ifndef __EV_LUA_CHANNEL_H__ #define __EV_LUA_CHANNEL_H__ @@ -17488,7 +17488,7 @@ int lev_channel(lua_State* L); #endif #endif - + #ifndef __EV_LUA_FS_H__ #define __EV_LUA_FS_H__ @@ -17552,7 +17552,7 @@ ev_file_t* lev_try_to_file(lua_State* L, int idx); #endif #endif - + #ifndef __EV_LUA_MISC_H__ #define __EV_LUA_MISC_H__ @@ -17613,7 +17613,7 @@ int lev_arg_unpack(lua_State* L); #endif #endif - + #ifndef __EV_LUA_PIPE_H__ #define __EV_LUA_PIPE_H__ @@ -17632,7 +17632,7 @@ ev_pipe_t* lev_try_to_pipe(lua_State* L, int idx); #endif #endif - + #ifndef __EV_LUA_PROCESS_H__ #define __EV_LUA_PROCESS_H__ @@ -17653,7 +17653,7 @@ int lev_exepath(lua_State* L); #endif #endif - + #ifndef __EV_LUA_PROMISE_H__ #define __EV_LUA_PROMISE_H__ @@ -17715,7 +17715,7 @@ int lev_promise_get_value(lua_State* L, lev_promise_t* promise, lev_promise_cb c } #endif #endif - + #ifndef __EV_LUA_TCP_H__ #define __EV_LUA_TCP_H__ @@ -17737,7 +17737,7 @@ int lev_tcp(lua_State* L); #endif #endif - + #ifndef __EV_LUA_TIMER_H__ #define __EV_LUA_TIMER_H__ @@ -17753,7 +17753,7 @@ int lev_sleep(lua_State* L); } #endif #endif - + #ifndef __EV_LUA_UDP_H__ #define __EV_LUA_UDP_H__ @@ -17781,7 +17781,7 @@ int lev_udp(lua_State* L); #endif #endif - + /* AMALGAMATE: #include "channel.lua.h" */ /* AMALGAMATE: #include "fs.lua.h" */ /* AMALGAMATE: #include "misc.lua.h" */ @@ -18367,7 +18367,7 @@ void lev_wakeup(ev_loop_t* loop) lev_loop_t* self = EV_CONTAINER_OF(loop, lev_loop_t, loop); ev_async_wakeup(&self->async); } - + /* AMALGAMATE: #include "channel.lua.h" */ #include @@ -18634,7 +18634,7 @@ int lev_channel(lua_State* L) return 1; } - + /* AMALGAMATE: #include "fs.lua.h" */ #define LEV_FILE_NAME "__ev_file" @@ -19229,7 +19229,7 @@ ev_file_t* lev_try_to_file(lua_State* L, int idx) lev_file_t* self = luaL_testudata(L, idx, LEV_FILE_NAME); return self != NULL ? &self->file : NULL; } - + /* AMALGAMATE: #include "misc.lua.h" */ #define LEV_SOCKADDR_STORAGE_NAME "__ev_sockaddr_storage" @@ -19339,7 +19339,7 @@ int lev_arg_unpack(lua_State* L) return tmp_sp; } - + /* AMALGAMATE: #include "pipe.lua.h" */ #include @@ -19588,7 +19588,7 @@ ev_pipe_t* lev_try_to_pipe(lua_State* L, int idx) lev_pipe_t* self = luaL_testudata(L, idx, LEV_PIPE_NAME); return self != NULL ? &self->pipe : NULL; } - + /* AMALGAMATE: #include "process.lua.h" */ /* AMALGAMATE: #include "fs.lua.h" */ /* AMALGAMATE: #include "pipe.lua.h" */ @@ -19980,7 +19980,7 @@ int lev_exepath(lua_State* L) { return _lev_path_template(L, ev_exepath); } - + /* AMALGAMATE: #include "promise.lua.h" */ #define LEV_PROMISE_NAME "__ev_promise" @@ -20239,7 +20239,7 @@ int lev_promise_set_value(lua_State* L, lev_promise_t* promise, int narg) return 0; } - + /* AMALGAMATE: #include "tcp.lua.h" */ /* AMALGAMATE: #include "misc.lua.h" */ #include @@ -20631,7 +20631,7 @@ int lev_tcp(lua_State* L) return 1; } - + /* AMALGAMATE: #include "timer.lua.h" */ typedef struct lev_timer @@ -20696,7 +20696,7 @@ int lev_sleep(lua_State* L) lev_set_state(L, loop, 0); return lua_yieldk(L, 0, (lua_KContext)NULL, _lev_on_sleep_resume); } - + /* AMALGAMATE: #include "udp.lua.h" */ /* AMALGAMATE: #include "misc.lua.h" */ #include @@ -21232,5 +21232,5 @@ int lev_udp(lua_State* L) return 1; } - -#endif /* FEATURE: EV_HAVE_LUA_BINDING (2/2) */ + +#endif /* FEATURE: EV_HAVE_LUA_BINDING (2/2) */ diff --git a/ev.h b/ev.h index ea3996541..0c1707457 100644 --- a/ev.h +++ b/ev.h @@ -1,27 +1,27 @@ -/** - * MIT License - * - * Copyright (c) 2021 qgymib - * - * 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. - */ -/** +/** + * MIT License + * + * Copyright (c) 2021 qgymib + * + * 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. + */ +/** * # Changelog * * ## v0.0.9 @@ -137,7 +137,7 @@ * ## v0.0.1 (2022/02/22) * * Initial release - */ + */ #ifndef __EV_EXPOSE_H__ #define __EV_EXPOSE_H__ @@ -174,7 +174,7 @@ #endif #endif - + #ifndef __EV_VERSION_H__ #define __EV_VERSION_H__ @@ -244,7 +244,7 @@ EV_API unsigned ev_version_code(void); } #endif #endif - + #ifndef __EV_LIST_H__ #define __EV_LIST_H__ @@ -408,7 +408,7 @@ EV_API void ev_list_migrate(ev_list_t* dst, ev_list_t* src); } #endif #endif - + #ifndef __EV_MAP_H__ #define __EV_MAP_H__ @@ -572,8 +572,8 @@ EV_API ev_map_node_t* ev_map_prev(const ev_map_node_t* node); } #endif #endif - -#if defined(_WIN32) /* AMALGAMATE: ev.h (1/3) */ + +#if defined(_WIN32) /* AMALGAMATE: ev.h (1/3) */ /** * @file */ @@ -1067,8 +1067,8 @@ typedef struct ev_pipe_win_ipc_info #endif #endif - -#else /* AMALGAMATE: ev.h (2/3) */ + +#else /* AMALGAMATE: ev.h (2/3) */ /** * @file */ @@ -1519,8 +1519,8 @@ struct ev_nonblock_stream #endif #endif - -#endif /* AMALGAMATE: ev.h (3/3) */ + +#endif /* AMALGAMATE: ev.h (3/3) */ /** * @mainpage libev * @@ -4565,7 +4565,7 @@ EV_API uint64_t ev_hrtime(void); /* AMALGAMATE: #include "ev/lua.h" */ #endif - + #ifndef __EV_LUA_H__ #define __EV_LUA_H__ @@ -4586,4 +4586,4 @@ int luaopen_ev(struct lua_State* L); } #endif #endif - + diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt new file mode 100644 index 000000000..ab537afe0 --- /dev/null +++ b/tool/CMakeLists.txt @@ -0,0 +1,9 @@ + +add_executable(amalgamate + "tool/amalgamate.c") + +target_link_libraries(amalgamate + PRIVATE + liblua54) + +ev_setup_target_wall(amalgamate) diff --git a/tool/amalgamate.c b/tool/amalgamate.c new file mode 100644 index 000000000..96eddebc5 --- /dev/null +++ b/tool/amalgamate.c @@ -0,0 +1,188 @@ +#include +#include +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" + +#define CRLF "\n" + +typedef struct global_ctx +{ + lua_State* L; +} global_ctx_t; + +static global_ctx_t _G = { NULL }; + +static const char* _script = +"local opt = {" CRLF +" no_line = false" CRLF +"}" CRLF + +"local out_path = nil" CRLF +"local out_data = \"\"" CRLF + +"local function split_string (inputstr)" CRLF +" local sep = \",\"" CRLF +" local t={}" CRLF +" for str in string.gmatch(inputstr, \"([^\" .. sep .. \"]+)\") do" CRLF +" table.insert(t, str)" CRLF +" end" CRLF +" return t" CRLF +"end" CRLF + +"-- Read file and return content" CRLF +"local function read_file(path)" CRLF +" local file = io.open(path)" CRLF +" local data = file:read(\"a\")" CRLF +" file:close()" CRLF +" return data" CRLF +"end" CRLF + +"-- Write content into file" CRLF +"local function write_file(path, content)" CRLF +" local f = io.open(path, \"w\")" CRLF +" f:write(content)" CRLF +" f:close()" CRLF +"end" CRLF + +"local function append_source(paths)" CRLF +" local path_list = split_string(paths)" CRLF +" for _,v in ipairs(path_list) do" CRLF +" local content = read_file(v)" CRLF +" local pattern = \"#%s*include%s+\\\"([-_%w%./]+)%.h\\\"\"" CRLF +" local replace = \"/* AMALGAMATE: %0 */\"" CRLF +"" CRLF +" content = string.gsub(content, pattern, replace)" CRLF +"" CRLF +" if opt.no_line == false then" CRLF +" out_data = out_data .. \"#line 1 \\\"\" .. v .. \"\\\"\\n\"" CRLF +" end" CRLF +" out_data = out_data .. content .. \"\\n\"" CRLF +" end" CRLF +"end" CRLF + +"local function append_commit(path)" CRLF +" out_data = out_data .. \"/**\\n\"" CRLF +" local f = io.open(path)" CRLF +" while true do" CRLF +" local d = f:read()" CRLF +" if d == nil then" CRLF +" break" CRLF +" end" CRLF +" out_data = out_data .. \" * \" .. d .. \"\\n\"" CRLF +" end" CRLF +" f:close()" CRLF +" out_data = out_data .. \" */\\n\"" CRLF +"end" CRLF + +"local function append_string(str)" CRLF +" out_data = out_data .. str .. \"\\n\"" CRLF +"end" CRLF + +"for i,v in ipairs(arg) do" CRLF +" if v == \"--no_line\" then" CRLF +" opt.no_line = true" CRLF +" end" CRLF +"" CRLF +" if v == \"--out\" then" CRLF +" out_path = arg[i+1]" CRLF +" end" CRLF +"" CRLF +" if v == \"--commit\" then" CRLF +" append_commit(arg[i+1])" CRLF +" end" CRLF +"" CRLF +" if v == \"--source\" then" CRLF +" append_source(arg[i+1])" CRLF +" end" CRLF +"" CRLF +" if v == \"--string\" then" CRLF +" append_string(arg[i+1])" CRLF +" end" CRLF +"end" CRLF + +"assert(out_path ~= nil)" CRLF + +"-- Write file" CRLF +"write_file(out_path, out_data)" CRLF +; + +static void _generate_arg_table(lua_State* L, int argc, char* argv[]) +{ + int i; + + lua_newtable(L); + for (i = 0; i < argc; i++) + { + lua_pushstring(L, argv[i]); + lua_seti(L, -2, i + 1); + } + lua_setglobal(L, "arg"); +} + +static int _pmain(lua_State* L) +{ + int argc = (int)lua_tointeger(L, 1); + char** argv = lua_touserdata(L, 2); + + luaL_openlibs(L); + _generate_arg_table(L, argc, argv); + + luaL_loadstring(L, _script); + lua_call(L, 0, LUA_MULTRET); + + return 0; +} + +static void _at_exit(void) +{ + if (_G.L != NULL) + { + lua_close(_G.L); + _G.L = NULL; + } +} + +/** + * @brief Lua error traceback helper. + * @param[in] L Lua VM. + * @return Always 1. + */ +static int _msg_handler(lua_State* L) +{ + const char* msg = lua_tostring(L, 1); + if (msg == NULL) + { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + { + return 1; /* that is the message */ + } + else + { + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + } + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} + +int main(int argc, char* argv[]) +{ + atexit(_at_exit); + + if ((_G.L = luaL_newstate()) == NULL) + { + fprintf(stderr, "create Lua VM failed.\n"); + abort(); + } + + lua_pushcfunction(_G.L, _msg_handler); + lua_pushcfunction(_G.L, _pmain); + lua_pushinteger(_G.L, argc); + lua_pushlightuserdata(_G.L, argv); + lua_pcall(_G.L, 2, 0, 1); + + return 0; +}