Compare commits
No commits in common. "master" and "V1.0.39" have entirely different histories.
|
|
@ -1,98 +0,0 @@
|
||||||
# Makefile.in
|
|
||||||
src/Makefile
|
|
||||||
src/tests/Makefile
|
|
||||||
|
|
||||||
# Prerequisites
|
|
||||||
*.d
|
|
||||||
|
|
||||||
# Compiled Object files
|
|
||||||
*.slo
|
|
||||||
*.lo
|
|
||||||
*.o
|
|
||||||
*.obj
|
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Compiled Dynamic libraries
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
*.dSYM
|
|
||||||
*.dll
|
|
||||||
|
|
||||||
# Compiled Static libraries
|
|
||||||
*.lai
|
|
||||||
*.la
|
|
||||||
*.a
|
|
||||||
*.lib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.out
|
|
||||||
src/_os_define.h
|
|
||||||
src/tests/test_allocator
|
|
||||||
src/tests/test_blocked_queue
|
|
||||||
src/tests/test_char_convert
|
|
||||||
src/tests/test_char_convert_loader
|
|
||||||
src/tests/test_crc32
|
|
||||||
src/tests/test_id_generator
|
|
||||||
src/tests/test_ini_parser
|
|
||||||
src/tests/test_json_parser
|
|
||||||
src/tests/test_logger
|
|
||||||
src/tests/test_mblock
|
|
||||||
src/tests/test_multi_skiplist
|
|
||||||
src/tests/test_sched_thread
|
|
||||||
src/tests/test_skiplist
|
|
||||||
src/tests/test_skiplist_set
|
|
||||||
src/tests/test_thourands_seperator
|
|
||||||
src/tests/test_pthread_lock
|
|
||||||
src/tests/test_split_string
|
|
||||||
src/tests/test_uniq_skiplist
|
|
||||||
src/tests/test_server_id_func
|
|
||||||
src/tests/test_pipe
|
|
||||||
src/tests/test_atomic
|
|
||||||
src/tests/test_file_write_hole
|
|
||||||
src/tests/test_file_lock
|
|
||||||
src/tests/test_thread_pool
|
|
||||||
src/tests/test_data_visible
|
|
||||||
src/tests/test_pthread_wait
|
|
||||||
src/tests/test_mutex_lock_perf
|
|
||||||
src/tests/test_queue_perf
|
|
||||||
src/tests/test_normalize_path
|
|
||||||
src/tests/test_sorted_array
|
|
||||||
src/tests/test_sorted_queue
|
|
||||||
src/tests/test_thread_local
|
|
||||||
src/tests/test_memcpy
|
|
||||||
src/tests/mblock_benchmark
|
|
||||||
src/tests/cpool_benchmark
|
|
||||||
src/tests/test_fast_buffer
|
|
||||||
|
|
||||||
# other
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
php-fastcommon/.deps
|
|
||||||
php-fastcommon/.libs/
|
|
||||||
|
|
||||||
php-fastcommon/Makefile
|
|
||||||
php-fastcommon/Makefile.fragments
|
|
||||||
php-fastcommon/Makefile.global
|
|
||||||
php-fastcommon/Makefile.objects
|
|
||||||
php-fastcommon/acinclude.m4
|
|
||||||
php-fastcommon/aclocal.m4
|
|
||||||
php-fastcommon/autom4te.cache/
|
|
||||||
php-fastcommon/build/
|
|
||||||
php-fastcommon/config.guess
|
|
||||||
php-fastcommon/config.h
|
|
||||||
php-fastcommon/config.h.in
|
|
||||||
php-fastcommon/config.log
|
|
||||||
php-fastcommon/config.nice
|
|
||||||
php-fastcommon/config.status
|
|
||||||
php-fastcommon/config.sub
|
|
||||||
php-fastcommon/configure
|
|
||||||
php-fastcommon/configure.ac
|
|
||||||
php-fastcommon/install-sh
|
|
||||||
php-fastcommon/libtool
|
|
||||||
php-fastcommon/ltmain.sh
|
|
||||||
php-fastcommon/missing
|
|
||||||
php-fastcommon/mkinstalldirs
|
|
||||||
php-fastcommon/run-tests.php
|
|
||||||
281
HISTORY
281
HISTORY
|
|
@ -1,285 +1,4 @@
|
||||||
|
|
||||||
Version 1.83 2025-11-15
|
|
||||||
* fast_task_queue.h: remove field finish_callback
|
|
||||||
|
|
||||||
Version 1.82 2025-11-04
|
|
||||||
* set use_io_uring explicitly
|
|
||||||
|
|
||||||
Version 1.81 2025-10-05
|
|
||||||
* support Linux io_uring
|
|
||||||
* free_queue support parameter: need_shrink and set task->shrinked
|
|
||||||
* IOEventCallback: change event type from short to int
|
|
||||||
|
|
||||||
Version 1.80 2025-09-10
|
|
||||||
* getIpaddrByNameEx: IPv4 has priority over IPv6
|
|
||||||
* shared_func.[hc]: add function fc_ftoa
|
|
||||||
|
|
||||||
Version 1.79 2025-08-29
|
|
||||||
* logger.h export function log_it_ex3
|
|
||||||
* shared_func.[hc]: add function bytes_to_human_str
|
|
||||||
|
|
||||||
Version 1.78 2025-08-07
|
|
||||||
* getIpaddrByName: normalize ip addr when input addr is IPv4 or IPv6
|
|
||||||
* add files: spinlock.[hc]
|
|
||||||
* shared_func.[hc]: change int2buff, buff2int etc. functions to static inline
|
|
||||||
* shared_func.[hc]: add functions short2hex, int2hex, long2hex etc.
|
|
||||||
* performance opt.: replace sprintf and snprintf as necessary
|
|
||||||
|
|
||||||
Version 1.77 2025-03-18
|
|
||||||
* impl. shorten_path for /./ and /../
|
|
||||||
* add function fc_compare_int64_ptr
|
|
||||||
|
|
||||||
Version 1.76 2025-01-27
|
|
||||||
* get_mounted_filesystems act as program df
|
|
||||||
* add function get_statfs_by_path
|
|
||||||
* add function is_rotational_device_by_path
|
|
||||||
* conn_pool_get_connection_ex add parameter: shared
|
|
||||||
|
|
||||||
Version 1.75 2024-09-22
|
|
||||||
* task init callback support extra argument
|
|
||||||
* connection pool performance optimization
|
|
||||||
|
|
||||||
Version 1.74 2024-05-18
|
|
||||||
* add functions: get_log_level and get_log_level_caption
|
|
||||||
* adapt to FreeBSD 13
|
|
||||||
|
|
||||||
Version 1.73 2024-03-05
|
|
||||||
* add macro FC_SET_STRING_EMPTY
|
|
||||||
* struct fast_task_info remove fields: connect_timeout and network_timeout
|
|
||||||
* format ip address for IPv6
|
|
||||||
|
|
||||||
Version 1.72 2024-01-21
|
|
||||||
* call fast_mblock_ref_counter_dec for delay free node correctly
|
|
||||||
* fc_queue.[hc]: add function fc_queue_remove
|
|
||||||
|
|
||||||
Version 1.71 2023-12-23
|
|
||||||
* full support IPv6 by pull request #47
|
|
||||||
* replace inet_ntop to getnameinfo for IPv6
|
|
||||||
|
|
||||||
Version 1.70 2023-09-30
|
|
||||||
* get full mac address of infiniband NIC under Linux
|
|
||||||
* struct fast_task_info add field conn for RDMA connection
|
|
||||||
* server_id_func.[hc]: support communication type
|
|
||||||
* connection_pool.[hc] support callbacks for RDMA
|
|
||||||
* nio thread data support busy_polling_callback
|
|
||||||
* connection_pool.[hc] support thread local for performance
|
|
||||||
* struct fast_task_info support send and recv double buffers
|
|
||||||
* add functions: fc_queue_push_with_check and fc_queue_peek
|
|
||||||
|
|
||||||
Version 1.69 2023-08-05
|
|
||||||
* bugfixed: array_allocator_alloc MUST init the array
|
|
||||||
* uniq_skiplist support arg for free callback
|
|
||||||
|
|
||||||
Version 1.68 2023-07-05
|
|
||||||
* sorted_queue.[hc]: pop_compare_func support argument
|
|
||||||
|
|
||||||
Version 1.67 2023-05-29
|
|
||||||
* lc_pair in struct fc_queue change to lcp
|
|
||||||
* sorted queue use double link chain for quick push
|
|
||||||
* add function uniq_skiplist_clear
|
|
||||||
* fast_mblock_malloc_trunk_notify_func prototype changed
|
|
||||||
* fast_mblock_init_ex2 add parameter prealloc_trunk_count
|
|
||||||
* sorted_queue.[hc] support pop_compare_func
|
|
||||||
* bugfixed: fast_mblock_batch_alloc correct return value
|
|
||||||
* add function fc_safe_writev
|
|
||||||
|
|
||||||
Version 1.66 2023-02-12
|
|
||||||
* struct fast_task_info add field: notify_next for nio notify queue
|
|
||||||
|
|
||||||
Version 1.65 2023-01-09
|
|
||||||
* locked_list.h: add functions locked_list_move and locked_list_move_tail
|
|
||||||
* add function tcp_socket_connected
|
|
||||||
* parse_bytes support space charactors (before and after the unit)
|
|
||||||
* add function get_groups
|
|
||||||
|
|
||||||
Version 1.64 2022-11-19
|
|
||||||
* shared_func.[hc]: normalize_path use type string_t for general purpose
|
|
||||||
* bugfixed: common_blocked_queue_[alloc|free]_node must use lock
|
|
||||||
* bugfixed: can't use global malloc_allocator
|
|
||||||
|
|
||||||
Version 1.63 2022-10-16
|
|
||||||
* sockopt.[hc]: getIpAndPort support ipv6
|
|
||||||
|
|
||||||
Version 1.62 2022-09-28
|
|
||||||
* add function fc_sleep_us
|
|
||||||
* add function fc_itoa
|
|
||||||
|
|
||||||
Version 1.61 2022-09-21
|
|
||||||
* get_base_path_from_conf_file_ex support parameter: noent_log_level
|
|
||||||
* add function common_blocked_queue_push_chain
|
|
||||||
|
|
||||||
Version 1.60 2022-08-27
|
|
||||||
* normalize_path for base_path
|
|
||||||
* struct fast_task_info add field recv_body for dynamic recv buffer
|
|
||||||
* add functions: iniGetDoubleCorrectValueEx and iniGetPercentCorrectValueEx
|
|
||||||
* fast_allocator.[hc] support object size and callbacks
|
|
||||||
|
|
||||||
Version 1.59 2022-07-21
|
|
||||||
* open file with flag O_CLOEXEC
|
|
||||||
* add global var g_set_cloexec and macro FC_SET_CLOEXEC
|
|
||||||
* add function fc_get_first_lines
|
|
||||||
|
|
||||||
Version 1.58 2022-06-04
|
|
||||||
* add function conn_pool_connect_server_ex1 to support service name
|
|
||||||
* add function conn_pool_get_connection_ex to support service name
|
|
||||||
* add function iniGetCharValueEx
|
|
||||||
* json_parser.[hc] refined for better performance
|
|
||||||
|
|
||||||
Version 1.57 2022-04-22
|
|
||||||
* add function fc_format_path
|
|
||||||
* add functions: fc_get_path_child_count and fc_copy_file
|
|
||||||
* fast_mblock.[hc] support object destroy callback
|
|
||||||
* bugfixed: fc_get_file_line_count_ex should rewind file
|
|
||||||
|
|
||||||
Version 1.56 2022-03-09
|
|
||||||
* add function fc_gettid
|
|
||||||
* function normalize_path: NULL from parameter for getcwd
|
|
||||||
* sockopt.[hc] support tcpwritev and tcpreadv
|
|
||||||
* add function fc_iov_get_bytes
|
|
||||||
* rename hash_xxx to fc_hash_xxx
|
|
||||||
* rename trim to fc_trim
|
|
||||||
* add function fc_check_rename_ex
|
|
||||||
|
|
||||||
Version 1.55 2022-01-12
|
|
||||||
* fastcommon php extension adapt to php 8
|
|
||||||
* function fast_mblock_batch_alloc changed
|
|
||||||
* add function sched_delay_free_ptr
|
|
||||||
|
|
||||||
Version 1.54 2021-12-23
|
|
||||||
* fast_allocator.[hc]: correct reclaim_interval logic
|
|
||||||
* shared_func.[hc]: add functions getFileContentEx1 and getFileContent1
|
|
||||||
* fc_queue.[hc]: add function fc_queue_timedpeek
|
|
||||||
* pthread_func.[hc]: add function init_pthread_rwlock
|
|
||||||
* add files: sorted_queue.[hc]
|
|
||||||
* add files: array_allocator.[hc]
|
|
||||||
* add files: sorted_array.[hc]
|
|
||||||
* shared_func.[hc]: add function fc_read_lines
|
|
||||||
* normalize_path removes prefix one ./ and multi ../
|
|
||||||
|
|
||||||
Version 1.53 2021-06-30
|
|
||||||
* process_action support action status
|
|
||||||
* uniq_skiplist.h: add function uniq_skiplist_iterator_at
|
|
||||||
|
|
||||||
Version 1.52 2021-06-08
|
|
||||||
* process_stop more gracefully (kill -9 on timeout)
|
|
||||||
* add function fc_queue_pop_to_queue_ex
|
|
||||||
* add function get_path_block_size and get_device_block_size
|
|
||||||
* add function fc_check_realloc_iovec_array
|
|
||||||
|
|
||||||
Version 1.51 2021-05-27
|
|
||||||
* fast_mblock.[hc]: support batch alloc and batch free
|
|
||||||
* uniq_skiplist.[hc]: init function add parameter: allocator_use_lock
|
|
||||||
* add function normalize_path_ex and normalize_uri
|
|
||||||
* use libcurl to fetch URL resource
|
|
||||||
* add function get_kernel_version
|
|
||||||
|
|
||||||
Version 1.50 2021-05-11
|
|
||||||
* add function is_digital_string
|
|
||||||
* add function fc_server_load_from_ini_context
|
|
||||||
* set thread name as necessary
|
|
||||||
* add macro fc_fallocate
|
|
||||||
|
|
||||||
Version 1.49 2021-04-17
|
|
||||||
* add macros: FC_ABS and FC_NEGATIVE
|
|
||||||
* uniq_skiplist.c: add uniq_skiplist_pair struct and init function
|
|
||||||
* add functions: fc_mkdirs and str_replace
|
|
||||||
* add FilenameString type and macro
|
|
||||||
* add functions: fc_string_case_compare, fc_string_case_equal etc.
|
|
||||||
* add function: fc_check_filename_ex
|
|
||||||
* add functions: fc_queue_push_queue_to_tail etc.
|
|
||||||
* add file locked_list.h
|
|
||||||
* parse_bytes function more graceful
|
|
||||||
|
|
||||||
Version 1.48 2021-02-01
|
|
||||||
* fast_buffer.[hc]: add function fast_buffer_append_binary
|
|
||||||
* fc_check_mkdir_ex return 0 when mkdir with errno EEXIST
|
|
||||||
* add function common_blocked_queue_timedpop
|
|
||||||
* add function fc_queue_timedpop
|
|
||||||
|
|
||||||
Version 1.47 2021-01-20
|
|
||||||
* fc_atomic.h: add FC_ATOMIC_GET and FC_ATOMIC_SET etc.
|
|
||||||
* fast_mblock.[hc]: support wait with element limit
|
|
||||||
|
|
||||||
Version 1.46 2020-12-29
|
|
||||||
* add function get_time_item_from_conf_ex
|
|
||||||
* INI_FIND_ITEM just break instead of return
|
|
||||||
|
|
||||||
Version 1.45 2020-12-24
|
|
||||||
* add function uniq_skiplist_find_node_ex
|
|
||||||
* use readdir instead of readdir_r in Linux
|
|
||||||
|
|
||||||
Version 1.44 2020-12-06
|
|
||||||
* add test file src/tests/test_pthread_lock.c
|
|
||||||
* add uniq_skiplist.[hc]
|
|
||||||
* add function split_string_ex
|
|
||||||
* fast_mblock.[hc]: add init_args for init_func
|
|
||||||
* struct fast_task_info add field: nio_stage
|
|
||||||
* add function fc_memrchr
|
|
||||||
* add function is_network_error
|
|
||||||
* add function fast_mpool_log_stats
|
|
||||||
* add files: server_id_func.[hc]
|
|
||||||
* common_blocked_queue support pop all nodes
|
|
||||||
* shared_func.[hc]: add functions fc_floor_prime and fc_ceil_prime
|
|
||||||
* fast_mpool.[hc]: change function fast_mpool_strdup
|
|
||||||
* fast_allocator.[hc]: add function fast_allocator_strdup
|
|
||||||
* shared_func.[hc]: add function getFileSize
|
|
||||||
* char_converter.[hc]: add function fast_char_unescape
|
|
||||||
* struct fast_task_info add ctx pointer for libserverframe nio
|
|
||||||
* struct thread_data add waiting_queue for Linux eventfd notify
|
|
||||||
* struct fast_task_info add canceled field for complicated thread model
|
|
||||||
* nio_thread_data support thread notify
|
|
||||||
* pthread_func.[hc] add functions: create_work_threads_ex and fc_create_thread
|
|
||||||
* sched_add_entries use temp ScheduleArray for rare case
|
|
||||||
* add function common_blocked_queue_return_nodes
|
|
||||||
* add functions getIpAndPort and getPeerIpAndPort
|
|
||||||
* bugfixed: call fast_mblock_destroy in common_blocked_queue_destroy
|
|
||||||
* add function fc_get_file_line_count_ex
|
|
||||||
* uniq_skiplist add function find_ge and support bidirection
|
|
||||||
* connection_pool support validate connection on error
|
|
||||||
* fast_task_queue.[hc]: free_queue support init_callback
|
|
||||||
* ini_file_reader.c: use mutex lock when access dynamic content array
|
|
||||||
* uniq_skiplist add function uniq_skiplist_replace_ex
|
|
||||||
* add files: fc_queue.[hc]
|
|
||||||
* add files: fc_memory.[hc]
|
|
||||||
* add files: shared_buffer.[hc]
|
|
||||||
* add files: thread_pool.[hc]
|
|
||||||
* shared_func.[hc]: add function fc_path_contains
|
|
||||||
* fast_mblock.[hc]: support alloc elements limit
|
|
||||||
* sockopt.[hc]: add function asyncconnectserverbyip
|
|
||||||
* add locked_timer.[hc]: time wheel timer with lock
|
|
||||||
* tcp_quick_ack option for Linux
|
|
||||||
|
|
||||||
Version 1.43 2019-12-25
|
|
||||||
* replace function call system to getExecResult,
|
|
||||||
system is the deprecated function in iOS 11
|
|
||||||
* correct function skiplist_iterator in skiplist.h
|
|
||||||
* add buffered_file_writer.[hc]
|
|
||||||
* add function fc_delete_file_ex
|
|
||||||
|
|
||||||
Version 1.42 2019-12-03
|
|
||||||
* add function get_gzip_command_filename
|
|
||||||
* function create_work_threads changed
|
|
||||||
|
|
||||||
Version 1.41 2019-09-30
|
|
||||||
* change CIDR network_bits range from [16, 32) to [10, 32)
|
|
||||||
* ini_file_reader.c: fix empty string compare
|
|
||||||
* multi_socket_client.c: code refine
|
|
||||||
* sockopt.[hc] support IPv6
|
|
||||||
|
|
||||||
Version 1.40 2018-11-09
|
|
||||||
* add function conn_pool_parse_server_info and conn_pool_load_server_info
|
|
||||||
* support directive: #@add_annotation, for example:
|
|
||||||
#@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf
|
|
||||||
* add function fc_split_string and fc_match_delim
|
|
||||||
* add json_parser.[hc] for parse json array and map
|
|
||||||
* add function fc_strdup
|
|
||||||
* add function fc_memmem
|
|
||||||
* add function format_http_date
|
|
||||||
* add function hash_find1 and hash_find2
|
|
||||||
* add function resolve_path and fast_buffer_append_file
|
|
||||||
* add function id_generator_next_extra_ptr, with NULL pointer to set
|
|
||||||
extra data to sn % (1 << extra_bits)
|
|
||||||
|
|
||||||
Version 1.39 2018-07-31
|
Version 1.39 2018-07-31
|
||||||
* add #@function REPLACE_VARS
|
* add #@function REPLACE_VARS
|
||||||
* #@set value can embed %{VARIABLE}
|
* #@set value can embed %{VARIABLE}
|
||||||
|
|
|
||||||
30
INSTALL
30
INSTALL
|
|
@ -4,22 +4,20 @@ libfastcommon may be copied only under the terms of the Less GNU General
|
||||||
Public License(LGPL).
|
Public License(LGPL).
|
||||||
Please visit the libfastcommon Home Page for more detail.
|
Please visit the libfastcommon Home Page for more detail.
|
||||||
English language: https://github.com/happyfish100/libfastcommon
|
English language: https://github.com/happyfish100/libfastcommon
|
||||||
Chinese language: http://www.fastken.com/
|
Chinese language: http://www.csource.org/
|
||||||
|
|
||||||
[Optional Step]
|
|
||||||
You can enable io_uring for higher performance when Linux kernel version >= 6.2,
|
|
||||||
CentOS, RockyLinux, AlmaLinux, RHEL etc.:
|
|
||||||
sudo yum install liburing-devel -y
|
|
||||||
|
|
||||||
Debian, Ubuntu etc.:
|
|
||||||
sudo apt install liburing-dev -y
|
|
||||||
|
|
||||||
|
|
||||||
# download libfastcommon source codes and install it,
|
#step 1. download libfastcommon source package and unpack it,
|
||||||
# github address: https://github.com/happyfish100/libfastcommon.git
|
tar xzf libfastcommon_v1.x.tar.gz
|
||||||
# gitee address: https://gitee.com/fastdfs100/libfastcommon.git
|
#for example:
|
||||||
# the command lines as:
|
tar xzf libfastcommon_v1.23.tar.gz
|
||||||
|
|
||||||
|
#step 2. enter the libfastcommon dir
|
||||||
|
cd libfastcommon
|
||||||
|
|
||||||
|
#step 3. make
|
||||||
|
./make.sh
|
||||||
|
|
||||||
|
#step 4. make install
|
||||||
|
./make.sh install
|
||||||
|
|
||||||
git clone https://github.com/happyfish100/libfastcommon.git
|
|
||||||
cd libfastcommon; git checkout V1.0.83
|
|
||||||
./make.sh clean && ./make.sh && sudo ./make.sh install
|
|
||||||
|
|
|
||||||
165
LICENSE
165
LICENSE
|
|
@ -1,165 +0,0 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
||||||
4
README
4
README
|
|
@ -4,7 +4,7 @@ libfastcommon may be copied only under the terms of the Less GNU General
|
||||||
Public License(LGPL).
|
Public License(LGPL).
|
||||||
Please visit the libfastcommon Home Page for more detail.
|
Please visit the libfastcommon Home Page for more detail.
|
||||||
English language: https://github.com/happyfish100/libfastcommon
|
English language: https://github.com/happyfish100/libfastcommon
|
||||||
Chinese language: http://www.fastken.com/
|
Chinese language: http://www.csource.org/
|
||||||
|
|
||||||
|
|
||||||
c common functions library extracted from my open source projects FastDFS and
|
c common functions library extracted from my open source projects FastDFS and
|
||||||
|
|
@ -47,7 +47,7 @@ C function including:
|
||||||
|
|
||||||
skiplist: [skiplist.h] [flat_skiplist.h] [multi_skiplist.h] flat skiplist and multi skiplist
|
skiplist: [skiplist.h] [flat_skiplist.h] [multi_skiplist.h] flat skiplist and multi skiplist
|
||||||
|
|
||||||
socket: [sockopt.h] socket wrapper for connect, recv, send etc. support IPv6
|
socket: [sockopt.h] socket wrapper for connect, recv, send etc.
|
||||||
|
|
||||||
ioevent: [ioevent.h] [ioevent_loop.h] like epoll (support Linux, FreeBSD and SunOS),
|
ioevent: [ioevent.h] [ioevent_loop.h] like epoll (support Linux, FreeBSD and SunOS),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
libfastcommon for Debian
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
<possible notes regarding this package - if none, delete this file>
|
|
||||||
|
|
||||||
-- zhangchunsheng <zhangchunsheng423@gmail.com> Mon, 24 May 2021 18:54:01 +0800
|
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
libfastcommon (1.0.83-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.83-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:47:37 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.83-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.83-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:00:00 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.83-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.83-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 09:05:57 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.78-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.78-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sat, 16 Aug 2025 16:31:05 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.77-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.77-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 06 Apr 2025 16:55:50 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.75-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.75-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 29 Sep 2024 15:23:57 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.74-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.74-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sat, 15 Jun 2024 14:45:01 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.73-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.73-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 17 Mar 2024 15:10:21 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.72-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.72-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Wed, 31 Jan 2024 11:59:25 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.71-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.71-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Mon, 01 Jan 2024 11:23:54 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.70-3) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.70-3
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Tue, 21 Nov 2023 14:35:29 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.70-2) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.70-2
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Mon, 20 Nov 2023 13:23:17 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.70-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.70-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 19 Nov 2023 14:45:34 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.69-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.69-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 06 Aug 2023 07:21:50 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.68-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.68-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 23 Jul 2023 14:27:27 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.67-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.67-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 04 Jun 2023 10:51:06 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.66-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.66-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sat, 18 Feb 2023 05:43:58 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.65-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.65-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 15 Jan 2023 13:49:19 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.63-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.63-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Mon, 21 Nov 2022 14:54:56 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.62-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.62-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sat, 08 Oct 2022 13:28:15 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.61-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.61-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Thu, 22 Sep 2022 12:22:09 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.60-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.60-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Wed, 07 Sep 2022 13:36:01 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.59-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.59-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Mon, 25 Jul 2022 13:51:25 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.58-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.58-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Wed, 15 Jun 2022 14:26:02 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.57-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade to 1.0.57-1
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Thu, 28 Apr 2022 11:53:21 +0000
|
|
||||||
|
|
||||||
libfastcommon (1.0.56-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* check pthread_rwlockattr_getkind_np for porting
|
|
||||||
* correct pthread_rwlockattr getkind_np to setkind_np
|
|
||||||
* change include <sys/poll.h> to #include <poll.h>
|
|
||||||
* add function fc_gettid
|
|
||||||
* NULL from parameter for getcwd
|
|
||||||
* sockopt.[hc] support tcpwritev and tcpreadv
|
|
||||||
* add const modifier for unification
|
|
||||||
* make.sh refined
|
|
||||||
* add function fc_iov_get_bytes
|
|
||||||
* make.sh: generate macros for dirent fields
|
|
||||||
* add function log_try_init2
|
|
||||||
* rename hash_xxx to fc_hash_xxx
|
|
||||||
* rename trim to fc_trim
|
|
||||||
* php-fastcommon compile OK
|
|
||||||
* add function locked_list_destroy
|
|
||||||
* upgrade version to 1.0.56
|
|
||||||
* add function fc_check_rename_ex
|
|
||||||
* small changes for logger.[hc]
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 13 Mar 2022 16:43:08 +0800
|
|
||||||
|
|
||||||
libfastcommon (1.0.55-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade version to 1.0.55
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sat, 15 Jan 2022 19:50:26 +0800
|
|
||||||
|
|
||||||
libfastcommon (1.0.54-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* upgrade version to 1.0.54
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Sun, 26 Dec 2021 20:29:05 +0800
|
|
||||||
|
|
||||||
libfastcommon (1.0.53-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* open for write MUST have the third parameter: mode
|
|
||||||
* uniq_skiplist.h: add function uniq_skiplist_iterator_at
|
|
||||||
* process_action support action status
|
|
||||||
|
|
||||||
-- YuQing <384681@qq.com> Tue, 6 Jul 2021 21:23:31 +0800
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
11
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
Source: libfastcommon
|
|
||||||
Section: libs
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: YuQing <384681@qq.com>
|
|
||||||
Build-Depends: debhelper (>=11~)
|
|
||||||
Standards-Version: 4.1.4
|
|
||||||
Homepage: http://github.com/happyfish100/libfastcommon/
|
|
||||||
|
|
||||||
Package: libfastcommon-dev
|
|
||||||
Architecture: any
|
|
||||||
Section: libdevel
|
|
||||||
Depends: libfastcommon (= ${binary:Version}), ${misc:Depends}
|
|
||||||
Description: libfastcommon (development files)
|
|
||||||
This package contains header files.
|
|
||||||
|
|
||||||
Package: libfastcommon
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
|
||||||
Description: c common functions library
|
|
||||||
c common functions library extracted from my open source projects FastDFS and
|
|
||||||
FastDHT. this library is very simple and stable.
|
|
||||||
.
|
|
||||||
some functions are wrappered into php extension, such as fastcommon_gethostaddrs,
|
|
||||||
fastcommon_id_generator_xxx, fastcommon_get_ifconfigs, fastcommon_get_sysinfo etc.
|
|
||||||
|
|
||||||
|
|
@ -1,530 +0,0 @@
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: libfastcommon
|
|
||||||
Source: http://github.com/happyfish100/libfastcommon/
|
|
||||||
#
|
|
||||||
# Please double check copyright with the licensecheck(1) command.
|
|
||||||
|
|
||||||
Files: php-fastcommon/fastcommon.c
|
|
||||||
php-fastcommon/fastcommon.h
|
|
||||||
src/avl_tree.c
|
|
||||||
src/avl_tree.h
|
|
||||||
src/base64.c
|
|
||||||
src/buffered_file_writer.c
|
|
||||||
src/buffered_file_writer.h
|
|
||||||
src/chain.c
|
|
||||||
src/chain.h
|
|
||||||
src/char_convert_loader.c
|
|
||||||
src/char_convert_loader.h
|
|
||||||
src/char_converter.c
|
|
||||||
src/char_converter.h
|
|
||||||
src/common_blocked_queue.c
|
|
||||||
src/common_blocked_queue.h
|
|
||||||
src/common_define.h
|
|
||||||
src/connection_pool.c
|
|
||||||
src/connection_pool.h
|
|
||||||
src/fast_allocator.c
|
|
||||||
src/fast_allocator.h
|
|
||||||
src/fast_blocked_queue.c
|
|
||||||
src/fast_blocked_queue.h
|
|
||||||
src/fast_buffer.c
|
|
||||||
src/fast_buffer.h
|
|
||||||
src/fast_mblock.c
|
|
||||||
src/fast_mblock.h
|
|
||||||
src/fast_mpool.c
|
|
||||||
src/fast_mpool.h
|
|
||||||
src/fast_task_queue.c
|
|
||||||
src/fast_task_queue.h
|
|
||||||
src/fast_timer.c
|
|
||||||
src/fast_timer.h
|
|
||||||
src/fc_atomic.h
|
|
||||||
src/fc_memory.c
|
|
||||||
src/fc_memory.h
|
|
||||||
src/fc_queue.c
|
|
||||||
src/fc_queue.h
|
|
||||||
src/flat_skiplist.c
|
|
||||||
src/flat_skiplist.h
|
|
||||||
src/hash.c
|
|
||||||
src/hash.h
|
|
||||||
src/http_func.h
|
|
||||||
src/id_generator.c
|
|
||||||
src/ini_file_reader.c
|
|
||||||
src/ini_file_reader.h
|
|
||||||
src/ioevent.c
|
|
||||||
src/ioevent.h
|
|
||||||
src/ioevent_loop.c
|
|
||||||
src/ioevent_loop.h
|
|
||||||
src/json_parser.c
|
|
||||||
src/json_parser.h
|
|
||||||
src/local_ip_func.c
|
|
||||||
src/local_ip_func.h
|
|
||||||
src/locked_timer.c
|
|
||||||
src/locked_timer.h
|
|
||||||
src/logger.c
|
|
||||||
src/multi_skiplist.c
|
|
||||||
src/multi_skiplist.h
|
|
||||||
src/multi_socket_client.c
|
|
||||||
src/multi_socket_client.h
|
|
||||||
src/process_ctrl.c
|
|
||||||
src/process_ctrl.h
|
|
||||||
src/pthread_func.c
|
|
||||||
src/pthread_func.h
|
|
||||||
src/sched_thread.c
|
|
||||||
src/sched_thread.h
|
|
||||||
src/server_id_func.c
|
|
||||||
src/server_id_func.h
|
|
||||||
src/shared_buffer.c
|
|
||||||
src/shared_buffer.h
|
|
||||||
src/shared_func.c
|
|
||||||
src/shared_func.h
|
|
||||||
src/skiplist_common.h
|
|
||||||
src/skiplist_set.c
|
|
||||||
src/system_info.c
|
|
||||||
src/system_info.h
|
|
||||||
src/tests/test_allocator.c
|
|
||||||
src/tests/test_atomic.c
|
|
||||||
src/tests/test_blocked_queue.c
|
|
||||||
src/tests/test_char_convert.c
|
|
||||||
src/tests/test_char_convert_loader.c
|
|
||||||
src/tests/test_crc32.c
|
|
||||||
src/tests/test_data_visible.c
|
|
||||||
src/tests/test_file_lock.c
|
|
||||||
src/tests/test_file_write_hole.c
|
|
||||||
src/tests/test_id_generator.c
|
|
||||||
src/tests/test_ini_parser.c
|
|
||||||
src/tests/test_json_parser.c
|
|
||||||
src/tests/test_logger.c
|
|
||||||
src/tests/test_mblock.c
|
|
||||||
src/tests/test_multi_skiplist.c
|
|
||||||
src/tests/test_mutex_lock_perf.c
|
|
||||||
src/tests/test_normalize_path.c
|
|
||||||
src/tests/test_pipe.c
|
|
||||||
src/tests/test_pthread_lock.c
|
|
||||||
src/tests/test_pthread_wait.c
|
|
||||||
src/tests/test_queue_perf.c
|
|
||||||
src/tests/test_sched_thread.c
|
|
||||||
src/tests/test_server_id_func.c
|
|
||||||
src/tests/test_skiplist.c
|
|
||||||
src/tests/test_skiplist_set.c
|
|
||||||
src/tests/test_split_string.c
|
|
||||||
src/tests/test_thourands_seperator.c
|
|
||||||
src/tests/test_thread_pool.c
|
|
||||||
src/tests/test_uniq_skiplist.c
|
|
||||||
src/thread_pool.c
|
|
||||||
src/thread_pool.h
|
|
||||||
src/uniq_skiplist.c
|
|
||||||
src/uniq_skiplist.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: .gitignore
|
|
||||||
HISTORY
|
|
||||||
INSTALL
|
|
||||||
debian/README.Debian
|
|
||||||
debian/compat
|
|
||||||
debian/control
|
|
||||||
debian/libfastcommon-dev.install
|
|
||||||
debian/libfastcommon.install
|
|
||||||
debian/rules
|
|
||||||
debian/source/format
|
|
||||||
debian/watch
|
|
||||||
doc/id_generator-Chinese.md
|
|
||||||
doc/ini_file_reader-Chinese.md
|
|
||||||
doc/php_log_file_performance-Chinese.md
|
|
||||||
libfastcommon.spec
|
|
||||||
make.sh
|
|
||||||
php-fastcommon/config.m4
|
|
||||||
php-fastcommon/fastcommon.ini
|
|
||||||
php-fastcommon/php-fastcommon.spec.in
|
|
||||||
src/Makefile.in
|
|
||||||
src/fast_link_library.sh
|
|
||||||
src/fc_list.h
|
|
||||||
src/io_opt.c
|
|
||||||
src/io_opt.h
|
|
||||||
src/locked_list.h
|
|
||||||
src/md5.c
|
|
||||||
src/md5.h
|
|
||||||
src/tests/Makefile
|
|
||||||
src/tests/servers.conf
|
|
||||||
src/tests/test.ini
|
|
||||||
Copyright: __NO_COPYRIGHT_NOR_LICENSE__
|
|
||||||
License: __NO_COPYRIGHT_NOR_LICENSE__
|
|
||||||
|
|
||||||
Files: src/skiplist.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
skiplist.h, support stable sort :)
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/skiplist_set.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
a set implemented by skiplist, the entry can occur only once
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/sockopt.c
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
socketopt.c
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/sockopt.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
socketopt.h
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/http_func.c
|
|
||||||
Copyright: 2008 Happy Fish / YuQing
|
|
||||||
2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
FastDFS may be copied only under the terms of the GNU General
|
|
||||||
Public License V3, which may be found in the FastDFS source kit.
|
|
||||||
Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/id_generator.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
64 bits id generator for multi processes, the generated id format:
|
|
||||||
32 bits timestamp + X bits machine id + Y bits of extra data + Z bits serial number
|
|
||||||
such as 12 bits machine id, 0 bits extra data and 20 bits serial number
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/php7_ext_wrapper.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
php7 extension wrapper
|
|
||||||
for compatibility, these wrapper functions are designed for old php version.
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/base64.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
base64.h
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: src/logger.h
|
|
||||||
Copyright: 2020 YuQing <384681@qq.com>
|
|
||||||
License: GPL-3.0+
|
|
||||||
This program is free software: you can use, redistribute, and/or modify
|
|
||||||
it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
.
|
|
||||||
You should have received a copy of the Lesser GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
.
|
|
||||||
logger.h
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General Public License
|
|
||||||
Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
|
|
||||||
|
|
||||||
Files: README
|
|
||||||
Copyright: 2010 Happy Fish / YuQing
|
|
||||||
License: __UNKNOWN__
|
|
||||||
libfastcommon may be copied only under the terms of the Less GNU General
|
|
||||||
Public License(LGPL).
|
|
||||||
Please visit the libfastcommon Home Page for more detail.
|
|
||||||
English language: https://github.com/happyfish100/libfastcommon
|
|
||||||
Chinese language: http://www.fastken.com/
|
|
||||||
.
|
|
||||||
c common functions library extracted from my open source projects FastDFS and
|
|
||||||
FastDHT. this library is very simple and stable.
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# xml and html files (skipped):
|
|
||||||
# php-fastcommon/test_file_put_contents.php
|
|
||||||
# php-fastcommon/test.php
|
|
||||||
# php-fastcommon/test_error_log.php
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# Files marked as NO_LICENSE_TEXT_FOUND may be covered by the following
|
|
||||||
# license/copyright files.
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# License file: LICENSE
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
.
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
.
|
|
||||||
.
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
.
|
|
||||||
0. Additional Definitions.
|
|
||||||
.
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
.
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
.
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
.
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
.
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
.
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
.
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
.
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
.
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
.
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
.
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
.
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
.
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
.
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
.
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
.
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
.
|
|
||||||
4. Combined Works.
|
|
||||||
.
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
.
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
.
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
.
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
.
|
|
||||||
d) Do one of the following:
|
|
||||||
.
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
.
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
.
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
.
|
|
||||||
5. Combined Libraries.
|
|
||||||
.
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
.
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
.
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
.
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
.
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
.
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
.
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
usr/include/fastcommon/*
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
usr/lib/libfastcommon.so*
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
#!/usr/bin/make -f
|
|
||||||
|
|
||||||
export DESTDIR = $(CURDIR)/debian/tmp
|
|
||||||
|
|
||||||
%:
|
|
||||||
dh $@
|
|
||||||
|
|
||||||
|
|
||||||
override_dh_auto_build:
|
|
||||||
./make.sh clean && ./make.sh
|
|
||||||
|
|
||||||
override_dh_auto_install:
|
|
||||||
./make.sh install
|
|
||||||
dh_auto_install
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
3.0 (quilt)
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version=3
|
|
||||||
opts="mode=git" https://github.com/happyfish100/libfastcommon.git \
|
|
||||||
refs/tags/v([\d\.]+) debian uupdate
|
|
||||||
|
|
@ -55,21 +55,7 @@ libfastcommon是在github开源的⼀个C函数库。它提供了ini⽂件解析
|
||||||
check_alive_command = /usr/local/lib/libdfscheckalive.so %{encoder_port} 2 30
|
check_alive_command = /usr/local/lib/libdfscheckalive.so %{encoder_port} 2 30
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5、 #@add_annotation 扩展#@function标签
|
### 5、⽀持简单的流程控制,控制标签包括:
|
||||||
|
|
||||||
```
|
|
||||||
格式:
|
|
||||||
#@add_annotation <function标签> <动态库文件名> [参数1, 参数2, ...]
|
|
||||||
参数个数0到3个。
|
|
||||||
|
|
||||||
使用libshmcache扩展标签CONFIG_GET示例:
|
|
||||||
#@add_annotation CONFIG_GET /usr/lib/libshmcache.so /etc/libshmcache.conf
|
|
||||||
|
|
||||||
#@function CONFIG_GET
|
|
||||||
app.version = app1.key1
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6、⽀持简单的流程控制,控制标签包括:
|
|
||||||
|
|
||||||
#### I. 条件判断
|
#### I. 条件判断
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
|
||||||
%define LibFastcommonDevel libfastcommon-devel
|
%define LibFastcommonDevel libfastcommon-devel
|
||||||
|
%define LibFastcommonDebuginfo libfastcommon-debuginfo
|
||||||
%define CommitVersion %(echo $COMMIT_VERSION)
|
%define CommitVersion %(echo $COMMIT_VERSION)
|
||||||
|
|
||||||
Name: libfastcommon
|
Name: libfastcommon
|
||||||
Version: 1.0.83
|
Version: 1.0.39
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: c common functions library extracted from my open source projects FastDFS
|
Summary: c common functions library extracted from my open source projects FastDFS
|
||||||
License: LGPL
|
License: LGPL
|
||||||
|
|
@ -13,18 +14,10 @@ Source: http://github.com/happyfish100/libfastcommon/%{name}-%{version}.tar.gz
|
||||||
|
|
||||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||||
|
|
||||||
BuildRequires: libcurl-devel
|
#Requires: /sbin/chkconfig
|
||||||
Requires: libcurl
|
#BuildRequires: perl %{_includedir}/linux/if.h gettext
|
||||||
Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
|
Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
|
||||||
|
|
||||||
%define kernel_major %(uname -r | cut -d'.' -f1)
|
|
||||||
%define kernel_minor %(uname -r | cut -d'.' -f2)
|
|
||||||
%define kernel_ver_int %(expr %{kernel_major} \\* 100 + %{kernel_minor})
|
|
||||||
%if %{kernel_ver_int} >= 514
|
|
||||||
BuildRequires: liburing-devel >= 2.4
|
|
||||||
Requires: liburing >= 2.4
|
|
||||||
%endif
|
|
||||||
|
|
||||||
%description
|
%description
|
||||||
c common functions library extracted from my open source projects FastDFS.
|
c common functions library extracted from my open source projects FastDFS.
|
||||||
this library is very simple and stable. functions including: string, logger,
|
this library is very simple and stable. functions including: string, logger,
|
||||||
|
|
@ -34,7 +27,6 @@ commit version: %{CommitVersion}
|
||||||
|
|
||||||
%package devel
|
%package devel
|
||||||
Summary: Development header file
|
Summary: Development header file
|
||||||
Requires: libcurl-devel
|
|
||||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||||
|
|
||||||
%description devel
|
%description devel
|
||||||
|
|
@ -64,11 +56,12 @@ rm -rf %{buildroot}
|
||||||
%files
|
%files
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
/usr/lib64/libfastcommon.so*
|
/usr/lib64/libfastcommon.so*
|
||||||
|
/usr/lib/libfastcommon.so*
|
||||||
|
|
||||||
%files devel
|
%files devel
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
/usr/include/fastcommon/*
|
/usr/include/fastcommon/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Mon Jun 23 2014 Zaixue Liao
|
* Mon Jun 23 2014 Zaixue Liao <liaozaixue@yongche.com>
|
||||||
- first RPM release (1.0)
|
- first RPM release (1.0)
|
||||||
|
|
|
||||||
159
make.sh
159
make.sh
|
|
@ -1,9 +1,3 @@
|
||||||
GCC_VERSION=$(gcc -dM -E - < /dev/null | grep -w __GNUC__ | awk '{print $NF;}')
|
|
||||||
if [ -z "$GCC_VERSION" ]; then
|
|
||||||
echo -e "gcc not found, please install gcc first\n" 1>&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
tmp_src_filename=fast_check_bits.c
|
tmp_src_filename=fast_check_bits.c
|
||||||
cat <<EOF > $tmp_src_filename
|
cat <<EOF > $tmp_src_filename
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -13,132 +7,75 @@ int main()
|
||||||
{
|
{
|
||||||
printf("%d\n", (int)sizeof(void*));
|
printf("%d\n", (int)sizeof(void*));
|
||||||
printf("%d\n", (int)sizeof(off_t));
|
printf("%d\n", (int)sizeof(off_t));
|
||||||
#ifdef __GLIBC_MINOR__
|
|
||||||
printf("%d\n", __GLIBC_MINOR__);
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
|
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
|
||||||
output=$(./a.out)
|
output=`./a.out`
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "Can't find a.out program\n" 1>&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f /bin/expr ]; then
|
if [ -f /bin/expr ]; then
|
||||||
EXPR=/bin/expr
|
EXPR=/bin/expr
|
||||||
elif [ -f /usr/bin/expr ]; then
|
|
||||||
EXPR=/usr/bin/expr
|
|
||||||
else
|
else
|
||||||
EXPR=$(which expr)
|
EXPR=/usr/bin/expr
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e "Can't find expr program\n" 1>&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
count=0
|
count=0
|
||||||
int_bytes=4
|
int_bytes=4
|
||||||
off_bytes=8
|
off_bytes=8
|
||||||
glibc_minor=0
|
|
||||||
LIB_VERSION=lib64
|
LIB_VERSION=lib64
|
||||||
|
|
||||||
for col in $output; do
|
for col in $output; do
|
||||||
if [ $count -eq 0 ]; then
|
if [ $count -eq 0 ]; then
|
||||||
int_bytes=$col
|
int_bytes=$col
|
||||||
elif [ $count -eq 1 ]; then
|
|
||||||
off_bytes=$col
|
|
||||||
else
|
else
|
||||||
glibc_minor=$col
|
off_bytes=$col
|
||||||
fi
|
fi
|
||||||
|
|
||||||
count=$($EXPR $count + 1)
|
count=`$EXPR $count + 1`
|
||||||
done
|
done
|
||||||
|
|
||||||
/bin/rm -f a.out $tmp_src_filename
|
/bin/rm -f a.out $tmp_src_filename
|
||||||
|
|
||||||
uname=$(uname)
|
|
||||||
TARGET_PREFIX=$DESTDIR/usr
|
TARGET_PREFIX=$DESTDIR/usr
|
||||||
if [ "$int_bytes" -eq 8 ]; then
|
if [ "$int_bytes" -eq 8 ]; then
|
||||||
OS_BITS=64
|
OS_BITS=64
|
||||||
if [ $uname = 'Linux' ]; then
|
LIB_VERSION=lib64
|
||||||
osname=$(cat /etc/os-release | grep -w NAME | awk -F '=' '{print $2;}' | \
|
|
||||||
awk -F '"' '{if (NF==3) {print $2} else {print $1}}' | awk '{print $1}')
|
|
||||||
if [ $osname = 'Ubuntu' -o $osname = 'Debian' ]; then
|
|
||||||
LIB_VERSION=lib
|
|
||||||
else
|
|
||||||
LIB_VERSION=lib64
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
LIB_VERSION=lib
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
OS_BITS=32
|
OS_BITS=32
|
||||||
LIB_VERSION=lib
|
LIB_VERSION=lib
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$off_bytes" -eq 8 ]; then
|
if [ "$off_bytes" -eq 8 ]; then
|
||||||
OFF_BITS=64
|
OFF_BITS=64
|
||||||
else
|
else
|
||||||
OFF_BITS=32
|
OFF_BITS=32
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DEBUG_FLAG=0
|
DEBUG_FLAG=0
|
||||||
|
|
||||||
export CC=gcc
|
CFLAGS='-Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE'
|
||||||
CFLAGS='-Wall'
|
|
||||||
if [ -n "$GCC_VERSION" ] && [ $GCC_VERSION -ge 7 ]; then
|
|
||||||
CFLAGS="$CFLAGS -Wformat-truncation=0 -Wformat-overflow=0"
|
|
||||||
fi
|
|
||||||
CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE"
|
|
||||||
if [ "$DEBUG_FLAG" = "1" ]; then
|
if [ "$DEBUG_FLAG" = "1" ]; then
|
||||||
CFLAGS="$CFLAGS -g -DDEBUG_FLAG"
|
CFLAGS="$CFLAGS -g -DDEBUG_FLAG"
|
||||||
else
|
else
|
||||||
CFLAGS="$CFLAGS -g -O3"
|
CFLAGS="$CFLAGS -g -O3"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INCS=''
|
LIBS='-lm'
|
||||||
LIBS='-lm -ldl'
|
|
||||||
if [ -f /usr/include/curl/curl.h ] || [ -f /usr/local/include/curl/curl.h ]; then
|
|
||||||
CFLAGS="$CFLAGS -DUSE_LIBCURL"
|
|
||||||
LIBS="$LIBS -lcurl"
|
|
||||||
fi
|
|
||||||
|
|
||||||
uname=`uname`
|
uname=`uname`
|
||||||
|
|
||||||
HAVE_VMMETER_H=0
|
HAVE_VMMETER_H=0
|
||||||
HAVE_USER_H=0
|
HAVE_USER_H=0
|
||||||
if [ "$uname" = "Linux" ]; then
|
if [ "$uname" = "Linux" ]; then
|
||||||
OS_NAME=OS_LINUX
|
OS_NAME=OS_LINUX
|
||||||
|
IOEVENT_USE=IOEVENT_USE_EPOLL
|
||||||
major_version=$(uname -r | awk -F . '{print $1;}')
|
|
||||||
minor_version=$(uname -r | awk -F . '{print $2;}')
|
|
||||||
if [ $major_version -eq 5 -a $minor_version -ge 14 ] || [ $major_version -gt 5 ]; then
|
|
||||||
out=$(grep -F IORING_OP_SEND_ZC /usr/include/liburing/io_uring.h 2>/dev/null)
|
|
||||||
if [ -n "$out" ]; then
|
|
||||||
IOEVENT_USE=IOEVENT_USE_URING
|
|
||||||
LIBS="$LIBS -luring"
|
|
||||||
else
|
|
||||||
IOEVENT_USE=IOEVENT_USE_EPOLL
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
IOEVENT_USE=IOEVENT_USE_EPOLL
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $glibc_minor -lt 17 ]; then
|
|
||||||
LIBS="$LIBS -lrt"
|
|
||||||
fi
|
|
||||||
elif [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
|
elif [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
|
||||||
OS_NAME=OS_FREEBSD
|
OS_NAME=OS_FREEBSD
|
||||||
IOEVENT_USE=IOEVENT_USE_KQUEUE
|
IOEVENT_USE=IOEVENT_USE_KQUEUE
|
||||||
if [ "$uname" = "Darwin" ]; then
|
if [ "$uname" = "Darwin" ]; then
|
||||||
CFLAGS="$CFLAGS -DDARWIN"
|
CFLAGS="$CFLAGS -DDARWIN"
|
||||||
TARGET_PREFIX=$TARGET_PREFIX/local
|
TARGET_PREFIX=$TARGET_PREFIX/local
|
||||||
else
|
LIB_VERSION=lib
|
||||||
INCS="$INCS -I/usr/local/include"
|
|
||||||
LIBS="$LIBS -L/usr/local/lib"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f /usr/include/sys/vmmeter.h ]; then
|
if [ -f /usr/include/sys/vmmeter.h ]; then
|
||||||
|
|
@ -153,10 +90,12 @@ elif [ "$uname" = "SunOS" ]; then
|
||||||
IOEVENT_USE=IOEVENT_USE_PORT
|
IOEVENT_USE=IOEVENT_USE_PORT
|
||||||
CFLAGS="$CFLAGS -D_THREAD_SAFE"
|
CFLAGS="$CFLAGS -D_THREAD_SAFE"
|
||||||
LIBS="$LIBS -lsocket -lnsl -lresolv"
|
LIBS="$LIBS -lsocket -lnsl -lresolv"
|
||||||
|
export CC=gcc
|
||||||
elif [ "$uname" = "AIX" ]; then
|
elif [ "$uname" = "AIX" ]; then
|
||||||
OS_NAME=OS_AIX
|
OS_NAME=OS_AIX
|
||||||
IOEVENT_USE=IOEVENT_USE_NONE
|
IOEVENT_USE=IOEVENT_USE_NONE
|
||||||
CFLAGS="$CFLAGS -D_THREAD_SAFE"
|
CFLAGS="$CFLAGS -D_THREAD_SAFE"
|
||||||
|
export CC=gcc
|
||||||
elif [ "$uname" = "HP-UX" ]; then
|
elif [ "$uname" = "HP-UX" ]; then
|
||||||
OS_NAME=OS_HPUX
|
OS_NAME=OS_HPUX
|
||||||
IOEVENT_USE=IOEVENT_USE_NONE
|
IOEVENT_USE=IOEVENT_USE_NONE
|
||||||
|
|
@ -165,36 +104,6 @@ else
|
||||||
IOEVENT_USE=IOEVENT_USE_NONE
|
IOEVENT_USE=IOEVENT_USE_NONE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
check_dirent_field()
|
|
||||||
{
|
|
||||||
field_name=$1
|
|
||||||
upper_fname=$(echo $field_name | tr '[a-z]' '[A-Z]')
|
|
||||||
|
|
||||||
tmp_src_filename=fast_check_dirent.c
|
|
||||||
cat <<EOF > $tmp_src_filename
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct dirent dir;
|
|
||||||
dir.$field_name = 1;
|
|
||||||
printf("#define HAVE_DIRENT_$upper_fname %d\n", dir.$field_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
gcc -o a.out $tmp_src_filename 2>/dev/null && ./a.out
|
|
||||||
/bin/rm -f a.out $tmp_src_filename
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_filename=fast_dirent_macros.txt
|
|
||||||
check_dirent_field d_type > $tmp_filename
|
|
||||||
check_dirent_field d_reclen >> $tmp_filename
|
|
||||||
check_dirent_field d_namlen >> $tmp_filename
|
|
||||||
check_dirent_field d_off >> $tmp_filename
|
|
||||||
|
|
||||||
cat <<EOF > src/_os_define.h
|
cat <<EOF > src/_os_define.h
|
||||||
#ifndef _OS_DEFINE_H
|
#ifndef _OS_DEFINE_H
|
||||||
#define _OS_DEFINE_H
|
#define _OS_DEFINE_H
|
||||||
|
|
@ -217,35 +126,13 @@ cat <<EOF > src/_os_define.h
|
||||||
#ifndef HAVE_USER_H
|
#ifndef HAVE_USER_H
|
||||||
#define HAVE_USER_H $HAVE_USER_H
|
#define HAVE_USER_H $HAVE_USER_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
$(cat $tmp_filename && /bin/rm -f $tmp_filename)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
pthread_path=''
|
if [ -f /usr/lib/libpthread.so ] || [ -f /usr/local/lib/libpthread.so ] || [ -f /usr/lib64/libpthread.so ] || [ -f /usr/lib/libpthread.a ] || [ -f /usr/local/lib/libpthread.a ] || [ -f /usr/lib64/libpthread.a ]; then
|
||||||
for path in /lib /lib64 /usr/lib /usr/lib64 /usr/local/lib; do
|
|
||||||
if [ -d $path ]; then
|
|
||||||
pthread_path=$(find $path -name libpthread.so | head -n 1)
|
|
||||||
if [ -n "$pthread_path" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
pthread_path=$(find $path -name libpthread.a | head -n 1)
|
|
||||||
if [ -n "$pthread_path" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$pthread_path" ]; then
|
|
||||||
LIBS="$LIBS -lpthread"
|
LIBS="$LIBS -lpthread"
|
||||||
line=$(nm $pthread_path 2>/dev/null | grep -F pthread_rwlockattr_setkind_np | grep -w T)
|
|
||||||
if [ -n "$line" ]; then
|
|
||||||
CFLAGS="$CFLAGS -DWITH_PTHREAD_RWLOCKATTR_SETKIND_NP=1"
|
|
||||||
fi
|
|
||||||
elif [ -f /usr/lib/libc_r.so ]; then
|
elif [ -f /usr/lib/libc_r.so ]; then
|
||||||
line=$(nm -D /usr/lib/libc_r.so 2>/dev/null | grep -F pthread_create | grep -w T)
|
line=`nm -D /usr/lib/libc_r.so | grep pthread_create | grep -w T`
|
||||||
if [ -n "$line" ]; then
|
if [ -n "$line" ]; then
|
||||||
LIBS="$LIBS -lc_r"
|
LIBS="$LIBS -lc_r"
|
||||||
fi
|
fi
|
||||||
|
|
@ -264,9 +151,7 @@ sed_replace()
|
||||||
|
|
||||||
cd src
|
cd src
|
||||||
cp Makefile.in Makefile
|
cp Makefile.in Makefile
|
||||||
sed_replace "s#\\\$(CC)#gcc#g" Makefile
|
|
||||||
sed_replace "s#\\\$(CFLAGS)#$CFLAGS#g" Makefile
|
sed_replace "s#\\\$(CFLAGS)#$CFLAGS#g" Makefile
|
||||||
sed_replace "s#\\\$(INCS)#$INCS#g" Makefile
|
|
||||||
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
|
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
|
||||||
sed_replace "s#\\\$(TARGET_PREFIX)#$TARGET_PREFIX#g" Makefile
|
sed_replace "s#\\\$(TARGET_PREFIX)#$TARGET_PREFIX#g" Makefile
|
||||||
sed_replace "s#\\\$(LIB_VERSION)#$LIB_VERSION#g" Makefile
|
sed_replace "s#\\\$(LIB_VERSION)#$LIB_VERSION#g" Makefile
|
||||||
|
|
@ -276,11 +161,3 @@ if [ "$1" = "clean" ]; then
|
||||||
/bin/rm -f Makefile _os_define.h
|
/bin/rm -f Makefile _os_define.h
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd tests
|
|
||||||
cp Makefile.in Makefile
|
|
||||||
sed_replace "s#\\\$(CC)#gcc#g" Makefile
|
|
||||||
sed_replace "s#\\\$(INCS)#$INCS#g" Makefile
|
|
||||||
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
|
|
||||||
if [ "$1" = "clean" ]; then
|
|
||||||
/bin/rm -f Makefile
|
|
||||||
fi
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include "php7_ext_wrapper.h"
|
#include "php7_ext_wrapper.h"
|
||||||
#include "ext/standard/info.h"
|
#include "ext/standard/info.h"
|
||||||
#include "ext/standard/file.h"
|
#include "ext/standard/file.h"
|
||||||
|
|
@ -37,29 +23,16 @@
|
||||||
#define MINOR_VERSION 0
|
#define MINOR_VERSION 0
|
||||||
#define PATCH_VERSION 8
|
#define PATCH_VERSION 8
|
||||||
|
|
||||||
#define IDG_FLAGS_EXTRA_DATA_BY_MOD 1
|
|
||||||
|
|
||||||
#define PHP_IDG_RESOURCE_NAME "fastcommon_idg"
|
#define PHP_IDG_RESOURCE_NAME "fastcommon_idg"
|
||||||
#define DEFAULT_SN_FILENAME "/tmp/fastcommon_id_generator.sn"
|
#define DEFAULT_SN_FILENAME "/tmp/fastcommon_id_generator.sn"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct idg_context *idg_context;
|
struct idg_context idg_context;
|
||||||
int flags;
|
|
||||||
} PHPIDGContext;
|
} PHPIDGContext;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char filename[MAX_PATH_SIZE];
|
|
||||||
int machine_id;
|
|
||||||
int mid_bits;
|
|
||||||
int extra_bits;
|
|
||||||
int sn_bits;
|
|
||||||
int flags;
|
|
||||||
} PHPIDGKeyInfo;
|
|
||||||
|
|
||||||
static int le_consumer;
|
static int le_consumer;
|
||||||
|
|
||||||
static PHPIDGContext *last_idg_context = NULL;
|
static PHPIDGContext *last_idg_context = NULL;
|
||||||
static HashArray idg_htable;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int alloc;
|
int alloc;
|
||||||
|
|
@ -93,111 +66,26 @@ const zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, N
|
||||||
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
|
{ NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_version, 0, 0, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_gethostaddrs, 0, 0, 0)
|
|
||||||
ZEND_ARG_INFO(0, if_alias_prefix)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_time33_hash, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, str)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_simple_hash, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, str)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_line_distance_km, 0, 0, 4)
|
|
||||||
ZEND_ARG_INFO(0, lat1)
|
|
||||||
ZEND_ARG_INFO(0, lon1)
|
|
||||||
ZEND_ARG_INFO(0, lat2)
|
|
||||||
ZEND_ARG_INFO(0, lon2)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_first_local_ip, 0, 0, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_next_local_ip, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, previous_ip)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_is_private_ip, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, ip)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_init, 0, 0, 0)
|
|
||||||
ZEND_ARG_INFO(0, filename)
|
|
||||||
ZEND_ARG_INFO(0, machine_id)
|
|
||||||
ZEND_ARG_INFO(0, mid_bits)
|
|
||||||
ZEND_ARG_INFO(0, extra_bits)
|
|
||||||
ZEND_ARG_INFO(0, sn_bits)
|
|
||||||
ZEND_ARG_INFO(0, mode)
|
|
||||||
ZEND_ARG_INFO(0, flags)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_next, 0, 0, 0)
|
|
||||||
ZEND_ARG_INFO(0, extra)
|
|
||||||
ZEND_ARG_INFO(0, handle)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_get_extra, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, id)
|
|
||||||
ZEND_ARG_INFO(0, handle)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_get_timestamp, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, id)
|
|
||||||
ZEND_ARG_INFO(0, handle)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_id_generator_destroy, 0, 0, 0)
|
|
||||||
ZEND_ARG_INFO(0, handle)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_ifconfigs, 0, 0, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_cpu_count, 0, 0, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_sysinfo, 0, 0, 0)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_error_log, 0, 0, 1)
|
|
||||||
ZEND_ARG_INFO(0, message)
|
|
||||||
ZEND_ARG_INFO(0, message_type)
|
|
||||||
ZEND_ARG_INFO(0, destination)
|
|
||||||
ZEND_ARG_INFO(0, headers)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_file_put_contents, 0, 0, 2)
|
|
||||||
ZEND_ARG_INFO(0, filename)
|
|
||||||
ZEND_ARG_INFO(0, data)
|
|
||||||
ZEND_ARG_INFO(0, flags)
|
|
||||||
ZEND_ARG_INFO(0, context)
|
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
// Every user visible function must have an entry in fastcommon_functions[].
|
// Every user visible function must have an entry in fastcommon_functions[].
|
||||||
zend_function_entry fastcommon_functions[] = {
|
zend_function_entry fastcommon_functions[] = {
|
||||||
ZEND_FE(fastcommon_version, arginfo_version)
|
ZEND_FE(fastcommon_version, NULL)
|
||||||
ZEND_FE(fastcommon_gethostaddrs, arginfo_gethostaddrs)
|
ZEND_FE(fastcommon_gethostaddrs, NULL)
|
||||||
ZEND_FE(fastcommon_time33_hash, arginfo_time33_hash)
|
ZEND_FE(fastcommon_time33_hash, NULL)
|
||||||
ZEND_FE(fastcommon_simple_hash, arginfo_simple_hash)
|
ZEND_FE(fastcommon_simple_hash, NULL)
|
||||||
ZEND_FE(fastcommon_get_line_distance_km, arginfo_get_line_distance_km)
|
ZEND_FE(fastcommon_get_line_distance_km, NULL)
|
||||||
ZEND_FE(fastcommon_get_first_local_ip, arginfo_get_first_local_ip)
|
ZEND_FE(fastcommon_get_first_local_ip, NULL)
|
||||||
ZEND_FE(fastcommon_get_next_local_ip, arginfo_get_next_local_ip)
|
ZEND_FE(fastcommon_get_next_local_ip, NULL)
|
||||||
ZEND_FE(fastcommon_is_private_ip, arginfo_is_private_ip)
|
ZEND_FE(fastcommon_is_private_ip, NULL)
|
||||||
ZEND_FE(fastcommon_id_generator_init, arginfo_id_generator_init)
|
ZEND_FE(fastcommon_id_generator_init, NULL)
|
||||||
ZEND_FE(fastcommon_id_generator_next, arginfo_id_generator_next)
|
ZEND_FE(fastcommon_id_generator_next, NULL)
|
||||||
ZEND_FE(fastcommon_id_generator_get_extra, arginfo_id_generator_get_extra)
|
ZEND_FE(fastcommon_id_generator_get_extra, NULL)
|
||||||
ZEND_FE(fastcommon_id_generator_get_timestamp, arginfo_id_generator_get_timestamp)
|
ZEND_FE(fastcommon_id_generator_get_timestamp, NULL)
|
||||||
ZEND_FE(fastcommon_id_generator_destroy, arginfo_id_generator_destroy)
|
ZEND_FE(fastcommon_id_generator_destroy, NULL)
|
||||||
ZEND_FE(fastcommon_get_ifconfigs, arginfo_get_ifconfigs)
|
ZEND_FE(fastcommon_get_ifconfigs, NULL)
|
||||||
ZEND_FE(fastcommon_get_cpu_count, arginfo_get_cpu_count)
|
ZEND_FE(fastcommon_get_cpu_count, NULL)
|
||||||
ZEND_FE(fastcommon_get_sysinfo, arginfo_get_sysinfo)
|
ZEND_FE(fastcommon_get_sysinfo, NULL)
|
||||||
ZEND_FE(fastcommon_error_log, arginfo_error_log)
|
ZEND_FE(fastcommon_error_log, NULL)
|
||||||
ZEND_FE(fastcommon_file_put_contents, arginfo_file_put_contents)
|
ZEND_FE(fastcommon_file_put_contents, NULL)
|
||||||
{NULL, NULL, NULL} /* Must be the last line */
|
{NULL, NULL, NULL} /* Must be the last line */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -220,25 +108,32 @@ zend_module_entry fastcommon_module_entry = {
|
||||||
|
|
||||||
ZEND_RSRC_DTOR_FUNC(id_generator_dtor)
|
ZEND_RSRC_DTOR_FUNC(id_generator_dtor)
|
||||||
{
|
{
|
||||||
PHPIDGContext *php_idg_context = NULL;
|
|
||||||
#if PHP_MAJOR_VERSION < 7
|
#if PHP_MAJOR_VERSION < 7
|
||||||
if (rsrc->ptr != NULL) {
|
if (rsrc->ptr != NULL)
|
||||||
php_idg_context = (PHPIDGContext *)rsrc->ptr;
|
{
|
||||||
|
PHPIDGContext *php_idg_context = (PHPIDGContext *)rsrc->ptr;
|
||||||
|
id_generator_destroy(&php_idg_context->idg_context);
|
||||||
|
if (last_idg_context == php_idg_context)
|
||||||
|
{
|
||||||
|
last_idg_context = NULL;
|
||||||
|
}
|
||||||
|
efree(php_idg_context);
|
||||||
rsrc->ptr = NULL;
|
rsrc->ptr = NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (res->ptr != NULL) {
|
if (res->ptr != NULL)
|
||||||
php_idg_context = (PHPIDGContext *)res->ptr;
|
{
|
||||||
|
PHPIDGContext *php_idg_context = (PHPIDGContext *)res->ptr;
|
||||||
|
id_generator_destroy(&php_idg_context->idg_context);
|
||||||
|
if (last_idg_context == php_idg_context)
|
||||||
|
{
|
||||||
|
last_idg_context = NULL;
|
||||||
|
}
|
||||||
|
efree(php_idg_context);
|
||||||
res->ptr = NULL;
|
res->ptr = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (php_idg_context != NULL) {
|
|
||||||
if (last_idg_context == php_idg_context) {
|
|
||||||
last_idg_context = NULL;
|
|
||||||
}
|
|
||||||
efree(php_idg_context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FASTCOMMON_REGISTER_CHAR_STR_CONSTANT(key, c, buff) \
|
#define FASTCOMMON_REGISTER_CHAR_STR_CONSTANT(key, c, buff) \
|
||||||
|
|
@ -249,12 +144,9 @@ PHP_MINIT_FUNCTION(fastcommon)
|
||||||
{
|
{
|
||||||
static char buff[16];
|
static char buff[16];
|
||||||
|
|
||||||
log_try_init();
|
log_init();
|
||||||
le_consumer = zend_register_list_destructors_ex(id_generator_dtor, NULL,
|
le_consumer = zend_register_list_destructors_ex(id_generator_dtor, NULL,
|
||||||
PHP_IDG_RESOURCE_NAME, module_number);
|
PHP_IDG_RESOURCE_NAME, module_number);
|
||||||
if (fc_hash_init(&idg_htable, fc_simple_hash, 64, 0.75) != 0) {
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(buff, 0, sizeof(buff));
|
memset(buff, 0, sizeof(buff));
|
||||||
FASTCOMMON_REGISTER_CHAR_STR_CONSTANT("FASTCOMMON_LOG_TIME_PRECISION_SECOND",
|
FASTCOMMON_REGISTER_CHAR_STR_CONSTANT("FASTCOMMON_LOG_TIME_PRECISION_SECOND",
|
||||||
|
|
@ -266,9 +158,6 @@ PHP_MINIT_FUNCTION(fastcommon)
|
||||||
FASTCOMMON_REGISTER_CHAR_STR_CONSTANT("FASTCOMMON_LOG_TIME_PRECISION_NONE",
|
FASTCOMMON_REGISTER_CHAR_STR_CONSTANT("FASTCOMMON_LOG_TIME_PRECISION_NONE",
|
||||||
LOG_TIME_PRECISION_NONE, buff + 6);
|
LOG_TIME_PRECISION_NONE, buff + 6);
|
||||||
|
|
||||||
REGISTER_LONG_CONSTANT("FASTCOMMON_IDG_FLAGS_EXTRA_DATA_BY_MOD",
|
|
||||||
IDG_FLAGS_EXTRA_DATA_BY_MOD, CONST_CS | CONST_PERSISTENT);
|
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,7 +354,7 @@ ZEND_FUNCTION(fastcommon_simple_hash)
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_LONG(fc_simple_hash(str, str_len) & 0x7FFFFFFF);
|
RETURN_LONG(simple_hash(str, str_len) & 0x7FFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -588,47 +477,9 @@ ZEND_FUNCTION(fastcommon_is_private_ip)
|
||||||
RETURN_BOOL(is_private_ip(ip));
|
RETURN_BOOL(is_private_ip(ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct idg_context *get_idg_context(const char *filename,
|
|
||||||
const int machine_id, const int mid_bits, const int extra_bits,
|
|
||||||
const int sn_bits, const int mode)
|
|
||||||
{
|
|
||||||
PHPIDGKeyInfo key_info;
|
|
||||||
struct idg_context *idg_context;
|
|
||||||
|
|
||||||
memset(&key_info, 0, sizeof(key_info));
|
|
||||||
snprintf(key_info.filename, sizeof(key_info.filename), "%s", filename);
|
|
||||||
key_info.machine_id = machine_id;
|
|
||||||
key_info.mid_bits = mid_bits;
|
|
||||||
key_info.extra_bits = extra_bits;
|
|
||||||
key_info.sn_bits = sn_bits;
|
|
||||||
|
|
||||||
idg_context = (struct idg_context *)fc_hash_find(&idg_htable,
|
|
||||||
&key_info, sizeof(key_info));
|
|
||||||
if (idg_context == NULL) {
|
|
||||||
idg_context = (struct idg_context *)malloc(sizeof(struct idg_context));
|
|
||||||
if (idg_context == NULL) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"malloc %d bytes fail!", __LINE__,
|
|
||||||
(int)sizeof(struct idg_context));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id_generator_init_extra_ex(idg_context, filename,
|
|
||||||
machine_id, mid_bits, extra_bits, sn_bits, mode) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
fc_hash_insert_ex(&idg_htable, &key_info, sizeof(key_info),
|
|
||||||
idg_context, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return idg_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
resource fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn",
|
resource fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn",
|
||||||
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16,
|
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16, int mode = 0644])
|
||||||
int mode = 0644, int flags = 0])
|
|
||||||
return resource handle for success, false for fail
|
return resource handle for success, false for fail
|
||||||
*/
|
*/
|
||||||
ZEND_FUNCTION(fastcommon_id_generator_init)
|
ZEND_FUNCTION(fastcommon_id_generator_init)
|
||||||
|
|
@ -640,50 +491,47 @@ ZEND_FUNCTION(fastcommon_id_generator_init)
|
||||||
long extra_bits;
|
long extra_bits;
|
||||||
long sn_bits;
|
long sn_bits;
|
||||||
long mode;
|
long mode;
|
||||||
long flags;
|
|
||||||
char *filename;
|
char *filename;
|
||||||
PHPIDGContext *php_idg_context;
|
PHPIDGContext *php_idg_context;
|
||||||
|
|
||||||
argc = ZEND_NUM_ARGS();
|
argc = ZEND_NUM_ARGS();
|
||||||
if (argc > 7) {
|
if (argc > 6) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"fastcommon_id_generator_init parameters count: %d is invalid",
|
"fastcommon_id_generator_init parameters count: %d is invalid",
|
||||||
__LINE__, argc);
|
__LINE__, argc);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = DEFAULT_SN_FILENAME;
|
filename = DEFAULT_SN_FILENAME;
|
||||||
filename_len = 0;
|
filename_len = 0;
|
||||||
machine_id = 0;
|
machine_id = 0;
|
||||||
mid_bits = 16;
|
mid_bits = 16;
|
||||||
extra_bits = 0;
|
extra_bits = 0;
|
||||||
sn_bits = 16;
|
sn_bits = 16;
|
||||||
mode = ID_GENERATOR_DEFAULT_FILE_MODE;
|
mode = ID_GENERATOR_DEFAULT_FILE_MODE;
|
||||||
flags = 0;
|
if (zend_parse_parameters(argc TSRMLS_CC, "|slllll", &filename,
|
||||||
if (zend_parse_parameters(argc TSRMLS_CC, "|sllllll", &filename,
|
|
||||||
&filename_len, &machine_id, &mid_bits, &extra_bits,
|
&filename_len, &machine_id, &mid_bits, &extra_bits,
|
||||||
&sn_bits, &mode, &flags) == FAILURE)
|
&sn_bits, &mode) == FAILURE)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"zend_parse_parameters fail!", __LINE__);
|
"zend_parse_parameters fail!", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
php_idg_context = (PHPIDGContext *)emalloc(sizeof(PHPIDGContext));
|
php_idg_context = (PHPIDGContext *)emalloc(sizeof(PHPIDGContext));
|
||||||
if (php_idg_context == NULL) {
|
if (php_idg_context == NULL)
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"emalloc %d bytes fail!", __LINE__,
|
|
||||||
(int)sizeof(PHPIDGContext));
|
|
||||||
RETURN_BOOL(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((php_idg_context->idg_context=get_idg_context(filename, machine_id,
|
|
||||||
mid_bits, extra_bits, sn_bits, mode)) == NULL)
|
|
||||||
{
|
{
|
||||||
RETURN_BOOL(false);
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"emalloc %d bytes fail!", __LINE__, (int)sizeof(PHPIDGContext));
|
||||||
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
php_idg_context->flags = flags;
|
if (id_generator_init_extra_ex(&php_idg_context->idg_context, filename,
|
||||||
|
machine_id, mid_bits, extra_bits, sn_bits, mode) != 0)
|
||||||
|
{
|
||||||
|
RETURN_BOOL(false);
|
||||||
|
}
|
||||||
|
|
||||||
last_idg_context = php_idg_context;
|
last_idg_context = php_idg_context;
|
||||||
ZEND_REGISTER_RESOURCE(return_value, php_idg_context, le_consumer);
|
ZEND_REGISTER_RESOURCE(return_value, php_idg_context, le_consumer);
|
||||||
}
|
}
|
||||||
|
|
@ -697,11 +545,10 @@ ZEND_FUNCTION(fastcommon_id_generator_next)
|
||||||
{
|
{
|
||||||
int argc;
|
int argc;
|
||||||
long extra;
|
long extra;
|
||||||
int extra_val;
|
|
||||||
int *extra_ptr;
|
|
||||||
int64_t id;
|
int64_t id;
|
||||||
zval *zhandle;
|
zval *zhandle;
|
||||||
PHPIDGContext *php_idg_context;
|
PHPIDGContext *php_idg_context;
|
||||||
|
struct idg_context *context;
|
||||||
|
|
||||||
argc = ZEND_NUM_ARGS();
|
argc = ZEND_NUM_ARGS();
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
|
|
@ -719,31 +566,26 @@ ZEND_FUNCTION(fastcommon_id_generator_next)
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
|
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
|
||||||
|
{
|
||||||
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
||||||
PHP_IDG_RESOURCE_NAME, le_consumer);
|
PHP_IDG_RESOURCE_NAME, le_consumer);
|
||||||
} else {
|
context = &php_idg_context->idg_context;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (last_idg_context == NULL) {
|
if (last_idg_context == NULL) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"must call fastcommon_id_generator_init first", __LINE__);
|
"must call fastcommon_id_generator_init first", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
php_idg_context = last_idg_context;
|
context = &last_idg_context->idg_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((php_idg_context->flags & IDG_FLAGS_EXTRA_DATA_BY_MOD)) {
|
if (id_generator_next_extra(context, extra, &id) != 0) {
|
||||||
extra_ptr = NULL;
|
RETURN_BOOL(false);
|
||||||
} else {
|
}
|
||||||
extra_val = extra;
|
|
||||||
extra_ptr = &extra_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id_generator_next_extra_ptr(php_idg_context->idg_context,
|
|
||||||
extra_ptr, &id) != 0)
|
|
||||||
{
|
|
||||||
RETURN_BOOL(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if OS_BITS == 64
|
#if OS_BITS == 64
|
||||||
RETURN_LONG(id);
|
RETURN_LONG(id);
|
||||||
|
|
@ -767,6 +609,7 @@ ZEND_FUNCTION(fastcommon_id_generator_get_extra)
|
||||||
long id;
|
long id;
|
||||||
zval *zhandle;
|
zval *zhandle;
|
||||||
PHPIDGContext *php_idg_context;
|
PHPIDGContext *php_idg_context;
|
||||||
|
struct idg_context *context;
|
||||||
|
|
||||||
argc = ZEND_NUM_ARGS();
|
argc = ZEND_NUM_ARGS();
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
|
|
@ -784,25 +627,29 @@ ZEND_FUNCTION(fastcommon_id_generator_get_extra)
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
|
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
|
||||||
|
{
|
||||||
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
||||||
PHP_IDG_RESOURCE_NAME, le_consumer);
|
PHP_IDG_RESOURCE_NAME, le_consumer);
|
||||||
} else {
|
context = &php_idg_context->idg_context;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (last_idg_context == NULL) {
|
if (last_idg_context == NULL) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"must call fastcommon_id_generator_init first", __LINE__);
|
"must call fastcommon_id_generator_init first", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
php_idg_context = last_idg_context;
|
context = &last_idg_context->idg_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (php_idg_context->idg_context->fd < 0) {
|
if (context->fd < 0) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"must call fastcommon_id_generator_init first", __LINE__);
|
"must call fastcommon_id_generator_init first", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_LONG(id_generator_get_extra(php_idg_context->idg_context, id));
|
RETURN_LONG(id_generator_get_extra(context, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -813,7 +660,8 @@ ZEND_FUNCTION(fastcommon_id_generator_destroy)
|
||||||
{
|
{
|
||||||
int argc;
|
int argc;
|
||||||
zval *zhandle;
|
zval *zhandle;
|
||||||
//PHPIDGContext *php_idg_context;
|
PHPIDGContext *php_idg_context;
|
||||||
|
struct idg_context *context;
|
||||||
|
|
||||||
argc = ZEND_NUM_ARGS();
|
argc = ZEND_NUM_ARGS();
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
|
|
@ -831,20 +679,24 @@ ZEND_FUNCTION(fastcommon_id_generator_destroy)
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
|
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
|
||||||
/*
|
{
|
||||||
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
||||||
PHP_IDG_RESOURCE_NAME, le_consumer);
|
PHP_IDG_RESOURCE_NAME, le_consumer);
|
||||||
*/
|
context = &php_idg_context->idg_context;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (last_idg_context == NULL) {
|
if (last_idg_context == NULL) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"must call fastcommon_id_generator_init first", __LINE__);
|
"must call fastcommon_id_generator_init first", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
context = &last_idg_context->idg_context;
|
||||||
last_idg_context = NULL;
|
last_idg_context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id_generator_destroy(context);
|
||||||
RETURN_BOOL(true);
|
RETURN_BOOL(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -858,6 +710,7 @@ ZEND_FUNCTION(fastcommon_id_generator_get_timestamp)
|
||||||
long id;
|
long id;
|
||||||
zval *zhandle;
|
zval *zhandle;
|
||||||
PHPIDGContext *php_idg_context;
|
PHPIDGContext *php_idg_context;
|
||||||
|
struct idg_context *context;
|
||||||
|
|
||||||
argc = ZEND_NUM_ARGS();
|
argc = ZEND_NUM_ARGS();
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
|
|
@ -875,25 +728,29 @@ ZEND_FUNCTION(fastcommon_id_generator_get_timestamp)
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle)) {
|
if (zhandle != NULL && !ZVAL_IS_NULL(zhandle))
|
||||||
|
{
|
||||||
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
ZEND_FETCH_RESOURCE(php_idg_context, PHPIDGContext *, &zhandle, -1,
|
||||||
PHP_IDG_RESOURCE_NAME, le_consumer);
|
PHP_IDG_RESOURCE_NAME, le_consumer);
|
||||||
} else {
|
context = &php_idg_context->idg_context;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (last_idg_context == NULL) {
|
if (last_idg_context == NULL) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"must call fastcommon_id_generator_init first", __LINE__);
|
"must call fastcommon_id_generator_init first", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
php_idg_context = last_idg_context;
|
context = &last_idg_context->idg_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (php_idg_context->idg_context->fd < 0) {
|
if (context->fd < 0) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"must call fastcommon_id_generator_init first", __LINE__);
|
"must call fastcommon_id_generator_init first", __LINE__);
|
||||||
RETURN_BOOL(false);
|
RETURN_BOOL(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_LONG(id_generator_get_timestamp(php_idg_context->idg_context, id));
|
RETURN_LONG(id_generator_get_timestamp(context, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1237,8 +1094,8 @@ static PHPFileContext *fetch_file_context(const char *filename)
|
||||||
|
|
||||||
static int fc_open_file(PHPFileContext *ctx)
|
static int fc_open_file(PHPFileContext *ctx)
|
||||||
{
|
{
|
||||||
if ((ctx->fd = open(ctx->filename, O_WRONLY | O_CREAT |
|
if ((ctx->fd = open(ctx->filename, O_WRONLY |
|
||||||
O_APPEND | O_CLOEXEC, 0644)) < 0)
|
O_CREAT | O_APPEND, 0644)) < 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"open file \"%s\" to write fail, "
|
"open file \"%s\" to write fail, "
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FASTCOMMON_H
|
#ifndef FASTCOMMON_H
|
||||||
#define FASTCOMMON_H
|
#define FASTCOMMON_H
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ unset($handle);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
resource fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn",
|
resource fastcommon_id_generator_init([string filename = "/tmp/fastcommon_id_generator.sn",
|
||||||
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16, int flags = 0])
|
int machine_id = 0, int mid_bits = 16, int extra_bits = 0, int sn_bits = 16])
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$id = 6301319781687017475;
|
$id = 6301319781687017475;
|
||||||
$handle1 = fastcommon_id_generator_init("/tmp/sn1.txt", 0, 8, 10, 14, 0666);
|
$handle1 = fastcommon_id_generator_init("/tmp/sn1.txt", 0, 8, 10, 14, 0775);
|
||||||
echo 'extra no: ' . fastcommon_id_generator_get_extra($id, $handle1) . "\n";
|
echo 'extra no: ' . fastcommon_id_generator_get_extra($id, $handle1) . "\n";
|
||||||
|
|
||||||
$handle2 = fastcommon_id_generator_init("/tmp/sn2.txt", 0, 8, 8, 16);
|
$handle2 = fastcommon_id_generator_init("/tmp/sn2.txt", 0, 8, 8, 16);
|
||||||
|
|
@ -58,6 +58,10 @@ for ($i=0; $i<10; $i++) {
|
||||||
fastcommon_id_generator_get_timestamp($id, $handle));
|
fastcommon_id_generator_get_timestamp($id, $handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fastcommon_id_generator_destroy($handle);
|
||||||
|
fastcommon_id_generator_destroy($handle1);
|
||||||
|
fastcommon_id_generator_destroy($handle2);
|
||||||
|
|
||||||
fastcommon_error_log("this is a test\n", 3, "/tmp/test.log");
|
fastcommon_error_log("this is a test\n", 3, "/tmp/test.log");
|
||||||
fastcommon_error_log("this is a test11\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
|
fastcommon_error_log("this is a test11\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
|
||||||
fastcommon_error_log("this is a test12\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
|
fastcommon_error_log("this is a test12\n", 3, "/tmp/test1.log", FASTCOMMON_LOG_TIME_PRECISION_MSECOND);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.SUFFIXES: .c .o .lo
|
.SUFFIXES: .c .o .lo
|
||||||
|
|
||||||
COMPILE = $(CC) $(CFLAGS)
|
COMPILE = $(CC) $(CFLAGS)
|
||||||
INC_PATH = $(INCS)
|
INC_PATH =
|
||||||
LIB_PATH = $(LIBS)
|
LIB_PATH = $(LIBS)
|
||||||
TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION)
|
TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION)
|
||||||
|
|
||||||
|
|
@ -9,45 +9,35 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
|
||||||
logger.lo sockopt.lo base64.lo sched_thread.lo \
|
logger.lo sockopt.lo base64.lo sched_thread.lo \
|
||||||
http_func.lo md5.lo pthread_func.lo local_ip_func.lo \
|
http_func.lo md5.lo pthread_func.lo local_ip_func.lo \
|
||||||
avl_tree.lo ioevent.lo ioevent_loop.lo fast_task_queue.lo \
|
avl_tree.lo ioevent.lo ioevent_loop.lo fast_task_queue.lo \
|
||||||
fast_timer.lo locked_timer.lo process_ctrl.lo fast_mblock.lo \
|
fast_timer.lo process_ctrl.lo fast_mblock.lo \
|
||||||
connection_pool.lo fast_mpool.lo fast_allocator.lo \
|
connection_pool.lo fast_mpool.lo fast_allocator.lo \
|
||||||
fast_buffer.lo multi_skiplist.lo flat_skiplist.lo \
|
fast_buffer.lo multi_skiplist.lo flat_skiplist.lo \
|
||||||
system_info.lo fast_blocked_queue.lo id_generator.lo \
|
system_info.lo fast_blocked_queue.lo id_generator.lo \
|
||||||
char_converter.lo char_convert_loader.lo common_blocked_queue.lo \
|
char_converter.lo char_convert_loader.lo common_blocked_queue.lo \
|
||||||
multi_socket_client.lo skiplist_set.lo uniq_skiplist.lo \
|
multi_socket_client.lo skiplist_set.lo
|
||||||
json_parser.lo buffered_file_writer.lo server_id_func.lo \
|
|
||||||
fc_queue.lo sorted_queue.lo fc_memory.lo shared_buffer.lo \
|
|
||||||
thread_pool.lo array_allocator.lo sorted_array.lo spinlock.lo
|
|
||||||
|
|
||||||
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
|
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
|
||||||
logger.o sockopt.o base64.o sched_thread.o \
|
logger.o sockopt.o base64.o sched_thread.o \
|
||||||
http_func.o md5.o pthread_func.o local_ip_func.o \
|
http_func.o md5.o pthread_func.o local_ip_func.o \
|
||||||
avl_tree.o ioevent.o ioevent_loop.o fast_task_queue.o \
|
avl_tree.o ioevent.o ioevent_loop.o fast_task_queue.o \
|
||||||
fast_timer.o locked_timer.o process_ctrl.o fast_mblock.o \
|
fast_timer.o process_ctrl.o fast_mblock.o \
|
||||||
connection_pool.o fast_mpool.o fast_allocator.o \
|
connection_pool.o fast_mpool.o fast_allocator.o \
|
||||||
fast_buffer.o multi_skiplist.o flat_skiplist.o \
|
fast_buffer.o multi_skiplist.o flat_skiplist.o \
|
||||||
system_info.o fast_blocked_queue.o id_generator.o \
|
system_info.o fast_blocked_queue.o id_generator.o \
|
||||||
char_converter.o char_convert_loader.o common_blocked_queue.o \
|
char_converter.o char_convert_loader.o common_blocked_queue.o \
|
||||||
multi_socket_client.o skiplist_set.o uniq_skiplist.o \
|
multi_socket_client.o skiplist_set.o
|
||||||
json_parser.o buffered_file_writer.o server_id_func.o \
|
|
||||||
fc_queue.o sorted_queue.o fc_memory.o shared_buffer.o \
|
|
||||||
thread_pool.o array_allocator.o sorted_array.o spinlock.o
|
|
||||||
|
|
||||||
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
|
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
|
||||||
shared_func.h pthread_func.h ini_file_reader.h _os_define.h \
|
shared_func.h pthread_func.h ini_file_reader.h _os_define.h \
|
||||||
sockopt.h sched_thread.h http_func.h md5.h local_ip_func.h \
|
sockopt.h sched_thread.h http_func.h md5.h local_ip_func.h \
|
||||||
avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h \
|
avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h \
|
||||||
fast_timer.h locked_timer.h process_ctrl.h fast_mblock.h \
|
fast_timer.h process_ctrl.h fast_mblock.h \
|
||||||
connection_pool.h fast_mpool.h fast_allocator.h \
|
connection_pool.h fast_mpool.h fast_allocator.h \
|
||||||
fast_buffer.h skiplist.h multi_skiplist.h flat_skiplist.h \
|
fast_buffer.h skiplist.h multi_skiplist.h flat_skiplist.h \
|
||||||
skiplist_common.h system_info.h fast_blocked_queue.h \
|
skiplist_common.h system_info.h fast_blocked_queue.h \
|
||||||
php7_ext_wrapper.h id_generator.h char_converter.h \
|
php7_ext_wrapper.h id_generator.h char_converter.h \
|
||||||
char_convert_loader.h common_blocked_queue.h \
|
char_convert_loader.h common_blocked_queue.h \
|
||||||
multi_socket_client.h skiplist_set.h uniq_skiplist.h \
|
multi_socket_client.h skiplist_set.h fc_list.h
|
||||||
fc_list.h locked_list.h json_parser.h buffered_file_writer.h \
|
|
||||||
server_id_func.h fc_queue.h sorted_queue.h fc_memory.h \
|
|
||||||
shared_buffer.h thread_pool.h fc_atomic.h array_allocator.h \
|
|
||||||
sorted_array.h spinlock.h
|
|
||||||
|
|
||||||
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
|
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
|
||||||
|
|
||||||
|
|
@ -76,9 +66,7 @@ install:
|
||||||
|
|
||||||
install -m 755 $(SHARED_LIBS) $(TARGET_LIB)
|
install -m 755 $(SHARED_LIBS) $(TARGET_LIB)
|
||||||
install -m 644 $(HEADER_FILES) $(TARGET_PREFIX)/include/fastcommon
|
install -m 644 $(HEADER_FILES) $(TARGET_PREFIX)/include/fastcommon
|
||||||
|
if [ ! -e $(TARGET_PREFIX)/lib/libfastcommon.so ]; then ln -s $(TARGET_LIB)/libfastcommon.so $(TARGET_PREFIX)/lib/libfastcommon.so; fi
|
||||||
@BUILDROOT=$$(echo "$(TARGET_PREFIX)" | grep BUILDROOT); \
|
|
||||||
if [ -z "$$BUILDROOT" ] && [ "$(TARGET_LIB)" != "$(TARGET_PREFIX)/lib" ]; then ln -sf $(TARGET_LIB)/libfastcommon.so $(TARGET_PREFIX)/lib/libfastcommon.so; fi
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "array_allocator.h"
|
|
||||||
|
|
||||||
int array_allocator_init_ex(ArrayAllocatorContext *ctx,
|
|
||||||
const char *name_prefix, const int element_size,
|
|
||||||
const int min_bits, const int max_bits,
|
|
||||||
const bool need_lock)
|
|
||||||
{
|
|
||||||
const int obj_size = 0;
|
|
||||||
const int reclaim_interval = 0;
|
|
||||||
char name[32];
|
|
||||||
struct fast_region_info regions[32];
|
|
||||||
struct fast_region_info *region;
|
|
||||||
int bit;
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
int alloc_elements_once;
|
|
||||||
int step;
|
|
||||||
|
|
||||||
ctx->element_size = element_size;
|
|
||||||
ctx->min_count = (1 << min_bits);
|
|
||||||
start = 0;
|
|
||||||
alloc_elements_once = (1 << (max_bits - min_bits + 2));
|
|
||||||
for (bit=min_bits, region=regions;
|
|
||||||
bit<=max_bits; bit++, region++)
|
|
||||||
{
|
|
||||||
end = sizeof(VoidArray) + (1 << bit) * ctx->element_size;
|
|
||||||
step = end - start;
|
|
||||||
FAST_ALLOCATOR_INIT_REGION(*region, start,
|
|
||||||
end, step, alloc_elements_once);
|
|
||||||
alloc_elements_once /= 2;
|
|
||||||
start = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc_combine_two_strings(name_prefix, "array", '-', name);
|
|
||||||
return fast_allocator_init_ex(&ctx->allocator, name,
|
|
||||||
obj_size, NULL, regions, region - regions, 0,
|
|
||||||
0.9999, reclaim_interval, need_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
|
|
||||||
const int target_count)
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int bytes;
|
|
||||||
VoidArray *array;
|
|
||||||
|
|
||||||
if (target_count <= ctx->min_count) {
|
|
||||||
alloc = ctx->min_count;
|
|
||||||
} else if (is_power2(target_count)) {
|
|
||||||
alloc = target_count;
|
|
||||||
} else {
|
|
||||||
alloc = ctx->min_count;
|
|
||||||
while (alloc < target_count) {
|
|
||||||
alloc *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = sizeof(VoidArray) + alloc * ctx->element_size;
|
|
||||||
if ((array=fast_allocator_alloc(&ctx->allocator, bytes)) != NULL) {
|
|
||||||
array->alloc = alloc;
|
|
||||||
array->count = 0;
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx,
|
|
||||||
VoidArray *old_array, const int target_count)
|
|
||||||
{
|
|
||||||
VoidArray *new_array;
|
|
||||||
|
|
||||||
if (old_array == NULL) {
|
|
||||||
return array_allocator_alloc(ctx, target_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_array->alloc >= target_count) {
|
|
||||||
return old_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((new_array=array_allocator_alloc(ctx, target_count)) != NULL) {
|
|
||||||
if (old_array->count > 0) {
|
|
||||||
memcpy(new_array->elts, old_array->elts, ctx->
|
|
||||||
element_size * old_array->count);
|
|
||||||
}
|
|
||||||
new_array->count = old_array->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
array_allocator_free(ctx, old_array);
|
|
||||||
return new_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
int array_compare_element_int64(const int64_t *n1, const int64_t *n2)
|
|
||||||
{
|
|
||||||
int64_t sub;
|
|
||||||
sub = *n1 - *n2;
|
|
||||||
if (sub < 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (sub > 0) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int array_compare_element_int32(const int32_t *n1, const int32_t *n2)
|
|
||||||
{
|
|
||||||
return *n1 - *n2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int array_compare_element_id_name(const id_name_pair_t *pair1,
|
|
||||||
const id_name_pair_t *pair2)
|
|
||||||
{
|
|
||||||
return fc_compare_int64(pair1->id, pair2->id);
|
|
||||||
}
|
|
||||||
|
|
@ -1,174 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3
|
|
||||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ARRAY_ALLOCATOR_H
|
|
||||||
#define ARRAY_ALLOCATOR_H
|
|
||||||
|
|
||||||
#include "fast_allocator.h"
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int count;
|
|
||||||
char elts[0];
|
|
||||||
} VoidArray;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int count;
|
|
||||||
int64_t elts[0];
|
|
||||||
} I64Array;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int count;
|
|
||||||
int32_t elts[0];
|
|
||||||
} I32Array;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int count;
|
|
||||||
id_name_pair_t elts[0];
|
|
||||||
} IdNameArray;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int count;
|
|
||||||
void *elts[0];
|
|
||||||
} PointerArray;
|
|
||||||
|
|
||||||
typedef struct array_allocator_context
|
|
||||||
{
|
|
||||||
struct fast_allocator_context allocator;
|
|
||||||
int element_size;
|
|
||||||
int min_count;
|
|
||||||
} ArrayAllocatorContext;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int array_allocator_init_ex(ArrayAllocatorContext *ctx,
|
|
||||||
const char *name_prefix, const int element_size,
|
|
||||||
const int min_bits, const int max_bits,
|
|
||||||
const bool need_lock);
|
|
||||||
|
|
||||||
VoidArray *array_allocator_alloc(ArrayAllocatorContext *ctx,
|
|
||||||
const int target_count);
|
|
||||||
|
|
||||||
VoidArray *array_allocator_realloc(ArrayAllocatorContext *ctx,
|
|
||||||
VoidArray *old_array, const int target_count);
|
|
||||||
|
|
||||||
static inline void array_allocator_free(ArrayAllocatorContext *ctx,
|
|
||||||
VoidArray *array)
|
|
||||||
{
|
|
||||||
fast_allocator_free(&ctx->allocator, array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* comparator for 64 bits integer */
|
|
||||||
int array_compare_element_int64(const int64_t *n1, const int64_t *n2);
|
|
||||||
|
|
||||||
/* comparator for 32 bits integer */
|
|
||||||
int array_compare_element_int32(const int32_t *n1, const int32_t *n2);
|
|
||||||
|
|
||||||
/* comparator for id name pair (sorted by id) */
|
|
||||||
int array_compare_element_id_name(const id_name_pair_t *pair1,
|
|
||||||
const id_name_pair_t *pair2);
|
|
||||||
|
|
||||||
#define array_allocator_init(ctx, name_prefix, \
|
|
||||||
element_size, min_bits, max_bits) \
|
|
||||||
array_allocator_init_ex(ctx, name_prefix, \
|
|
||||||
element_size, min_bits, max_bits, true)
|
|
||||||
|
|
||||||
#define i64_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
|
|
||||||
array_allocator_init_ex(ctx, "i64", sizeof(int64_t), \
|
|
||||||
min_bits, max_bits, need_lock)
|
|
||||||
|
|
||||||
#define i64_array_allocator_init(ctx, min_bits, max_bits) \
|
|
||||||
i64_array_allocator_init_ex(ctx, min_bits, max_bits, true)
|
|
||||||
|
|
||||||
#define i64_array_allocator_alloc(ctx, target_count) \
|
|
||||||
(I64Array *)array_allocator_alloc(ctx, target_count)
|
|
||||||
|
|
||||||
#define i64_array_allocator_realloc(ctx, old_array, target_count) \
|
|
||||||
(I64Array *)array_allocator_realloc(ctx, \
|
|
||||||
(VoidArray *)old_array, target_count)
|
|
||||||
|
|
||||||
#define i64_array_allocator_free(ctx, array) \
|
|
||||||
array_allocator_free(ctx, (VoidArray *)array)
|
|
||||||
|
|
||||||
|
|
||||||
#define i32_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
|
|
||||||
array_allocator_init_ex(ctx, "i32", sizeof(int32_t), \
|
|
||||||
min_bits, max_bits, need_lock)
|
|
||||||
|
|
||||||
#define i32_array_allocator_init(ctx, min_bits, max_bits) \
|
|
||||||
i32_array_allocator_init_ex(ctx, min_bits, max_bits, true)
|
|
||||||
|
|
||||||
#define i32_array_allocator_alloc(ctx, target_count) \
|
|
||||||
(I32Array *)array_allocator_alloc(ctx, target_count)
|
|
||||||
|
|
||||||
#define i32_array_allocator_realloc(ctx, old_array, target_count) \
|
|
||||||
(I32Array *)array_allocator_realloc(ctx, \
|
|
||||||
(VoidArray *)old_array, target_count)
|
|
||||||
|
|
||||||
#define i32_array_allocator_free(ctx, array) \
|
|
||||||
array_allocator_free(ctx, (VoidArray *)array)
|
|
||||||
|
|
||||||
|
|
||||||
#define id_name_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
|
|
||||||
array_allocator_init_ex(ctx, "id_name", sizeof(id_name_pair_t), \
|
|
||||||
min_bits, max_bits, need_lock)
|
|
||||||
|
|
||||||
#define id_name_array_allocator_init(ctx, min_bits, max_bits) \
|
|
||||||
id_name_array_allocator_init_ex(ctx, min_bits, max_bits, true)
|
|
||||||
|
|
||||||
#define id_name_array_allocator_alloc(ctx, target_count) \
|
|
||||||
(IdNameArray *)array_allocator_alloc(ctx, target_count)
|
|
||||||
|
|
||||||
#define id_name_array_allocator_realloc(ctx, old_array, target_count) \
|
|
||||||
(IdNameArray *)array_allocator_realloc(ctx, \
|
|
||||||
(VoidArray *)old_array, target_count)
|
|
||||||
|
|
||||||
#define id_name_array_allocator_free(ctx, array) \
|
|
||||||
array_allocator_free(ctx, (VoidArray *)array)
|
|
||||||
|
|
||||||
|
|
||||||
#define ptr_array_allocator_init_ex(ctx, min_bits, max_bits, need_lock) \
|
|
||||||
array_allocator_init_ex(ctx, "ptr", sizeof(void *), \
|
|
||||||
min_bits, max_bits, need_lock)
|
|
||||||
|
|
||||||
#define ptr_array_allocator_init(ctx, min_bits, max_bits) \
|
|
||||||
ptr_array_allocator_init_ex(ctx, min_bits, max_bits, true)
|
|
||||||
|
|
||||||
#define ptr_array_allocator_alloc(ctx, target_count) \
|
|
||||||
(PointerArray *)array_allocator_alloc(ctx, target_count)
|
|
||||||
|
|
||||||
#define ptr_array_allocator_realloc(ctx, old_array, target_count) \
|
|
||||||
(PointerArray *)array_allocator_realloc(ctx, \
|
|
||||||
(VoidArray *)old_array, target_count)
|
|
||||||
|
|
||||||
#define ptr_array_allocator_free(ctx, array) \
|
|
||||||
array_allocator_free(ctx, (VoidArray *)array)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,19 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "avl_tree.h"
|
#include "avl_tree.h"
|
||||||
|
|
||||||
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
|
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
|
||||||
|
|
@ -61,9 +45,14 @@ void avl_tree_destroy(AVLTreeInfo *tree)
|
||||||
static AVLTreeNode *createTreeNode(AVLTreeNode *pParentNode, void *target_data)
|
static AVLTreeNode *createTreeNode(AVLTreeNode *pParentNode, void *target_data)
|
||||||
{
|
{
|
||||||
AVLTreeNode *pNewNode;
|
AVLTreeNode *pNewNode;
|
||||||
pNewNode = (AVLTreeNode *)fc_malloc(sizeof(AVLTreeNode));
|
pNewNode = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
|
||||||
if (pNewNode == NULL)
|
if (pNewNode == NULL)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail!\n", __LINE__, \
|
||||||
|
(int)sizeof(AVLTreeNode));
|
||||||
|
*/
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef AVL_TREE_H
|
#ifndef AVL_TREE_H
|
||||||
#define AVL_TREE_H
|
#define AVL_TREE_H
|
||||||
|
|
|
||||||
37
src/base64.c
37
src/base64.c
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -23,8 +16,6 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,11 +45,15 @@ void base64_set_line_length(struct base64_context *context, const int length)
|
||||||
* Usually contains only a combination of chars \n and \r.
|
* Usually contains only a combination of chars \n and \r.
|
||||||
* Could be any chars not in set A-Z a-z 0-9 + /.
|
* Could be any chars not in set A-Z a-z 0-9 + /.
|
||||||
*/
|
*/
|
||||||
void base64_set_line_separator(struct base64_context *context,
|
void base64_set_line_separator(struct base64_context *context, \
|
||||||
const char *pLineSeparator)
|
const char *pLineSeparator)
|
||||||
{
|
{
|
||||||
context->line_sep_len = fc_safe_strcpy(context->
|
context->line_sep_len = snprintf(context->line_separator, \
|
||||||
line_separator, pLineSeparator);
|
sizeof(context->line_separator), "%s", pLineSeparator);
|
||||||
|
if (context->line_sep_len >= sizeof(context->line_separator))
|
||||||
|
{
|
||||||
|
context->line_sep_len = sizeof(context->line_separator) - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void base64_init_ex(struct base64_context *context, const int nLineLength, \
|
void base64_init_ex(struct base64_context *context, const int nLineLength, \
|
||||||
|
|
@ -286,9 +281,11 @@ char *base64_decode_auto(struct base64_context *context, const char *src, \
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pBuff = (char *)fc_malloc(nNewLen);
|
pBuff = (char *)malloc(nNewLen);
|
||||||
if (pBuff == NULL)
|
if (pBuff == NULL)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "Can't malloc %d bytes\n", \
|
||||||
|
nSrcLen + nPadLen + 1);
|
||||||
*dest_len = 0;
|
*dest_len = 0;
|
||||||
*dest = '\0';
|
*dest = '\0';
|
||||||
return dest;
|
return dest;
|
||||||
|
|
|
||||||
21
src/base64.h
21
src/base64.h
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//base64.h
|
//base64.h
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,214 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "buffered_file_writer.h"
|
|
||||||
|
|
||||||
int buffered_file_writer_open_ex(BufferedFileWriter *writer,
|
|
||||||
const char *filename, const int buffer_size,
|
|
||||||
const int max_written_once, const int mode)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int written_once;
|
|
||||||
|
|
||||||
writer->buffer_size = (buffer_size > 0) ? buffer_size : 64 * 1024;
|
|
||||||
written_once = (max_written_once > 0) ? max_written_once : 256;
|
|
||||||
if (written_once > writer->buffer_size)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"max_written_once: %d > buffer_size: %d",
|
|
||||||
__LINE__, written_once, writer->buffer_size);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->buff = (char *)fc_malloc(writer->buffer_size);
|
|
||||||
if (writer->buff == NULL)
|
|
||||||
{
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc_safe_strcpy(writer->filename, filename);
|
|
||||||
writer->fd = open(writer->filename, O_WRONLY |
|
|
||||||
O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
|
||||||
if (writer->fd < 0)
|
|
||||||
{
|
|
||||||
result = errno != 0 ? errno : EIO;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"open file %s fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, writer->filename,
|
|
||||||
result, STRERROR(result));
|
|
||||||
|
|
||||||
free(writer->buff);
|
|
||||||
writer->buff = NULL;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->current = writer->buff;
|
|
||||||
writer->buff_end = writer->buff + writer->buffer_size;
|
|
||||||
writer->water_mark = writer->buff_end - written_once;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int buffered_file_writer_close(BufferedFileWriter *writer)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (writer->buff == NULL)
|
|
||||||
{
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = buffered_file_writer_flush(writer);
|
|
||||||
if (result == 0 && fsync(writer->fd) != 0)
|
|
||||||
{
|
|
||||||
result = errno != 0 ? errno : EIO;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"fsync file %s fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, writer->filename,
|
|
||||||
result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (close(writer->fd) != 0)
|
|
||||||
{
|
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
result = errno != 0 ? errno : EIO;
|
|
||||||
}
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"close file %s fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, writer->filename,
|
|
||||||
errno, STRERROR(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
free(writer->buff);
|
|
||||||
writer->buff = NULL;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int buffered_file_writer_flush(BufferedFileWriter *writer)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = writer->current - writer->buff;
|
|
||||||
if (len == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fc_safe_write(writer->fd, writer->buff, len) != len)
|
|
||||||
{
|
|
||||||
result = errno != 0 ? errno : EIO;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"write to file %s fail, "
|
|
||||||
"errno: %d, error info: %s", __LINE__,
|
|
||||||
writer->filename, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->current = writer->buff;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int buffered_file_writer_append(BufferedFileWriter *writer,
|
|
||||||
const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
int result;
|
|
||||||
int remain_size;
|
|
||||||
int len;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
result = 0;
|
|
||||||
for (i=0; i<2; i++)
|
|
||||||
{
|
|
||||||
remain_size = writer->buff_end - writer->current;
|
|
||||||
va_start(ap, format);
|
|
||||||
len = vsnprintf(writer->current, remain_size, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (len < remain_size)
|
|
||||||
{
|
|
||||||
writer->current += len;
|
|
||||||
if (writer->current > writer->water_mark)
|
|
||||||
{
|
|
||||||
result = buffered_file_writer_flush(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > writer->buffer_size)
|
|
||||||
{
|
|
||||||
result = ENOSPC;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"too large output buffer, %d > %d!",
|
|
||||||
__LINE__, len, writer->buffer_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//maybe full, try again
|
|
||||||
if ((result=buffered_file_writer_flush(writer)) != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int buffered_file_writer_append_buff(BufferedFileWriter *writer,
|
|
||||||
const char *buff, const int len)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (len >= writer->water_mark - writer->current)
|
|
||||||
{
|
|
||||||
if ((result=buffered_file_writer_flush(writer)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fc_safe_write(writer->fd, buff, len) != len)
|
|
||||||
{
|
|
||||||
result = errno != 0 ? errno : EIO;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"write to file %s fail, "
|
|
||||||
"errno: %d, error info: %s", __LINE__,
|
|
||||||
writer->filename, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(writer->current, buff, len);
|
|
||||||
writer->current += len;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BUFFERED_FILE_WRITER_H
|
|
||||||
#define BUFFERED_FILE_WRITER_H
|
|
||||||
|
|
||||||
#include "common_define.h"
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int buffer_size;
|
|
||||||
char filename[MAX_PATH_SIZE];
|
|
||||||
char *buff;
|
|
||||||
char *current;
|
|
||||||
char *buff_end;
|
|
||||||
char *water_mark;
|
|
||||||
} BufferedFileWriter;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** open buffered file writer
|
|
||||||
* parameters:
|
|
||||||
* writer: the writer
|
|
||||||
* filename: the filename to write
|
|
||||||
* buffer_size: the buffer size, <= 0 for recommend 64KB
|
|
||||||
* max_written_once: max written bytes per call, <= 0 for 256
|
|
||||||
* mode: the file privilege such as 0644
|
|
||||||
* return: error code, 0 for success, != 0 for errno
|
|
||||||
*/
|
|
||||||
int buffered_file_writer_open_ex(BufferedFileWriter *writer,
|
|
||||||
const char *filename, const int buffer_size,
|
|
||||||
const int max_written_once, const int mode);
|
|
||||||
|
|
||||||
static inline int buffered_file_writer_open(BufferedFileWriter *writer,
|
|
||||||
const char *filename)
|
|
||||||
{
|
|
||||||
const int buffer_size = 0;
|
|
||||||
const int max_written_once = 0;
|
|
||||||
const int mode = 0644;
|
|
||||||
return buffered_file_writer_open_ex(writer, filename,
|
|
||||||
buffer_size, max_written_once, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** close buffered file writer
|
|
||||||
* parameters:
|
|
||||||
* writer: the writer
|
|
||||||
* return: error code, 0 for success, != 0 for errno
|
|
||||||
*/
|
|
||||||
int buffered_file_writer_close(BufferedFileWriter *writer);
|
|
||||||
|
|
||||||
int buffered_file_writer_append(BufferedFileWriter *writer,
|
|
||||||
const char *format, ...);
|
|
||||||
|
|
||||||
int buffered_file_writer_append_buff(BufferedFileWriter *writer,
|
|
||||||
const char *buff, const int len);
|
|
||||||
|
|
||||||
int buffered_file_writer_flush(BufferedFileWriter *writer);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
28
src/chain.c
28
src/chain.c
|
|
@ -1,24 +1,16 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
//#include "use_mmalloc.h"
|
//#include "use_mmalloc.h"
|
||||||
|
|
||||||
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
|
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
|
||||||
|
|
@ -77,7 +69,7 @@ int insertNodePrior(ChainList *pList, void *data)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNode = (ChainNode *)fc_malloc(sizeof(ChainNode));
|
pNode = (ChainNode *)malloc(sizeof(ChainNode));
|
||||||
if (pNode == NULL)
|
if (pNode == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
@ -103,7 +95,7 @@ int appendNode(ChainList *pList, void *data)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNode = (ChainNode *)fc_malloc(sizeof(ChainNode));
|
pNode = (ChainNode *)malloc(sizeof(ChainNode));
|
||||||
if (pNode == NULL)
|
if (pNode == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
@ -136,7 +128,7 @@ int insertNodeAsc(ChainList *pList, void *data)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNew = (ChainNode *)fc_malloc(sizeof(ChainNode));
|
pNew = (ChainNode *)malloc(sizeof(ChainNode));
|
||||||
if (pNew == NULL)
|
if (pNew == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
|
||||||
21
src/chain.h
21
src/chain.h
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CHAIN_H
|
#ifndef CHAIN_H
|
||||||
#define CHAIN_H
|
#define CHAIN_H
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//char_convert_loader.h
|
//char_convert_loader.h
|
||||||
#ifndef CHAR_CONVERT_LOADER_H
|
#ifndef CHAR_CONVERT_LOADER_H
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -27,8 +20,7 @@ int char_converter_init_ex(FastCharConverter *pCharConverter,
|
||||||
const unsigned op)
|
const unsigned op)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned char from;
|
unsigned char src;
|
||||||
unsigned char to;
|
|
||||||
if (count > FAST_MAX_CHAR_COUNT)
|
if (count > FAST_MAX_CHAR_COUNT)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
|
@ -41,15 +33,10 @@ int char_converter_init_ex(FastCharConverter *pCharConverter,
|
||||||
pCharConverter->count = count;
|
pCharConverter->count = count;
|
||||||
for (i=0; i<count; i++)
|
for (i=0; i<count; i++)
|
||||||
{
|
{
|
||||||
from = charPairs[i].src;
|
src = charPairs[i].src;
|
||||||
to = charPairs[i].dest;
|
pCharConverter->char_table[src].op = op;
|
||||||
pCharConverter->char_table[from].op = op;
|
pCharConverter->char_table[src].dest = charPairs[i].dest;
|
||||||
pCharConverter->char_table[from].dest = to;
|
|
||||||
|
|
||||||
pCharConverter->unescape_chars[to].op = op;
|
|
||||||
pCharConverter->unescape_chars[to].dest = from;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,14 +67,14 @@ int std_spaces_add_backslash_converter_init(FastCharConverter *pCharConverter)
|
||||||
#define SPACE_CHAR_PAIR_COUNT2 8
|
#define SPACE_CHAR_PAIR_COUNT2 8
|
||||||
FastCharPair pairs[SPACE_CHAR_PAIR_COUNT2];
|
FastCharPair pairs[SPACE_CHAR_PAIR_COUNT2];
|
||||||
|
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[0], '\0', '0');
|
pairs[0].src = '\0'; pairs[0].dest = '0';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[1], '\t', 't');
|
pairs[1].src = '\t'; pairs[1].dest = 't';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[2], '\n', 'n');
|
pairs[2].src = '\n'; pairs[2].dest = 'n';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[3], '\v', 'v');
|
pairs[3].src = '\v'; pairs[3].dest = 'v';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[4], '\f', 'f');
|
pairs[4].src = '\f'; pairs[4].dest = 'f';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[5], '\r', 'r');
|
pairs[5].src = '\r'; pairs[5].dest = 'r';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[6], ' ', 's');
|
pairs[6].src = ' '; pairs[6].dest = '-';
|
||||||
FAST_CHAR_MAKE_PAIR(pairs[7], '\\', '\\');
|
pairs[7].src = '\\'; pairs[7].dest = '\\';
|
||||||
|
|
||||||
return char_converter_init_ex(pCharConverter, pairs,
|
return char_converter_init_ex(pCharConverter, pairs,
|
||||||
SPACE_CHAR_PAIR_COUNT2, FAST_CHAR_OP_ADD_BACKSLASH);
|
SPACE_CHAR_PAIR_COUNT2, FAST_CHAR_OP_ADD_BACKSLASH);
|
||||||
|
|
@ -155,7 +142,7 @@ int fast_char_convert(FastCharConverter *pCharConverter,
|
||||||
out_size_sub1 = out_size - 1;
|
out_size_sub1 = out_size - 1;
|
||||||
for (; pi<end; pi++) {
|
for (; pi<end; pi++) {
|
||||||
if (po - (unsigned char *)output >= out_size_sub1) {
|
if (po - (unsigned char *)output >= out_size_sub1) {
|
||||||
logWarning("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
"exceeds max size: %d", __LINE__, out_size);
|
"exceeds max size: %d", __LINE__, out_size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -175,47 +162,3 @@ int fast_char_convert(FastCharConverter *pCharConverter,
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_char_unescape(FastCharConverter *pCharConverter, char *str, int *len)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
unsigned char *backslash;
|
|
||||||
unsigned char *p;
|
|
||||||
unsigned char *end;
|
|
||||||
unsigned char *dest;
|
|
||||||
|
|
||||||
backslash = (unsigned char *)memchr(str, '\\', *len);
|
|
||||||
if (backslash == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
end = (unsigned char *)str + *len;
|
|
||||||
p = dest = backslash;
|
|
||||||
while (p < end) {
|
|
||||||
if (*p == '\\') {
|
|
||||||
if (p + 1 < end) {
|
|
||||||
if (pCharConverter->unescape_chars[p[1]].op ==
|
|
||||||
FAST_CHAR_OP_ADD_BACKSLASH)
|
|
||||||
{
|
|
||||||
*dest++ = pCharConverter->unescape_chars[p[1]].dest;
|
|
||||||
p += 2;
|
|
||||||
++count;
|
|
||||||
} else {
|
|
||||||
*dest++ = *p++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*dest++ = *p++;
|
|
||||||
}
|
|
||||||
} else if (pCharConverter->unescape_chars[*p].op ==
|
|
||||||
FAST_CHAR_OP_NO_BACKSLASH)
|
|
||||||
{
|
|
||||||
*dest++ = pCharConverter->unescape_chars[*p++].dest;
|
|
||||||
++count;
|
|
||||||
} else {
|
|
||||||
*dest++ = *p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*len = dest - (unsigned char *)str;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//char_converter.h
|
//char_converter.h
|
||||||
#ifndef CHAR_CONVERTER_H
|
#ifndef CHAR_CONVERTER_H
|
||||||
|
|
@ -31,9 +24,6 @@ extern "C" {
|
||||||
#define FAST_CHAR_OP_ADD_BACKSLASH 1
|
#define FAST_CHAR_OP_ADD_BACKSLASH 1
|
||||||
#define FAST_CHAR_OP_NO_BACKSLASH 2
|
#define FAST_CHAR_OP_NO_BACKSLASH 2
|
||||||
|
|
||||||
#define FAST_CHAR_MAKE_PAIR(pair, from, to) \
|
|
||||||
pair.src = from; pair.dest = to
|
|
||||||
|
|
||||||
typedef struct fast_char_pair
|
typedef struct fast_char_pair
|
||||||
{
|
{
|
||||||
unsigned char src;
|
unsigned char src;
|
||||||
|
|
@ -57,11 +47,6 @@ typedef struct fast_char_converter
|
||||||
* char table to convert
|
* char table to convert
|
||||||
* */
|
* */
|
||||||
FastCharTarget char_table[FAST_MAX_CHAR_COUNT];
|
FastCharTarget char_table[FAST_MAX_CHAR_COUNT];
|
||||||
|
|
||||||
/*
|
|
||||||
* char table to unescape
|
|
||||||
* */
|
|
||||||
FastCharTarget unescape_chars[FAST_MAX_CHAR_COUNT];
|
|
||||||
} FastCharConverter;
|
} FastCharConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -148,21 +133,6 @@ int fast_char_convert(FastCharConverter *pCharConverter,
|
||||||
const char *input, const int input_len,
|
const char *input, const int input_len,
|
||||||
char *output, int *out_len, const int out_size);
|
char *output, int *out_len, const int out_size);
|
||||||
|
|
||||||
#define fast_char_escape(pCharConverter, input, input_len, \
|
|
||||||
output, out_len, out_size) \
|
|
||||||
fast_char_convert(pCharConverter, input, input_len, \
|
|
||||||
output, out_len, out_size)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* char unescape function
|
|
||||||
* parameters:
|
|
||||||
* pCharConverter: the char converter
|
|
||||||
* str: the string to unescape
|
|
||||||
* len: the input string length and store the unscaped string length
|
|
||||||
* return: converted char count
|
|
||||||
*/
|
|
||||||
int fast_char_unescape(FastCharConverter *pCharConverter, char *str, int *len);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//common_blocked_queue.c
|
//common_blocked_queue.c
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -26,18 +11,29 @@
|
||||||
int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
|
int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
|
||||||
const int alloc_elements_once)
|
const int alloc_elements_once)
|
||||||
{
|
{
|
||||||
const int64_t alloc_elements_limit = 0;
|
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result=init_pthread_lock_cond_pair(&queue->lc_pair)) != 0)
|
if ((result=init_pthread_lock(&(queue->lock))) != 0)
|
||||||
{
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"init_pthread_lock fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=fast_mblock_init_ex1(&queue->mblock, "queue-node",
|
result = pthread_cond_init(&(queue->cond), NULL);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"pthread_cond_init fail, "
|
||||||
|
"errno: %d, error info: %s",
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=fast_mblock_init_ex(&queue->mblock,
|
||||||
sizeof(struct common_blocked_node),
|
sizeof(struct common_blocked_node),
|
||||||
alloc_elements_once, alloc_elements_limit,
|
alloc_elements_once, NULL, false)) != 0)
|
||||||
NULL, NULL, false)) != 0)
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -50,17 +46,17 @@ int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
|
||||||
|
|
||||||
void common_blocked_queue_destroy(struct common_blocked_queue *queue)
|
void common_blocked_queue_destroy(struct common_blocked_queue *queue)
|
||||||
{
|
{
|
||||||
destroy_pthread_lock_cond_pair(&queue->lc_pair);
|
pthread_cond_destroy(&(queue->cond));
|
||||||
fast_mblock_destroy(&queue->mblock);
|
pthread_mutex_destroy(&(queue->lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
|
int common_blocked_queue_push(struct common_blocked_queue *queue, void *data)
|
||||||
void *data, bool *notify)
|
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct common_blocked_node *node;
|
struct common_blocked_node *node;
|
||||||
|
bool notify;
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
|
if ((result=pthread_mutex_lock(&(queue->lock))) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_lock fail, " \
|
"call pthread_mutex_lock fail, " \
|
||||||
|
|
@ -69,29 +65,29 @@ int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = (struct common_blocked_node *)fast_mblock_alloc_object(
|
node = (struct common_blocked_node *)fast_mblock_alloc_object(&queue->mblock);
|
||||||
&queue->mblock);
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&(queue->lc_pair.lock));
|
pthread_mutex_unlock(&(queue->lock));
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
node->next = NULL;
|
node->next = NULL;
|
||||||
|
|
||||||
if (queue->tail == NULL)
|
if (queue->tail == NULL)
|
||||||
{
|
{
|
||||||
queue->head = node;
|
queue->head = node;
|
||||||
*notify = true;
|
notify = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
queue->tail->next = node;
|
queue->tail->next = node;
|
||||||
*notify = false;
|
notify = false;
|
||||||
}
|
}
|
||||||
queue->tail = node;
|
queue->tail = node;
|
||||||
|
|
||||||
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
|
if ((result=pthread_mutex_unlock(&(queue->lock))) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_unlock fail, " \
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
|
@ -99,57 +95,14 @@ int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
{
|
||||||
|
pthread_cond_signal(&(queue->cond));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void common_blocked_queue_push_chain_ex(struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_chain *chain, bool *notify)
|
|
||||||
{
|
|
||||||
if (chain->head == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(queue->lc_pair.lock));
|
|
||||||
if (queue->head == NULL)
|
|
||||||
{
|
|
||||||
queue->head = chain->head;
|
|
||||||
*notify = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
queue->tail->next = chain->head;
|
|
||||||
*notify = false;
|
|
||||||
}
|
|
||||||
queue->tail = chain->tail;
|
|
||||||
pthread_mutex_unlock(&(queue->lc_pair.lock));
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_blocked_queue_return_nodes(struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_node *node)
|
|
||||||
{
|
|
||||||
struct common_blocked_node *last;
|
|
||||||
|
|
||||||
if (node == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = node;
|
|
||||||
while (last->next != NULL) {
|
|
||||||
last = last->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(queue->lc_pair.lock));
|
|
||||||
last->next = queue->head;
|
|
||||||
queue->head = node;
|
|
||||||
if (queue->tail == NULL)
|
|
||||||
{
|
|
||||||
queue->tail = last;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(queue->lc_pair.lock));
|
|
||||||
}
|
|
||||||
|
|
||||||
void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
||||||
const bool blocked)
|
const bool blocked)
|
||||||
{
|
{
|
||||||
|
|
@ -157,7 +110,7 @@ void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
||||||
void *data;
|
void *data;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
|
if ((result=pthread_mutex_lock(&(queue->lock))) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_lock fail, " \
|
"call pthread_mutex_lock fail, " \
|
||||||
|
|
@ -176,7 +129,7 @@ void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_cond_wait(&(queue->lc_pair.cond), &(queue->lc_pair.lock));
|
pthread_cond_wait(&(queue->cond), &(queue->lock));
|
||||||
node = queue->head;
|
node = queue->head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,7 +150,7 @@ void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
||||||
}
|
}
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
|
if ((result=pthread_mutex_unlock(&(queue->lock))) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_unlock fail, " \
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
|
@ -208,104 +161,3 @@ void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *common_blocked_queue_timedpop(struct common_blocked_queue *queue,
|
|
||||||
const int timeout, const int time_unit)
|
|
||||||
{
|
|
||||||
struct common_blocked_node *node;
|
|
||||||
void *data;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_mutex_lock fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
node = queue->head;
|
|
||||||
if (node == NULL)
|
|
||||||
{
|
|
||||||
fc_cond_timedwait(&queue->lc_pair, timeout, time_unit);
|
|
||||||
node = queue->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node != NULL)
|
|
||||||
{
|
|
||||||
queue->head = node->next;
|
|
||||||
if (queue->head == NULL)
|
|
||||||
{
|
|
||||||
queue->tail = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = node->data;
|
|
||||||
fast_mblock_free_object(&queue->mblock, node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_mutex_unlock fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct common_blocked_node *common_blocked_queue_pop_all_nodes_ex(
|
|
||||||
struct common_blocked_queue *queue, const bool blocked)
|
|
||||||
{
|
|
||||||
struct common_blocked_node *node;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(queue->lc_pair.lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_mutex_lock fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queue->head == NULL)
|
|
||||||
{
|
|
||||||
if (blocked)
|
|
||||||
{
|
|
||||||
pthread_cond_wait(&(queue->lc_pair.cond), &(queue->lc_pair.lock));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node = queue->head;
|
|
||||||
queue->head = queue->tail = NULL;
|
|
||||||
if ((result=pthread_mutex_unlock(&(queue->lc_pair.lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_mutex_unlock fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_blocked_queue_free_all_nodes(struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_node *node)
|
|
||||||
{
|
|
||||||
struct common_blocked_node *deleted;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(queue->lc_pair.lock));
|
|
||||||
while (node != NULL) {
|
|
||||||
deleted = node;
|
|
||||||
node = node->next;
|
|
||||||
fast_mblock_free_object(&queue->mblock, deleted);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(queue->lc_pair.lock));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//common_blocked_queue.h
|
//common_blocked_queue.h
|
||||||
|
|
||||||
|
|
@ -31,18 +24,13 @@ struct common_blocked_node
|
||||||
struct common_blocked_node *next;
|
struct common_blocked_node *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct common_blocked_chain
|
|
||||||
{
|
|
||||||
struct common_blocked_node *head;
|
|
||||||
struct common_blocked_node *tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct common_blocked_queue
|
struct common_blocked_queue
|
||||||
{
|
{
|
||||||
struct common_blocked_node *head;
|
struct common_blocked_node *head;
|
||||||
struct common_blocked_node *tail;
|
struct common_blocked_node *tail;
|
||||||
struct fast_mblock_man mblock;
|
struct fast_mblock_man mblock;
|
||||||
pthread_lock_cond_pair_t lc_pair;
|
pthread_mutex_t lock;
|
||||||
|
pthread_cond_t cond;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
@ -57,10 +45,9 @@ int common_blocked_queue_init_ex(struct common_blocked_queue *queue,
|
||||||
|
|
||||||
void common_blocked_queue_destroy(struct common_blocked_queue *queue);
|
void common_blocked_queue_destroy(struct common_blocked_queue *queue);
|
||||||
|
|
||||||
static inline void common_blocked_queue_terminate(
|
static inline void common_blocked_queue_terminate(struct common_blocked_queue *queue)
|
||||||
struct common_blocked_queue *queue)
|
|
||||||
{
|
{
|
||||||
pthread_cond_signal(&(queue->lc_pair.cond));
|
pthread_cond_signal(&(queue->cond));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void common_blocked_queue_terminate_all(
|
static inline void common_blocked_queue_terminate_all(
|
||||||
|
|
@ -69,136 +56,25 @@ static inline void common_blocked_queue_terminate_all(
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<count; i++)
|
for (i=0; i<count; i++)
|
||||||
{
|
{
|
||||||
pthread_cond_signal(&(queue->lc_pair.cond));
|
pthread_cond_signal(&(queue->cond));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//notify by the caller
|
int common_blocked_queue_push(struct common_blocked_queue *queue, void *data);
|
||||||
int common_blocked_queue_push_ex(struct common_blocked_queue *queue,
|
|
||||||
void *data, bool *notify);
|
|
||||||
|
|
||||||
static inline int common_blocked_queue_push(struct common_blocked_queue
|
|
||||||
*queue, void *data)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=common_blocked_queue_push_ex(queue, data, ¬ify)) == 0)
|
|
||||||
{
|
|
||||||
if (notify)
|
|
||||||
{
|
|
||||||
pthread_cond_signal(&(queue->lc_pair.cond));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct common_blocked_node *common_blocked_queue_alloc_node(
|
|
||||||
struct common_blocked_queue *queue)
|
|
||||||
{
|
|
||||||
struct common_blocked_node *node;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(queue->lc_pair.lock));
|
|
||||||
node = (struct common_blocked_node *)fast_mblock_alloc_object(&queue->mblock);
|
|
||||||
pthread_mutex_unlock(&(queue->lc_pair.lock));
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void common_blocked_queue_free_node(
|
|
||||||
struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_node *node)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&(queue->lc_pair.lock));
|
|
||||||
fast_mblock_free_object(&queue->mblock, node);
|
|
||||||
pthread_mutex_unlock(&(queue->lc_pair.lock));
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_blocked_queue_push_chain_ex(struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_chain *chain, bool *notify);
|
|
||||||
|
|
||||||
static inline void common_blocked_queue_push_chain(
|
|
||||||
struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_chain *chain)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
|
|
||||||
common_blocked_queue_push_chain_ex(queue, chain, ¬ify);
|
|
||||||
if (notify)
|
|
||||||
{
|
|
||||||
pthread_cond_signal(&(queue->lc_pair.cond));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void common_blocked_queue_return_nodes(struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_node *node);
|
|
||||||
|
|
||||||
void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
void *common_blocked_queue_pop_ex(struct common_blocked_queue *queue,
|
||||||
const bool blocked);
|
const bool blocked);
|
||||||
|
|
||||||
static inline bool common_blocked_queue_empty(
|
static inline void *common_blocked_queue_pop(struct common_blocked_queue *queue)
|
||||||
struct common_blocked_queue *queue)
|
|
||||||
{
|
{
|
||||||
bool empty;
|
return common_blocked_queue_pop_ex(queue, true);
|
||||||
|
|
||||||
pthread_mutex_lock(&queue->lc_pair.lock);
|
|
||||||
empty = (queue->head == NULL);
|
|
||||||
pthread_mutex_unlock(&queue->lc_pair.lock);
|
|
||||||
return empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int common_blocked_queue_count(
|
static inline void *common_blocked_queue_try_pop(struct common_blocked_queue *queue)
|
||||||
struct common_blocked_queue *queue)
|
|
||||||
{
|
{
|
||||||
int count;
|
return common_blocked_queue_pop_ex(queue, false);
|
||||||
struct common_blocked_node *node;
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
pthread_mutex_lock(&queue->lc_pair.lock);
|
|
||||||
node = queue->head;
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
++count;
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&queue->lc_pair.lock);
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define common_blocked_queue_pop(queue) \
|
|
||||||
common_blocked_queue_pop_ex(queue, true)
|
|
||||||
|
|
||||||
#define common_blocked_queue_try_pop(queue) \
|
|
||||||
common_blocked_queue_pop_ex(queue, false)
|
|
||||||
|
|
||||||
struct common_blocked_node *common_blocked_queue_pop_all_nodes_ex(
|
|
||||||
struct common_blocked_queue *queue, const bool blocked);
|
|
||||||
|
|
||||||
#define common_blocked_queue_pop_all_nodes(queue) \
|
|
||||||
common_blocked_queue_pop_all_nodes_ex(queue, true)
|
|
||||||
|
|
||||||
#define common_blocked_queue_try_pop_all_nodes(queue) \
|
|
||||||
common_blocked_queue_pop_all_nodes_ex(queue, false)
|
|
||||||
|
|
||||||
#define common_blocked_queue_free_one_node(queue, node) \
|
|
||||||
common_blocked_queue_free_node(&queue->mblock, node)
|
|
||||||
|
|
||||||
void common_blocked_queue_free_all_nodes(struct common_blocked_queue *queue,
|
|
||||||
struct common_blocked_node *node);
|
|
||||||
|
|
||||||
void *common_blocked_queue_timedpop(struct common_blocked_queue *queue,
|
|
||||||
const int timeout, const int time_unit);
|
|
||||||
|
|
||||||
#define common_blocked_queue_timedpop_sec(queue, timeout) \
|
|
||||||
common_blocked_queue_timedpop(queue, timeout, FC_TIME_UNIT_SECOND)
|
|
||||||
|
|
||||||
#define common_blocked_queue_timedpop_ms(queue, timeout) \
|
|
||||||
common_blocked_queue_timedpop(queue, timeout, FC_TIME_UNIT_MSECOND)
|
|
||||||
|
|
||||||
#define common_blocked_queue_timedpop_us(queue, timeout) \
|
|
||||||
common_blocked_queue_timedpop(queue, timeout, FC_TIME_UNIT_USECOND)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//common_define.h
|
//common_define.h
|
||||||
|
|
||||||
|
|
@ -21,7 +14,6 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
|
||||||
|
|
@ -35,7 +27,6 @@ typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
@ -43,14 +34,6 @@ typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#ifdef OS_FREEBSD
|
|
||||||
//#include <sys/syscall.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Internet address (兼容IPv6长度). */
|
|
||||||
typedef uint64_t in_addr_64_t;
|
|
||||||
|
|
||||||
#define FILE_SEPERATOR "/"
|
#define FILE_SEPERATOR "/"
|
||||||
typedef int SOCKET;
|
typedef int SOCKET;
|
||||||
#define closesocket close
|
#define closesocket close
|
||||||
|
|
@ -68,10 +51,6 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||||
|
|
||||||
#include "_os_define.h"
|
#include "_os_define.h"
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#ifdef OS_LINUX
|
||||||
#ifndef PTHREAD_MUTEX_ERRORCHECK
|
#ifndef PTHREAD_MUTEX_ERRORCHECK
|
||||||
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
|
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
|
||||||
|
|
@ -102,47 +81,19 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||||
#define USE_SENDFILE
|
#define USE_SENDFILE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_PATH_SIZE 256
|
#define MAX_PATH_SIZE 256
|
||||||
#define LOG_FILE_DIR "logs"
|
#define LOG_FILE_DIR "logs"
|
||||||
#define CONF_FILE_DIR "conf"
|
#define CONF_FILE_DIR "conf"
|
||||||
#define DEFAULT_CONNECT_TIMEOUT 10
|
#define DEFAULT_CONNECT_TIMEOUT 30
|
||||||
#define DEFAULT_NETWORK_TIMEOUT 30
|
#define DEFAULT_NETWORK_TIMEOUT 30
|
||||||
#define DEFAULT_MAX_CONNECTONS 256
|
#define DEFAULT_MAX_CONNECTONS 256
|
||||||
#define DEFAULT_WORK_THREADS 4
|
#define DEFAULT_WORK_THREADS 4
|
||||||
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
|
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
|
||||||
#define TIME_NONE -1
|
#define TIME_NONE -1
|
||||||
|
|
||||||
#define FC_BYTES_ONE_KB ( 1 << 10)
|
#define IP_ADDRESS_SIZE 16
|
||||||
#define FC_BYTES_ONE_MB ( 1 << 20)
|
|
||||||
#define FC_BYTES_ONE_GB ( 1 << 30)
|
|
||||||
#define FC_BYTES_ONE_TB (1LL << 40)
|
|
||||||
#define FC_BYTES_ONE_PB (1LL << 50)
|
|
||||||
#define FC_BYTES_ONE_EB (1LL << 60)
|
|
||||||
|
|
||||||
#if defined(IOV_MAX) && IOV_MAX > 256
|
|
||||||
#define FC_IOV_BATCH_SIZE 256
|
|
||||||
#else
|
|
||||||
#define FC_IOV_BATCH_SIZE IOV_MAX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IPV4_ADDRESS_SIZE INET_ADDRSTRLEN //16
|
|
||||||
#define IPV6_ADDRESS_SIZE INET6_ADDRSTRLEN //46
|
|
||||||
#define IP_ADDRESS_SIZE INET6_ADDRSTRLEN //46
|
|
||||||
#define FORMATTED_IP_SIZE (IP_ADDRESS_SIZE + 2)
|
|
||||||
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
|
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
|
||||||
|
|
||||||
#define FILE_RESOURCE_TAG_STR "file://"
|
|
||||||
#define FILE_RESOURCE_TAG_LEN (sizeof(FILE_RESOURCE_TAG_STR) - 1)
|
|
||||||
|
|
||||||
#define IS_FILE_RESOURCE(filename) \
|
|
||||||
(strncasecmp(filename, FILE_RESOURCE_TAG_STR, \
|
|
||||||
FILE_RESOURCE_TAG_LEN) == 0)
|
|
||||||
|
|
||||||
#define IS_FILE_RESOURCE_EX(filename) \
|
|
||||||
((filename)->len >= FILE_RESOURCE_TAG_LEN && \
|
|
||||||
memcmp((filename)->str, FILE_RESOURCE_TAG_STR, \
|
|
||||||
FILE_RESOURCE_TAG_LEN) == 0)
|
|
||||||
|
|
||||||
#ifndef byte
|
#ifndef byte
|
||||||
#define byte signed char
|
#define byte signed char
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -161,50 +112,12 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||||
#define ECANCELED 125
|
#define ECANCELED 125
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ENODATA
|
|
||||||
#define ENODATA 61 /* No data available */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ENONET
|
#ifndef ENONET
|
||||||
#define ENONET 64 /* Machine is not on the network */
|
#define ENONET 64 /* Machine is not on the network */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define compile_barrier() __asm__ __volatile__("" : : : "memory")
|
|
||||||
|
|
||||||
#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
|
#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
|
||||||
#define IS_HEX_CHAR(ch) (IS_UPPER_HEX(ch) || (ch >= 'a' && ch <= 'f'))
|
#define IS_HEX_CHAR(ch) (IS_UPPER_HEX(ch) || (ch >= 'a' && ch <= 'f'))
|
||||||
#define FC_IS_DIGITAL(ch) (ch >= '0' && ch <= '9')
|
|
||||||
#define FC_IS_LETTER(ch) ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
|
|
||||||
#define FC_IS_UPPER_LETTER(ch) (ch >= 'A' && ch <= 'Z')
|
|
||||||
#define FC_IS_LOWER_LETTER(ch) (ch >= 'a' && ch <= 'z')
|
|
||||||
#define FC_MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2))
|
|
||||||
#define FC_MAX(v1, v2) ((v1) > (v2) ? (v1) : (v2))
|
|
||||||
#define FC_ABS(n) ((n) >= 0 ? (n) : -1 * (n))
|
|
||||||
#define FC_NEGATIVE(n) ((n) <= 0 ? (n) : -1 * (n))
|
|
||||||
|
|
||||||
#define FC_TIME_UNIT_SECOND 's' //second
|
|
||||||
#define FC_TIME_UNIT_MSECOND 'm' //millisecond
|
|
||||||
#define FC_TIME_UNIT_USECOND 'u' //microsecond
|
|
||||||
#define FC_TIME_UNIT_NSECOND 'n' //nanosecond
|
|
||||||
|
|
||||||
#define FC_1E01 10LL
|
|
||||||
#define FC_1E02 100LL
|
|
||||||
#define FC_1E03 1000LL
|
|
||||||
#define FC_1E04 10000LL
|
|
||||||
#define FC_1E05 100000LL
|
|
||||||
#define FC_1E06 1000000LL
|
|
||||||
#define FC_1E07 10000000LL
|
|
||||||
#define FC_1E08 100000000LL
|
|
||||||
#define FC_1E09 1000000000LL
|
|
||||||
#define FC_1E10 10000000000LL
|
|
||||||
#define FC_1E11 100000000000LL
|
|
||||||
#define FC_1E12 1000000000000LL
|
|
||||||
#define FC_1E13 10000000000000LL
|
|
||||||
#define FC_1E14 100000000000000LL
|
|
||||||
#define FC_1E15 1000000000000000LL
|
|
||||||
#define FC_1E16 10000000000000000LL
|
|
||||||
#define FC_1E17 100000000000000000LL
|
|
||||||
#define FC_1E18 1000000000000000000LL
|
|
||||||
|
|
||||||
#define STRERROR(no) (strerror(no) != NULL ? strerror(no) : "Unkown error")
|
#define STRERROR(no) (strerror(no) != NULL ? strerror(no) : "Unkown error")
|
||||||
|
|
||||||
|
|
@ -215,12 +128,10 @@ extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||||
#define st_ctimensec st_ctim.tv_nsec
|
#define st_ctimensec st_ctim.tv_nsec
|
||||||
#endif
|
#endif
|
||||||
#elif defined(OS_FREEBSD)
|
#elif defined(OS_FREEBSD)
|
||||||
#ifndef st_atimensec
|
|
||||||
#define st_atimensec st_atimespec.tv_nsec
|
#define st_atimensec st_atimespec.tv_nsec
|
||||||
#define st_mtimensec st_mtimespec.tv_nsec
|
#define st_mtimensec st_mtimespec.tv_nsec
|
||||||
#define st_ctimensec st_ctimespec.tv_nsec
|
#define st_ctimensec st_ctimespec.tv_nsec
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -240,12 +151,6 @@ typedef struct
|
||||||
char patch;
|
char patch;
|
||||||
} Version;
|
} Version;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char **strs;
|
|
||||||
int count;
|
|
||||||
} str_ptr_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *key;
|
char *key;
|
||||||
|
|
@ -273,104 +178,12 @@ typedef struct
|
||||||
int len;
|
int len;
|
||||||
} string_t;
|
} string_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
string_t *strings;
|
|
||||||
int count;
|
|
||||||
} string_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int64_t id;
|
|
||||||
string_t name;
|
|
||||||
} id_name_pair_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
string_t key;
|
|
||||||
string_t value;
|
|
||||||
} key_value_pair_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
key_value_pair_t *kv_pairs;
|
|
||||||
int count;
|
|
||||||
} key_value_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int32_t *elts;
|
|
||||||
int count;
|
|
||||||
} int32_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int64_t *elts;
|
|
||||||
int count;
|
|
||||||
} int64_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
id_name_pair_t *elts;
|
|
||||||
int count;
|
|
||||||
} id_name_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
void *elts;
|
|
||||||
int count;
|
|
||||||
} void_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
pthread_cond_t cond;
|
|
||||||
} pthread_lock_cond_pair_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int alloc;
|
|
||||||
int count;
|
|
||||||
struct iovec *iovs;
|
|
||||||
} iovec_array_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char buff[PATH_MAX];
|
|
||||||
string_t s;
|
|
||||||
} FilenameString;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *filename;
|
|
||||||
char *tmp_filename;
|
|
||||||
int fd;
|
|
||||||
} SafeWriteFileInfo;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char filename[PATH_MAX];
|
|
||||||
int fd;
|
|
||||||
} FilenameFDPair;
|
|
||||||
|
|
||||||
typedef void (*FreeDataFunc)(void *ptr);
|
typedef void (*FreeDataFunc)(void *ptr);
|
||||||
typedef int (*CompareFunc)(void *p1, void *p2);
|
typedef int (*CompareFunc)(void *p1, void *p2);
|
||||||
typedef void* (*MallocFunc)(size_t size);
|
typedef void* (*MallocFunc)(size_t size);
|
||||||
|
|
||||||
#define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c)
|
#define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c)
|
||||||
|
#define MEM_ALIGN(x) (((x) + 7) & (~7))
|
||||||
#define MEM_ALIGN_FLOOR(x, align_size) ((x) & (~(align_size - 1)))
|
|
||||||
#define MEM_ALIGN_CEIL(x, align_size) \
|
|
||||||
(((x) + (align_size - 1)) & (~(align_size - 1)))
|
|
||||||
#define MEM_ALIGN(x) MEM_ALIGN_CEIL(x, 8)
|
|
||||||
|
|
||||||
#define MEM_ALIGN_FLOOR_BY_MASK(x, align_mask) ((x) & (~align_mask))
|
|
||||||
#define MEM_ALIGN_CEIL_BY_MASK(x, align_mask) \
|
|
||||||
(((x) + align_mask) & (~align_mask))
|
|
||||||
|
|
||||||
#define FC_INIT_CHAIN(chain) (chain).head = (chain).tail = NULL
|
|
||||||
#define FC_IS_CHAIN_EMPTY(chain) ((chain).head == NULL)
|
|
||||||
|
|
||||||
#define FC_SET_CHAIN_TAIL_NEXT(chain, type, ptr) \
|
|
||||||
((type *)(chain).tail)->next = ptr
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
|
|
@ -394,54 +207,7 @@ typedef void* (*MallocFunc)(size_t size);
|
||||||
#define __gcc_attribute__(x)
|
#define __gcc_attribute__(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FC_IS_CHINESE_UTF8_CHAR(p, end) \
|
static inline int fc_compare_string(const string_t *s1, const string_t *s2)
|
||||||
((p + 2 < end) && \
|
|
||||||
((((unsigned char)*p) & 0xF0) == 0xE0) && \
|
|
||||||
((((unsigned char)*(p + 1)) & 0xC0) == 0x80) && \
|
|
||||||
((((unsigned char)*(p + 2)) & 0xC0) == 0x80))
|
|
||||||
|
|
||||||
//for printf format %.*s
|
|
||||||
#define FC_PRINTF_STAR_STRING_PARAMS(s) (s).len, (s).str
|
|
||||||
|
|
||||||
#define FC_SET_IOVEC(iovec, buff, len) \
|
|
||||||
do { \
|
|
||||||
(iovec).iov_base = buff; \
|
|
||||||
(iovec).iov_len = len; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define FC_SET_STRING(dest, src) \
|
|
||||||
do { \
|
|
||||||
(dest).str = src; \
|
|
||||||
(dest).len = strlen(src); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define FC_SET_STRING_EX(dest, s, l) \
|
|
||||||
do { \
|
|
||||||
(dest).str = s; \
|
|
||||||
(dest).len = l; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define FC_SET_STRING_EMPTY(dest, s) FC_SET_STRING_EX(dest, s, 0)
|
|
||||||
|
|
||||||
#define FC_SET_STRING_NULL(dest) \
|
|
||||||
do { \
|
|
||||||
(dest).str = NULL; \
|
|
||||||
(dest).len = 0; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define FC_IS_NULL_STRING(s) ((s)->str == NULL)
|
|
||||||
#define FC_IS_EMPTY_STRING(s) ((s)->len == 0)
|
|
||||||
|
|
||||||
#define FC_INIT_FILENAME_STRING(filename) \
|
|
||||||
FC_SET_STRING_EX((filename).s, (filename).buff, 0)
|
|
||||||
|
|
||||||
#define FC_FILENAME_STRING_OBJ(filename) ((filename).s)
|
|
||||||
#define FC_FILENAME_STRING_PTR(filename) ((filename).buff)
|
|
||||||
#define FC_FILENAME_BUFFER_SIZE(filename) sizeof((filename).buff)
|
|
||||||
|
|
||||||
#define fc_compare_string(s1, s2) fc_string_compare(s1, s2)
|
|
||||||
|
|
||||||
static inline int fc_string_compare(const string_t *s1, const string_t *s2)
|
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
if (s1->len == s2->len) {
|
if (s1->len == s2->len) {
|
||||||
|
|
@ -455,110 +221,6 @@ static inline int fc_string_compare(const string_t *s1, const string_t *s2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool fc_string_equal_ex(const char *str1,
|
|
||||||
const int len1, const char *str2, const int len2)
|
|
||||||
{
|
|
||||||
return (len1 == len2) && (memcmp(str1, str2, len1) == 0);
|
|
||||||
}
|
|
||||||
#define fc_string_equals_ex(str1, len1, str2, len2) \
|
|
||||||
fc_string_equal_ex(str1, len1, str2, len2)
|
|
||||||
|
|
||||||
static inline bool fc_string_equal(const string_t *s1, const string_t *s2)
|
|
||||||
{
|
|
||||||
return (s1->len == s2->len) && (memcmp(s1->str, s2->str, s1->len) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool fc_string_equal2(const string_t *s1,
|
|
||||||
const char *str2, const int len2)
|
|
||||||
{
|
|
||||||
return (s1->len == len2) && (memcmp(s1->str, str2, s1->len) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fc_string_equals(s1, s2) fc_string_equal(s1, s2)
|
|
||||||
#define fc_string_equals2(s1, str2, len2) fc_string_equal2(s1, str2, len2)
|
|
||||||
|
|
||||||
|
|
||||||
#define fc_case_compare_string(s1, s2) fc_string_case_compare(s1, s2)
|
|
||||||
|
|
||||||
static inline int fc_string_case_compare(const string_t *s1, const string_t *s2)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if (s1->len == s2->len) {
|
|
||||||
return strncasecmp(s1->str, s2->str, s1->len);
|
|
||||||
} else if (s1->len < s2->len) {
|
|
||||||
result = strncasecmp(s1->str, s2->str, s1->len);
|
|
||||||
return result == 0 ? -1 : result;
|
|
||||||
} else {
|
|
||||||
result = strncasecmp(s1->str, s2->str, s2->len);
|
|
||||||
return result == 0 ? 1 : result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool fc_string_case_equal(const string_t *s1, const string_t *s2)
|
|
||||||
{
|
|
||||||
return (s1->len == s2->len) && (strncasecmp(s1->str, s2->str, s1->len) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool fc_string_case_equal2(const string_t *s1,
|
|
||||||
const char *str2, const int len2)
|
|
||||||
{
|
|
||||||
return (s1->len == len2) && (strncasecmp(s1->str, str2, s1->len) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fc_string_case_equals(s1, s2) fc_string_case_equal(s1, s2)
|
|
||||||
#define fc_string_case_equals2(s1, str2, len2) \
|
|
||||||
fc_string_case_equal2(s1, str2, len2)
|
|
||||||
|
|
||||||
|
|
||||||
static inline int fc_compare_int64(const int64_t n1, const int64_t n2)
|
|
||||||
{
|
|
||||||
int64_t sub;
|
|
||||||
sub = n1 - n2;
|
|
||||||
if (sub < 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (sub > 0) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
static inline int fc_fallocate(int fd, const int64_t size)
|
|
||||||
{
|
|
||||||
if (fallocate(fd, 0, 0, size) < 0) {
|
|
||||||
if (errno == EOPNOTSUPP) {
|
|
||||||
return ftruncate(fd, size);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define fc_fallocate(fd, size) ftruncate(fd, size)
|
|
||||||
#define posix_fadvise(fd, offset, len, advice) 0
|
|
||||||
|
|
||||||
#ifndef POSIX_FADV_NORMAL
|
|
||||||
#define POSIX_FADV_NORMAL 0 /* No further special treatment. */
|
|
||||||
#define POSIX_FADV_RANDOM 1 /* Expect random page references. */
|
|
||||||
#define POSIX_FADV_SEQUENTIAL 2 /* Expect sequential page references. */
|
|
||||||
#define POSIX_FADV_WILLNEED 3 /* Will need these pages. */
|
|
||||||
#define POSIX_FADV_DONTNEED 4 /* Don't need these pages. */
|
|
||||||
#define POSIX_FADV_NOREUSE 5 /* Data will be accessed once. */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef OS_FREEBSD
|
|
||||||
//#define fdatasync(fd) syscall(SYS_fdatasync, fd)
|
|
||||||
#define fdatasync(fd) fsync(fd)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FC_MACRO_STRINGIFY(x) #x
|
|
||||||
#define FC_MACRO_TOSTRING(x) FC_MACRO_STRINGIFY(x)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//connection_pool.h
|
//connection_pool.h
|
||||||
|
|
||||||
|
|
@ -23,125 +16,21 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include "fast_mblock.h"
|
|
||||||
#include "ini_file_reader.h"
|
|
||||||
#include "pthread_func.h"
|
#include "pthread_func.h"
|
||||||
#include "sockopt.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FC_CONNECTION_SERVER_EQUAL(conn, target_ip, target_port) \
|
typedef struct
|
||||||
(strcmp((conn).ip_addr, target_ip) == 0 && \
|
{
|
||||||
(conn).port == target_port)
|
int sock;
|
||||||
|
int port;
|
||||||
#define FC_CONNECTION_SERVER_EQUAL1(conn1, conn2) \
|
char ip_addr[INET6_ADDRSTRLEN];
|
||||||
(strcmp((conn1).ip_addr, (conn2).ip_addr) == 0 && \
|
int socket_domain; //socket domain, AF_INET, AF_INET6 or PF_UNSPEC for auto dedect
|
||||||
(conn1).port == (conn2).port)
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
fc_comm_type_sock = 0,
|
|
||||||
fc_comm_type_rdma,
|
|
||||||
fc_comm_type_both
|
|
||||||
} FCCommunicationType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int sock;
|
|
||||||
uint16_t port;
|
|
||||||
uint8_t af; //address family, AF_INET, AF_INET6 or AF_UNSPEC for auto dedect
|
|
||||||
bool shared; //for connection pool
|
|
||||||
FCCommunicationType comm_type;
|
|
||||||
bool validate_flag; //for connection pool
|
|
||||||
char ip_addr[IP_ADDRESS_SIZE];
|
|
||||||
void *arg1; //for RDMA
|
|
||||||
char args[0]; //for extra data
|
|
||||||
} ConnectionInfo;
|
} ConnectionInfo;
|
||||||
|
|
||||||
struct fc_server_config;
|
|
||||||
struct ibv_pd;
|
|
||||||
typedef void (*fc_set_busy_polling_callback)(const bool busy_polling);
|
|
||||||
typedef struct ibv_pd *(*fc_alloc_pd_callback)(const char **ip_addrs,
|
|
||||||
const int count, const int port);
|
|
||||||
typedef int (*fc_get_connection_size_callback)();
|
|
||||||
typedef int (*fc_init_connection_callback)(ConnectionInfo *conn,
|
|
||||||
const bool double_buffers, const int buffer_size, void *arg);
|
|
||||||
typedef int (*fc_make_connection_callback)(ConnectionInfo *conn,
|
|
||||||
const char *service_name, const int timeout_ms,
|
|
||||||
const char *bind_ipaddr, const bool log_connect_error);
|
|
||||||
typedef bool (*fc_is_connected_callback)(ConnectionInfo *conn);
|
|
||||||
typedef bool (*fc_send_done_callback)(ConnectionInfo *conn);
|
|
||||||
typedef void (*fc_close_connection_callback)(ConnectionInfo *conn);
|
|
||||||
typedef void (*fc_destroy_connection_callback)(ConnectionInfo *conn);
|
|
||||||
|
|
||||||
typedef BufferInfo *(*fc_rdma_get_recv_buffer_callback)(ConnectionInfo *conn);
|
|
||||||
typedef int (*fc_rdma_request_by_buf1_callback)(ConnectionInfo *conn,
|
|
||||||
const char *data, const int length, const int timeout_ms);
|
|
||||||
typedef int (*fc_rdma_request_by_buf2_callback)(ConnectionInfo *conn,
|
|
||||||
const char *data1, const int length1, const char *data2,
|
|
||||||
const int length2, const int timeout_ms);
|
|
||||||
typedef int (*fc_rdma_request_by_iov_callback)(ConnectionInfo *conn,
|
|
||||||
const struct iovec *iov, const int iovcnt,
|
|
||||||
const int timeout_ms);
|
|
||||||
typedef int (*fc_rdma_request_by_mix_callback)(ConnectionInfo *conn,
|
|
||||||
const char *data, const int length, const struct iovec *iov,
|
|
||||||
const int iovcnt, const int timeout_ms);
|
|
||||||
typedef int (*fc_rdma_send_by_buf1_callback)(ConnectionInfo *conn,
|
|
||||||
const char *data, const int length);
|
|
||||||
typedef int (*fc_rdma_recv_data_callback)(ConnectionInfo *conn,
|
|
||||||
const bool call_post_recv, const int timeout_ms);
|
|
||||||
typedef int (*fc_rdma_post_recv_callback)(ConnectionInfo *conn);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fc_make_connection_callback make_connection;
|
|
||||||
fc_close_connection_callback close_connection;
|
|
||||||
fc_is_connected_callback is_connected;
|
|
||||||
} CommonConnectionCallbacks;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
fc_set_busy_polling_callback set_busy_polling;
|
|
||||||
fc_alloc_pd_callback alloc_pd;
|
|
||||||
fc_get_connection_size_callback get_connection_size;
|
|
||||||
fc_init_connection_callback init_connection;
|
|
||||||
fc_make_connection_callback make_connection;
|
|
||||||
fc_close_connection_callback close_connection;
|
|
||||||
fc_destroy_connection_callback destroy_connection;
|
|
||||||
fc_is_connected_callback is_connected;
|
|
||||||
fc_send_done_callback send_done;
|
|
||||||
|
|
||||||
fc_rdma_get_recv_buffer_callback get_recv_buffer;
|
|
||||||
fc_rdma_request_by_buf1_callback request_by_buf1;
|
|
||||||
fc_rdma_request_by_buf2_callback request_by_buf2;
|
|
||||||
fc_rdma_request_by_iov_callback request_by_iov;
|
|
||||||
fc_rdma_request_by_mix_callback request_by_mix;
|
|
||||||
|
|
||||||
fc_rdma_send_by_buf1_callback send_by_buf1;
|
|
||||||
fc_rdma_recv_data_callback recv_data;
|
|
||||||
fc_rdma_post_recv_callback post_recv;
|
|
||||||
} RDMAConnectionCallbacks;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool inited;
|
|
||||||
CommonConnectionCallbacks common_callbacks[2];
|
|
||||||
RDMAConnectionCallbacks rdma_callbacks;
|
|
||||||
} ConnectionCallbacks;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
struct {
|
|
||||||
bool enabled;
|
|
||||||
int htable_capacity;
|
|
||||||
} tls; //for thread local
|
|
||||||
|
|
||||||
struct {
|
|
||||||
bool double_buffers;
|
|
||||||
int buffer_size;
|
|
||||||
struct ibv_pd *pd;
|
|
||||||
} rdma;
|
|
||||||
} ConnectionExtraParams;
|
|
||||||
|
|
||||||
typedef int (*fc_connection_callback_func)(ConnectionInfo *conn, void *args);
|
|
||||||
|
|
||||||
struct tagConnectionManager;
|
struct tagConnectionManager;
|
||||||
|
|
||||||
typedef struct tagConnectionNode {
|
typedef struct tagConnectionNode {
|
||||||
|
|
@ -152,75 +41,26 @@ typedef struct tagConnectionNode {
|
||||||
} ConnectionNode;
|
} ConnectionNode;
|
||||||
|
|
||||||
typedef struct tagConnectionManager {
|
typedef struct tagConnectionManager {
|
||||||
string_t key;
|
ConnectionNode *head;
|
||||||
ConnectionNode *head;
|
int total_count; //total connections
|
||||||
int total_count; //total connections
|
int free_count; //free connections
|
||||||
int free_count; //free connections
|
pthread_mutex_t lock;
|
||||||
struct tagConnectionManager *next;
|
|
||||||
} ConnectionManager;
|
} ConnectionManager;
|
||||||
|
|
||||||
typedef struct tagConnectionBucket {
|
|
||||||
ConnectionManager *head;
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
} ConnectionBucket;
|
|
||||||
|
|
||||||
struct tagConnectionPool;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
ConnectionNode **buckets;
|
|
||||||
struct tagConnectionPool *cp;
|
|
||||||
} ConnectionThreadHashTable;
|
|
||||||
|
|
||||||
typedef struct tagConnectionPool {
|
typedef struct tagConnectionPool {
|
||||||
struct {
|
HashArray hash_array; //key is ip:port, value is ConnectionManager
|
||||||
ConnectionBucket *buckets;
|
pthread_mutex_t lock;
|
||||||
uint32_t capacity;
|
int connect_timeout;
|
||||||
} hashtable;
|
|
||||||
|
|
||||||
int connect_timeout_ms;
|
|
||||||
int max_count_per_entry; //0 means no limit
|
int max_count_per_entry; //0 means no limit
|
||||||
|
|
||||||
/*
|
/*
|
||||||
connections whose idle time exceeds this time will be closed
|
connections whose the idle time exceeds this time will be closed
|
||||||
unit: second
|
unit: second
|
||||||
*/
|
*/
|
||||||
int max_idle_time;
|
int max_idle_time;
|
||||||
|
int socket_domain; //socket domain
|
||||||
struct fast_mblock_man manager_allocator;
|
|
||||||
struct fast_mblock_man node_allocator;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
fc_connection_callback_func func;
|
|
||||||
void *args;
|
|
||||||
} connect_done_callback;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
fc_connection_callback_func func;
|
|
||||||
void *args;
|
|
||||||
} validate_callback;
|
|
||||||
|
|
||||||
int extra_data_size;
|
|
||||||
ConnectionExtraParams extra_params;
|
|
||||||
pthread_key_t tls_key; //for ConnectionThreadHashTable
|
|
||||||
} ConnectionPool;
|
} ConnectionPool;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int htable_capacity;
|
|
||||||
int bucket_used;
|
|
||||||
int server_count;
|
|
||||||
struct {
|
|
||||||
int total_count;
|
|
||||||
int free_count;
|
|
||||||
} connection;
|
|
||||||
} ConnectionPoolStat;
|
|
||||||
|
|
||||||
extern ConnectionCallbacks g_connection_callbacks;
|
|
||||||
|
|
||||||
int conn_pool_global_init_for_rdma();
|
|
||||||
|
|
||||||
#define G_COMMON_CONNECTION_CALLBACKS g_connection_callbacks.common_callbacks
|
|
||||||
#define G_RDMA_CONNECTION_CALLBACKS g_connection_callbacks.rdma_callbacks
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init ex function
|
* init ex function
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
@ -228,43 +68,12 @@ int conn_pool_global_init_for_rdma();
|
||||||
* connect_timeout: the connect timeout in seconds
|
* connect_timeout: the connect timeout in seconds
|
||||||
* max_count_per_entry: max connection count per host:port
|
* max_count_per_entry: max connection count per host:port
|
||||||
* max_idle_time: reconnect the server after max idle time in seconds
|
* max_idle_time: reconnect the server after max idle time in seconds
|
||||||
* af: the socket domain
|
* socket_domain: the socket domain
|
||||||
* htable_capacity: the capacity of connection hash table
|
|
||||||
* connect_done_func: the connect done connection callback
|
|
||||||
* connect_done_args: the args for connect done connection callback
|
|
||||||
* validate_func: the validate connection callback
|
|
||||||
* validate_args: the args for validate connection callback
|
|
||||||
* extra_data_size: the extra data size of connection
|
|
||||||
* extra_params: for RDMA
|
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
int conn_pool_init_ex1(ConnectionPool *cp, const int connect_timeout,
|
int conn_pool_init_ex(ConnectionPool *cp, int connect_timeout,
|
||||||
const int max_count_per_entry, const int max_idle_time,
|
const int max_count_per_entry, const int max_idle_time,
|
||||||
const int htable_capacity, fc_connection_callback_func connect_done_func,
|
const int socket_domain);
|
||||||
void *connect_done_args, fc_connection_callback_func validate_func,
|
|
||||||
void *validate_args, const int extra_data_size,
|
|
||||||
const ConnectionExtraParams *extra_params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* init ex function
|
|
||||||
* parameters:
|
|
||||||
* cp: the ConnectionPool
|
|
||||||
* connect_timeout: the connect timeout in seconds
|
|
||||||
* max_count_per_entry: max connection count per host:port
|
|
||||||
* max_idle_time: reconnect the server after max idle time in seconds
|
|
||||||
* return 0 for success, != 0 for error
|
|
||||||
*/
|
|
||||||
static inline int conn_pool_init_ex(ConnectionPool *cp,
|
|
||||||
const int connect_timeout, const int max_count_per_entry,
|
|
||||||
const int max_idle_time)
|
|
||||||
{
|
|
||||||
const int htable_capacity = 0;
|
|
||||||
const int extra_data_size = 0;
|
|
||||||
const ConnectionExtraParams *extra_params = NULL;
|
|
||||||
return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry,
|
|
||||||
max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
|
|
||||||
extra_data_size, extra_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init function
|
* init function
|
||||||
|
|
@ -275,16 +84,8 @@ static inline int conn_pool_init_ex(ConnectionPool *cp,
|
||||||
* max_idle_time: reconnect the server after max idle time in seconds
|
* max_idle_time: reconnect the server after max idle time in seconds
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
static inline int conn_pool_init(ConnectionPool *cp, const int connect_timeout,
|
int conn_pool_init(ConnectionPool *cp, int connect_timeout,
|
||||||
const int max_count_per_entry, const int max_idle_time)
|
const int max_count_per_entry, const int max_idle_time);
|
||||||
{
|
|
||||||
const int htable_capacity = 0;
|
|
||||||
const int extra_data_size = 0;
|
|
||||||
const ConnectionExtraParams *extra_params = NULL;
|
|
||||||
return conn_pool_init_ex1(cp, connect_timeout, max_count_per_entry,
|
|
||||||
max_idle_time, htable_capacity, NULL, NULL, NULL, NULL,
|
|
||||||
extra_data_size, extra_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* destroy function
|
* destroy function
|
||||||
|
|
@ -299,17 +100,11 @@ void conn_pool_destroy(ConnectionPool *cp);
|
||||||
* parameters:
|
* parameters:
|
||||||
* cp: the ConnectionPool
|
* cp: the ConnectionPool
|
||||||
* conn: the connection
|
* conn: the connection
|
||||||
* service_name: the service name to log
|
|
||||||
* shared: if the connection shared
|
|
||||||
* err_no: return the the errno, 0 for success
|
* err_no: return the the errno, 0 for success
|
||||||
* return != NULL for success, NULL for error
|
* return != NULL for success, NULL for error
|
||||||
*/
|
*/
|
||||||
ConnectionInfo *conn_pool_get_connection_ex(ConnectionPool *cp,
|
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
|
||||||
const ConnectionInfo *conn, const char *service_name,
|
const ConnectionInfo *conn, int *err_no);
|
||||||
const bool shared, int *err_no);
|
|
||||||
|
|
||||||
#define conn_pool_get_connection(cp, conn, err_no) \
|
|
||||||
conn_pool_get_connection_ex(cp, conn, NULL, false, err_no)
|
|
||||||
|
|
||||||
#define conn_pool_close_connection(cp, conn) \
|
#define conn_pool_close_connection(cp, conn) \
|
||||||
conn_pool_close_connection_ex(cp, conn, false)
|
conn_pool_close_connection_ex(cp, conn, false)
|
||||||
|
|
@ -322,220 +117,35 @@ ConnectionInfo *conn_pool_get_connection_ex(ConnectionPool *cp,
|
||||||
* bForce: set true to close the socket, else only push back to connection pool
|
* bForce: set true to close the socket, else only push back to connection pool
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
int conn_pool_close_connection_ex(ConnectionPool *cp,
|
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn,
|
||||||
ConnectionInfo *conn, const bool bForce);
|
const bool bForce);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* disconnect from the server
|
* disconnect from the server
|
||||||
* parameters:
|
* parameters:
|
||||||
* conn: the connection
|
* pConnection: the connection
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
static inline void conn_pool_disconnect_server(ConnectionInfo *conn)
|
void conn_pool_disconnect_server(ConnectionInfo *pConnection);
|
||||||
{
|
|
||||||
if (conn->sock >= 0)
|
|
||||||
{
|
|
||||||
close(conn->sock);
|
|
||||||
conn->sock = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool conn_pool_is_connected(ConnectionInfo *conn)
|
|
||||||
{
|
|
||||||
return (conn->sock >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connect to the server
|
* connect to the server
|
||||||
* parameters:
|
* parameters:
|
||||||
* pConnection: the connection
|
* pConnection: the connection
|
||||||
* service_name: the service name to log
|
* connect_timeout: the connect timeout in seconds
|
||||||
* connect_timeout_ms: the connect timeout in milliseconds
|
|
||||||
* bind_ipaddr: the ip address to bind, NULL or empty for any
|
|
||||||
* log_connect_error: if log error info when connect fail
|
|
||||||
* NOTE: pConnection->sock will be closed when it >= 0 before connect
|
* NOTE: pConnection->sock will be closed when it >= 0 before connect
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
int conn_pool_connect_server_ex1(ConnectionInfo *conn,
|
int conn_pool_connect_server(ConnectionInfo *pConnection, \
|
||||||
const char *service_name, const int connect_timeout_ms,
|
const int connect_timeout);
|
||||||
const char *bind_ipaddr, const bool log_connect_error);
|
|
||||||
/**
|
|
||||||
* connect to the server
|
|
||||||
* parameters:
|
|
||||||
* pConnection: the connection
|
|
||||||
* connect_timeout_ms: the connect timeout in milliseconds
|
|
||||||
* bind_ipaddr: the ip address to bind, NULL or empty for any
|
|
||||||
* log_connect_error: if log error info when connect fail
|
|
||||||
* NOTE: pConnection->sock will be closed when it >= 0 before connect
|
|
||||||
* return 0 for success, != 0 for error
|
|
||||||
*/
|
|
||||||
static inline int conn_pool_connect_server_ex(ConnectionInfo *pConnection,
|
|
||||||
const int connect_timeout_ms, const char *bind_ipaddr,
|
|
||||||
const bool log_connect_error)
|
|
||||||
{
|
|
||||||
const char *service_name = NULL;
|
|
||||||
return conn_pool_connect_server_ex1(pConnection, service_name,
|
|
||||||
connect_timeout_ms, bind_ipaddr, log_connect_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connect to the server
|
* get connection count of the pool
|
||||||
* parameters:
|
|
||||||
* pConnection: the connection
|
|
||||||
* connect_timeout_ms: the connect timeout in seconds
|
|
||||||
* NOTE: pConnection->sock will be closed when it >= 0 before connect
|
|
||||||
* return 0 for success, != 0 for error
|
|
||||||
*/
|
|
||||||
static inline int conn_pool_connect_server(ConnectionInfo *pConnection,
|
|
||||||
const int connect_timeout_ms)
|
|
||||||
{
|
|
||||||
const char *service_name = NULL;
|
|
||||||
const char *bind_ipaddr = NULL;
|
|
||||||
return conn_pool_connect_server_ex1(pConnection, service_name,
|
|
||||||
connect_timeout_ms, bind_ipaddr, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* connect to the server
|
|
||||||
* parameters:
|
|
||||||
* pConnection: the connection
|
|
||||||
* connect_timeout_ms: the connect timeout in seconds
|
|
||||||
* return 0 for success, != 0 for error
|
|
||||||
*/
|
|
||||||
static inline int conn_pool_connect_server_anyway(ConnectionInfo *pConnection,
|
|
||||||
const int connect_timeout_ms)
|
|
||||||
{
|
|
||||||
const char *service_name = NULL;
|
|
||||||
const char *bind_ipaddr = NULL;
|
|
||||||
pConnection->sock = -1;
|
|
||||||
return conn_pool_connect_server_ex1(pConnection, service_name,
|
|
||||||
connect_timeout_ms, bind_ipaddr, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* async connect to the server
|
|
||||||
* parameters:
|
|
||||||
* pConnection: the connection
|
|
||||||
* bind_ipaddr: the ip address to bind, NULL or empty for any
|
|
||||||
* NOTE: pConnection->sock will be closed when it >= 0 before connect
|
|
||||||
* return 0 or EINPROGRESS for success, others for error
|
|
||||||
*/
|
|
||||||
int conn_pool_async_connect_server_ex(ConnectionInfo *conn,
|
|
||||||
const char *bind_ipaddr);
|
|
||||||
|
|
||||||
#define conn_pool_async_connect_server(conn) \
|
|
||||||
conn_pool_async_connect_server_ex(conn, NULL)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* connection pool stat
|
|
||||||
* parameters:
|
* parameters:
|
||||||
* cp: the ConnectionPool
|
* cp: the ConnectionPool
|
||||||
* stat: the output stat
|
* return current connection count
|
||||||
* return none
|
|
||||||
*/
|
*/
|
||||||
void conn_pool_stat(ConnectionPool *cp, ConnectionPoolStat *stat);
|
int conn_pool_get_connection_count(ConnectionPool *cp);
|
||||||
|
|
||||||
/**
|
|
||||||
* load server info from config file
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the ini context
|
|
||||||
* filename: the config filename
|
|
||||||
* item_name: the item name in config file, format item_name=server:port
|
|
||||||
* pServerInfo: store server info
|
|
||||||
* default_port: the default port
|
|
||||||
* return 0 for success, != 0 for error
|
|
||||||
*/
|
|
||||||
int conn_pool_load_server_info(IniContext *pIniContext, const char *filename,
|
|
||||||
const char *item_name, ConnectionInfo *pServerInfo,
|
|
||||||
const int default_port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* parse server info from string
|
|
||||||
* parameters:
|
|
||||||
* pServerStr: server and port string as server:port
|
|
||||||
* pServerInfo: store server info
|
|
||||||
* default_port: the default port
|
|
||||||
* return 0 for success, != 0 for error
|
|
||||||
*/
|
|
||||||
int conn_pool_parse_server_info(const char *pServerStr,
|
|
||||||
ConnectionInfo *pServerInfo, const int default_port);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set server info with ip address and port
|
|
||||||
* parameters:
|
|
||||||
* pServerInfo: store server info
|
|
||||||
* ip_addr: the ip address
|
|
||||||
* port: the port
|
|
||||||
* return none
|
|
||||||
*/
|
|
||||||
static inline void conn_pool_set_server_info(ConnectionInfo *pServerInfo,
|
|
||||||
const char *ip_addr, const int port)
|
|
||||||
{
|
|
||||||
fc_safe_strcpy(pServerInfo->ip_addr, ip_addr);
|
|
||||||
pServerInfo->port = port;
|
|
||||||
pServerInfo->af = is_ipv6_addr(ip_addr) ? AF_INET6 : AF_INET;
|
|
||||||
pServerInfo->sock = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int conn_pool_compare_ip_and_port(const char *ip1,
|
|
||||||
const int port1, const char *ip2, const int port2)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if ((result=strcmp(ip1, ip2)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return port1 - port2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionInfo *conn_pool_alloc_connection_ex(
|
|
||||||
const FCCommunicationType comm_type,
|
|
||||||
const int extra_data_size,
|
|
||||||
const ConnectionExtraParams *extra_params,
|
|
||||||
int *err_no);
|
|
||||||
|
|
||||||
static inline ConnectionInfo *conn_pool_alloc_connection(
|
|
||||||
const FCCommunicationType comm_type,
|
|
||||||
const ConnectionExtraParams *extra_params,
|
|
||||||
int *err_no)
|
|
||||||
{
|
|
||||||
const int extra_data_size = 0;
|
|
||||||
return conn_pool_alloc_connection_ex(comm_type,
|
|
||||||
extra_data_size, extra_params, err_no);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void conn_pool_free_connection(ConnectionInfo *conn)
|
|
||||||
{
|
|
||||||
free(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_pool_set_rdma_extra_params_ex(ConnectionExtraParams *extra_params,
|
|
||||||
struct fc_server_config *server_cfg, const int server_group_index,
|
|
||||||
const bool double_buffers);
|
|
||||||
|
|
||||||
static inline int conn_pool_set_rdma_extra_params(
|
|
||||||
ConnectionExtraParams *extra_params,
|
|
||||||
struct fc_server_config *server_cfg,
|
|
||||||
const int server_group_index)
|
|
||||||
{
|
|
||||||
const bool double_buffers = false;
|
|
||||||
return conn_pool_set_rdma_extra_params_ex(extra_params,
|
|
||||||
server_cfg, server_group_index, double_buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const char *fc_comm_type_str(const FCCommunicationType type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case fc_comm_type_sock:
|
|
||||||
return "socket";
|
|
||||||
case fc_comm_type_rdma:
|
|
||||||
return "rdma";
|
|
||||||
case fc_comm_type_both:
|
|
||||||
return "both";
|
|
||||||
default:
|
|
||||||
return "unkown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_allocator.c
|
//fast_allocator.c
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -25,6 +10,14 @@
|
||||||
|
|
||||||
#define BYTES_ALIGN(x, pad_mask) (((x) + pad_mask) & (~pad_mask))
|
#define BYTES_ALIGN(x, pad_mask) (((x) + pad_mask) & (~pad_mask))
|
||||||
|
|
||||||
|
struct allocator_wrapper {
|
||||||
|
int alloc_bytes;
|
||||||
|
short allocator_index;
|
||||||
|
short magic_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fast_allocator_info malloc_allocator;
|
||||||
|
|
||||||
#define ADD_ALLOCATOR_TO_ARRAY(acontext, allocator, _pooled) \
|
#define ADD_ALLOCATOR_TO_ARRAY(acontext, allocator, _pooled) \
|
||||||
do { \
|
do { \
|
||||||
(allocator)->index = acontext->allocator_array.count; \
|
(allocator)->index = acontext->allocator_array.count; \
|
||||||
|
|
@ -32,8 +25,7 @@
|
||||||
(allocator)->pooled = _pooled; \
|
(allocator)->pooled = _pooled; \
|
||||||
acontext->allocator_array.allocators[ \
|
acontext->allocator_array.allocators[ \
|
||||||
acontext->allocator_array.count++] = allocator; \
|
acontext->allocator_array.count++] = allocator; \
|
||||||
/* logInfo("count: %d, magic_number: %d", acontext->allocator_array.count, \
|
/* logInfo("count: %d, magic_number: %d", acontext->allocator_array.count, (allocator)->magic_number); */\
|
||||||
(allocator)->magic_number); */ \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -55,72 +47,53 @@ static int fast_allocator_malloc_trunk_check(const int alloc_bytes, void *args)
|
||||||
acontext->allocator_array.malloc_bytes_limit ? 0 : EOVERFLOW;
|
acontext->allocator_array.malloc_bytes_limit ? 0 : EOVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fast_allocator_malloc_trunk_notify_func(
|
static void fast_allocator_malloc_trunk_notify_func(const int alloc_bytes, void *args)
|
||||||
const enum fast_mblock_notify_type type,
|
|
||||||
const struct fast_mblock_malloc *node, void *args)
|
|
||||||
{
|
{
|
||||||
if (type == fast_mblock_notify_type_alloc)
|
if (alloc_bytes > 0)
|
||||||
{
|
{
|
||||||
__sync_add_and_fetch(&((struct fast_allocator_context *)args)->
|
__sync_add_and_fetch(&((struct fast_allocator_context *)args)->
|
||||||
allocator_array.malloc_bytes, node->trunk_size);
|
allocator_array.malloc_bytes, alloc_bytes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
__sync_sub_and_fetch(&((struct fast_allocator_context *)args)->
|
__sync_sub_and_fetch(&((struct fast_allocator_context *)args)->
|
||||||
allocator_array.malloc_bytes, node->trunk_size);
|
allocator_array.malloc_bytes, -1 * alloc_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int allocator_array_check_capacity(struct fast_allocator_context *acontext,
|
static int allocator_array_check_capacity(struct fast_allocator_context *acontext,
|
||||||
const int allocator_count)
|
const int allocator_count)
|
||||||
{
|
{
|
||||||
|
int result;
|
||||||
int bytes;
|
int bytes;
|
||||||
int target_count;
|
|
||||||
int alloc_count;
|
|
||||||
struct fast_allocator_info **new_allocators;
|
struct fast_allocator_info **new_allocators;
|
||||||
|
|
||||||
target_count = acontext->allocator_array.count + allocator_count;
|
if (acontext->allocator_array.alloc >= acontext->allocator_array.count +
|
||||||
if (acontext->allocator_array.alloc >= target_count)
|
allocator_count)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (acontext->allocator_array.alloc == 0)
|
if (acontext->allocator_array.alloc == 0)
|
||||||
{
|
{
|
||||||
if (target_count < 128)
|
acontext->allocator_array.alloc = 2 * allocator_count;
|
||||||
{
|
|
||||||
alloc_count = 128;
|
|
||||||
}
|
|
||||||
else if (target_count < 256)
|
|
||||||
{
|
|
||||||
alloc_count = 256;
|
|
||||||
}
|
|
||||||
else if (target_count < 512)
|
|
||||||
{
|
|
||||||
alloc_count = 512;
|
|
||||||
}
|
|
||||||
else if (target_count < 1024)
|
|
||||||
{
|
|
||||||
alloc_count = 1024;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alloc_count = 2 * target_count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alloc_count = acontext->allocator_array.alloc;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
alloc_count *= 2;
|
acontext->allocator_array.alloc *= 2;
|
||||||
} while (alloc_count < target_count);
|
} while (acontext->allocator_array.alloc < allocator_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(struct fast_allocator_info *) * alloc_count;
|
bytes = sizeof(struct fast_allocator_info*) * acontext->allocator_array.alloc;
|
||||||
new_allocators = (struct fast_allocator_info **)fc_malloc(bytes);
|
new_allocators = (struct fast_allocator_info **)malloc(bytes);
|
||||||
if (new_allocators == NULL)
|
if (new_allocators == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acontext->allocator_array.allocators != NULL)
|
if (acontext->allocator_array.allocators != NULL)
|
||||||
|
|
@ -130,73 +103,48 @@ static int allocator_array_check_capacity(struct fast_allocator_context *acontex
|
||||||
acontext->allocator_array.count);
|
acontext->allocator_array.count);
|
||||||
free(acontext->allocator_array.allocators);
|
free(acontext->allocator_array.allocators);
|
||||||
}
|
}
|
||||||
acontext->allocator_array.alloc = alloc_count;
|
|
||||||
acontext->allocator_array.allocators = new_allocators;
|
acontext->allocator_array.allocators = new_allocators;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int region_init(struct fast_allocator_context *acontext,
|
static int region_init(struct fast_allocator_context *acontext,
|
||||||
const char *mblock_name_prefix, struct fast_mblock_object_callbacks
|
struct fast_region_info *region)
|
||||||
*object_callbacks, struct fast_region_info *region)
|
|
||||||
{
|
{
|
||||||
const int64_t alloc_elements_limit = 0;
|
|
||||||
const int prealloc_trunk_count = 0;
|
|
||||||
int result;
|
int result;
|
||||||
int bytes;
|
int bytes;
|
||||||
int element_size;
|
int element_size;
|
||||||
struct fast_mblock_trunk_callbacks trunk_callbacks;
|
int allocator_count;
|
||||||
struct fast_allocator_info *allocator;
|
struct fast_allocator_info *allocator;
|
||||||
char *name;
|
|
||||||
char name_buff[FAST_MBLOCK_NAME_SIZE];
|
|
||||||
|
|
||||||
region->pad_mask = region->step - 1;
|
region->pad_mask = region->step - 1;
|
||||||
region->count = (region->end - region->start) / region->step;
|
allocator_count = (region->end - region->start) / region->step;
|
||||||
bytes = sizeof(struct fast_allocator_info) * region->count;
|
bytes = sizeof(struct fast_allocator_info) * allocator_count;
|
||||||
region->allocators = (struct fast_allocator_info *)fc_malloc(bytes);
|
region->allocators = (struct fast_allocator_info *)malloc(bytes);
|
||||||
if (region->allocators == NULL)
|
if (region->allocators == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
memset(region->allocators, 0, bytes);
|
memset(region->allocators, 0, bytes);
|
||||||
|
|
||||||
if ((result=allocator_array_check_capacity(acontext, region->count)) != 0)
|
|
||||||
|
if ((result=allocator_array_check_capacity(acontext, allocator_count)) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region->count == 1) {
|
|
||||||
if (region->start == 0) {
|
|
||||||
region->step += acontext->extra_size;
|
|
||||||
} else {
|
|
||||||
region->start += acontext->extra_size;
|
|
||||||
}
|
|
||||||
region->end += acontext->extra_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
trunk_callbacks.check_func = fast_allocator_malloc_trunk_check;
|
|
||||||
trunk_callbacks.notify_func = fast_allocator_malloc_trunk_notify_func;
|
|
||||||
name = name_buff;
|
|
||||||
result = 0;
|
result = 0;
|
||||||
allocator = region->allocators;
|
allocator = region->allocators;
|
||||||
for (element_size = region->start + region->step;
|
for (element_size=region->start+region->step; element_size<=region->end;
|
||||||
element_size <= region->end;
|
element_size+=region->step,allocator++)
|
||||||
element_size += region->step, allocator++)
|
{
|
||||||
{
|
result = fast_mblock_init_ex2(&allocator->mblock, NULL, element_size,
|
||||||
if (mblock_name_prefix != NULL)
|
region->alloc_elements_once, NULL, acontext->need_lock,
|
||||||
{
|
fast_allocator_malloc_trunk_check,
|
||||||
snprintf(name, FAST_MBLOCK_NAME_SIZE, "%s-%d",
|
fast_allocator_malloc_trunk_notify_func, acontext);
|
||||||
mblock_name_prefix, element_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
trunk_callbacks.args = acontext;
|
|
||||||
result = fast_mblock_init_ex2(&allocator->mblock, name, element_size,
|
|
||||||
region->alloc_elements_once, alloc_elements_limit,
|
|
||||||
prealloc_trunk_count, object_callbacks,
|
|
||||||
acontext->need_lock, &trunk_callbacks);
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|
@ -226,11 +174,9 @@ static void region_destroy(struct fast_allocator_context *acontext,
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
||||||
const char *mblock_name_prefix, const int obj_size,
|
|
||||||
struct fast_mblock_object_callbacks *object_callbacks,
|
|
||||||
struct fast_region_info *regions, const int region_count,
|
struct fast_region_info *regions, const int region_count,
|
||||||
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
|
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
|
||||||
const int reclaim_interval, const bool need_lock)
|
const int reclaim_interval, const bool need_lock)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
@ -246,10 +192,14 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(struct fast_region_info) * region_count;
|
bytes = sizeof(struct fast_region_info) * region_count;
|
||||||
acontext->regions = (struct fast_region_info *)fc_malloc(bytes);
|
acontext->regions = (struct fast_region_info *)malloc(bytes);
|
||||||
if (acontext->regions == NULL)
|
if (acontext->regions == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
memcpy(acontext->regions, regions, bytes);
|
memcpy(acontext->regions, regions, bytes);
|
||||||
acontext->region_count = region_count;
|
acontext->region_count = region_count;
|
||||||
|
|
@ -265,7 +215,6 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
||||||
acontext->allocator_array.malloc_bytes_limit = alloc_bytes_limit /
|
acontext->allocator_array.malloc_bytes_limit = alloc_bytes_limit /
|
||||||
acontext->allocator_array.expect_usage_ratio;
|
acontext->allocator_array.expect_usage_ratio;
|
||||||
acontext->allocator_array.reclaim_interval = reclaim_interval;
|
acontext->allocator_array.reclaim_interval = reclaim_interval;
|
||||||
acontext->extra_size = sizeof(struct fast_allocator_wrapper) + obj_size;
|
|
||||||
acontext->need_lock = need_lock;
|
acontext->need_lock = need_lock;
|
||||||
result = 0;
|
result = 0;
|
||||||
previous_end = 0;
|
previous_end = 0;
|
||||||
|
|
@ -288,46 +237,33 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
||||||
result = EINVAL;
|
result = EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pRegion->step <= 0)
|
if (pRegion->step <= 0 || !is_power2(pRegion->step))
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"invalid step: %d <= 0",
|
"invalid step: %d",
|
||||||
__LINE__, pRegion->step);
|
__LINE__, pRegion->step);
|
||||||
result = EINVAL;
|
result = EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (pRegion->start % pRegion->step != 0)
|
||||||
if ((pRegion->end - pRegion->start) / pRegion->step > 1)
|
{
|
||||||
{
|
logError("file: "__FILE__", line: %d, "
|
||||||
if (!is_power2(pRegion->step))
|
"invalid start: %d, must multiple of step: %d",
|
||||||
{
|
__LINE__, pRegion->start, pRegion->step);
|
||||||
logError("file: "__FILE__", line: %d, "
|
result = EINVAL;
|
||||||
"invalid step: %d, expect power of 2",
|
break;
|
||||||
__LINE__, pRegion->step);
|
}
|
||||||
result = EINVAL;
|
if (pRegion->end % pRegion->step != 0)
|
||||||
break;
|
{
|
||||||
}
|
logError("file: "__FILE__", line: %d, "
|
||||||
if (pRegion->start % pRegion->step != 0)
|
"invalid end: %d, must multiple of step: %d",
|
||||||
{
|
__LINE__, pRegion->end, pRegion->step);
|
||||||
logError("file: "__FILE__", line: %d, "
|
result = EINVAL;
|
||||||
"invalid start: %d, must multiple of step: %d",
|
break;
|
||||||
__LINE__, pRegion->start, pRegion->step);
|
}
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pRegion->end % pRegion->step != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"invalid end: %d, must multiple of step: %d",
|
|
||||||
__LINE__, pRegion->end, pRegion->step);
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
previous_end = pRegion->end;
|
previous_end = pRegion->end;
|
||||||
|
|
||||||
if ((result=region_init(acontext, mblock_name_prefix,
|
if ((result=region_init(acontext, pRegion)) != 0)
|
||||||
object_callbacks, pRegion)) != 0)
|
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -343,35 +279,39 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_ALLOCATOR_TO_ARRAY(acontext, &acontext->
|
ADD_ALLOCATOR_TO_ARRAY(acontext, &malloc_allocator, false);
|
||||||
allocator_array.malloc_allocator, false);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
logInfo("sizeof(struct fast_allocator_wrapper): %d, allocator_array count: %d",
|
logInfo("sizeof(struct allocator_wrapper): %d, allocator_array count: %d",
|
||||||
(int)sizeof(struct fast_allocator_wrapper), acontext->allocator_array.count);
|
(int)sizeof(struct allocator_wrapper), acontext->allocator_array.count);
|
||||||
*/
|
*/
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define INIT_REGION(region, _start, _end, _step, _alloc_once) \
|
||||||
|
do { \
|
||||||
|
region.start = _start; \
|
||||||
|
region.end = _end; \
|
||||||
|
region.step = _step; \
|
||||||
|
region.alloc_elements_once = _alloc_once; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
int fast_allocator_init(struct fast_allocator_context *acontext,
|
int fast_allocator_init(struct fast_allocator_context *acontext,
|
||||||
const char *mblock_name_prefix, const int64_t alloc_bytes_limit,
|
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
|
||||||
const double expect_usage_ratio, const int reclaim_interval,
|
const int reclaim_interval, const bool need_lock)
|
||||||
const bool need_lock)
|
|
||||||
{
|
{
|
||||||
#define DEFAULT_REGION_COUNT 5
|
#define DEFAULT_REGION_COUNT 5
|
||||||
|
|
||||||
const int obj_size = 0;
|
struct fast_region_info regions[DEFAULT_REGION_COUNT];
|
||||||
struct fast_region_info regions[DEFAULT_REGION_COUNT];
|
|
||||||
|
|
||||||
FAST_ALLOCATOR_INIT_REGION(regions[0], 0, 256, 8, 4096);
|
INIT_REGION(regions[0], 0, 256, 8, 4096);
|
||||||
FAST_ALLOCATOR_INIT_REGION(regions[1], 256, 1024, 16, 1024);
|
INIT_REGION(regions[1], 256, 1024, 16, 1024);
|
||||||
FAST_ALLOCATOR_INIT_REGION(regions[2], 1024, 4096, 64, 256);
|
INIT_REGION(regions[2], 1024, 4096, 64, 256);
|
||||||
FAST_ALLOCATOR_INIT_REGION(regions[3], 4096, 16384, 256, 64);
|
INIT_REGION(regions[3], 4096, 16384, 256, 64);
|
||||||
FAST_ALLOCATOR_INIT_REGION(regions[4], 16384, 65536, 1024, 16);
|
INIT_REGION(regions[4], 16384, 65536, 1024, 16);
|
||||||
|
|
||||||
return fast_allocator_init_ex(acontext, mblock_name_prefix, obj_size,
|
return fast_allocator_init_ex(acontext, regions,
|
||||||
NULL, regions, DEFAULT_REGION_COUNT, alloc_bytes_limit,
|
DEFAULT_REGION_COUNT, alloc_bytes_limit,
|
||||||
expect_usage_ratio, reclaim_interval, need_lock);
|
expect_usage_ratio, reclaim_interval, need_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fast_allocator_destroy(struct fast_allocator_context *acontext)
|
void fast_allocator_destroy(struct fast_allocator_context *acontext)
|
||||||
|
|
@ -396,8 +336,8 @@ void fast_allocator_destroy(struct fast_allocator_context *acontext)
|
||||||
memset(acontext, 0, sizeof(*acontext));
|
memset(acontext, 0, sizeof(*acontext));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fast_allocator_info *get_allocator(struct fast_allocator_context
|
static struct fast_allocator_info *get_allocator(struct fast_allocator_context *acontext,
|
||||||
*acontext, int *alloc_bytes)
|
int *alloc_bytes)
|
||||||
{
|
{
|
||||||
struct fast_region_info *pRegion;
|
struct fast_region_info *pRegion;
|
||||||
struct fast_region_info *region_end;
|
struct fast_region_info *region_end;
|
||||||
|
|
@ -406,19 +346,14 @@ static struct fast_allocator_info *get_allocator(struct fast_allocator_context
|
||||||
for (pRegion=acontext->regions; pRegion<region_end; pRegion++)
|
for (pRegion=acontext->regions; pRegion<region_end; pRegion++)
|
||||||
{
|
{
|
||||||
if (*alloc_bytes <= pRegion->end)
|
if (*alloc_bytes <= pRegion->end)
|
||||||
{
|
{
|
||||||
if (pRegion->count == 1) {
|
*alloc_bytes = BYTES_ALIGN(*alloc_bytes, pRegion->pad_mask);
|
||||||
*alloc_bytes = pRegion->allocators[0].mblock.info.element_size;
|
return pRegion->allocators + ((*alloc_bytes -
|
||||||
return pRegion->allocators + 0;
|
pRegion->start) / pRegion->step) - 1;
|
||||||
} else {
|
}
|
||||||
*alloc_bytes = BYTES_ALIGN(*alloc_bytes, pRegion->pad_mask);
|
|
||||||
return pRegion->allocators + ((*alloc_bytes -
|
|
||||||
pRegion->start) / pRegion->step) - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &acontext->allocator_array.malloc_allocator;
|
return &malloc_allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
||||||
|
|
@ -437,10 +372,8 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
||||||
|
|
||||||
acontext->allocator_array.last_reclaim_time = get_current_time();
|
acontext->allocator_array.last_reclaim_time = get_current_time();
|
||||||
malloc_bytes = acontext->allocator_array.malloc_bytes;
|
malloc_bytes = acontext->allocator_array.malloc_bytes;
|
||||||
/*
|
logInfo("malloc_bytes: %"PRId64", ratio: %f", malloc_bytes, (double)acontext->alloc_bytes /
|
||||||
logInfo("malloc_bytes: %"PRId64", ratio: %f", malloc_bytes,
|
(double)malloc_bytes);
|
||||||
(double)acontext->alloc_bytes / (double)malloc_bytes);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (malloc_bytes == 0 || (double)acontext->alloc_bytes /
|
if (malloc_bytes == 0 || (double)acontext->alloc_bytes /
|
||||||
(double)malloc_bytes >= acontext->allocator_array.expect_usage_ratio)
|
(double)malloc_bytes >= acontext->allocator_array.expect_usage_ratio)
|
||||||
|
|
@ -448,12 +381,12 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
||||||
return EAGAIN;
|
return EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<acontext->allocator_array.count; i++)
|
for (i=0; i< acontext->allocator_array.count; i++)
|
||||||
{
|
{
|
||||||
if (fast_mblock_reclaim(&acontext->allocator_array.
|
if (fast_mblock_reclaim(&acontext->allocator_array.
|
||||||
allocators[i]->mblock, 0, &reclaim_count, NULL) == 0)
|
allocators[i]->mblock, 0, &reclaim_count, NULL) == 0)
|
||||||
{
|
{
|
||||||
//logInfo("reclaim_count: %d", reclaim_count);
|
logInfo("reclaim_count: %d", reclaim_count);
|
||||||
*total_reclaim_bytes += reclaim_count *
|
*total_reclaim_bytes += reclaim_count *
|
||||||
acontext->allocator_array.allocators[i]->
|
acontext->allocator_array.allocators[i]->
|
||||||
mblock.info.trunk_size;
|
mblock.info.trunk_size;
|
||||||
|
|
@ -463,15 +396,6 @@ int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
||||||
return *total_reclaim_bytes > 0 ? 0 : EAGAIN;
|
return *total_reclaim_bytes > 0 ? 0 : EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void malloc_trunk_notify(
|
|
||||||
const enum fast_mblock_notify_type type,
|
|
||||||
const int alloc_bytes, void *args)
|
|
||||||
{
|
|
||||||
struct fast_mblock_malloc node;
|
|
||||||
node.trunk_size = alloc_bytes;
|
|
||||||
fast_allocator_malloc_trunk_notify_func(type, &node, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fast_allocator_alloc(struct fast_allocator_context *acontext,
|
void *fast_allocator_alloc(struct fast_allocator_context *acontext,
|
||||||
const int bytes)
|
const int bytes)
|
||||||
{
|
{
|
||||||
|
|
@ -479,21 +403,20 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
|
||||||
int64_t total_reclaim_bytes;
|
int64_t total_reclaim_bytes;
|
||||||
struct fast_allocator_info *allocator_info;
|
struct fast_allocator_info *allocator_info;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
void *obj;
|
|
||||||
|
|
||||||
if (bytes < 0)
|
if (bytes < 0)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_bytes = acontext->extra_size + bytes;
|
alloc_bytes = sizeof(struct allocator_wrapper) + bytes;
|
||||||
allocator_info = get_allocator(acontext, &alloc_bytes);
|
allocator_info = get_allocator(acontext, &alloc_bytes);
|
||||||
if (allocator_info->pooled)
|
if (allocator_info->pooled)
|
||||||
{
|
{
|
||||||
ptr = fast_mblock_alloc_object(&allocator_info->mblock);
|
ptr = fast_mblock_alloc_object(&allocator_info->mblock);
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
if (acontext->allocator_array.reclaim_interval < 0)
|
if (acontext->allocator_array.reclaim_interval <= 0)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -501,7 +424,7 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
//logInfo("reclaimed bytes: %"PRId64, total_reclaim_bytes);
|
logInfo("reclaimed bytes: %"PRId64, total_reclaim_bytes);
|
||||||
if (total_reclaim_bytes < allocator_info->mblock.info.trunk_size)
|
if (total_reclaim_bytes < allocator_info->mblock.info.trunk_size)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -512,7 +435,6 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obj = (char *)ptr + sizeof(struct fast_allocator_wrapper);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -520,47 +442,34 @@ void *fast_allocator_alloc(struct fast_allocator_context *acontext,
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ptr = fc_malloc(alloc_bytes);
|
ptr = malloc(alloc_bytes);
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
malloc_trunk_notify(fast_mblock_notify_type_alloc,
|
fast_allocator_malloc_trunk_notify_func(alloc_bytes, acontext);
|
||||||
alloc_bytes, acontext);
|
|
||||||
|
|
||||||
obj = (char *)ptr + sizeof(struct fast_allocator_wrapper);
|
|
||||||
if (acontext->allocator_array.allocators[0]->mblock.
|
|
||||||
object_callbacks.init_func != NULL)
|
|
||||||
{
|
|
||||||
struct fast_mblock_man *mblock;
|
|
||||||
mblock = &acontext->allocator_array.allocators[0]->mblock;
|
|
||||||
mblock->object_callbacks.init_func(obj,
|
|
||||||
mblock->object_callbacks.args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
((struct fast_allocator_wrapper *)ptr)->allocator_index =
|
((struct allocator_wrapper *)ptr)->allocator_index = allocator_info->index;
|
||||||
allocator_info->index;
|
((struct allocator_wrapper *)ptr)->magic_number = allocator_info->magic_number;
|
||||||
((struct fast_allocator_wrapper *)ptr)->magic_number =
|
((struct allocator_wrapper *)ptr)->alloc_bytes = alloc_bytes;
|
||||||
allocator_info->magic_number;
|
|
||||||
((struct fast_allocator_wrapper *)ptr)->alloc_bytes = alloc_bytes;
|
|
||||||
__sync_add_and_fetch(&acontext->alloc_bytes, alloc_bytes);
|
__sync_add_and_fetch(&acontext->alloc_bytes, alloc_bytes);
|
||||||
return obj;
|
return (char *)ptr + sizeof(struct allocator_wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
|
void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
|
||||||
{
|
{
|
||||||
struct fast_allocator_wrapper *pWrapper;
|
struct allocator_wrapper *pWrapper;
|
||||||
struct fast_allocator_info *allocator_info;
|
struct fast_allocator_info *allocator_info;
|
||||||
void *ptr;
|
void *obj;
|
||||||
|
if (ptr == NULL)
|
||||||
if (obj == NULL)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = (char *)obj - sizeof(struct fast_allocator_wrapper);
|
obj = (char *)ptr - sizeof(struct allocator_wrapper);
|
||||||
pWrapper = (struct fast_allocator_wrapper *)ptr;
|
pWrapper = (struct allocator_wrapper *)obj;
|
||||||
if (pWrapper->allocator_index < 0 || pWrapper->allocator_index >=
|
if (pWrapper->allocator_index < 0 || pWrapper->allocator_index >=
|
||||||
acontext->allocator_array.count)
|
acontext->allocator_array.count)
|
||||||
{
|
{
|
||||||
|
|
@ -570,8 +479,7 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator_info = acontext->allocator_array.
|
allocator_info = acontext->allocator_array.allocators[pWrapper->allocator_index];
|
||||||
allocators[pWrapper->allocator_index];
|
|
||||||
if (pWrapper->magic_number != allocator_info->magic_number)
|
if (pWrapper->magic_number != allocator_info->magic_number)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
|
@ -586,36 +494,12 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *obj)
|
||||||
pWrapper->magic_number = 0;
|
pWrapper->magic_number = 0;
|
||||||
if (allocator_info->pooled)
|
if (allocator_info->pooled)
|
||||||
{
|
{
|
||||||
fast_mblock_free_object(&allocator_info->mblock, ptr);
|
fast_mblock_free_object(&allocator_info->mblock, obj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
malloc_trunk_notify(fast_mblock_notify_type_reclaim,
|
fast_allocator_malloc_trunk_notify_func(-1 * pWrapper->alloc_bytes, acontext);
|
||||||
pWrapper->alloc_bytes, acontext);
|
free(obj);
|
||||||
|
}
|
||||||
if (acontext->allocator_array.allocators[0]->mblock.
|
|
||||||
object_callbacks.destroy_func != NULL)
|
|
||||||
{
|
|
||||||
struct fast_mblock_man *mblock;
|
|
||||||
mblock = &acontext->allocator_array.allocators[0]->mblock;
|
|
||||||
mblock->object_callbacks.destroy_func(obj,
|
|
||||||
mblock->object_callbacks.args);
|
|
||||||
}
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *fast_allocator_memdup(struct fast_allocator_context *acontext,
|
|
||||||
const char *src, const int len)
|
|
||||||
{
|
|
||||||
char *dest;
|
|
||||||
dest = (char *)fast_allocator_alloc(acontext, len);
|
|
||||||
if (dest == NULL) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"malloc %d bytes fail", __LINE__, len);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(dest, src, len);
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_allocator.h
|
//fast_allocator.h
|
||||||
|
|
||||||
|
|
@ -35,55 +28,38 @@ struct fast_allocator_info
|
||||||
|
|
||||||
struct fast_region_info
|
struct fast_region_info
|
||||||
{
|
{
|
||||||
int start; //exclude
|
int start;
|
||||||
int end; //include
|
int end;
|
||||||
int step;
|
int step;
|
||||||
int alloc_elements_once;
|
int alloc_elements_once;
|
||||||
int pad_mask; //for internal use
|
int pad_mask; //for internal use
|
||||||
int count;
|
|
||||||
struct fast_allocator_info *allocators;
|
struct fast_allocator_info *allocators;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fast_allocator_array
|
struct fast_allocator_array
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
int alloc;
|
int alloc;
|
||||||
int reclaim_interval; //< 0 for never reclaim
|
int reclaim_interval; //<= 0 for never reclaim
|
||||||
int last_reclaim_time;
|
int last_reclaim_time;
|
||||||
volatile int64_t malloc_bytes; //total alloc bytes
|
volatile int64_t malloc_bytes; //total alloc bytes
|
||||||
int64_t malloc_bytes_limit; //water mark bytes for malloc
|
int64_t malloc_bytes_limit; //water mark bytes for malloc
|
||||||
double expect_usage_ratio;
|
double expect_usage_ratio;
|
||||||
struct fast_allocator_info malloc_allocator;
|
struct fast_allocator_info **allocators;
|
||||||
struct fast_allocator_info **allocators;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_allocator_wrapper {
|
|
||||||
int alloc_bytes;
|
|
||||||
short allocator_index;
|
|
||||||
short magic_number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fast_allocator_context
|
struct fast_allocator_context
|
||||||
{
|
{
|
||||||
struct fast_region_info *regions;
|
struct fast_region_info *regions;
|
||||||
int region_count;
|
int region_count;
|
||||||
int extra_size;
|
|
||||||
|
|
||||||
struct fast_allocator_array allocator_array;
|
struct fast_allocator_array allocator_array;
|
||||||
|
|
||||||
int64_t alloc_bytes_limit; //water mark bytes for alloc
|
int64_t alloc_bytes_limit; //mater mark bytes for alloc
|
||||||
volatile int64_t alloc_bytes; //total alloc bytes
|
volatile int64_t alloc_bytes; //total alloc bytes
|
||||||
bool need_lock; //if need mutex lock for acontext
|
bool need_lock; //if need mutex lock for acontext
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FAST_ALLOCATOR_INIT_REGION(region, _start, _end, _step, _alloc_once) \
|
|
||||||
do { \
|
|
||||||
(region).start = _start; \
|
|
||||||
(region).end = _end; \
|
|
||||||
(region).step = _step; \
|
|
||||||
(region).alloc_elements_once = _alloc_once; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -92,39 +68,32 @@ extern "C" {
|
||||||
allocator init by default region allocators
|
allocator init by default region allocators
|
||||||
parameters:
|
parameters:
|
||||||
acontext: the context pointer
|
acontext: the context pointer
|
||||||
mblock_name_prefix: the name prefix of mblock
|
alloc_bytes_limit: the alloc limit, 0 for no limit
|
||||||
alloc_bytes_limit: the alloc limit, 0 for no limit
|
|
||||||
expect_usage_ratio: the trunk usage ratio
|
expect_usage_ratio: the trunk usage ratio
|
||||||
reclaim_interval: reclaim interval in second, < 0 for never reclaim
|
reclaim_interval: reclaim interval in second, 0 for never reclaim
|
||||||
need_lock: if need lock
|
need_lock: if need lock
|
||||||
return error no, 0 for success, != 0 fail
|
return error no, 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int fast_allocator_init(struct fast_allocator_context *acontext,
|
int fast_allocator_init(struct fast_allocator_context *acontext,
|
||||||
const char *mblock_name_prefix, const int64_t alloc_bytes_limit,
|
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
|
||||||
const double expect_usage_ratio, const int reclaim_interval,
|
const int reclaim_interval, const bool need_lock);
|
||||||
const bool need_lock);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
allocator init
|
allocator init
|
||||||
parameters:
|
parameters:
|
||||||
acontext: the context pointer
|
acontext: the context pointer
|
||||||
mblock_name_prefix: name prefix of object alloctors
|
|
||||||
obj_size: element size of object as sizeof(obj)
|
|
||||||
object_callbacks: object init and destroy callbacks
|
|
||||||
regions: the region array
|
regions: the region array
|
||||||
region_count: the region count
|
region_count: the region count
|
||||||
alloc_bytes_limit: the alloc limit, 0 for no limit
|
alloc_bytes_limit: the alloc limit, 0 for no limit
|
||||||
expect_usage_ratio: the trunk usage ratio
|
expect_usage_ratio: the trunk usage ratio
|
||||||
reclaim_interval: reclaim interval in second, < 0 for never reclaim
|
reclaim_interval: reclaim interval in second, 0 for never reclaim
|
||||||
need_lock: if need lock
|
need_lock: if need lock
|
||||||
return error no, 0 for success, != 0 fail
|
return error no, 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
int fast_allocator_init_ex(struct fast_allocator_context *acontext,
|
||||||
const char *mblock_name_prefix, const int obj_size,
|
|
||||||
struct fast_mblock_object_callbacks *object_callbacks,
|
|
||||||
struct fast_region_info *regions, const int region_count,
|
struct fast_region_info *regions, const int region_count,
|
||||||
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
|
const int64_t alloc_bytes_limit, const double expect_usage_ratio,
|
||||||
const int reclaim_interval, const bool need_lock);
|
const int reclaim_interval, const bool need_lock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
allocator destroy
|
allocator destroy
|
||||||
|
|
@ -147,10 +116,10 @@ void* fast_allocator_alloc(struct fast_allocator_context *acontext,
|
||||||
free a node (put a node to the context)
|
free a node (put a node to the context)
|
||||||
parameters:
|
parameters:
|
||||||
acontext: the context pointer
|
acontext: the context pointer
|
||||||
obj: the object ptr to free
|
ptr: the pointer to free
|
||||||
return none
|
return none
|
||||||
*/
|
*/
|
||||||
void fast_allocator_free(struct fast_allocator_context *acontext, void *obj);
|
void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
retry reclaim free trunks
|
retry reclaim free trunks
|
||||||
|
|
@ -162,48 +131,9 @@ return error no, 0 for success, != 0 fail
|
||||||
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
int fast_allocator_retry_reclaim(struct fast_allocator_context *acontext,
|
||||||
int64_t *total_reclaim_bytes);
|
int64_t *total_reclaim_bytes);
|
||||||
|
|
||||||
char *fast_allocator_memdup(struct fast_allocator_context *acontext,
|
|
||||||
const char *src, const int len);
|
|
||||||
|
|
||||||
static inline char *fast_allocator_strdup_ex(struct fast_allocator_context *
|
|
||||||
acontext, const char *src, const int len)
|
|
||||||
{
|
|
||||||
return fast_allocator_memdup(acontext, src, len + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline char *fast_allocator_strdup(struct fast_allocator_context *
|
|
||||||
acontext, const char *src)
|
|
||||||
{
|
|
||||||
return fast_allocator_memdup(acontext, src, strlen(src) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_allocator_alloc_string_ex(struct fast_allocator_context
|
|
||||||
*acontext, string_t *dest, const char *src, const int len)
|
|
||||||
{
|
|
||||||
dest->str = fast_allocator_memdup(acontext, src, len);
|
|
||||||
dest->len = len;
|
|
||||||
return dest->str != NULL ? 0 : ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_allocator_alloc_string(struct fast_allocator_context
|
|
||||||
*acontext, string_t *dest, const string_t *src)
|
|
||||||
{
|
|
||||||
return fast_allocator_alloc_string_ex(acontext, dest, src->str, src->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int64_t fast_allocator_avail_memory(
|
|
||||||
struct fast_allocator_context *acontext)
|
|
||||||
{
|
|
||||||
if (acontext->alloc_bytes_limit == 0) {
|
|
||||||
return INT64_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return acontext->alloc_bytes_limit - __sync_add_and_fetch(
|
|
||||||
&acontext->allocator_array.malloc_bytes, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_blocked_queue.c
|
//fast_blocked_queue.c
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_blocked_queue.h
|
//fast_blocked_queue.h
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -20,34 +5,28 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "shared_func.h"
|
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "fast_buffer.h"
|
#include "fast_buffer.h"
|
||||||
|
|
||||||
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity,
|
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity)
|
||||||
const bool binary_mode, const bool check_capacity)
|
|
||||||
{
|
{
|
||||||
buffer->length = 0;
|
buffer->length = 0;
|
||||||
buffer->binary_mode = binary_mode;
|
|
||||||
if (init_capacity > 0)
|
if (init_capacity > 0)
|
||||||
{
|
{
|
||||||
buffer->alloc_size = init_capacity;
|
buffer->alloc_size = init_capacity;
|
||||||
buffer->check_capacity = check_capacity;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->alloc_size = 256;
|
buffer->alloc_size = 256;
|
||||||
buffer->check_capacity = true;
|
|
||||||
}
|
}
|
||||||
buffer->data = (char *)fc_malloc(buffer->alloc_size);
|
buffer->data = (char *)malloc(buffer->alloc_size);
|
||||||
if (buffer->data == NULL)
|
if (buffer->data == NULL)
|
||||||
{
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail", __LINE__, buffer->alloc_size);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
*(buffer->data) = '\0';
|
||||||
fast_buffer_set_null_terminator(buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,41 +40,32 @@ void fast_buffer_destroy(FastBuffer *buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity)
|
int fast_buffer_check(FastBuffer *buffer, const int inc_len)
|
||||||
{
|
{
|
||||||
int alloc_size;
|
int alloc_size;
|
||||||
int new_capacity;
|
|
||||||
char *buff;
|
char *buff;
|
||||||
|
|
||||||
new_capacity = FC_MAX(capacity, buffer->length + 1);
|
if (buffer->alloc_size > buffer->length + inc_len)
|
||||||
if (buffer->alloc_size >= new_capacity) {
|
{
|
||||||
if (new_capacity > 1024) {
|
return 0;
|
||||||
alloc_size = 2048;
|
|
||||||
} else if (new_capacity > 512) {
|
|
||||||
alloc_size = 1024;
|
|
||||||
} else if (new_capacity > 256) {
|
|
||||||
alloc_size = 512;
|
|
||||||
} else {
|
|
||||||
alloc_size = 256;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alloc_size = buffer->alloc_size * 2;
|
|
||||||
}
|
}
|
||||||
|
alloc_size = buffer->alloc_size * 2;
|
||||||
while (alloc_size < new_capacity) {
|
while (alloc_size <= buffer->length + inc_len)
|
||||||
|
{
|
||||||
alloc_size *= 2;
|
alloc_size *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff = (char *)fc_malloc(alloc_size);
|
buff = (char *)malloc(alloc_size);
|
||||||
if (buff == NULL) {
|
if (buff == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail", __LINE__, alloc_size);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->length > 0) {
|
if (buffer->length > 0)
|
||||||
|
{
|
||||||
memcpy(buff, buffer->data, buffer->length);
|
memcpy(buff, buffer->data, buffer->length);
|
||||||
if (!buffer->binary_mode) {
|
|
||||||
*(buff + buffer->length) = '\0';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer->data);
|
free(buffer->data);
|
||||||
|
|
@ -125,7 +95,7 @@ int fast_buffer_append(FastBuffer *buffer, const char *format, ...)
|
||||||
}
|
}
|
||||||
else //maybe full, realloc and try again
|
else //maybe full, realloc and try again
|
||||||
{
|
{
|
||||||
if ((result=fast_buffer_check(buffer, len + 1)) == 0)
|
if ((result=fast_buffer_check(buffer, len)) == 0)
|
||||||
{
|
{
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
buffer->length += vsnprintf(buffer->data + buffer->length,
|
buffer->length += vsnprintf(buffer->data + buffer->length,
|
||||||
|
|
@ -134,7 +104,7 @@ int fast_buffer_append(FastBuffer *buffer, const char *format, ...)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fast_buffer_set_null_terminator(buffer); //restore
|
*(buffer->data + buffer->length) = '\0'; //restore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -144,26 +114,6 @@ int fast_buffer_append_buff(FastBuffer *buffer, const char *data, const int len)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (len <= 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((result=fast_buffer_check(buffer, len + 1)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer->data + buffer->length, data, len);
|
|
||||||
buffer->length += len;
|
|
||||||
fast_buffer_set_null_terminator(buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fast_buffer_append_binary(FastBuffer *buffer,
|
|
||||||
const void *data, const int len)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -175,49 +125,33 @@ int fast_buffer_append_binary(FastBuffer *buffer,
|
||||||
|
|
||||||
memcpy(buffer->data + buffer->length, data, len);
|
memcpy(buffer->data + buffer->length, data, len);
|
||||||
buffer->length += len;
|
buffer->length += len;
|
||||||
|
*(buffer->data + buffer->length) = '\0';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_buffer_append_file(FastBuffer *buffer, const char *filename)
|
int fast_buffer_append_int(FastBuffer *buffer, const int n)
|
||||||
{
|
{
|
||||||
struct stat st;
|
|
||||||
int result;
|
int result;
|
||||||
int64_t file_size;
|
|
||||||
|
|
||||||
if (stat(filename, &st) != 0) {
|
if ((result=fast_buffer_check(buffer, 16)) != 0)
|
||||||
result = errno != 0 ? errno : ENOENT;
|
|
||||||
if (result == ENOENT) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"file %s not exist!", __LINE__,
|
|
||||||
filename);
|
|
||||||
} else {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"stat file %s fail, "
|
|
||||||
"result: %d, error info: %s", __LINE__,
|
|
||||||
filename, result, strerror(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!S_ISREG(st.st_mode)) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"file %s is NOT a regular file!",
|
|
||||||
__LINE__, filename);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_size = st.st_size + 1;
|
|
||||||
if ((result=fast_buffer_check(buffer, file_size)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=getFileContentEx(filename, buffer->data + buffer->length,
|
|
||||||
0, &file_size)) != 0)
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->length += file_size;
|
buffer->length += sprintf(buffer->data + buffer->length, "%d", n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=fast_buffer_check(buffer, 32)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->length += sprintf(buffer->data + buffer->length, "%"PRId64, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,12 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FAST_BUFFER_H__
|
#ifndef __FAST_BUFFER_H__
|
||||||
#define __FAST_BUFFER_H__
|
#define __FAST_BUFFER_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "shared_func.h"
|
|
||||||
|
|
||||||
typedef struct fast_buffer {
|
typedef struct fast_buffer {
|
||||||
char *data;
|
char *data;
|
||||||
int alloc_size;
|
int alloc_size;
|
||||||
int length;
|
int length;
|
||||||
bool binary_mode;
|
|
||||||
bool check_capacity;
|
|
||||||
} FastBuffer;
|
} FastBuffer;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
@ -41,123 +23,38 @@ static inline char *fast_buffer_data(FastBuffer *buffer)
|
||||||
return buffer->data;
|
return buffer->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity,
|
int fast_buffer_init_ex(FastBuffer *buffer, const int init_capacity);
|
||||||
const bool binary_mode, const bool check_capacity);
|
|
||||||
|
|
||||||
static inline int fast_buffer_init1(FastBuffer *buffer, const int init_capacity)
|
|
||||||
{
|
|
||||||
const bool binary_mode = false;
|
|
||||||
const bool check_capacity = true;
|
|
||||||
return fast_buffer_init_ex(buffer, init_capacity,
|
|
||||||
binary_mode, check_capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_buffer_init(FastBuffer *buffer)
|
static inline int fast_buffer_init(FastBuffer *buffer)
|
||||||
{
|
{
|
||||||
const int init_capacity = 0;
|
return fast_buffer_init_ex(buffer, 0);
|
||||||
return fast_buffer_init1(buffer, init_capacity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define fast_buffer_set_null_terminator(buffer) \
|
|
||||||
if (!buffer->binary_mode) *(buffer->data + buffer->length) = '\0'
|
|
||||||
|
|
||||||
#define fast_buffer_check(buffer, inc_len) \
|
|
||||||
((buffer)->check_capacity ? fast_buffer_check_inc_size(buffer, inc_len) : 0)
|
|
||||||
|
|
||||||
#define fast_buffer_clear(buffer) fast_buffer_reset(buffer)
|
#define fast_buffer_clear(buffer) fast_buffer_reset(buffer)
|
||||||
|
|
||||||
static inline void fast_buffer_reset(FastBuffer *buffer)
|
static inline void fast_buffer_reset(FastBuffer *buffer)
|
||||||
{
|
{
|
||||||
buffer->length = 0;
|
buffer->length = 0;
|
||||||
fast_buffer_set_null_terminator(buffer);
|
*buffer->data = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void fast_buffer_destroy(FastBuffer *buffer);
|
void fast_buffer_destroy(FastBuffer *buffer);
|
||||||
|
|
||||||
int fast_buffer_set_capacity(FastBuffer *buffer, const int capacity);
|
int fast_buffer_check(FastBuffer *buffer, const int inc_len);
|
||||||
|
|
||||||
static inline int fast_buffer_check_capacity(FastBuffer *buffer,
|
|
||||||
const int capacity)
|
|
||||||
{
|
|
||||||
if (buffer->alloc_size >= capacity)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fast_buffer_set_capacity(buffer, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_buffer_check_inc_size(FastBuffer *buffer,
|
|
||||||
const int inc_size)
|
|
||||||
{
|
|
||||||
return fast_buffer_check_capacity(buffer, buffer->length + inc_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fast_buffer_append(FastBuffer *buffer, const char *format, ...);
|
int fast_buffer_append(FastBuffer *buffer, const char *format, ...);
|
||||||
|
|
||||||
int fast_buffer_append_buff(FastBuffer *buffer,
|
int fast_buffer_append_buff(FastBuffer *buffer, const char *data, const int len);
|
||||||
const char *data, const int len);
|
|
||||||
|
|
||||||
int fast_buffer_append_binary(FastBuffer *buffer,
|
int fast_buffer_append_int(FastBuffer *buffer, const int n);
|
||||||
const void *data, const int len);
|
|
||||||
|
|
||||||
static inline int fast_buffer_append_char(FastBuffer *buffer, const char ch)
|
int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n);
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=fast_buffer_check(buffer, 1)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(buffer->data + buffer->length++) = ch;
|
|
||||||
fast_buffer_set_null_terminator(buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_buffer_append_int32(FastBuffer *buffer, const int n)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=fast_buffer_check(buffer, 16)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer->length += fc_itoa(n, buffer->data + buffer->length);
|
|
||||||
fast_buffer_set_null_terminator(buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_buffer_append_int64(FastBuffer *buffer, const int64_t n)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=fast_buffer_check(buffer, 32)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer->length += fc_itoa(n, buffer->data + buffer->length);
|
|
||||||
fast_buffer_set_null_terminator(buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fast_buffer_append_int(buffer, n) \
|
|
||||||
fast_buffer_append_int64(buffer, n)
|
|
||||||
|
|
||||||
int fast_buffer_append_file(FastBuffer *buffer, const char *filename);
|
|
||||||
|
|
||||||
static inline int fast_buffer_append_string(FastBuffer *buffer, const char *str)
|
static inline int fast_buffer_append_string(FastBuffer *buffer, const char *str)
|
||||||
{
|
{
|
||||||
return fast_buffer_append_buff(buffer, str, strlen(str));
|
return fast_buffer_append_buff(buffer, str, strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int fast_buffer_append_string2(FastBuffer *buffer, const string_t *add)
|
|
||||||
{
|
|
||||||
return fast_buffer_append_buff(buffer, add->str, add->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fast_buffer_append_buffer(FastBuffer *buffer, FastBuffer *src)
|
static inline int fast_buffer_append_buffer(FastBuffer *buffer, FastBuffer *src)
|
||||||
{
|
{
|
||||||
return fast_buffer_append_buff(buffer, src->data, src->length);
|
return fast_buffer_append_buff(buffer, src->data, src->length);
|
||||||
|
|
@ -168,3 +65,4 @@ static inline int fast_buffer_append_buffer(FastBuffer *buffer, FastBuffer *src)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_mblock.h
|
//fast_mblock.h
|
||||||
|
|
||||||
|
|
@ -23,26 +16,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include "fc_memory.h"
|
#include "chain.h"
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
/* following two macros for debug only */
|
|
||||||
/*
|
|
||||||
#define FAST_MBLOCK_MAGIC_CHECK 1
|
|
||||||
#define FAST_MBLOCK_MAGIC_NUMBER 1234567890
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#define FAST_MBLOCK_NAME_SIZE 32
|
#define FAST_MBLOCK_NAME_SIZE 32
|
||||||
|
|
||||||
#define FAST_MBLOCK_ORDER_BY_ALLOC_BYTES 1
|
#define FAST_MBLOCK_ORDER_BY_ALLOC_BYTES 1
|
||||||
#define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2
|
#define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2
|
||||||
#define FAST_MBLOCK_ORDER_BY_USED_RATIO 3
|
|
||||||
|
|
||||||
enum fast_mblock_notify_type {
|
|
||||||
fast_mblock_notify_type_alloc,
|
|
||||||
fast_mblock_notify_type_reclaim,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* free node chain */
|
/* free node chain */
|
||||||
struct fast_mblock_node
|
struct fast_mblock_node
|
||||||
|
|
@ -50,19 +29,13 @@ struct fast_mblock_node
|
||||||
struct fast_mblock_node *next;
|
struct fast_mblock_node *next;
|
||||||
int offset; //trunk offset
|
int offset; //trunk offset
|
||||||
int recycle_timestamp;
|
int recycle_timestamp;
|
||||||
#ifdef FAST_MBLOCK_MAGIC_CHECK
|
|
||||||
int index;
|
|
||||||
int magic; //magic number
|
|
||||||
#endif
|
|
||||||
char data[0]; //the data buffer
|
char data[0]; //the data buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
/* malloc chain */
|
/* malloc chain */
|
||||||
struct fast_mblock_malloc
|
struct fast_mblock_malloc
|
||||||
{
|
{
|
||||||
int64_t ref_count; //refference count
|
int64_t ref_count; //refference count
|
||||||
int alloc_count; //allocated element count
|
|
||||||
int trunk_size; //trunk bytes
|
|
||||||
struct fast_mblock_malloc *prev;
|
struct fast_mblock_malloc *prev;
|
||||||
struct fast_mblock_malloc *next;
|
struct fast_mblock_malloc *next;
|
||||||
};
|
};
|
||||||
|
|
@ -72,31 +45,24 @@ struct fast_mblock_chain {
|
||||||
struct fast_mblock_node *tail;
|
struct fast_mblock_node *tail;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* call by alloc trunk */
|
typedef int (*fast_mblock_alloc_init_func)(void *element);
|
||||||
typedef int (*fast_mblock_object_init_func)(void *element, void *args);
|
|
||||||
|
|
||||||
/* call by free trunk */
|
|
||||||
typedef void (*fast_mblock_object_destroy_func)(void *element, void *args);
|
|
||||||
|
|
||||||
typedef int (*fast_mblock_malloc_trunk_check_func)(
|
typedef int (*fast_mblock_malloc_trunk_check_func)(
|
||||||
const int alloc_bytes, void *args);
|
const int alloc_bytes, void *args);
|
||||||
|
|
||||||
typedef void (*fast_mblock_malloc_trunk_notify_func)(
|
typedef void (*fast_mblock_malloc_trunk_notify_func)(
|
||||||
const enum fast_mblock_notify_type type,
|
const int alloc_bytes, void *args);
|
||||||
const struct fast_mblock_malloc *node, void *args);
|
|
||||||
|
|
||||||
struct fast_mblock_info
|
struct fast_mblock_info
|
||||||
{
|
{
|
||||||
char name[FAST_MBLOCK_NAME_SIZE];
|
char name[FAST_MBLOCK_NAME_SIZE];
|
||||||
int element_size; //element size
|
int element_size; //element size
|
||||||
|
int element_total_count; //total element count
|
||||||
|
int element_used_count; //used element count
|
||||||
int trunk_size; //trunk size
|
int trunk_size; //trunk size
|
||||||
|
int trunk_total_count; //total trunk count
|
||||||
|
int trunk_used_count; //used trunk count
|
||||||
int instance_count; //instance count
|
int instance_count; //instance count
|
||||||
int block_size;
|
|
||||||
int64_t element_total_count; //total element count
|
|
||||||
int64_t element_used_count; //used element count
|
|
||||||
int64_t delay_free_elements; //delay free element count
|
|
||||||
int64_t trunk_total_count; //total trunk count
|
|
||||||
int64_t trunk_used_count; //used trunk count
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fast_mblock_trunks
|
struct fast_mblock_trunks
|
||||||
|
|
@ -104,13 +70,7 @@ struct fast_mblock_trunks
|
||||||
struct fast_mblock_malloc head; //malloc chain to be freed
|
struct fast_mblock_malloc head; //malloc chain to be freed
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fast_mblock_object_callbacks {
|
struct fast_mblock_malloc_trunk_callback
|
||||||
fast_mblock_object_init_func init_func;
|
|
||||||
fast_mblock_object_destroy_func destroy_func;
|
|
||||||
void *args;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_mblock_trunk_callbacks
|
|
||||||
{
|
{
|
||||||
fast_mblock_malloc_trunk_check_func check_func;
|
fast_mblock_malloc_trunk_check_func check_func;
|
||||||
fast_mblock_malloc_trunk_notify_func notify_func;
|
fast_mblock_malloc_trunk_notify_func notify_func;
|
||||||
|
|
@ -120,35 +80,24 @@ struct fast_mblock_trunk_callbacks
|
||||||
struct fast_mblock_man
|
struct fast_mblock_man
|
||||||
{
|
{
|
||||||
struct fast_mblock_info info;
|
struct fast_mblock_info info;
|
||||||
struct {
|
int alloc_elements_once; //alloc elements once
|
||||||
bool need_wait;
|
struct fast_mblock_node *free_chain_head; //free node chain
|
||||||
int exceed_log_level; //for exceed limit
|
|
||||||
int once; //alloc elements once
|
|
||||||
int64_t limit; //<= 0 for no limit
|
|
||||||
bool *pcontinue_flag;
|
|
||||||
} alloc_elements;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
struct fast_mblock_node *head;
|
|
||||||
} freelist; //free node chain
|
|
||||||
|
|
||||||
struct fast_mblock_trunks trunks;
|
struct fast_mblock_trunks trunks;
|
||||||
struct fast_mblock_chain delay_free_chain; //delay free node chain
|
struct fast_mblock_chain delay_free_chain; //delay free node chain
|
||||||
|
|
||||||
struct fast_mblock_object_callbacks object_callbacks;
|
fast_mblock_alloc_init_func alloc_init_func;
|
||||||
struct fast_mblock_trunk_callbacks trunk_callbacks;
|
struct fast_mblock_malloc_trunk_callback malloc_trunk_callback;
|
||||||
|
|
||||||
bool need_lock; //if need mutex lock
|
bool need_lock; //if need mutex lock
|
||||||
pthread_lock_cond_pair_t lcp; //for read / write free node chain
|
pthread_mutex_t lock; //the lock for read / write free node chain
|
||||||
struct fast_mblock_man *prev; //for stat manager
|
struct fast_mblock_man *prev; //for stat manager
|
||||||
struct fast_mblock_man *next; //for stat manager
|
struct fast_mblock_man *next; //for stat manager
|
||||||
};
|
};
|
||||||
|
|
||||||
#define fast_mblock_get_block_size(element_size) \
|
#define GET_BLOCK_SIZE(info) \
|
||||||
(MEM_ALIGN(sizeof(struct fast_mblock_node) + element_size))
|
(MEM_ALIGN(sizeof(struct fast_mblock_node) + (info).element_size))
|
||||||
|
|
||||||
#define fast_mblock_get_trunk_size(block_size, element_count) \
|
#define fast_mblock_get_block_size(mblock) GET_BLOCK_SIZE(mblock->info)
|
||||||
(sizeof(struct fast_mblock_malloc) + block_size * element_count)
|
|
||||||
|
|
||||||
#define fast_mblock_to_node_ptr(data_ptr) \
|
#define fast_mblock_to_node_ptr(data_ptr) \
|
||||||
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
|
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
|
||||||
|
|
@ -159,8 +108,21 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define fast_mblock_init(mblock, element_size, alloc_elements_once) \
|
#define fast_mblock_init(mblock, element_size, alloc_elements_once) \
|
||||||
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, \
|
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, NULL, true)
|
||||||
0, NULL, NULL, true)
|
|
||||||
|
/**
|
||||||
|
mblock init
|
||||||
|
parameters:
|
||||||
|
mblock: the mblock pointer
|
||||||
|
element_size: element size, such as sizeof(struct xxx)
|
||||||
|
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
|
||||||
|
init_func: the init function
|
||||||
|
need_lock: if need lock
|
||||||
|
return error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int fast_mblock_init_ex(struct fast_mblock_man *mblock,
|
||||||
|
const int element_size, const int alloc_elements_once,
|
||||||
|
fast_mblock_alloc_init_func init_func, const bool need_lock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
mblock init
|
mblock init
|
||||||
|
|
@ -169,19 +131,19 @@ parameters:
|
||||||
mblock: the mblock pointer
|
mblock: the mblock pointer
|
||||||
element_size: element size, such as sizeof(struct xxx)
|
element_size: element size, such as sizeof(struct xxx)
|
||||||
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
|
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
|
||||||
alloc_elements_limit: malloc elements limit, <= 0 for no limit
|
init_func: the init function
|
||||||
prealloc_trunk_count: prealloc trunk node count
|
|
||||||
object_callbacks: the object callback functions and args
|
|
||||||
need_lock: if need lock
|
need_lock: if need lock
|
||||||
trunk_callbacks: the trunk callback functions and args
|
malloc_trunk_check: the malloc trunk check function pointor
|
||||||
|
malloc_trunk_notify: the malloc trunk notify function pointor
|
||||||
|
malloc_trunk_args: the malloc trunk args
|
||||||
return error no, 0 for success, != 0 fail
|
return error no, 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
|
int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
|
||||||
const int element_size, const int alloc_elements_once,
|
const int element_size, const int alloc_elements_once,
|
||||||
const int64_t alloc_elements_limit, const int prealloc_trunk_count,
|
fast_mblock_alloc_init_func init_func, const bool need_lock,
|
||||||
struct fast_mblock_object_callbacks *object_callbacks,
|
fast_mblock_malloc_trunk_check_func malloc_trunk_check,
|
||||||
const bool need_lock, struct fast_mblock_trunk_callbacks
|
fast_mblock_malloc_trunk_notify_func malloc_trunk_notify,
|
||||||
*trunk_callbacks);
|
void *malloc_trunk_args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
mblock init
|
mblock init
|
||||||
|
|
@ -190,52 +152,18 @@ parameters:
|
||||||
mblock: the mblock pointer
|
mblock: the mblock pointer
|
||||||
element_size: element size, such as sizeof(struct xxx)
|
element_size: element size, such as sizeof(struct xxx)
|
||||||
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
|
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
|
||||||
alloc_elements_limit: malloc elements limit, <= 0 for no limit
|
init_func: the init function
|
||||||
init_func: the object init function
|
|
||||||
init_args: the args for object init function
|
|
||||||
need_lock: if need lock
|
need_lock: if need lock
|
||||||
return error no, 0 for success, != 0 fail
|
return error no, 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock,
|
static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock,
|
||||||
const char *name, const int element_size,
|
const char *name, const int element_size, const int alloc_elements_once,
|
||||||
const int alloc_elements_once, const int64_t alloc_elements_limit,
|
fast_mblock_alloc_init_func init_func, const bool need_lock)
|
||||||
fast_mblock_object_init_func init_func, void *init_args,
|
|
||||||
const bool need_lock)
|
|
||||||
{
|
{
|
||||||
const int prealloc_trunk_count = 0;
|
|
||||||
struct fast_mblock_object_callbacks object_callbacks;
|
|
||||||
|
|
||||||
object_callbacks.init_func = init_func;
|
|
||||||
object_callbacks.destroy_func = NULL;
|
|
||||||
object_callbacks.args = init_args;
|
|
||||||
return fast_mblock_init_ex2(mblock, name, element_size,
|
return fast_mblock_init_ex2(mblock, name, element_size,
|
||||||
alloc_elements_once, alloc_elements_limit,
|
alloc_elements_once, init_func, need_lock, NULL, NULL, NULL);
|
||||||
prealloc_trunk_count, &object_callbacks,
|
|
||||||
need_lock, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
mblock init
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
element_size: element size, such as sizeof(struct xxx)
|
|
||||||
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
|
|
||||||
alloc_elements_limit: malloc elements limit, <= 0 for no limit
|
|
||||||
object_callbacks: the object callback functions and args
|
|
||||||
need_lock: if need lock
|
|
||||||
return error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
static inline int fast_mblock_init_ex(struct fast_mblock_man *mblock,
|
|
||||||
const int element_size, const int alloc_elements_once,
|
|
||||||
const int64_t alloc_elements_limit, fast_mblock_object_init_func
|
|
||||||
init_func, void *init_args, const bool need_lock)
|
|
||||||
{
|
|
||||||
return fast_mblock_init_ex1(mblock, NULL, element_size,
|
|
||||||
alloc_elements_once, alloc_elements_limit,
|
|
||||||
init_func, init_args, need_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
mblock destroy
|
mblock destroy
|
||||||
parameters:
|
parameters:
|
||||||
|
|
@ -243,35 +171,6 @@ parameters:
|
||||||
*/
|
*/
|
||||||
void fast_mblock_destroy(struct fast_mblock_man *mblock);
|
void fast_mblock_destroy(struct fast_mblock_man *mblock);
|
||||||
|
|
||||||
static inline int fast_mblock_set_need_wait(struct fast_mblock_man *mblock,
|
|
||||||
const bool need_wait, bool * volatile pcontinue_flag)
|
|
||||||
{
|
|
||||||
if (!mblock->need_lock || mblock->alloc_elements.limit <= 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"need_lock: %d != 1 or alloc_elements.limit: %"PRId64" <= 0",
|
|
||||||
__LINE__, mblock->need_lock, mblock->alloc_elements.limit);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mblock->alloc_elements.need_wait = need_wait;
|
|
||||||
mblock->alloc_elements.pcontinue_flag = pcontinue_flag;
|
|
||||||
if (need_wait)
|
|
||||||
{
|
|
||||||
mblock->alloc_elements.exceed_log_level = LOG_NOTHING;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fast_mblock_set_exceed_log_level(
|
|
||||||
struct fast_mblock_man *mblock, const int log_level)
|
|
||||||
{
|
|
||||||
mblock->alloc_elements.exceed_log_level = log_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fast_mblock_set_exceed_silence(mblock) \
|
|
||||||
fast_mblock_set_exceed_log_level(mblock, LOG_NOTHING)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
alloc a node from the mblock
|
alloc a node from the mblock
|
||||||
parameters:
|
parameters:
|
||||||
|
|
@ -290,45 +189,6 @@ return 0 for success, return none zero if fail
|
||||||
int fast_mblock_free(struct fast_mblock_man *mblock,
|
int fast_mblock_free(struct fast_mblock_man *mblock,
|
||||||
struct fast_mblock_node *pNode);
|
struct fast_mblock_node *pNode);
|
||||||
|
|
||||||
/**
|
|
||||||
batch alloc nodes from the mblock
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
count: alloc count
|
|
||||||
chain: return the mblock node chain
|
|
||||||
return 0 for success, return none zero if fail
|
|
||||||
*/
|
|
||||||
int fast_mblock_batch_alloc(struct fast_mblock_man *mblock,
|
|
||||||
const int count, struct fast_mblock_chain *chain);
|
|
||||||
|
|
||||||
/**
|
|
||||||
batch alloc nodes from the mblock
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
count: alloc count
|
|
||||||
return the alloced node head, return NULL if fail
|
|
||||||
*/
|
|
||||||
static inline struct fast_mblock_node *fast_mblock_batch_alloc1(
|
|
||||||
struct fast_mblock_man *mblock, const int count)
|
|
||||||
{
|
|
||||||
struct fast_mblock_chain chain;
|
|
||||||
if (fast_mblock_batch_alloc(mblock, count, &chain) == 0) {
|
|
||||||
return chain.head;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
batch free nodes
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
chain: the node chain to free
|
|
||||||
return 0 for success, return none zero if fail
|
|
||||||
*/
|
|
||||||
int fast_mblock_batch_free(struct fast_mblock_man *mblock,
|
|
||||||
struct fast_mblock_chain *chain);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
delay free a node (put a node to the mblock)
|
delay free a node (put a node to the mblock)
|
||||||
parameters:
|
parameters:
|
||||||
|
|
@ -370,17 +230,6 @@ static inline int fast_mblock_free_object(struct fast_mblock_man *mblock,
|
||||||
return fast_mblock_free(mblock, fast_mblock_to_node_ptr(object));
|
return fast_mblock_free(mblock, fast_mblock_to_node_ptr(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
free objects (put objects to the mblock)
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
objs: the object array to free
|
|
||||||
count: the count of the object array
|
|
||||||
return none
|
|
||||||
*/
|
|
||||||
void fast_mblock_free_objects(struct fast_mblock_man *mblock,
|
|
||||||
void **objs, const int count);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
delay free a object (put a node to the mblock)
|
delay free a object (put a node to the mblock)
|
||||||
parameters:
|
parameters:
|
||||||
|
|
@ -411,7 +260,7 @@ return the delay free node count of the mblock, return -1 if fail
|
||||||
*/
|
*/
|
||||||
int fast_mblock_delay_free_count(struct fast_mblock_man *mblock);
|
int fast_mblock_delay_free_count(struct fast_mblock_man *mblock);
|
||||||
|
|
||||||
#define fast_mblock_total_count(mblock) (mblock)->info.element_total_count
|
#define fast_mblock_total_count(mblock) (mblock)->total_count
|
||||||
|
|
||||||
/**
|
/**
|
||||||
init mblock manager
|
init mblock manager
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_mpool.c
|
//fast_mpool.c
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -48,10 +33,6 @@ int fast_mpool_init(struct fast_mpool_man *mpool,
|
||||||
|
|
||||||
mpool->malloc_chain_head = NULL;
|
mpool->malloc_chain_head = NULL;
|
||||||
mpool->free_chain_head = NULL;
|
mpool->free_chain_head = NULL;
|
||||||
mpool->alloc_count = 0;
|
|
||||||
mpool->alloc_bytes = 0;
|
|
||||||
mpool->reset.count = 0;
|
|
||||||
mpool->reset.last_alloc_count = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -63,10 +44,14 @@ static int fast_mpool_prealloc(struct fast_mpool_man *mpool,
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
bytes = sizeof(struct fast_mpool_malloc) + alloc_size;
|
bytes = sizeof(struct fast_mpool_malloc) + alloc_size;
|
||||||
pMallocNode = (struct fast_mpool_malloc *)fc_malloc(bytes);
|
pMallocNode = (struct fast_mpool_malloc *)malloc(bytes);
|
||||||
if (pMallocNode == NULL)
|
if (pMallocNode == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, bytes, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
pMallocNode->alloc_size = alloc_size;
|
pMallocNode->alloc_size = alloc_size;
|
||||||
|
|
@ -142,8 +127,6 @@ static inline void *fast_mpool_do_alloc(struct fast_mpool_man *mpool,
|
||||||
fast_mpool_remove_free_node(mpool, pMallocNode);
|
fast_mpool_remove_free_node(mpool, pMallocNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpool->alloc_count++;
|
|
||||||
mpool->alloc_bytes += size;
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -182,50 +165,24 @@ void *fast_mpool_alloc(struct fast_mpool_man *mpool, const int size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *fast_mpool_memdup(struct fast_mpool_man *mpool,
|
|
||||||
const void *src, const int len)
|
|
||||||
{
|
|
||||||
void *dest;
|
|
||||||
dest = (char *)fast_mpool_alloc(mpool, len);
|
|
||||||
if (dest == NULL)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"alloc %d bytes from mpool fail", __LINE__, len);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
memcpy(dest, src, len);
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fast_mpool_reset(struct fast_mpool_man *mpool)
|
void fast_mpool_reset(struct fast_mpool_man *mpool)
|
||||||
{
|
{
|
||||||
struct fast_mpool_malloc *pMallocNode;
|
struct fast_mpool_malloc *pMallocNode;
|
||||||
|
|
||||||
mpool->reset.count++;
|
mpool->free_chain_head = NULL;
|
||||||
if (mpool->reset.last_alloc_count == mpool->alloc_count)
|
pMallocNode = mpool->malloc_chain_head;
|
||||||
{
|
while (pMallocNode != NULL)
|
||||||
return;
|
{
|
||||||
}
|
|
||||||
|
|
||||||
mpool->reset.last_alloc_count = mpool->alloc_count;
|
|
||||||
mpool->free_chain_head = NULL;
|
|
||||||
pMallocNode = mpool->malloc_chain_head;
|
|
||||||
while (pMallocNode != NULL)
|
|
||||||
{
|
|
||||||
pMallocNode->free_ptr = pMallocNode->base_ptr;
|
pMallocNode->free_ptr = pMallocNode->base_ptr;
|
||||||
|
|
||||||
pMallocNode->free_next = mpool->free_chain_head;
|
pMallocNode->free_next = mpool->free_chain_head;
|
||||||
mpool->free_chain_head = pMallocNode;
|
mpool->free_chain_head = pMallocNode;
|
||||||
|
|
||||||
pMallocNode = pMallocNode->malloc_next;
|
pMallocNode = pMallocNode->malloc_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fast_mpool_stats(struct fast_mpool_man *mpool,
|
void fast_mpool_stats(struct fast_mpool_man *mpool, struct fast_mpool_stats *stats)
|
||||||
struct fast_mpool_stats *stats)
|
|
||||||
{
|
{
|
||||||
struct fast_mpool_malloc *pMallocNode;
|
struct fast_mpool_malloc *pMallocNode;
|
||||||
|
|
||||||
|
|
@ -238,8 +195,7 @@ void fast_mpool_stats(struct fast_mpool_man *mpool,
|
||||||
while (pMallocNode != NULL)
|
while (pMallocNode != NULL)
|
||||||
{
|
{
|
||||||
stats->total_bytes += pMallocNode->alloc_size;
|
stats->total_bytes += pMallocNode->alloc_size;
|
||||||
stats->free_bytes += (int)(pMallocNode->end_ptr -
|
stats->free_bytes += (int)(pMallocNode->end_ptr - pMallocNode->free_ptr);
|
||||||
pMallocNode->free_ptr);
|
|
||||||
stats->total_trunk_count++;
|
stats->total_trunk_count++;
|
||||||
|
|
||||||
pMallocNode = pMallocNode->malloc_next;
|
pMallocNode = pMallocNode->malloc_next;
|
||||||
|
|
@ -253,25 +209,3 @@ void fast_mpool_stats(struct fast_mpool_man *mpool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fast_mpool_log_stats(struct fast_mpool_man *mpool)
|
|
||||||
{
|
|
||||||
struct fast_mpool_stats stats;
|
|
||||||
char sz_total_bytes[32];
|
|
||||||
char sz_free_bytes[32];
|
|
||||||
char sz_alloc_bytes[32];
|
|
||||||
|
|
||||||
fast_mpool_stats(mpool, &stats);
|
|
||||||
|
|
||||||
long_to_comma_str(stats.total_bytes, sz_total_bytes);
|
|
||||||
long_to_comma_str(stats.free_bytes, sz_free_bytes);
|
|
||||||
long_to_comma_str(mpool->alloc_bytes, sz_alloc_bytes);
|
|
||||||
logInfo("alloc_size_once: %d, discard_size: %d, "
|
|
||||||
"bytes: {total: %s, free: %s}, "
|
|
||||||
"trunk_count: {total: %d, free: %d}, "
|
|
||||||
"alloc_count: %"PRId64", alloc_bytes: %s, "
|
|
||||||
"reset_count: %"PRId64, mpool->alloc_size_once,
|
|
||||||
mpool->discard_size, sz_total_bytes,
|
|
||||||
sz_free_bytes, stats.total_trunk_count,
|
|
||||||
stats.free_trunk_count, mpool->alloc_count,
|
|
||||||
sz_alloc_bytes, mpool->reset.count);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
135
src/fast_mpool.h
135
src/fast_mpool.h
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_mpool.h
|
//fast_mpool.h
|
||||||
|
|
||||||
|
|
@ -37,16 +30,10 @@ struct fast_mpool_malloc
|
||||||
|
|
||||||
struct fast_mpool_man
|
struct fast_mpool_man
|
||||||
{
|
{
|
||||||
struct fast_mpool_malloc *malloc_chain_head; //malloc chain to be freed
|
struct fast_mpool_malloc *malloc_chain_head; //malloc chain to be freed
|
||||||
struct fast_mpool_malloc *free_chain_head; //free node chain
|
struct fast_mpool_malloc *free_chain_head; //free node chain
|
||||||
int alloc_size_once; //alloc size once, default: 1MB
|
int alloc_size_once; //alloc size once, default: 1MB
|
||||||
int discard_size; //discard size, default: 64 bytes
|
int discard_size; //discard size, default: 64 bytes
|
||||||
int64_t alloc_count;
|
|
||||||
int64_t alloc_bytes;
|
|
||||||
struct {
|
|
||||||
int64_t count;
|
|
||||||
int64_t last_alloc_count;
|
|
||||||
} reset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fast_mpool_stats
|
struct fast_mpool_stats
|
||||||
|
|
@ -95,111 +82,13 @@ return the alloced ptr, return NULL if fail
|
||||||
*/
|
*/
|
||||||
void *fast_mpool_alloc(struct fast_mpool_man *mpool, const int size);
|
void *fast_mpool_alloc(struct fast_mpool_man *mpool, const int size);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc and copy memory from the mpool
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
src: the source memory pointer
|
|
||||||
len: the length of the source memory
|
|
||||||
return alloc and duplicate memory pointer, NULL for fail
|
|
||||||
*/
|
|
||||||
void *fast_mpool_memdup(struct fast_mpool_man *mpool,
|
|
||||||
const void *src, const int len);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc and copy string from the mpool
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
src: the source '\0' terminated string
|
|
||||||
len: the length of the source string
|
|
||||||
return alloc and duplicate string pointer, NULL for fail
|
|
||||||
*/
|
|
||||||
static inline char *fast_mpool_strdup_ex(struct fast_mpool_man *mpool,
|
|
||||||
const char *src, const int len)
|
|
||||||
{
|
|
||||||
return (char *)fast_mpool_memdup(mpool, src, len + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc and copy string from the mpool
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
src: the source '\0' terminated string
|
|
||||||
len: the length of the source string
|
|
||||||
return alloc and duplicate string pointer, NULL for fail
|
|
||||||
*/
|
|
||||||
static inline char *fast_mpool_strdup(struct fast_mpool_man *mpool,
|
|
||||||
const char *src)
|
|
||||||
{
|
|
||||||
return (char *)fast_mpool_memdup(mpool, src, strlen(src) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc and copy string from the mpool
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
dest: the dest string (return the alloced memory in dest->str)
|
|
||||||
src: the source string
|
|
||||||
len: the length of the source string
|
|
||||||
return error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
static inline int fast_mpool_alloc_string_ex(struct fast_mpool_man *mpool,
|
|
||||||
string_t *dest, const char *src, const int len)
|
|
||||||
{
|
|
||||||
dest->str = (char *)fast_mpool_memdup(mpool, src, len);
|
|
||||||
dest->len = len;
|
|
||||||
return dest->str != NULL ? 0 : ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc and copy string from the mpool
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
dest: the dest string (return the alloced memory in dest->str)
|
|
||||||
src: the source string
|
|
||||||
return error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
static inline int fast_mpool_alloc_string(struct fast_mpool_man *mpool,
|
|
||||||
string_t *dest, const char *src)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
len = (src != NULL) ? strlen(src) : 0;
|
|
||||||
return fast_mpool_alloc_string_ex(mpool, dest, src, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc and copy string from the mpool
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
dest: the dest string (return the alloced memory in dest->str)
|
|
||||||
src: the source string
|
|
||||||
return error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
static inline int fast_mpool_alloc_string_ex2(struct fast_mpool_man *mpool,
|
|
||||||
string_t *dest, const string_t *src)
|
|
||||||
{
|
|
||||||
return fast_mpool_alloc_string_ex(mpool, dest, src->str, src->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
get stats
|
get stats
|
||||||
parameters:
|
parameters:
|
||||||
mpool: the mpool pointer
|
mpool: the mpool pointer
|
||||||
stats: return the stats
|
stats: return the stats
|
||||||
return none
|
|
||||||
*/
|
*/
|
||||||
void fast_mpool_stats(struct fast_mpool_man *mpool,
|
void fast_mpool_stats(struct fast_mpool_man *mpool, struct fast_mpool_stats *stats);
|
||||||
struct fast_mpool_stats *stats);
|
|
||||||
|
|
||||||
/**
|
|
||||||
log stats info
|
|
||||||
parameters:
|
|
||||||
mpool: the mpool pointer
|
|
||||||
return none
|
|
||||||
*/
|
|
||||||
void fast_mpool_log_stats(struct fast_mpool_man *mpool);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,238 +1,676 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_task_queue.c
|
//fast_task_queue.c
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include "fast_task_queue.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "shared_func.h"
|
#include "shared_func.h"
|
||||||
#include "pthread_func.h"
|
#include "pthread_func.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "fast_task_queue.h"
|
|
||||||
|
|
||||||
static int task_alloc_init(struct fast_task_info *task,
|
static struct fast_task_queue g_free_queue;
|
||||||
struct fast_task_queue *queue)
|
|
||||||
|
struct mpool_node {
|
||||||
|
struct fast_task_info *blocks;
|
||||||
|
struct fast_task_info *last_block; //last block
|
||||||
|
struct mpool_node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mpool_chain {
|
||||||
|
struct mpool_node *head;
|
||||||
|
struct mpool_node *tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mpool_chain g_mpool = {NULL, NULL};
|
||||||
|
|
||||||
|
int task_queue_init(struct fast_task_queue *pQueue)
|
||||||
{
|
{
|
||||||
task->arg = (char *)task + ALIGNED_TASK_INFO_SIZE + queue->padding_size;
|
int result;
|
||||||
task->send.ptr = &task->send.holder;
|
|
||||||
task->send.ptr->size = queue->min_buff_size;
|
|
||||||
if (queue->malloc_whole_block) {
|
|
||||||
task->send.ptr->data = (char *)task->arg + queue->arg_size;
|
|
||||||
} else {
|
|
||||||
task->send.ptr->data = (char *)fc_malloc(task->send.ptr->size);
|
|
||||||
if (task->send.ptr->data == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queue->double_buffers) {
|
if ((result=init_pthread_lock(&(pQueue->lock))) != 0)
|
||||||
task->recv.ptr = &task->recv.holder;
|
{
|
||||||
task->recv.ptr->size = queue->min_buff_size;
|
logError("file: "__FILE__", line: %d, " \
|
||||||
task->recv.ptr->data = (char *)fc_malloc(task->recv.ptr->size);
|
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||||
if (task->recv.ptr->data == NULL) {
|
__LINE__, result, STRERROR(result));
|
||||||
return ENOMEM;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
task->recv.ptr = &task->send.holder;
|
|
||||||
}
|
|
||||||
|
|
||||||
task->free_queue = queue;
|
pQueue->head = NULL;
|
||||||
if (queue->init_callback != NULL) {
|
pQueue->tail = NULL;
|
||||||
return queue->init_callback(task, queue->init_arg);
|
|
||||||
}
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int free_queue_init_ex2(struct fast_task_queue *queue, const char *name,
|
static struct mpool_node *malloc_mpool(const int total_alloc_size)
|
||||||
const bool double_buffers, const bool need_shrink,
|
{
|
||||||
const int max_connections, const int alloc_task_once,
|
struct fast_task_info *pTask;
|
||||||
const int min_buff_size, const int max_buff_size,
|
char *p;
|
||||||
const int padding_size, const int arg_size,
|
char *pCharEnd;
|
||||||
TaskInitCallback init_callback, void *init_arg)
|
struct mpool_node *mpool;
|
||||||
|
|
||||||
|
mpool = (struct mpool_node *)malloc(sizeof(struct mpool_node));
|
||||||
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, (int)sizeof(struct mpool_node), \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpool->next = NULL;
|
||||||
|
mpool->blocks = (struct fast_task_info *)malloc(total_alloc_size);
|
||||||
|
if (mpool->blocks == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, total_alloc_size, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
free(mpool);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(mpool->blocks, 0, total_alloc_size);
|
||||||
|
|
||||||
|
pCharEnd = ((char *)mpool->blocks) + total_alloc_size;
|
||||||
|
for (p=(char *)mpool->blocks; p<pCharEnd; p += g_free_queue.block_size)
|
||||||
|
{
|
||||||
|
pTask = (struct fast_task_info *)p;
|
||||||
|
pTask->size = g_free_queue.min_buff_size;
|
||||||
|
|
||||||
|
pTask->arg = p + ALIGNED_TASK_INFO_SIZE;
|
||||||
|
if (g_free_queue.malloc_whole_block)
|
||||||
|
{
|
||||||
|
pTask->data = (char *)pTask->arg + \
|
||||||
|
g_free_queue.arg_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pTask->data = (char *)malloc(pTask->size);
|
||||||
|
if (pTask->data == NULL)
|
||||||
|
{
|
||||||
|
char *pt;
|
||||||
|
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, pTask->size, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
|
||||||
|
for (pt=(char *)mpool->blocks; pt < p; \
|
||||||
|
pt += g_free_queue.block_size)
|
||||||
|
{
|
||||||
|
free(((struct fast_task_info *)pt)->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(mpool->blocks);
|
||||||
|
free(mpool);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpool->last_block = (struct fast_task_info *)(pCharEnd - g_free_queue.block_size);
|
||||||
|
for (p=(char *)mpool->blocks; p<(char *)mpool->last_block; p += g_free_queue.block_size)
|
||||||
|
{
|
||||||
|
pTask = (struct fast_task_info *)p;
|
||||||
|
pTask->next = (struct fast_task_info *)(p + g_free_queue.block_size);
|
||||||
|
}
|
||||||
|
mpool->last_block->next = NULL;
|
||||||
|
|
||||||
|
return mpool;
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_init_ex(const int max_connections, const int init_connections,
|
||||||
|
const int alloc_task_once, const int min_buff_size,
|
||||||
|
const int max_buff_size, const int arg_size)
|
||||||
{
|
{
|
||||||
#define MAX_DATA_SIZE (256 * 1024 * 1024)
|
#define MAX_DATA_SIZE (256 * 1024 * 1024)
|
||||||
|
int64_t total_size;
|
||||||
|
struct mpool_node *mpool;
|
||||||
|
int alloc_size;
|
||||||
int alloc_once;
|
int alloc_once;
|
||||||
|
int result;
|
||||||
|
int loop_count;
|
||||||
int aligned_min_size;
|
int aligned_min_size;
|
||||||
int aligned_max_size;
|
int aligned_max_size;
|
||||||
int aligned_padding_size;
|
|
||||||
int aligned_arg_size;
|
int aligned_arg_size;
|
||||||
rlim_t max_data_size;
|
rlim_t max_data_size;
|
||||||
char aname[64];
|
|
||||||
|
if ((result=init_pthread_lock(&(g_free_queue.lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
aligned_min_size = MEM_ALIGN(min_buff_size);
|
aligned_min_size = MEM_ALIGN(min_buff_size);
|
||||||
aligned_max_size = MEM_ALIGN(max_buff_size);
|
aligned_max_size = MEM_ALIGN(max_buff_size);
|
||||||
aligned_padding_size = MEM_ALIGN(padding_size);
|
|
||||||
aligned_arg_size = MEM_ALIGN(arg_size);
|
aligned_arg_size = MEM_ALIGN(arg_size);
|
||||||
queue->block_size = ALIGNED_TASK_INFO_SIZE +
|
g_free_queue.block_size = ALIGNED_TASK_INFO_SIZE + aligned_arg_size;
|
||||||
aligned_padding_size + aligned_arg_size;
|
alloc_size = g_free_queue.block_size * init_connections;
|
||||||
if (alloc_task_once <= 0) {
|
if (aligned_max_size > aligned_min_size)
|
||||||
alloc_once = FC_MIN(MAX_DATA_SIZE / queue->block_size, 256);
|
{
|
||||||
if (alloc_once == 0) {
|
total_size = alloc_size;
|
||||||
alloc_once = 1;
|
g_free_queue.malloc_whole_block = false;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alloc_once = alloc_task_once;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aligned_max_size > aligned_min_size) {
|
|
||||||
queue->malloc_whole_block = false;
|
|
||||||
max_data_size = 0;
|
max_data_size = 0;
|
||||||
} else {
|
}
|
||||||
struct rlimit rlimit_data;
|
else
|
||||||
|
{
|
||||||
|
struct rlimit rlimit_data;
|
||||||
|
|
||||||
if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0) {
|
if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0)
|
||||||
logError("file: "__FILE__", line: %d, "
|
{
|
||||||
"call getrlimit fail, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"call getrlimit fail, " \
|
||||||
__LINE__, errno, STRERROR(errno));
|
"errno: %d, error info: %s", \
|
||||||
return errno != 0 ? errno : EPERM;
|
__LINE__, errno, STRERROR(errno));
|
||||||
}
|
return errno != 0 ? errno : EPERM;
|
||||||
if (rlimit_data.rlim_cur == RLIM_INFINITY) {
|
}
|
||||||
max_data_size = MAX_DATA_SIZE;
|
if (rlimit_data.rlim_cur == RLIM_INFINITY)
|
||||||
} else {
|
{
|
||||||
max_data_size = rlimit_data.rlim_cur;
|
max_data_size = MAX_DATA_SIZE;
|
||||||
if (max_data_size > MAX_DATA_SIZE) {
|
}
|
||||||
max_data_size = MAX_DATA_SIZE;
|
else
|
||||||
}
|
{
|
||||||
}
|
max_data_size = rlimit_data.rlim_cur;
|
||||||
|
if (max_data_size > MAX_DATA_SIZE)
|
||||||
|
{
|
||||||
|
max_data_size = MAX_DATA_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (max_data_size >= (int64_t)(queue->block_size +
|
if (max_data_size >= (int64_t)(g_free_queue.block_size + aligned_min_size) *
|
||||||
aligned_min_size) * (int64_t)alloc_once)
|
(int64_t)init_connections)
|
||||||
|
{
|
||||||
|
total_size = alloc_size + (int64_t)aligned_min_size *
|
||||||
|
init_connections;
|
||||||
|
g_free_queue.malloc_whole_block = true;
|
||||||
|
g_free_queue.block_size += aligned_min_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
total_size = alloc_size;
|
||||||
|
g_free_queue.malloc_whole_block = false;
|
||||||
|
max_data_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free_queue.max_connections = max_connections;
|
||||||
|
g_free_queue.alloc_connections = init_connections;
|
||||||
|
if (alloc_task_once <= 0)
|
||||||
|
{
|
||||||
|
g_free_queue.alloc_task_once = 256;
|
||||||
|
alloc_once = MAX_DATA_SIZE / g_free_queue.block_size;
|
||||||
|
if (g_free_queue.alloc_task_once > alloc_once)
|
||||||
{
|
{
|
||||||
queue->malloc_whole_block = true;
|
g_free_queue.alloc_task_once = alloc_once > 0 ? alloc_once : 1;
|
||||||
queue->block_size += aligned_min_size;
|
|
||||||
} else {
|
|
||||||
queue->malloc_whole_block = false;
|
|
||||||
max_data_size = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_free_queue.alloc_task_once = alloc_task_once;
|
||||||
|
}
|
||||||
|
g_free_queue.min_buff_size = aligned_min_size;
|
||||||
|
g_free_queue.max_buff_size = aligned_max_size;
|
||||||
|
g_free_queue.arg_size = aligned_arg_size;
|
||||||
|
|
||||||
queue->double_buffers = double_buffers;
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
queue->need_shrink = need_shrink;
|
"max_connections: %d, init_connections: %d, alloc_task_once: %d, "
|
||||||
queue->min_buff_size = aligned_min_size;
|
|
||||||
queue->max_buff_size = aligned_max_size;
|
|
||||||
queue->padding_size = aligned_padding_size;
|
|
||||||
queue->arg_size = aligned_arg_size;
|
|
||||||
queue->init_callback = init_callback;
|
|
||||||
queue->init_arg = init_arg;
|
|
||||||
queue->release_callback = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
logInfo("file: "__FILE__", line: %d, [%s] double_buffers: %d, "
|
|
||||||
"max_connections: %d, alloc_once: %d, malloc_whole_block: %d, "
|
|
||||||
"min_buff_size: %d, max_buff_size: %d, block_size: %d, "
|
"min_buff_size: %d, max_buff_size: %d, block_size: %d, "
|
||||||
"padding_size: %d, arg_size: %d, max_data_size: %"PRId64,
|
"arg_size: %d, max_data_size: %d, total_size: %"PRId64,
|
||||||
__LINE__, name, double_buffers, max_connections, alloc_once,
|
__LINE__, max_connections, init_connections,
|
||||||
queue->malloc_whole_block, aligned_min_size, aligned_max_size,
|
g_free_queue.alloc_task_once, aligned_min_size, aligned_max_size,
|
||||||
queue->block_size, aligned_padding_size, aligned_arg_size,
|
g_free_queue.block_size, aligned_arg_size, (int)max_data_size, total_size);
|
||||||
(int64_t)max_data_size);
|
|
||||||
*/
|
|
||||||
|
|
||||||
fc_combine_two_strings(name, "task", '-', aname);
|
if ((!g_free_queue.malloc_whole_block) || (total_size <= max_data_size))
|
||||||
return fast_mblock_init_ex1(&queue->allocator, aname,
|
{
|
||||||
queue->block_size, alloc_once, max_connections,
|
loop_count = 1;
|
||||||
(fast_mblock_object_init_func)task_alloc_init,
|
mpool = malloc_mpool(total_size);
|
||||||
queue, true);
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
g_mpool.head = mpool;
|
||||||
|
g_mpool.tail = mpool;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int remain_count;
|
||||||
|
int alloc_count;
|
||||||
|
int current_alloc_size;
|
||||||
|
|
||||||
|
loop_count = 0;
|
||||||
|
remain_count = init_connections;
|
||||||
|
alloc_once = max_data_size / g_free_queue.block_size;
|
||||||
|
while (remain_count > 0)
|
||||||
|
{
|
||||||
|
alloc_count = (remain_count > alloc_once) ?
|
||||||
|
alloc_once : remain_count;
|
||||||
|
current_alloc_size = g_free_queue.block_size * alloc_count;
|
||||||
|
mpool = malloc_mpool(current_alloc_size);
|
||||||
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
free_queue_destroy();
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_mpool.tail == NULL)
|
||||||
|
{
|
||||||
|
g_mpool.head = mpool;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_mpool.tail->next = mpool;
|
||||||
|
g_mpool.tail->last_block->next = mpool->blocks; //link previous mpool to current
|
||||||
|
}
|
||||||
|
g_mpool.tail = mpool;
|
||||||
|
|
||||||
|
remain_count -= alloc_count;
|
||||||
|
loop_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"alloc_once: %d", __LINE__, alloc_once);
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc task info as whole: %d, malloc loop count: %d", \
|
||||||
|
__LINE__, g_free_queue.malloc_whole_block, loop_count);
|
||||||
|
|
||||||
|
if (g_mpool.head != NULL)
|
||||||
|
{
|
||||||
|
g_free_queue.head = g_mpool.head->blocks;
|
||||||
|
g_free_queue.tail = g_mpool.tail->last_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_queue_destroy(struct fast_task_queue *queue)
|
int free_queue_init(const int max_connections, const int min_buff_size,
|
||||||
|
const int max_buff_size, const int arg_size)
|
||||||
{
|
{
|
||||||
fast_mblock_destroy(&queue->allocator);
|
return free_queue_init_ex(max_connections, max_connections,
|
||||||
|
0, min_buff_size, max_buff_size, arg_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _realloc_buffer(struct fast_net_buffer *buffer,
|
void free_queue_destroy()
|
||||||
const int new_size, const bool copy_data)
|
|
||||||
{
|
{
|
||||||
char *new_buff;
|
struct mpool_node *mpool;
|
||||||
|
struct mpool_node *mp;
|
||||||
|
|
||||||
new_buff = (char *)fc_malloc(new_size);
|
if (g_mpool.head == NULL)
|
||||||
if (new_buff == NULL) {
|
{
|
||||||
return ENOMEM;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_free_queue.malloc_whole_block)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *pCharEnd;
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
|
||||||
|
mpool = g_mpool.head;
|
||||||
|
while (mpool != NULL)
|
||||||
|
{
|
||||||
|
pCharEnd = (char *)mpool->last_block + g_free_queue.block_size;
|
||||||
|
for (p=(char *)mpool->blocks; p<pCharEnd; p += g_free_queue.block_size)
|
||||||
|
{
|
||||||
|
pTask = (struct fast_task_info *)p;
|
||||||
|
if (pTask->data != NULL)
|
||||||
|
{
|
||||||
|
free(pTask->data);
|
||||||
|
pTask->data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mpool = mpool->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpool = g_mpool.head;
|
||||||
|
while (mpool != NULL)
|
||||||
|
{
|
||||||
|
mp = mpool;
|
||||||
|
mpool = mpool->next;
|
||||||
|
|
||||||
|
free(mp->blocks);
|
||||||
|
free(mp);
|
||||||
|
}
|
||||||
|
g_mpool.head = g_mpool.tail = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&(g_free_queue.lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int free_queue_realloc()
|
||||||
|
{
|
||||||
|
struct mpool_node *mpool;
|
||||||
|
struct fast_task_info *head;
|
||||||
|
struct fast_task_info *tail;
|
||||||
|
int remain_count;
|
||||||
|
int alloc_count;
|
||||||
|
int current_alloc_size;
|
||||||
|
|
||||||
|
head = tail = NULL;
|
||||||
|
remain_count = g_free_queue.max_connections -
|
||||||
|
g_free_queue.alloc_connections;
|
||||||
|
alloc_count = (remain_count > g_free_queue.alloc_task_once) ?
|
||||||
|
g_free_queue.alloc_task_once : remain_count;
|
||||||
|
if (alloc_count > 0)
|
||||||
|
{
|
||||||
|
current_alloc_size = g_free_queue.block_size * alloc_count;
|
||||||
|
mpool = malloc_mpool(current_alloc_size);
|
||||||
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_mpool.tail == NULL)
|
||||||
|
{
|
||||||
|
g_mpool.head = mpool;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_mpool.tail->next = mpool;
|
||||||
|
}
|
||||||
|
g_mpool.tail = mpool;
|
||||||
|
|
||||||
|
head = mpool->blocks;
|
||||||
|
tail = mpool->last_block;
|
||||||
|
|
||||||
|
remain_count -= alloc_count;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copy_data && buffer->offset > 0) {
|
if (g_free_queue.head == NULL)
|
||||||
memcpy(new_buff, buffer->data, buffer->offset);
|
{
|
||||||
|
g_free_queue.head = head;
|
||||||
}
|
}
|
||||||
free(buffer->data);
|
if (g_free_queue.tail != NULL)
|
||||||
buffer->size = new_size;
|
{
|
||||||
buffer->data = new_buff;
|
g_free_queue.tail->next = head;
|
||||||
|
}
|
||||||
|
g_free_queue.tail = tail;
|
||||||
|
|
||||||
|
g_free_queue.alloc_connections += alloc_count;
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
|
"alloc_connections: %d, realloc %d elements", __LINE__,
|
||||||
|
g_free_queue.alloc_connections, alloc_count);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_queue_push(struct fast_task_info *task)
|
struct fast_task_info *free_queue_pop()
|
||||||
{
|
{
|
||||||
if (task->free_queue->release_callback != NULL) {
|
struct fast_task_info *pTask;
|
||||||
task->free_queue->release_callback(task);
|
int i;
|
||||||
|
|
||||||
|
if ((pTask=task_queue_pop(&g_free_queue)) != NULL)
|
||||||
|
{
|
||||||
|
return pTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
*(task->client_ip) = '\0';
|
if (g_free_queue.alloc_connections >= g_free_queue.max_connections)
|
||||||
task->send.ptr->length = 0;
|
{
|
||||||
task->send.ptr->offset = 0;
|
return NULL;
|
||||||
task->req_count = 0;
|
|
||||||
if (task->free_queue->need_shrink && task->send.
|
|
||||||
ptr->size > task->free_queue->min_buff_size)
|
|
||||||
{ //need thrink
|
|
||||||
_realloc_buffer(task->send.ptr, task->free_queue->
|
|
||||||
min_buff_size, false);
|
|
||||||
task->shrinked = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task->free_queue->double_buffers) {
|
for (i=0; i<10; i++)
|
||||||
task->recv.ptr->length = 0;
|
{
|
||||||
task->recv.ptr->offset = 0;
|
pthread_mutex_lock(&g_free_queue.lock);
|
||||||
if (task->free_queue->need_shrink && task->recv.
|
if (g_free_queue.alloc_connections >= g_free_queue.max_connections)
|
||||||
ptr->size > task->free_queue->min_buff_size)
|
|
||||||
{
|
{
|
||||||
_realloc_buffer(task->recv.ptr, task->free_queue->
|
if (g_free_queue.head == NULL)
|
||||||
min_buff_size, false);
|
{
|
||||||
task->shrinked = true;
|
pthread_mutex_unlock(&g_free_queue.lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_free_queue.head == NULL && free_queue_realloc() != 0)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&g_free_queue.lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&g_free_queue.lock);
|
||||||
|
|
||||||
|
if ((pTask=task_queue_pop(&g_free_queue)) != NULL)
|
||||||
|
{
|
||||||
|
return pTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fast_mblock_free_object(&task->free_queue->allocator, task);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int free_queue_get_new_buffer_size(const int min_buff_size,
|
static int _realloc_buffer(struct fast_task_info *pTask, const int new_size,
|
||||||
|
const bool copy_data)
|
||||||
|
{
|
||||||
|
char *new_buff;
|
||||||
|
new_buff = (char *)malloc(new_size);
|
||||||
|
if (new_buff == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, "
|
||||||
|
"errno: %d, error info: %s",
|
||||||
|
__LINE__, new_size,
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (copy_data && pTask->offset > 0) {
|
||||||
|
memcpy(new_buff, pTask->data, pTask->offset);
|
||||||
|
}
|
||||||
|
free(pTask->data);
|
||||||
|
pTask->size = new_size;
|
||||||
|
pTask->data = new_buff;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_push(struct fast_task_info *pTask)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
*(pTask->client_ip) = '\0';
|
||||||
|
pTask->length = 0;
|
||||||
|
pTask->offset = 0;
|
||||||
|
pTask->req_count = 0;
|
||||||
|
|
||||||
|
if (pTask->size > g_free_queue.min_buff_size) //need thrink
|
||||||
|
{
|
||||||
|
_realloc_buffer(pTask, g_free_queue.min_buff_size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&g_free_queue.lock)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask->next = g_free_queue.head;
|
||||||
|
g_free_queue.head = pTask;
|
||||||
|
if (g_free_queue.tail == NULL)
|
||||||
|
{
|
||||||
|
g_free_queue.tail = pTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&g_free_queue.lock)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_count()
|
||||||
|
{
|
||||||
|
return task_queue_count(&g_free_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_alloc_connections()
|
||||||
|
{
|
||||||
|
return g_free_queue.alloc_connections;
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_set_buffer_size(struct fast_task_info *pTask,
|
||||||
|
const int expect_size)
|
||||||
|
{
|
||||||
|
return task_queue_set_buffer_size(&g_free_queue, pTask, expect_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_realloc_buffer(struct fast_task_info *pTask,
|
||||||
|
const int expect_size)
|
||||||
|
{
|
||||||
|
return task_queue_realloc_buffer(&g_free_queue, pTask, expect_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int task_queue_push(struct fast_task_queue *pQueue, \
|
||||||
|
struct fast_task_info *pTask)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask->next = NULL;
|
||||||
|
if (pQueue->tail == NULL)
|
||||||
|
{
|
||||||
|
pQueue->head = pTask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pQueue->tail->next = pTask;
|
||||||
|
}
|
||||||
|
pQueue->tail = pTask;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue)
|
||||||
|
{
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask = pQueue->head;
|
||||||
|
if (pTask != NULL)
|
||||||
|
{
|
||||||
|
pQueue->head = pTask->next;
|
||||||
|
if (pQueue->head == NULL)
|
||||||
|
{
|
||||||
|
pQueue->tail = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int task_queue_count(struct fast_task_queue *pQueue)
|
||||||
|
{
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
int count;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
pTask = pQueue->head;
|
||||||
|
while (pTask != NULL)
|
||||||
|
{
|
||||||
|
pTask = pTask->next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int task_queue_get_new_buffer_size(const int min_buff_size,
|
||||||
const int max_buff_size, const int expect_size, int *new_size)
|
const int max_buff_size, const int expect_size, int *new_size)
|
||||||
{
|
{
|
||||||
if (min_buff_size == max_buff_size) {
|
if (min_buff_size == max_buff_size)
|
||||||
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"can't change buffer size because NOT supported", __LINE__);
|
"can't change buffer size because NOT supported", __LINE__);
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expect_size > max_buff_size) {
|
if (expect_size > max_buff_size)
|
||||||
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"can't change buffer size because expect buffer size: %d "
|
"can't change buffer size because expect buffer size: %d "
|
||||||
"exceeds max buffer size: %d", __LINE__, expect_size,
|
"exceeds max buffer size: %d", __LINE__, expect_size,
|
||||||
max_buff_size);
|
max_buff_size);
|
||||||
return EOVERFLOW;
|
return EOVERFLOW;
|
||||||
} else if (expect_size == max_buff_size) {
|
|
||||||
*new_size = max_buff_size;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*new_size = min_buff_size;
|
*new_size = min_buff_size;
|
||||||
if (expect_size > min_buff_size) {
|
if (expect_size > min_buff_size)
|
||||||
while (*new_size < expect_size) {
|
{
|
||||||
|
while (*new_size < expect_size)
|
||||||
|
{
|
||||||
*new_size *= 2;
|
*new_size *= 2;
|
||||||
}
|
}
|
||||||
if (*new_size > max_buff_size) {
|
if (*new_size > max_buff_size)
|
||||||
|
{
|
||||||
*new_size = max_buff_size;
|
*new_size = max_buff_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -240,43 +678,42 @@ int free_queue_get_new_buffer_size(const int min_buff_size,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _get_new_buffer_size(queue, expect_size, new_size) \
|
#define _get_new_buffer_size(pQueue, expect_size, new_size) \
|
||||||
free_queue_get_new_buffer_size(queue->min_buff_size, \
|
task_queue_get_new_buffer_size(pQueue->min_buff_size, \
|
||||||
queue->max_buff_size, expect_size, new_size)
|
pQueue->max_buff_size, expect_size, new_size)
|
||||||
|
|
||||||
int free_queue_set_buffer_size(struct fast_task_info *task,
|
int task_queue_set_buffer_size(struct fast_task_queue *pQueue,
|
||||||
struct fast_net_buffer *buffer, const int expect_size)
|
struct fast_task_info *pTask, const int expect_size)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int new_size;
|
int new_size;
|
||||||
|
|
||||||
if ((result=_get_new_buffer_size(task->free_queue,
|
if ((result=_get_new_buffer_size(pQueue, expect_size, &new_size)) != 0) {
|
||||||
expect_size, &new_size)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (buffer->size == new_size) { //do NOT need change buffer size
|
if (pTask->size == new_size) //do NOT need change buffer size
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _realloc_buffer(buffer, new_size, false);
|
return _realloc_buffer(pTask, new_size, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int free_queue_realloc_buffer(struct fast_task_info *task,
|
int task_queue_realloc_buffer(struct fast_task_queue *pQueue,
|
||||||
struct fast_net_buffer *buffer, const int expect_size)
|
struct fast_task_info *pTask, const int expect_size)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int new_size;
|
int new_size;
|
||||||
|
|
||||||
if (buffer->size >= expect_size) { //do NOT need change buffer size
|
if (pTask->size >= expect_size) //do NOT need change buffer size
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=_get_new_buffer_size(task->free_queue,
|
if ((result=_get_new_buffer_size(pQueue, expect_size, &new_size)) != 0) {
|
||||||
expect_size, &new_size)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _realloc_buffer(buffer, new_size, true);
|
return _realloc_buffer(pTask, new_size, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fast_task_queue.h
|
//fast_task_queue.h
|
||||||
|
|
||||||
|
|
@ -23,13 +16,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include "fc_list.h"
|
|
||||||
#include "ioevent.h"
|
#include "ioevent.h"
|
||||||
#include "fast_timer.h"
|
#include "fast_timer.h"
|
||||||
#include "fast_mblock.h"
|
|
||||||
|
|
||||||
#define FC_NOTIFY_READ_FD(tdata) (tdata)->pipe_fds[0]
|
|
||||||
#define FC_NOTIFY_WRITE_FD(tdata) (tdata)->pipe_fds[1]
|
|
||||||
|
|
||||||
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
|
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
|
||||||
|
|
||||||
|
|
@ -37,279 +25,92 @@ struct nio_thread_data;
|
||||||
struct fast_task_info;
|
struct fast_task_info;
|
||||||
|
|
||||||
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
|
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
|
||||||
typedef void (*TaskCleanUpCallback) (struct fast_task_info *task);
|
typedef int (*TaskFinishCallback) (struct fast_task_info *pTask);
|
||||||
typedef int (*TaskInitCallback)(struct fast_task_info *task, void *arg);
|
typedef void (*TaskCleanUpCallback) (struct fast_task_info *pTask);
|
||||||
typedef void (*TaskReleaseCallback)(struct fast_task_info *task);
|
|
||||||
|
|
||||||
typedef void (*IOEventCallback) (int sock, const int event, void *arg);
|
typedef void (*IOEventCallback) (int sock, short event, void *arg);
|
||||||
typedef int (*TaskContinueCallback)(struct fast_task_info *task);
|
|
||||||
|
|
||||||
struct sf_network_handler;
|
|
||||||
struct fast_task_info;
|
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
#define FC_URING_OP_TYPE(task) (task)->uring.op_type
|
|
||||||
#define FC_URING_IS_CLIENT(task) (task)->uring.is_client
|
|
||||||
#define FC_URING_IS_SEND_ZC(task) ((task)->uring.op_type == IORING_OP_SEND_ZC)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct ioevent_entry
|
typedef struct ioevent_entry
|
||||||
{
|
{
|
||||||
FastTimerEntry timer; //must first
|
int fd;
|
||||||
int fd;
|
FastTimerEntry timer;
|
||||||
int res; //just for io_uring, since v1.0.81
|
IOEventCallback callback;
|
||||||
IOEventCallback callback;
|
|
||||||
} IOEventEntry;
|
} IOEventEntry;
|
||||||
|
|
||||||
struct nio_thread_data
|
struct nio_thread_data
|
||||||
{
|
{
|
||||||
struct ioevent_puller ev_puller;
|
struct ioevent_puller ev_puller;
|
||||||
struct fast_timer timer;
|
struct fast_timer timer;
|
||||||
int pipe_fds[2]; //for notify
|
int pipe_fds[2];
|
||||||
struct fast_task_info *deleted_list; //tasks for cleanup
|
struct fast_task_info *deleted_list;
|
||||||
ThreadLoopCallback thread_loop_callback;
|
ThreadLoopCallback thread_loop_callback;
|
||||||
ThreadLoopCallback busy_polling_callback;
|
|
||||||
void *arg; //extra argument pointer
|
void *arg; //extra argument pointer
|
||||||
struct {
|
|
||||||
struct fast_task_info *head;
|
|
||||||
struct fast_task_info *tail;
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
} waiting_queue; //task queue
|
|
||||||
|
|
||||||
struct {
|
|
||||||
bool enabled;
|
|
||||||
volatile int64_t counter;
|
|
||||||
} notify; //for thread notify
|
|
||||||
|
|
||||||
int timeout_ms; //for restore
|
|
||||||
struct fc_list_head polling_queue; //for RDMA busy polling
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ioevent_notify_entry
|
|
||||||
{
|
|
||||||
IOEventEntry event; //must first
|
|
||||||
struct nio_thread_data *thread_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_net_buffer
|
|
||||||
{
|
|
||||||
int size; //alloc size
|
|
||||||
int length; //data length
|
|
||||||
int offset; //current offset
|
|
||||||
char *data; //buffer for write or read
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_net_buffer_wrapper
|
|
||||||
{
|
|
||||||
struct fast_net_buffer holder;
|
|
||||||
struct fast_net_buffer *ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_task_queue;
|
|
||||||
struct fast_task_info
|
struct fast_task_info
|
||||||
{
|
{
|
||||||
IOEventEntry event; //must first
|
IOEventEntry event; //must first
|
||||||
union {
|
char client_ip[IP_ADDRESS_SIZE];
|
||||||
char server_ip[IP_ADDRESS_SIZE];
|
void *arg; //extra argument pointer
|
||||||
char client_ip[IP_ADDRESS_SIZE];
|
char *data; //buffer for write or recv
|
||||||
};
|
int size; //alloc size
|
||||||
void *arg; //extra argument pointer
|
int length; //data length
|
||||||
char *recv_body; //for extra (dynamic) recv buffer
|
int offset; //current offset
|
||||||
|
int64_t req_count; //request count
|
||||||
struct {
|
TaskFinishCallback finish_callback;
|
||||||
struct iovec *iovs;
|
struct nio_thread_data *thread_data;
|
||||||
int count;
|
struct fast_task_info *next;
|
||||||
} iovec_array; //for writev
|
|
||||||
|
|
||||||
struct fast_net_buffer_wrapper send; //send buffer
|
|
||||||
struct fast_net_buffer_wrapper recv; //recv buffer
|
|
||||||
|
|
||||||
uint16_t port; //peer port
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int8_t is_client;
|
|
||||||
uint8_t op_type;
|
|
||||||
} uring; //just for io_uring, since v1.0.81
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t current;
|
|
||||||
volatile uint8_t notify;
|
|
||||||
} nio_stages; //stages for network IO
|
|
||||||
volatile int8_t canceled; //if task canceled
|
|
||||||
volatile int8_t shrinked; //if task shrinked, since V1.0.81
|
|
||||||
volatile int reffer_count;
|
|
||||||
int pending_send_count;
|
|
||||||
int64_t req_count; //request count
|
|
||||||
struct {
|
|
||||||
int64_t last_req_count;
|
|
||||||
uint32_t last_calc_time;
|
|
||||||
uint16_t continuous_count;
|
|
||||||
bool in_queue;
|
|
||||||
struct fc_list_head dlink; //for polling queue
|
|
||||||
} polling; //for RDMA busy polling
|
|
||||||
TaskContinueCallback continue_callback; //for continue stage
|
|
||||||
struct nio_thread_data *thread_data;
|
|
||||||
struct sf_network_handler *handler; //network handler for libserverframe nio
|
|
||||||
struct fast_task_info *next; //for free queue and deleted list
|
|
||||||
struct fast_task_info *notify_next; //for nio notify queue
|
|
||||||
struct fast_task_queue *free_queue; //task allocator
|
|
||||||
char conn[0]; //for RDMA connection
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fast_task_queue
|
struct fast_task_queue
|
||||||
{
|
{
|
||||||
int min_buff_size;
|
struct fast_task_info *head;
|
||||||
int max_buff_size;
|
struct fast_task_info *tail;
|
||||||
int padding_size; //for last field: conn[0]
|
pthread_mutex_t lock;
|
||||||
int arg_size; //for arg pointer
|
int max_connections;
|
||||||
int block_size;
|
int alloc_connections;
|
||||||
bool malloc_whole_block;
|
int alloc_task_once;
|
||||||
bool double_buffers; //if send buffer and recv buffer are independent
|
int min_buff_size;
|
||||||
bool need_shrink;
|
int max_buff_size;
|
||||||
struct fast_mblock_man allocator;
|
int arg_size;
|
||||||
TaskInitCallback init_callback;
|
int block_size;
|
||||||
void *init_arg;
|
bool malloc_whole_block;
|
||||||
TaskReleaseCallback release_callback;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int free_queue_init_ex2(struct fast_task_queue *queue, const char *name,
|
int free_queue_init(const int max_connections, const int min_buff_size, \
|
||||||
const bool double_buffers, const bool need_shrink,
|
const int max_buff_size, const int arg_size);
|
||||||
const int max_connections, const int alloc_task_once,
|
int free_queue_init_ex(const int max_connections, const int init_connections,
|
||||||
const int min_buff_size, const int max_buff_size,
|
|
||||||
const int padding_size, const int arg_size,
|
|
||||||
TaskInitCallback init_callback, void *init_arg);
|
|
||||||
|
|
||||||
static inline int free_queue_init_ex(struct fast_task_queue *queue,
|
|
||||||
const char *name, const bool double_buffers,
|
|
||||||
const bool need_shrink, const int max_connections,
|
|
||||||
const int alloc_task_once, const int min_buff_size,
|
const int alloc_task_once, const int min_buff_size,
|
||||||
const int max_buff_size, const int arg_size)
|
const int max_buff_size, const int arg_size);
|
||||||
{
|
|
||||||
const int padding_size = 0;
|
|
||||||
return free_queue_init_ex2(queue, name, double_buffers, need_shrink,
|
|
||||||
max_connections, alloc_task_once, min_buff_size, max_buff_size,
|
|
||||||
padding_size, arg_size, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_init(struct fast_task_queue *queue,
|
void free_queue_destroy();
|
||||||
const int max_connections, const int alloc_task_once,
|
|
||||||
const int min_buff_size, const int max_buff_size)
|
|
||||||
{
|
|
||||||
const char *name = "";
|
|
||||||
const bool double_buffers = false;
|
|
||||||
const bool need_shrink = true;
|
|
||||||
const int arg_size = 0;
|
|
||||||
return free_queue_init_ex(queue, name, double_buffers,
|
|
||||||
need_shrink, max_connections, alloc_task_once,
|
|
||||||
min_buff_size, max_buff_size, arg_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void free_queue_set_release_callback(
|
int free_queue_push(struct fast_task_info *pTask);
|
||||||
struct fast_task_queue *queue,
|
struct fast_task_info *free_queue_pop();
|
||||||
TaskReleaseCallback callback)
|
int free_queue_count();
|
||||||
{
|
int free_queue_alloc_connections();
|
||||||
queue->release_callback = callback;
|
int free_queue_set_buffer_size(struct fast_task_info *pTask,
|
||||||
}
|
const int expect_size);
|
||||||
|
int free_queue_realloc_buffer(struct fast_task_info *pTask,
|
||||||
|
const int expect_size);
|
||||||
|
|
||||||
void free_queue_destroy(struct fast_task_queue *queue);
|
int task_queue_init(struct fast_task_queue *pQueue);
|
||||||
|
int task_queue_push(struct fast_task_queue *pQueue, \
|
||||||
|
struct fast_task_info *pTask);
|
||||||
|
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue);
|
||||||
|
int task_queue_count(struct fast_task_queue *pQueue);
|
||||||
|
int task_queue_set_buffer_size(struct fast_task_queue *pQueue,
|
||||||
|
struct fast_task_info *pTask, const int expect_size);
|
||||||
|
int task_queue_realloc_buffer(struct fast_task_queue *pQueue,
|
||||||
|
struct fast_task_info *pTask, const int expect_size);
|
||||||
|
|
||||||
static inline struct fast_task_info *free_queue_pop(
|
int task_queue_get_new_buffer_size(const int min_buff_size,
|
||||||
struct fast_task_queue *queue)
|
|
||||||
{
|
|
||||||
return (struct fast_task_info *)fast_mblock_alloc_object(&queue->allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_queue_push(struct fast_task_info *task);
|
|
||||||
|
|
||||||
static inline int free_queue_count(struct fast_task_queue *queue)
|
|
||||||
{
|
|
||||||
return queue->allocator.info.element_total_count -
|
|
||||||
queue->allocator.info.element_used_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_alloc_connections(struct fast_task_queue *queue)
|
|
||||||
{
|
|
||||||
return queue->allocator.info.element_total_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int free_queue_get_new_buffer_size(const int min_buff_size,
|
|
||||||
const int max_buff_size, const int expect_size, int *new_size);
|
const int max_buff_size, const int expect_size, int *new_size);
|
||||||
|
|
||||||
int free_queue_set_buffer_size(struct fast_task_info *task,
|
|
||||||
struct fast_net_buffer *buffer, const int expect_size);
|
|
||||||
|
|
||||||
static inline int free_queue_set_max_buffer_size(
|
|
||||||
struct fast_task_info *task,
|
|
||||||
struct fast_net_buffer *buffer)
|
|
||||||
{
|
|
||||||
return free_queue_set_buffer_size(task, buffer,
|
|
||||||
task->free_queue->max_buff_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int free_queue_realloc_buffer(struct fast_task_info *task,
|
|
||||||
struct fast_net_buffer *buffer, const int expect_size);
|
|
||||||
|
|
||||||
static inline int free_queue_realloc_max_buffer(
|
|
||||||
struct fast_task_info *task,
|
|
||||||
struct fast_net_buffer *buffer)
|
|
||||||
{
|
|
||||||
return free_queue_realloc_buffer(task, buffer,
|
|
||||||
task->free_queue->max_buff_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send and recv buffer operations */
|
|
||||||
static inline int free_queue_set_send_buffer_size(
|
|
||||||
struct fast_task_info *task, const int expect_size)
|
|
||||||
{
|
|
||||||
return free_queue_set_buffer_size(task, task->send.ptr, expect_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_set_recv_buffer_size(
|
|
||||||
struct fast_task_info *task, const int expect_size)
|
|
||||||
{
|
|
||||||
return free_queue_set_buffer_size(task, task->recv.ptr, expect_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_set_send_max_buffer_size(
|
|
||||||
struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
return free_queue_set_max_buffer_size(task, task->send.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_set_recv_max_buffer_size(
|
|
||||||
struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
return free_queue_set_max_buffer_size(task, task->recv.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_realloc_send_buffer(
|
|
||||||
struct fast_task_info *task, const int expect_size)
|
|
||||||
{
|
|
||||||
return free_queue_realloc_buffer(task, task->send.ptr, expect_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_realloc_recv_buffer(
|
|
||||||
struct fast_task_info *task, const int expect_size)
|
|
||||||
{
|
|
||||||
return free_queue_realloc_buffer(task, task->recv.ptr, expect_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_realloc_send_max_buffer(
|
|
||||||
struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
return free_queue_realloc_max_buffer(task, task->send.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int free_queue_realloc_recv_max_buffer(
|
|
||||||
struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
return free_queue_realloc_max_buffer(task, task->recv.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
279
src/fast_timer.c
279
src/fast_timer.c
|
|
@ -1,56 +1,37 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "pthread_func.h"
|
|
||||||
#include "fast_timer.h"
|
#include "fast_timer.h"
|
||||||
|
|
||||||
int fast_timer_init(FastTimer *timer, const int slot_count,
|
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||||
const int64_t current_time)
|
const int64_t current_time)
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
|
if (slot_count <= 0 || current_time <= 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (slot_count <= 0 || current_time <= 0) {
|
timer->slot_count = slot_count;
|
||||||
return EINVAL;
|
timer->base_time = current_time; //base time for slot 0
|
||||||
}
|
timer->current_time = current_time;
|
||||||
|
bytes = sizeof(FastTimerSlot) * slot_count;
|
||||||
timer->slot_count = slot_count;
|
timer->slots = (FastTimerSlot *)malloc(bytes);
|
||||||
timer->base_time = current_time; //base time for slot 0
|
if (timer->slots == NULL) {
|
||||||
timer->current_time = current_time;
|
return errno != 0 ? errno : ENOMEM;
|
||||||
bytes = sizeof(FastTimerSlot) * slot_count;
|
}
|
||||||
timer->slots = (FastTimerSlot *)fc_malloc(bytes);
|
memset(timer->slots, 0, bytes);
|
||||||
if (timer->slots == NULL) {
|
return 0;
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
memset(timer->slots, 0, bytes);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fast_timer_destroy(FastTimer *timer)
|
void fast_timer_destroy(FastTimer *timer)
|
||||||
{
|
{
|
||||||
if (timer->slots != NULL) {
|
if (timer->slots != NULL) {
|
||||||
free(timer->slots);
|
free(timer->slots);
|
||||||
timer->slots = NULL;
|
timer->slots = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
||||||
|
|
@ -59,160 +40,138 @@ void fast_timer_destroy(FastTimer *timer)
|
||||||
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
||||||
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
||||||
|
|
||||||
static inline void add_entry(FastTimer *timer, FastTimerSlot *slot,
|
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
|
||||||
FastTimerEntry *entry, const int64_t expires, const bool set_expires)
|
|
||||||
{
|
{
|
||||||
if (set_expires) {
|
FastTimerSlot *slot;
|
||||||
entry->expires = expires;
|
|
||||||
}
|
|
||||||
entry->next = slot->head.next;
|
|
||||||
if (slot->head.next != NULL) {
|
|
||||||
slot->head.next->prev = entry;
|
|
||||||
}
|
|
||||||
entry->prev = &slot->head;
|
|
||||||
slot->head.next = entry;
|
|
||||||
entry->rehash = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fast_timer_add_ex(FastTimer *timer, FastTimerEntry *entry,
|
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
|
||||||
const int64_t expires, const bool set_expires)
|
timer->current_time ? entry->expires : timer->current_time);
|
||||||
{
|
entry->next = slot->head.next;
|
||||||
FastTimerSlot *slot;
|
if (slot->head.next != NULL) {
|
||||||
int64_t new_expires;
|
slot->head.next->prev = entry;
|
||||||
bool new_set_expires;
|
}
|
||||||
|
entry->prev = &slot->head;
|
||||||
if (expires > timer->current_time) {
|
slot->head.next = entry;
|
||||||
new_expires = expires;
|
entry->rehash = false;
|
||||||
new_set_expires = set_expires;
|
return 0;
|
||||||
} else {
|
|
||||||
new_expires = timer->current_time + 1; //plus 1 for rare case
|
|
||||||
new_set_expires = true;
|
|
||||||
}
|
|
||||||
slot = TIMER_GET_SLOT_POINTER(timer, new_expires);
|
|
||||||
add_entry(timer, slot, entry, new_expires, new_set_expires);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||||
const int64_t new_expires)
|
const int64_t new_expires)
|
||||||
{
|
{
|
||||||
int result;
|
if (new_expires == entry->expires) {
|
||||||
|
|
||||||
if (new_expires > entry->expires) {
|
|
||||||
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
|
|
||||||
TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
|
||||||
entry->expires = new_expires; //lazy move
|
|
||||||
} else if (new_expires < entry->expires) {
|
|
||||||
if ((result=fast_timer_remove(timer, entry)) == 0) {
|
|
||||||
fast_timer_add_ex(timer, entry, new_expires, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_expires < entry->expires) {
|
||||||
|
fast_timer_remove(timer, entry);
|
||||||
|
entry->expires = new_expires;
|
||||||
|
return fast_timer_add(timer, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
|
||||||
|
TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
||||||
|
entry->expires = new_expires; //lazy move
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
||||||
{
|
{
|
||||||
if (entry->prev == NULL) {
|
if (entry->prev == NULL) {
|
||||||
return ENOENT; //already removed
|
return ENOENT; //already removed
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->next != NULL) {
|
if (entry->next != NULL) {
|
||||||
entry->next->prev = entry->prev;
|
entry->next->prev = entry->prev;
|
||||||
entry->prev->next = entry->next;
|
entry->prev->next = entry->next;
|
||||||
entry->next = NULL;
|
entry->next = NULL;
|
||||||
} else {
|
}
|
||||||
entry->prev->next = NULL;
|
else {
|
||||||
}
|
entry->prev->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
entry->prev = NULL;
|
entry->prev = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
|
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
|
||||||
{
|
{
|
||||||
if (timer->current_time >= current_time) {
|
if (timer->current_time >= current_time) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
||||||
FastTimerEntry *head)
|
FastTimerEntry *head)
|
||||||
{
|
{
|
||||||
FastTimerSlot *slot;
|
FastTimerSlot *slot;
|
||||||
FastTimerSlot *new_slot;
|
FastTimerEntry *entry;
|
||||||
FastTimerEntry *entry;
|
FastTimerEntry *first;
|
||||||
FastTimerEntry *first;
|
FastTimerEntry *last;
|
||||||
FastTimerEntry *last;
|
FastTimerEntry *tail;
|
||||||
FastTimerEntry *tail;
|
int count;
|
||||||
int count;
|
|
||||||
|
|
||||||
head->prev = NULL;
|
head->prev = NULL;
|
||||||
head->next = NULL;
|
head->next = NULL;
|
||||||
if (timer->current_time >= current_time) {
|
if (timer->current_time >= current_time) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
first = NULL;
|
first = NULL;
|
||||||
last = NULL;
|
last = NULL;
|
||||||
tail = head;
|
tail = head;
|
||||||
count = 0;
|
count = 0;
|
||||||
while (timer->current_time < current_time) {
|
while (timer->current_time < current_time) {
|
||||||
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||||
entry = slot->head.next;
|
entry = slot->head.next;
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
if (entry->expires >= current_time) { //not expired
|
if (entry->expires >= current_time) { //not expired
|
||||||
if (first != NULL) {
|
if (first != NULL) {
|
||||||
first->prev->next = entry;
|
first->prev->next = entry;
|
||||||
entry->prev = first->prev;
|
entry->prev = first->prev;
|
||||||
|
|
||||||
tail->next = first;
|
|
||||||
first->prev = tail;
|
|
||||||
tail = last;
|
|
||||||
first = NULL;
|
|
||||||
}
|
|
||||||
if (entry->rehash) {
|
|
||||||
last = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
|
|
||||||
new_slot = TIMER_GET_SLOT_POINTER(timer, last->expires);
|
|
||||||
if (new_slot != slot) { //check to avoid deadlock
|
|
||||||
if (fast_timer_remove(timer, last) == 0) {
|
|
||||||
add_entry(timer, new_slot, last,
|
|
||||||
last->expires, false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last->rehash = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else { //expired
|
|
||||||
count++;
|
|
||||||
if (first == NULL) {
|
|
||||||
first = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != NULL) {
|
|
||||||
first->prev->next = NULL;
|
|
||||||
|
|
||||||
tail->next = first;
|
tail->next = first;
|
||||||
first->prev = tail;
|
first->prev = tail;
|
||||||
tail = last;
|
tail = last;
|
||||||
first = NULL;
|
first = NULL;
|
||||||
}
|
}
|
||||||
|
if (entry->rehash) {
|
||||||
|
last = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
|
||||||
|
last->rehash = false;
|
||||||
|
fast_timer_remove(timer, last);
|
||||||
|
fast_timer_add(timer, last);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { //expired
|
||||||
|
count++;
|
||||||
|
if (first == NULL) {
|
||||||
|
first = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last = entry;
|
||||||
|
entry = entry->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > 0) {
|
if (first != NULL) {
|
||||||
tail->next = NULL;
|
first->prev->next = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
tail->next = first;
|
||||||
|
first->prev = tail;
|
||||||
|
tail = last;
|
||||||
|
first = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
tail->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,37 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __FAST_TIMER_H__
|
#ifndef __FAST_TIMER_H__
|
||||||
#define __FAST_TIMER_H__
|
#define __FAST_TIMER_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
|
|
||||||
struct fast_timer_slot;
|
|
||||||
typedef struct fast_timer_entry {
|
typedef struct fast_timer_entry {
|
||||||
int64_t expires;
|
int64_t expires;
|
||||||
struct fast_timer_entry *prev;
|
void *data;
|
||||||
struct fast_timer_entry *next;
|
struct fast_timer_entry *prev;
|
||||||
int slot_index;
|
struct fast_timer_entry *next;
|
||||||
bool rehash;
|
bool rehash;
|
||||||
} FastTimerEntry;
|
} FastTimerEntry;
|
||||||
|
|
||||||
typedef struct fast_timer_slot {
|
typedef struct fast_timer_slot {
|
||||||
struct fast_timer_entry head;
|
struct fast_timer_entry head;
|
||||||
} FastTimerSlot;
|
} FastTimerSlot;
|
||||||
|
|
||||||
typedef struct fast_timer {
|
typedef struct fast_timer {
|
||||||
int slot_count; //time wheel slot count
|
int slot_count; //time wheel slot count
|
||||||
int64_t base_time; //base time for slot 0
|
int64_t base_time; //base time for slot 0
|
||||||
volatile int64_t current_time;
|
int64_t current_time;
|
||||||
FastTimerSlot *slots;
|
FastTimerSlot *slots;
|
||||||
} FastTimer;
|
} FastTimer;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define fast_timer_add(timer, entry) \
|
|
||||||
fast_timer_add_ex(timer, entry, (entry)->expires, false)
|
|
||||||
|
|
||||||
int fast_timer_init(FastTimer *timer, const int slot_count,
|
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||||
const int64_t current_time);
|
const int64_t current_time);
|
||||||
void fast_timer_destroy(FastTimer *timer);
|
void fast_timer_destroy(FastTimer *timer);
|
||||||
|
|
||||||
void fast_timer_add_ex(FastTimer *timer, FastTimerEntry *entry,
|
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry);
|
||||||
const int64_t expires, const bool set_expires);
|
|
||||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
|
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
|
||||||
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||||
const int64_t new_expires);
|
const int64_t new_expires);
|
||||||
|
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _FC_ATOMIC_H
|
|
||||||
#define _FC_ATOMIC_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FC_ATOMIC_GET(var) __sync_add_and_fetch(&var, 0)
|
|
||||||
|
|
||||||
#define FC_ATOMIC_INC(var) __sync_add_and_fetch(&var, 1)
|
|
||||||
#define FC_ATOMIC_DEC(var) __sync_sub_and_fetch(&var, 1)
|
|
||||||
|
|
||||||
#define FC_ATOMIC_INC_EX(var, n) __sync_add_and_fetch(&var, n)
|
|
||||||
#define FC_ATOMIC_DEC_EX(var, n) __sync_sub_and_fetch(&var, n)
|
|
||||||
|
|
||||||
#define FC_ATOMIC_CAS(var, old_value, new_value) \
|
|
||||||
do { \
|
|
||||||
if (__sync_bool_compare_and_swap(&var, old_value, new_value)) { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
old_value = __sync_add_and_fetch(&var, 0); \
|
|
||||||
} while (new_value != old_value)
|
|
||||||
|
|
||||||
|
|
||||||
#define FC_ATOMIC_SET(var, new_value) \
|
|
||||||
do { \
|
|
||||||
typeof(var) _old_value; \
|
|
||||||
_old_value = var; \
|
|
||||||
do { \
|
|
||||||
if (__sync_bool_compare_and_swap(&var, _old_value, new_value)) { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
_old_value = __sync_add_and_fetch(&var, 0); \
|
|
||||||
} while (new_value != _old_value); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define FC_ATOMIC_SET_BY_CONDITION(var, value, skip_operator) \
|
|
||||||
do { \
|
|
||||||
typeof(var) old; \
|
|
||||||
old = __sync_add_and_fetch(&var, 0); \
|
|
||||||
if (value skip_operator old) { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
if (__sync_bool_compare_and_swap(&var, old, value)) { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} while (1)
|
|
||||||
|
|
||||||
|
|
||||||
#define FC_ATOMIC_SET_LARGER(var, value) \
|
|
||||||
FC_ATOMIC_SET_BY_CONDITION(var, value, <=)
|
|
||||||
|
|
||||||
#define FC_ATOMIC_SET_SMALLER(var, value) \
|
|
||||||
FC_ATOMIC_SET_BY_CONDITION(var, value, >=)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -25,6 +25,7 @@ fc_list_add (struct fc_list_head *_new, struct fc_list_head *head)
|
||||||
_new->next->prev = _new;
|
_new->next->prev = _new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
fc_list_add_tail (struct fc_list_head *_new, struct fc_list_head *head)
|
fc_list_add_tail (struct fc_list_head *_new, struct fc_list_head *head)
|
||||||
{
|
{
|
||||||
|
|
@ -36,27 +37,7 @@ fc_list_add_tail (struct fc_list_head *_new, struct fc_list_head *head)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
fc_list_add_before (struct fc_list_head *_new, struct fc_list_head *current)
|
fc_list_add_internal(struct fc_list_head *_new, struct fc_list_head *prev,
|
||||||
{
|
|
||||||
_new->prev = current->prev;
|
|
||||||
_new->next = current;
|
|
||||||
|
|
||||||
_new->prev->next = _new;
|
|
||||||
_new->next->prev = _new;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
fc_list_add_after (struct fc_list_head *_new, struct fc_list_head *current)
|
|
||||||
{
|
|
||||||
_new->prev = current;
|
|
||||||
_new->next = current->next;
|
|
||||||
|
|
||||||
current->next->prev = _new;
|
|
||||||
current->next = _new;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
fc_list_add_internal (struct fc_list_head *_new, struct fc_list_head *prev,
|
|
||||||
struct fc_list_head *next)
|
struct fc_list_head *next)
|
||||||
{
|
{
|
||||||
next->prev = _new;
|
next->prev = _new;
|
||||||
|
|
@ -166,15 +147,6 @@ static inline int fc_list_count(struct fc_list_head *head)
|
||||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||||
|
|
||||||
|
|
||||||
#define fc_list_first_entry(head, type, member) \
|
|
||||||
((head)->next == head ? NULL : \
|
|
||||||
fc_list_entry((head)->next, type, member))
|
|
||||||
|
|
||||||
#define fc_list_last_entry(head, type, member) \
|
|
||||||
((head)->prev == head ? NULL : \
|
|
||||||
fc_list_entry((head)->prev, type, member))
|
|
||||||
|
|
||||||
|
|
||||||
#define fc_list_for_each(pos, head) \
|
#define fc_list_for_each(pos, head) \
|
||||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fc_memory.c
|
|
||||||
|
|
||||||
#include "fc_memory.h"
|
|
||||||
|
|
||||||
fc_memory_oom_notify_func g_oom_notify = NULL;
|
|
||||||
112
src/fc_memory.h
112
src/fc_memory.h
|
|
@ -1,112 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fc_memory.h
|
|
||||||
|
|
||||||
#ifndef _FC_MEMORY_H
|
|
||||||
#define _FC_MEMORY_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "common_define.h"
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
typedef void (*fc_memory_oom_notify_func)(const size_t curr_size);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern fc_memory_oom_notify_func g_oom_notify;
|
|
||||||
|
|
||||||
static inline void *fc_malloc_ex(const char *file,
|
|
||||||
const int line, size_t size)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
ptr = malloc(size);
|
|
||||||
if (ptr == NULL) {
|
|
||||||
logError("file: %s, line: %d, malloc %"PRId64" bytes fail, "
|
|
||||||
"errno: %d, error info: %s", file, line,
|
|
||||||
(int64_t)size, errno, STRERROR(errno));
|
|
||||||
if (g_oom_notify != NULL) {
|
|
||||||
g_oom_notify(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *fc_realloc_ex(const char *file,
|
|
||||||
const int line, void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
void *new_ptr;
|
|
||||||
new_ptr = realloc(ptr, size);
|
|
||||||
if (new_ptr == NULL) {
|
|
||||||
logError("file: %s, line: %d, realloc %"PRId64" bytes fail, "
|
|
||||||
"errno: %d, error info: %s", file, line,
|
|
||||||
(int64_t)size, errno, STRERROR(errno));
|
|
||||||
if (g_oom_notify != NULL) {
|
|
||||||
g_oom_notify(size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline char *fc_strdup_ex(const char *file,
|
|
||||||
const int line, const char *str)
|
|
||||||
{
|
|
||||||
char *output;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = strlen(str);
|
|
||||||
output = (char *)fc_malloc_ex(file, line, len + 1);
|
|
||||||
if (output == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
memcpy(output, str, len);
|
|
||||||
}
|
|
||||||
*(output + len) = '\0';
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *fc_calloc_ex(const char *file,
|
|
||||||
const int line, size_t count, size_t size)
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
ptr = calloc(count, size);
|
|
||||||
if (ptr == NULL) {
|
|
||||||
logError("file: %s, line: %d, malloc %"PRId64" bytes fail, "
|
|
||||||
"errno: %d, error info: %s", file, line,
|
|
||||||
(int64_t)(count * size), errno, STRERROR(errno));
|
|
||||||
if (g_oom_notify != NULL) {
|
|
||||||
g_oom_notify(count * size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fc_malloc(size) fc_malloc_ex(__FILE__, __LINE__, size)
|
|
||||||
#define fc_realloc(ptr, size) fc_realloc_ex(__FILE__, __LINE__, ptr, size)
|
|
||||||
#define fc_calloc(count, size) fc_calloc_ex(__FILE__, __LINE__, count, size)
|
|
||||||
#define fc_strdup(str) fc_strdup_ex(__FILE__, __LINE__, str)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
343
src/fc_queue.c
343
src/fc_queue.c
|
|
@ -1,343 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fc_queue.c
|
|
||||||
|
|
||||||
#include "pthread_func.h"
|
|
||||||
#include "fc_queue.h"
|
|
||||||
|
|
||||||
int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=init_pthread_lock_cond_pair(&queue->lcp)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
queue->head = NULL;
|
|
||||||
queue->tail = NULL;
|
|
||||||
queue->next_ptr_offset = next_ptr_offset;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_destroy(struct fc_queue *queue)
|
|
||||||
{
|
|
||||||
destroy_pthread_lock_cond_pair(&queue->lcp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, data) = NULL;
|
|
||||||
if (queue->tail == NULL) {
|
|
||||||
queue->head = data;
|
|
||||||
*notify = true;
|
|
||||||
} else {
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, queue->tail) = data;
|
|
||||||
*notify = false;
|
|
||||||
}
|
|
||||||
queue->tail = data;
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool fc_queue_exists(struct fc_queue *queue, void *data)
|
|
||||||
{
|
|
||||||
void *current;
|
|
||||||
if (queue->head == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = queue->head;
|
|
||||||
do {
|
|
||||||
if (current == data) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
current = FC_QUEUE_NEXT_PTR(queue, current);
|
|
||||||
} while (current != NULL);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_queue_push_with_check_ex(struct fc_queue *queue,
|
|
||||||
void *data, bool *notify)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
if (fc_queue_exists(queue, data)) {
|
|
||||||
result = EEXIST;
|
|
||||||
*notify = false;
|
|
||||||
} else {
|
|
||||||
result = 0;
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, data) = NULL;
|
|
||||||
if (queue->tail == NULL) {
|
|
||||||
queue->head = data;
|
|
||||||
*notify = true;
|
|
||||||
} else {
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, queue->tail) = data;
|
|
||||||
*notify = false;
|
|
||||||
}
|
|
||||||
queue->tail = data;
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked)
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
do {
|
|
||||||
data = queue->head;
|
|
||||||
if (data == NULL) {
|
|
||||||
if (!blocked) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
|
|
||||||
data = queue->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != NULL) {
|
|
||||||
queue->head = FC_QUEUE_NEXT_PTR(queue, data);
|
|
||||||
if (queue->head == NULL) {
|
|
||||||
queue->tail = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked)
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
do {
|
|
||||||
data = queue->head;
|
|
||||||
if (data == NULL) {
|
|
||||||
if (!blocked) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
|
|
||||||
data = queue->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != NULL) {
|
|
||||||
queue->head = queue->tail = NULL;
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo, bool *notify)
|
|
||||||
{
|
|
||||||
if (qinfo->head == NULL) {
|
|
||||||
*notify = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, qinfo->tail) = queue->head;
|
|
||||||
queue->head = qinfo->head;
|
|
||||||
if (queue->tail == NULL) {
|
|
||||||
queue->tail = qinfo->tail;
|
|
||||||
*notify = true;
|
|
||||||
} else {
|
|
||||||
*notify = false;
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo, bool *notify)
|
|
||||||
{
|
|
||||||
if (qinfo->head == NULL) {
|
|
||||||
*notify = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
if (queue->head == NULL) {
|
|
||||||
queue->head = qinfo->head;
|
|
||||||
*notify = true;
|
|
||||||
} else {
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, queue->tail) = qinfo->head;
|
|
||||||
*notify = false;
|
|
||||||
}
|
|
||||||
queue->tail = qinfo->tail;
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_pop_to_queue_ex(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo, const bool blocked)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
if (queue->head == NULL) {
|
|
||||||
if (blocked) {
|
|
||||||
pthread_cond_wait(&queue->lcp.cond, &queue->lcp.lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queue->head != NULL) {
|
|
||||||
qinfo->head = queue->head;
|
|
||||||
qinfo->tail = queue->tail;
|
|
||||||
queue->head = queue->tail = NULL;
|
|
||||||
} else {
|
|
||||||
qinfo->head = qinfo->tail = NULL;
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fc_queue_timedpop(struct fc_queue *queue,
|
|
||||||
const int timeout, const int time_unit)
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
data = queue->head;
|
|
||||||
if (data == NULL) {
|
|
||||||
fc_cond_timedwait(&queue->lcp, timeout, time_unit);
|
|
||||||
data = queue->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data != NULL) {
|
|
||||||
queue->head = FC_QUEUE_NEXT_PTR(queue, data);
|
|
||||||
if (queue->head == NULL) {
|
|
||||||
queue->tail = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fc_queue_timedpeek(struct fc_queue *queue,
|
|
||||||
const int timeout, const int time_unit)
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&queue->lcp.lock);
|
|
||||||
data = queue->head;
|
|
||||||
if (data == NULL) {
|
|
||||||
fc_cond_timedwait(&queue->lcp, timeout, time_unit);
|
|
||||||
data = queue->head;
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&queue->lcp.lock);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_queue_alloc_chain(struct fc_queue *queue, struct fast_mblock_man
|
|
||||||
*mblock, const int count, struct fc_queue_info *chain)
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *node;
|
|
||||||
|
|
||||||
if ((node=fast_mblock_batch_alloc1(mblock, count)) == NULL) {
|
|
||||||
chain->head = chain->tail = NULL;
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
chain->head = chain->tail = node->data;
|
|
||||||
while ((node=node->next) != NULL) {
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, chain->tail) = node->data;
|
|
||||||
chain->tail = node->data;
|
|
||||||
}
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, chain->tail) = NULL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
|
|
||||||
*mblock, struct fc_queue_info *qinfo)
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *previous;
|
|
||||||
struct fast_mblock_node *current;
|
|
||||||
struct fast_mblock_chain chain;
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
if (qinfo->head == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
chain.head = previous = fast_mblock_to_node_ptr(qinfo->head);
|
|
||||||
data = FC_QUEUE_NEXT_PTR(queue, qinfo->head);
|
|
||||||
while (data != NULL) {
|
|
||||||
current = fast_mblock_to_node_ptr(data);
|
|
||||||
previous->next = current;
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
data = FC_QUEUE_NEXT_PTR(queue, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
previous->next = NULL;
|
|
||||||
chain.tail = previous;
|
|
||||||
return fast_mblock_batch_free(mblock, &chain);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_queue_remove(struct fc_queue *queue, void *data)
|
|
||||||
{
|
|
||||||
void *previous;
|
|
||||||
void *current;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&queue->lcp.lock);
|
|
||||||
if (queue->head == NULL)
|
|
||||||
{
|
|
||||||
result = ENOENT;
|
|
||||||
}
|
|
||||||
else if (queue->head == data)
|
|
||||||
{
|
|
||||||
queue->head = FC_QUEUE_NEXT_PTR(queue, queue->head);
|
|
||||||
if (queue->head == NULL)
|
|
||||||
{
|
|
||||||
queue->tail = NULL;
|
|
||||||
}
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = ENOENT;
|
|
||||||
previous = queue->head;
|
|
||||||
while ((current=FC_QUEUE_NEXT_PTR(queue, previous)) != NULL)
|
|
||||||
{
|
|
||||||
if (current == data)
|
|
||||||
{
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, previous) =
|
|
||||||
FC_QUEUE_NEXT_PTR(queue, current);
|
|
||||||
if (queue->tail == current)
|
|
||||||
{
|
|
||||||
queue->tail = previous;
|
|
||||||
}
|
|
||||||
result = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&queue->lcp.lock);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
235
src/fc_queue.h
235
src/fc_queue.h
|
|
@ -1,235 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//fc_queue.h
|
|
||||||
|
|
||||||
#ifndef _FC_QUEUE_H
|
|
||||||
#define _FC_QUEUE_H
|
|
||||||
|
|
||||||
#include "common_define.h"
|
|
||||||
#include "fast_mblock.h"
|
|
||||||
|
|
||||||
struct fc_queue_info
|
|
||||||
{
|
|
||||||
void *head;
|
|
||||||
void *tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fc_queue
|
|
||||||
{
|
|
||||||
void *head;
|
|
||||||
void *tail;
|
|
||||||
pthread_lock_cond_pair_t lcp;
|
|
||||||
int next_ptr_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FC_QUEUE_NEXT_PTR(queue, data) \
|
|
||||||
*((void **)(((char *)data) + (queue)->next_ptr_offset))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int fc_queue_init(struct fc_queue *queue, const int next_ptr_offset);
|
|
||||||
|
|
||||||
void fc_queue_destroy(struct fc_queue *queue);
|
|
||||||
|
|
||||||
static inline void fc_queue_terminate(struct fc_queue *queue)
|
|
||||||
{
|
|
||||||
pthread_cond_signal(&queue->lcp.cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_queue_terminate_all(
|
|
||||||
struct fc_queue *queue, const int count)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i=0; i<count; i++) {
|
|
||||||
pthread_cond_signal(&(queue->lcp.cond));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fc_queue_notify(queue) fc_queue_terminate(queue)
|
|
||||||
|
|
||||||
#define fc_queue_notify_all(queue, count) \
|
|
||||||
fc_queue_terminate_all(queue, count)
|
|
||||||
|
|
||||||
//notify by the caller
|
|
||||||
void fc_queue_push_ex(struct fc_queue *queue, void *data, bool *notify);
|
|
||||||
int fc_queue_push_with_check_ex(struct fc_queue *queue,
|
|
||||||
void *data, bool *notify);
|
|
||||||
|
|
||||||
static inline void fc_queue_push(struct fc_queue *queue, void *data)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
|
|
||||||
fc_queue_push_ex(queue, data, ¬ify);
|
|
||||||
if (notify) {
|
|
||||||
pthread_cond_signal(&(queue->lcp.cond));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_queue_push_with_check(struct fc_queue *queue, void *data)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
bool notify;
|
|
||||||
|
|
||||||
result = fc_queue_push_with_check_ex(queue, data, ¬ify);
|
|
||||||
if (notify) {
|
|
||||||
pthread_cond_signal(&(queue->lcp.cond));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_queue_push_silence(struct fc_queue *queue, void *data)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
fc_queue_push_ex(queue, data, ¬ify);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_push_queue_to_head_ex(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo, bool *notify);
|
|
||||||
|
|
||||||
static inline void fc_queue_push_queue_to_head(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
|
|
||||||
fc_queue_push_queue_to_head_ex(queue, qinfo, ¬ify);
|
|
||||||
if (notify) {
|
|
||||||
pthread_cond_signal(&(queue->lcp.cond));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_queue_push_queue_to_head_silence(
|
|
||||||
struct fc_queue *queue, struct fc_queue_info *qinfo)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
fc_queue_push_queue_to_head_ex(queue, qinfo, ¬ify);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fc_queue_push_queue_to_tail_ex(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo, bool *notify);
|
|
||||||
|
|
||||||
static inline void fc_queue_push_queue_to_tail(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
|
|
||||||
fc_queue_push_queue_to_tail_ex(queue, qinfo, ¬ify);
|
|
||||||
if (notify) {
|
|
||||||
pthread_cond_signal(&(queue->lcp.cond));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_queue_push_queue_to_tail_silence(
|
|
||||||
struct fc_queue *queue, struct fc_queue_info *qinfo)
|
|
||||||
{
|
|
||||||
bool notify;
|
|
||||||
fc_queue_push_queue_to_tail_ex(queue, qinfo, ¬ify);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fc_queue_pop_ex(struct fc_queue *queue, const bool blocked);
|
|
||||||
#define fc_queue_pop(queue) fc_queue_pop_ex(queue, true)
|
|
||||||
#define fc_queue_try_pop(queue) fc_queue_pop_ex(queue, false)
|
|
||||||
|
|
||||||
void *fc_queue_pop_all_ex(struct fc_queue *queue, const bool blocked);
|
|
||||||
#define fc_queue_pop_all(queue) fc_queue_pop_all_ex(queue, true)
|
|
||||||
#define fc_queue_try_pop_all(queue) fc_queue_pop_all_ex(queue, false)
|
|
||||||
|
|
||||||
void fc_queue_pop_to_queue_ex(struct fc_queue *queue,
|
|
||||||
struct fc_queue_info *qinfo, const bool blocked);
|
|
||||||
|
|
||||||
#define fc_queue_pop_to_queue(queue, qinfo) \
|
|
||||||
fc_queue_pop_to_queue_ex(queue, qinfo, true)
|
|
||||||
|
|
||||||
#define fc_queue_try_pop_to_queue(queue, qinfo) \
|
|
||||||
fc_queue_pop_to_queue_ex(queue, qinfo, false)
|
|
||||||
|
|
||||||
static inline bool fc_queue_empty(struct fc_queue *queue)
|
|
||||||
{
|
|
||||||
bool empty;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&queue->lcp.lock);
|
|
||||||
empty = (queue->head == NULL);
|
|
||||||
pthread_mutex_unlock(&queue->lcp.lock);
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_queue_count(struct fc_queue *queue)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
pthread_mutex_lock(&queue->lcp.lock);
|
|
||||||
data = queue->head;
|
|
||||||
while (data != NULL)
|
|
||||||
{
|
|
||||||
++count;
|
|
||||||
data = FC_QUEUE_NEXT_PTR(queue, data);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&queue->lcp.lock);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *fc_queue_peek(struct fc_queue *queue)
|
|
||||||
{
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&queue->lcp.lock);
|
|
||||||
data = queue->head;
|
|
||||||
pthread_mutex_unlock(&queue->lcp.lock);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *fc_queue_timedpop(struct fc_queue *queue,
|
|
||||||
const int timeout, const int time_unit);
|
|
||||||
|
|
||||||
#define fc_queue_timedpop_sec(queue, timeout) \
|
|
||||||
fc_queue_timedpop(queue, timeout, FC_TIME_UNIT_SECOND)
|
|
||||||
|
|
||||||
#define fc_queue_timedpop_ms(queue, timeout_ms) \
|
|
||||||
fc_queue_timedpop(queue, timeout_ms, FC_TIME_UNIT_MSECOND)
|
|
||||||
|
|
||||||
#define fc_queue_timedpop_us(queue, timeout_us) \
|
|
||||||
fc_queue_timedpop(queue, timeout_us, FC_TIME_UNIT_USECOND)
|
|
||||||
|
|
||||||
void *fc_queue_timedpeek(struct fc_queue *queue,
|
|
||||||
const int timeout, const int time_unit);
|
|
||||||
|
|
||||||
#define fc_queue_timedpeek_sec(queue, timeout) \
|
|
||||||
fc_queue_timedpeek(queue, timeout, FC_TIME_UNIT_SECOND)
|
|
||||||
|
|
||||||
#define fc_queue_timedpeek_ms(queue, timeout_ms) \
|
|
||||||
fc_queue_timedpeek(queue, timeout_ms, FC_TIME_UNIT_MSECOND)
|
|
||||||
|
|
||||||
#define fc_queue_timedpeek_us(queue, timeout_us) \
|
|
||||||
fc_queue_timedpeek(queue, timeout_us, FC_TIME_UNIT_USECOND)
|
|
||||||
|
|
||||||
int fc_queue_alloc_chain(struct fc_queue *queue, struct fast_mblock_man
|
|
||||||
*mblock, const int count, struct fc_queue_info *chain);
|
|
||||||
|
|
||||||
int fc_queue_free_chain(struct fc_queue *queue, struct fast_mblock_man
|
|
||||||
*mblock, struct fc_queue_info *qinfo);
|
|
||||||
|
|
||||||
int fc_queue_remove(struct fc_queue *queue, void *data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2015 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* libfastcommon may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//flat_skiplist.c
|
//flat_skiplist.c
|
||||||
|
|
||||||
|
|
@ -22,15 +15,12 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "flat_skiplist.h"
|
#include "flat_skiplist.h"
|
||||||
|
|
||||||
int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
|
int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
|
||||||
skiplist_compare_func compare_func, skiplist_free_func free_func,
|
skiplist_compare_func compare_func, skiplist_free_func free_func,
|
||||||
const int min_alloc_elements_once)
|
const int min_alloc_elements_once)
|
||||||
{
|
{
|
||||||
const int64_t alloc_elements_limit = 0;
|
|
||||||
char name[64];
|
|
||||||
int bytes;
|
int bytes;
|
||||||
int element_size;
|
int element_size;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -53,15 +43,21 @@ int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(FlatSkiplistNode *) * level_count;
|
bytes = sizeof(FlatSkiplistNode *) * level_count;
|
||||||
sl->tmp_previous = (FlatSkiplistNode **)fc_malloc(bytes);
|
sl->tmp_previous = (FlatSkiplistNode **)malloc(bytes);
|
||||||
if (sl->tmp_previous == NULL) {
|
if (sl->tmp_previous == NULL) {
|
||||||
return ENOMEM;
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(struct fast_mblock_man) * level_count;
|
bytes = sizeof(struct fast_mblock_man) * level_count;
|
||||||
sl->mblocks = (struct fast_mblock_man *)fc_malloc(bytes);
|
sl->mblocks = (struct fast_mblock_man *)malloc(bytes);
|
||||||
if (sl->mblocks == NULL) {
|
if (sl->mblocks == NULL) {
|
||||||
return ENOMEM;
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
memset(sl->mblocks, 0, bytes);
|
memset(sl->mblocks, 0, bytes);
|
||||||
|
|
||||||
|
|
@ -74,12 +70,9 @@ int flat_skiplist_init_ex(FlatSkiplist *sl, const int level_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=level_count-1; i>=0; i--) {
|
for (i=level_count-1; i>=0; i--) {
|
||||||
sprintf(name, "flat-sl-level%02d", i);
|
element_size = sizeof(FlatSkiplistNode) + sizeof(FlatSkiplistNode *) * (i + 1);
|
||||||
element_size = sizeof(FlatSkiplistNode) +
|
if ((result=fast_mblock_init_ex(sl->mblocks + i,
|
||||||
sizeof(FlatSkiplistNode *) * (i + 1);
|
element_size, alloc_elements_once, NULL, false)) != 0)
|
||||||
if ((result=fast_mblock_init_ex1(sl->mblocks + i, name,
|
|
||||||
element_size, alloc_elements_once, alloc_elements_limit,
|
|
||||||
NULL, NULL, false)) != 0)
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -370,16 +363,6 @@ int flat_skiplist_find_all(FlatSkiplist *sl, void *data, FlatSkiplistIterator *i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *flat_skiplist_find_ge(FlatSkiplist *sl, void *data)
|
|
||||||
{
|
|
||||||
FlatSkiplistNode *node;
|
|
||||||
node = flat_skiplist_get_first_larger_or_equal(sl, data);
|
|
||||||
if (node == sl->top) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return node->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int flat_skiplist_find_range(FlatSkiplist *sl, void *start_data, void *end_data,
|
int flat_skiplist_find_range(FlatSkiplist *sl, void *start_data, void *end_data,
|
||||||
FlatSkiplistIterator *iterator)
|
FlatSkiplistIterator *iterator)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2015 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* libfastcommon may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//flat_skiplist.h, support duplicated entries, and support stable sort :)
|
//flat_skiplist.h, support duplicated entries, and support stable sort :)
|
||||||
//you should use multi_skiplist with too many duplicated entries
|
//you should use multi_skiplist with too many duplicated entries
|
||||||
|
|
@ -71,7 +64,6 @@ void *flat_skiplist_find(FlatSkiplist *sl, void *data);
|
||||||
int flat_skiplist_find_all(FlatSkiplist *sl, void *data, FlatSkiplistIterator *iterator);
|
int flat_skiplist_find_all(FlatSkiplist *sl, void *data, FlatSkiplistIterator *iterator);
|
||||||
int flat_skiplist_find_range(FlatSkiplist *sl, void *start_data, void *end_data,
|
int flat_skiplist_find_range(FlatSkiplist *sl, void *start_data, void *end_data,
|
||||||
FlatSkiplistIterator *iterator);
|
FlatSkiplistIterator *iterator);
|
||||||
void *flat_skiplist_find_ge(FlatSkiplist *sl, void *data);
|
|
||||||
|
|
||||||
static inline void flat_skiplist_iterator(FlatSkiplist *sl, FlatSkiplistIterator *iterator)
|
static inline void flat_skiplist_iterator(FlatSkiplist *sl, FlatSkiplistIterator *iterator)
|
||||||
{
|
{
|
||||||
|
|
@ -92,15 +84,6 @@ static inline void *flat_skiplist_next(FlatSkiplistIterator *iterator)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *flat_skiplist_get_first(FlatSkiplist *sl)
|
|
||||||
{
|
|
||||||
if (sl->top->links[0] != sl->tail) {
|
|
||||||
return sl->top->links[0]->data;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool flat_skiplist_empty(FlatSkiplist *sl)
|
static inline bool flat_skiplist_empty(FlatSkiplist *sl)
|
||||||
{
|
{
|
||||||
return sl->top->links[0] == sl->tail;
|
return sl->top->links[0] == sl->tail;
|
||||||
|
|
|
||||||
121
src/hash.c
121
src/hash.c
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -19,7 +12,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "pthread_func.h"
|
#include "pthread_func.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
static unsigned int prime_array[] = {
|
static unsigned int prime_array[] = {
|
||||||
|
|
@ -67,7 +59,7 @@ static int _hash_alloc_buckets(HashArray *pHash, const unsigned int old_capacity
|
||||||
return ENOSPC;
|
return ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
pHash->buckets = (HashData **)fc_malloc(bytes);
|
pHash->buckets = (HashData **)malloc(bytes);
|
||||||
if (pHash->buckets == NULL)
|
if (pHash->buckets == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
@ -79,7 +71,7 @@ static int _hash_alloc_buckets(HashArray *pHash, const unsigned int old_capacity
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int *fc_hash_get_prime_capacity(const int capacity)
|
unsigned int *hash_get_prime_capacity(const int capacity)
|
||||||
{
|
{
|
||||||
unsigned int *pprime;
|
unsigned int *pprime;
|
||||||
unsigned int *prime_end;
|
unsigned int *prime_end;
|
||||||
|
|
@ -95,14 +87,14 @@ unsigned int *fc_hash_get_prime_capacity(const int capacity)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
||||||
const unsigned int capacity, const double load_factor, \
|
const unsigned int capacity, const double load_factor, \
|
||||||
const int64_t max_bytes, const bool bMallocValue)
|
const int64_t max_bytes, const bool bMallocValue)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
memset(pHash, 0, sizeof(HashArray));
|
memset(pHash, 0, sizeof(HashArray));
|
||||||
pHash->capacity = fc_hash_get_prime_capacity(capacity);
|
pHash->capacity = hash_get_prime_capacity(capacity);
|
||||||
if (pHash->capacity == NULL)
|
if (pHash->capacity == NULL)
|
||||||
{
|
{
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
@ -129,7 +121,7 @@ int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_set_locks(HashArray *pHash, const int lock_count)
|
int hash_set_locks(HashArray *pHash, const int lock_count)
|
||||||
{
|
{
|
||||||
size_t bytes;
|
size_t bytes;
|
||||||
pthread_mutex_t *lock;
|
pthread_mutex_t *lock;
|
||||||
|
|
@ -152,7 +144,7 @@ int fc_hash_set_locks(HashArray *pHash, const int lock_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(pthread_mutex_t) * lock_count;
|
bytes = sizeof(pthread_mutex_t) * lock_count;
|
||||||
pHash->locks = (pthread_mutex_t *)fc_malloc(bytes);
|
pHash->locks = (pthread_mutex_t *)malloc(bytes);
|
||||||
if (pHash->locks == NULL)
|
if (pHash->locks == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
@ -168,7 +160,7 @@ int fc_hash_set_locks(HashArray *pHash, const int lock_count)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fc_hash_destroy(HashArray *pHash)
|
void hash_destroy(HashArray *pHash)
|
||||||
{
|
{
|
||||||
HashData **ppBucket;
|
HashData **ppBucket;
|
||||||
HashData **bucket_end;
|
HashData **bucket_end;
|
||||||
|
|
@ -238,7 +230,7 @@ void fc_hash_destroy(HashArray *pHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
|
int hash_stat(HashArray *pHash, HashStat *pStat, \
|
||||||
int *stat_by_lens, const int stat_size)
|
int *stat_by_lens, const int stat_size)
|
||||||
{
|
{
|
||||||
HashData **ppBucket;
|
HashData **ppBucket;
|
||||||
|
|
@ -299,13 +291,13 @@ int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fc_hash_stat_print(HashArray *pHash)
|
void hash_stat_print(HashArray *pHash)
|
||||||
{
|
{
|
||||||
#define STAT_MAX_NUM 64
|
#define STAT_MAX_NUM 64
|
||||||
HashStat hs;
|
HashStat hs;
|
||||||
int stats[STAT_MAX_NUM];
|
int stats[STAT_MAX_NUM];
|
||||||
|
|
||||||
if (fc_hash_stat(pHash, &hs, stats, STAT_MAX_NUM) != 0)
|
if (hash_stat(pHash, &hs, stats, STAT_MAX_NUM) != 0)
|
||||||
{
|
{
|
||||||
printf("hash max length exceeds %d!\n", STAT_MAX_NUM);
|
printf("hash max length exceeds %d!\n", STAT_MAX_NUM);
|
||||||
return;
|
return;
|
||||||
|
|
@ -381,7 +373,7 @@ static int _rehash(HashArray *pHash)
|
||||||
pOldCapacity = pHash->capacity;
|
pOldCapacity = pHash->capacity;
|
||||||
if (pHash->is_malloc_capacity)
|
if (pHash->is_malloc_capacity)
|
||||||
{
|
{
|
||||||
pHash->capacity = fc_hash_get_prime_capacity(*pOldCapacity);
|
pHash->capacity = hash_get_prime_capacity(*pOldCapacity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -456,7 +448,7 @@ static int _hash_conflict_count(HashArray *pHash)
|
||||||
return conflict_count;
|
return conflict_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
|
int hash_best_op(HashArray *pHash, const int suggest_capacity)
|
||||||
{
|
{
|
||||||
int old_capacity;
|
int old_capacity;
|
||||||
int conflict_count;
|
int conflict_count;
|
||||||
|
|
@ -469,7 +461,7 @@ int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
old_capacity = *pHash->capacity;
|
old_capacity = *pHash->capacity;
|
||||||
new_capacity = (unsigned int *)fc_malloc(sizeof(unsigned int));
|
new_capacity = (unsigned int *)malloc(sizeof(unsigned int));
|
||||||
if (new_capacity == NULL)
|
if (new_capacity == NULL)
|
||||||
{
|
{
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
@ -513,7 +505,7 @@ int fc_hash_best_op(HashArray *pHash, const int suggest_capacity)
|
||||||
|
|
||||||
pHash->is_malloc_capacity = true;
|
pHash->is_malloc_capacity = true;
|
||||||
|
|
||||||
//fc_hash_stat_print(pHash);
|
//hash_stat_print(pHash);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -537,7 +529,7 @@ static HashData *_chain_find_entry(HashData **ppBucket, const void *key, \
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len)
|
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len)
|
||||||
{
|
{
|
||||||
unsigned int hash_code;
|
unsigned int hash_code;
|
||||||
HashData **ppBucket;
|
HashData **ppBucket;
|
||||||
|
|
@ -553,7 +545,7 @@ HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len)
|
||||||
return hash_data;
|
return hash_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *fc_hash_find(HashArray *pHash, const void *key, const int key_len)
|
void *hash_find(HashArray *pHash, const void *key, const int key_len)
|
||||||
{
|
{
|
||||||
unsigned int hash_code;
|
unsigned int hash_code;
|
||||||
HashData **ppBucket;
|
HashData **ppBucket;
|
||||||
|
|
@ -576,25 +568,7 @@ void *fc_hash_find(HashArray *pHash, const void *key, const int key_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value)
|
int hash_get(HashArray *pHash, const void *key, const int key_len,
|
||||||
{
|
|
||||||
HashData *hdata;
|
|
||||||
if ((hdata=fc_hash_find1_ex(pHash, key)) == NULL)
|
|
||||||
{
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
value->str = hdata->value;
|
|
||||||
value->len = hdata->value_len;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key)
|
|
||||||
{
|
|
||||||
return fc_hash_find_ex(pHash, key->str, key->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
|
|
||||||
void *value, int *value_len)
|
void *value, int *value_len)
|
||||||
{
|
{
|
||||||
unsigned int hash_code;
|
unsigned int hash_code;
|
||||||
|
|
@ -628,7 +602,7 @@ int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
|
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
|
||||||
void *value, const int value_len, const bool needLock)
|
void *value, const int value_len, const bool needLock)
|
||||||
{
|
{
|
||||||
unsigned int hash_code;
|
unsigned int hash_code;
|
||||||
|
|
@ -712,7 +686,7 @@ int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
pBuff = (char *)fc_malloc(bytes);
|
pBuff = (char *)malloc(bytes);
|
||||||
if (pBuff == NULL)
|
if (pBuff == NULL)
|
||||||
{
|
{
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
@ -760,7 +734,7 @@ int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
|
int64_t hash_inc_value(const HashData *old_data, const int inc,
|
||||||
char *new_value, int *new_value_len, void *arg)
|
char *new_value, int *new_value_len, void *arg)
|
||||||
{
|
{
|
||||||
int64_t n;
|
int64_t n;
|
||||||
|
|
@ -768,26 +742,27 @@ int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
|
||||||
{
|
{
|
||||||
if (old_data->value_len < *new_value_len)
|
if (old_data->value_len < *new_value_len)
|
||||||
{
|
{
|
||||||
memcpy(new_value, old_data->value, old_data->value_len);
|
memcpy(new_value, old_data->value, old_data->value_len);
|
||||||
new_value[old_data->value_len] = '\0';
|
new_value[old_data->value_len] = '\0';
|
||||||
n = strtoll(new_value, NULL, 10);
|
n = strtoll(new_value, NULL, 10);
|
||||||
n += inc;
|
n += inc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = inc;
|
n = inc;
|
||||||
}
|
}
|
||||||
|
*new_value_len = sprintf(new_value, "%"PRId64, n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = inc;
|
n = inc;
|
||||||
|
*new_value_len = sprintf(new_value, "%"PRId64, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
*new_value_len = fc_itoa(n, new_value);
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
const int inc, char *value, int *value_len,
|
const int inc, char *value, int *value_len,
|
||||||
ConvertValueFunc convert_func, void *arg)
|
ConvertValueFunc convert_func, void *arg)
|
||||||
{
|
{
|
||||||
|
|
@ -822,7 +797,7 @@ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = fc_hash_insert_ex(pHash, key, key_len, value, *value_len, false);
|
result = hash_insert_ex(pHash, key, key_len, value, *value_len, false);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
*value = '\0';
|
*value = '\0';
|
||||||
|
|
@ -838,7 +813,7 @@ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
const char *value, const int offset, const int value_len)
|
const char *value, const int offset, const int value_len)
|
||||||
{
|
{
|
||||||
unsigned int hash_code;
|
unsigned int hash_code;
|
||||||
|
|
@ -868,7 +843,7 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNewBuff = (char *)fc_malloc(offset + value_len);
|
pNewBuff = (char *)malloc(offset + value_len);
|
||||||
if (pNewBuff == NULL)
|
if (pNewBuff == NULL)
|
||||||
{
|
{
|
||||||
result = errno != 0 ? errno : ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
|
@ -880,7 +855,7 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
memcpy(pNewBuff, hash_data->value, offset);
|
memcpy(pNewBuff, hash_data->value, offset);
|
||||||
}
|
}
|
||||||
memcpy(pNewBuff + offset, value, value_len);
|
memcpy(pNewBuff + offset, value, value_len);
|
||||||
result = fc_hash_insert_ex(pHash, key, key_len, pNewBuff,
|
result = hash_insert_ex(pHash, key, key_len, pNewBuff,
|
||||||
offset + value_len, false);
|
offset + value_len, false);
|
||||||
free(pNewBuff);
|
free(pNewBuff);
|
||||||
}
|
}
|
||||||
|
|
@ -891,8 +866,8 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
result = ENOENT;
|
result = ENOENT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result = fc_hash_insert_ex(pHash, key, key_len,
|
result = hash_insert_ex(pHash, key, key_len, (void *)value,
|
||||||
(void *)value, value_len, false);
|
value_len, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
|
|
@ -909,7 +884,7 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_delete(HashArray *pHash, const void *key, const int key_len)
|
int hash_delete(HashArray *pHash, const void *key, const int key_len)
|
||||||
{
|
{
|
||||||
HashData **ppBucket;
|
HashData **ppBucket;
|
||||||
HashData *hash_data;
|
HashData *hash_data;
|
||||||
|
|
@ -942,7 +917,7 @@ int fc_hash_delete(HashArray *pHash, const void *key, const int key_len)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
|
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
|
||||||
{
|
{
|
||||||
HashData **ppBucket;
|
HashData **ppBucket;
|
||||||
HashData **bucket_end;
|
HashData **bucket_end;
|
||||||
|
|
@ -971,12 +946,12 @@ int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_count(HashArray *pHash)
|
int hash_count(HashArray *pHash)
|
||||||
{
|
{
|
||||||
return pHash->item_count;
|
return pHash->item_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
|
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
|
||||||
{
|
{
|
||||||
if (pHash->lock_count <= 0)
|
if (pHash->lock_count <= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -987,7 +962,7 @@ int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index)
|
||||||
pHash->lock_count);
|
pHash->lock_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index)
|
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index)
|
||||||
{
|
{
|
||||||
if (pHash->lock_count <= 0)
|
if (pHash->lock_count <= 0)
|
||||||
{
|
{
|
||||||
|
|
@ -1307,19 +1282,19 @@ int calc_hashnr1_ex(const void* key, const int key_len, \
|
||||||
\
|
\
|
||||||
h = init_value; \
|
h = init_value; \
|
||||||
pEnd = (unsigned char *)key + key_len; \
|
pEnd = (unsigned char *)key + key_len; \
|
||||||
for (p = (unsigned char *)key; p != pEnd; p++) \
|
for (p = (unsigned char *)key; p!= pEnd; p++) \
|
||||||
{ \
|
{ \
|
||||||
h = 31 * h + *p; \
|
h = 31 * h + *p; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
return h; \
|
return h; \
|
||||||
|
|
||||||
int fc_simple_hash(const void* key, const int key_len)
|
int simple_hash(const void* key, const int key_len)
|
||||||
{
|
{
|
||||||
SIMPLE_HASH_FUNC(0)
|
SIMPLE_HASH_FUNC(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_simple_hash_ex(const void* key, const int key_len, \
|
int simple_hash_ex(const void* key, const int key_len, \
|
||||||
const int init_value)
|
const int init_value)
|
||||||
{
|
{
|
||||||
SIMPLE_HASH_FUNC(init_value)
|
SIMPLE_HASH_FUNC(init_value)
|
||||||
|
|
|
||||||
111
src/hash.h
111
src/hash.h
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HASH_H_
|
#ifndef _HASH_H_
|
||||||
#define _HASH_H_
|
#define _HASH_H_
|
||||||
|
|
@ -93,16 +86,16 @@ typedef struct tagHashStat
|
||||||
* parameters:
|
* parameters:
|
||||||
* index: item index based 0
|
* index: item index based 0
|
||||||
* data: hash data, including key and value
|
* data: hash data, including key and value
|
||||||
* args: passed by fc_hash_walk function
|
* args: passed by hash_walk function
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
|
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
|
||||||
|
|
||||||
#define fc_hash_init(pHash, hash_func, capacity, load_factor) \
|
#define hash_init(pHash, hash_func, capacity, load_factor) \
|
||||||
fc_hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
|
hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
|
||||||
|
|
||||||
#define fc_hash_insert(pHash, key, key_len, value) \
|
#define hash_insert(pHash, key, key_len, value) \
|
||||||
fc_hash_insert_ex(pHash, key, key_len, value, 0, true)
|
hash_insert_ex(pHash, key, key_len, value, 0, true)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash init function
|
* hash init function
|
||||||
|
|
@ -115,7 +108,7 @@ typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
|
||||||
* bMallocValue: if need malloc value buffer
|
* bMallocValue: if need malloc value buffer
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
||||||
const unsigned int capacity, const double load_factor, \
|
const unsigned int capacity, const double load_factor, \
|
||||||
const int64_t max_bytes, const bool bMallocValue);
|
const int64_t max_bytes, const bool bMallocValue);
|
||||||
|
|
||||||
|
|
@ -125,7 +118,7 @@ int fc_hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
||||||
* lock_count: the lock count
|
* lock_count: the lock count
|
||||||
* return 0 for success, != 0 for error
|
* return 0 for success, != 0 for error
|
||||||
*/
|
*/
|
||||||
int fc_hash_set_locks(HashArray *pHash, const int lock_count);
|
int hash_set_locks(HashArray *pHash, const int lock_count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert the value
|
* convert the value
|
||||||
|
|
@ -137,12 +130,12 @@ int fc_hash_set_locks(HashArray *pHash, const int lock_count);
|
||||||
* arg: the user data
|
* arg: the user data
|
||||||
* return the number after increasement
|
* return the number after increasement
|
||||||
*/
|
*/
|
||||||
int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
|
int64_t hash_inc_value(const HashData *old_data, const int inc,
|
||||||
char *new_value, int *new_value_len, void *arg);
|
char *new_value, int *new_value_len, void *arg);
|
||||||
|
|
||||||
#define fc_hash_inc(pHash, key, key_len, inc, value, value_len) \
|
#define hash_inc(pHash, key, key_len, inc, value, value_len) \
|
||||||
fc_hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
|
hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
|
||||||
fc_hash_inc_value, NULL)
|
hash_inc_value, NULL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* atomic increase value
|
* atomic increase value
|
||||||
|
|
@ -158,7 +151,7 @@ int64_t fc_hash_inc_value(const HashData *old_data, const int inc,
|
||||||
* return 0 for success, != 0 for error (errno)
|
* return 0 for success, != 0 for error (errno)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
const int inc, char *value, int *value_len,
|
const int inc, char *value, int *value_len,
|
||||||
ConvertValueFunc convert_func, void *arg);
|
ConvertValueFunc convert_func, void *arg);
|
||||||
|
|
||||||
|
|
@ -168,7 +161,7 @@ int fc_hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
* pHash: the hash table
|
* pHash: the hash table
|
||||||
* return none
|
* return none
|
||||||
*/
|
*/
|
||||||
void fc_hash_destroy(HashArray *pHash);
|
void hash_destroy(HashArray *pHash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash insert key
|
* hash insert key
|
||||||
|
|
@ -182,7 +175,7 @@ void fc_hash_destroy(HashArray *pHash);
|
||||||
* return >= 0 for success, 0 for key already exist (update),
|
* return >= 0 for success, 0 for key already exist (update),
|
||||||
* 1 for new key (insert), < 0 for error
|
* 1 for new key (insert), < 0 for error
|
||||||
*/
|
*/
|
||||||
int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
|
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
|
||||||
void *value, const int value_len, const bool needLock);
|
void *value, const int value_len, const bool needLock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -193,7 +186,7 @@ int fc_hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
|
||||||
* key_len: length of th key
|
* key_len: length of th key
|
||||||
* return user data, return NULL when the key not exist
|
* return user data, return NULL when the key not exist
|
||||||
*/
|
*/
|
||||||
void *fc_hash_find(HashArray *pHash, const void *key, const int key_len);
|
void *hash_find(HashArray *pHash, const void *key, const int key_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash find key
|
* hash find key
|
||||||
|
|
@ -203,38 +196,8 @@ void *fc_hash_find(HashArray *pHash, const void *key, const int key_len);
|
||||||
* key_len: length of th key
|
* key_len: length of th key
|
||||||
* return hash data, return NULL when the key not exist
|
* return hash data, return NULL when the key not exist
|
||||||
*/
|
*/
|
||||||
HashData *fc_hash_find_ex(HashArray *pHash, const void *key, const int key_len);
|
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
|
||||||
|
|
||||||
/**
|
|
||||||
* hash find key
|
|
||||||
* parameters:
|
|
||||||
* pHash: the hash table
|
|
||||||
* key: the key to find
|
|
||||||
* return user data, return NULL when the key not exist
|
|
||||||
*/
|
|
||||||
static inline void *fc_hash_find1(HashArray *pHash, const string_t *key)
|
|
||||||
{
|
|
||||||
return fc_hash_find(pHash, key->str, key->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash get the value of the key
|
|
||||||
* parameters:
|
|
||||||
* pHash: the hash table
|
|
||||||
* key: the key to find
|
|
||||||
* value: store the value
|
|
||||||
* return 0 for success, != 0 fail (errno)
|
|
||||||
*/
|
|
||||||
int fc_hash_find2(HashArray *pHash, const string_t *key, string_t *value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hash find key
|
|
||||||
* parameters:
|
|
||||||
* pHash: the hash table
|
|
||||||
* key: the key to find
|
|
||||||
* return hash data, return NULL when the key not exist
|
|
||||||
*/
|
|
||||||
HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash get the value of the key
|
* hash get the value of the key
|
||||||
|
|
@ -247,7 +210,7 @@ HashData *fc_hash_find1_ex(HashArray *pHash, const string_t *key);
|
||||||
* output for the length fo the value
|
* output for the length fo the value
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
|
int hash_get(HashArray *pHash, const void *key, const int key_len,
|
||||||
void *value, int *value_len);
|
void *value, int *value_len);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -262,7 +225,7 @@ int fc_hash_get(HashArray *pHash, const void *key, const int key_len,
|
||||||
* value_len: length of the value
|
* value_len: length of the value
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
const char *value, const int offset, const int value_len);
|
const char *value, const int offset, const int value_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -273,7 +236,7 @@ int fc_hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
* key_len: length of th key
|
* key_len: length of th key
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_delete(HashArray *pHash, const void *key, const int key_len);
|
int hash_delete(HashArray *pHash, const void *key, const int key_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash walk (iterator)
|
* hash walk (iterator)
|
||||||
|
|
@ -283,7 +246,7 @@ int fc_hash_delete(HashArray *pHash, const void *key, const int key_len);
|
||||||
* args: extra args which will be passed to walkFunc
|
* args: extra args which will be passed to walkFunc
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
|
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get hash item count
|
* get hash item count
|
||||||
|
|
@ -291,7 +254,7 @@ int fc_hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
|
||||||
* pHash: the hash table
|
* pHash: the hash table
|
||||||
* return item count
|
* return item count
|
||||||
*/
|
*/
|
||||||
int fc_hash_count(HashArray *pHash);
|
int hash_count(HashArray *pHash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash best optimize
|
* hash best optimize
|
||||||
|
|
@ -300,7 +263,7 @@ int fc_hash_count(HashArray *pHash);
|
||||||
* suggest_capacity: suggest init capacity for speed
|
* suggest_capacity: suggest init capacity for speed
|
||||||
* return >0 for success, < 0 fail (errno)
|
* return >0 for success, < 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_best_op(HashArray *pHash, const int suggest_capacity);
|
int hash_best_op(HashArray *pHash, const int suggest_capacity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hash stat
|
* hash stat
|
||||||
|
|
@ -314,7 +277,7 @@ int fc_hash_best_op(HashArray *pHash, const int suggest_capacity);
|
||||||
* stat_size: stats array size (contain max elments)
|
* stat_size: stats array size (contain max elments)
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
|
int hash_stat(HashArray *pHash, HashStat *pStat, \
|
||||||
int *stat_by_lens, const int stat_size);
|
int *stat_by_lens, const int stat_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -323,7 +286,7 @@ int fc_hash_stat(HashArray *pHash, HashStat *pStat, \
|
||||||
* pHash: the hash table
|
* pHash: the hash table
|
||||||
* return none
|
* return none
|
||||||
*/
|
*/
|
||||||
void fc_hash_stat_print(HashArray *pHash);
|
void hash_stat_print(HashArray *pHash);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lock the bucket of hash table
|
* lock the bucket of hash table
|
||||||
|
|
@ -332,7 +295,7 @@ void fc_hash_stat_print(HashArray *pHash);
|
||||||
* bucket_index: the index of bucket
|
* bucket_index: the index of bucket
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
|
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unlock the bucket of hash table
|
* unlock the bucket of hash table
|
||||||
|
|
@ -341,7 +304,7 @@ int fc_hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
|
||||||
* bucket_index: the index of bucket
|
* bucket_index: the index of bucket
|
||||||
* return 0 for success, != 0 fail (errno)
|
* return 0 for success, != 0 fail (errno)
|
||||||
*/
|
*/
|
||||||
int fc_hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
|
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
|
||||||
|
|
||||||
int RSHash(const void *key, const int key_len);
|
int RSHash(const void *key, const int key_len);
|
||||||
|
|
||||||
|
|
@ -383,8 +346,8 @@ int calc_hashnr1(const void* key, const int key_len);
|
||||||
int calc_hashnr1_ex(const void* key, const int key_len, \
|
int calc_hashnr1_ex(const void* key, const int key_len, \
|
||||||
const int init_value);
|
const int init_value);
|
||||||
|
|
||||||
int fc_simple_hash(const void* key, const int key_len);
|
int simple_hash(const void* key, const int key_len);
|
||||||
int fc_simple_hash_ex(const void* key, const int key_len, \
|
int simple_hash_ex(const void* key, const int key_len, \
|
||||||
const int init_value);
|
const int init_value);
|
||||||
|
|
||||||
int CRC32(const void *key, const int key_len);
|
int CRC32(const void *key, const int key_len);
|
||||||
|
|
@ -402,7 +365,7 @@ int64_t CRC32_ex(const void *key, const int key_len, \
|
||||||
#define CALC_HASH_CODES4(buff, buff_len, hash_codes) \
|
#define CALC_HASH_CODES4(buff, buff_len, hash_codes) \
|
||||||
hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \
|
hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \
|
||||||
hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \
|
hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \
|
||||||
hash_codes[2] = fc_simple_hash_ex(buff, buff_len, hash_codes[2]); \
|
hash_codes[2] = simple_hash_ex(buff, buff_len, hash_codes[2]); \
|
||||||
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
|
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -410,7 +373,7 @@ int64_t CRC32_ex(const void *key, const int key_len, \
|
||||||
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
|
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
|
||||||
|
|
||||||
|
|
||||||
unsigned int *fc_hash_get_prime_capacity(const int capacity);
|
unsigned int *hash_get_prime_capacity(const int capacity);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
185
src/http_func.c
185
src/http_func.c
|
|
@ -1,25 +1,10 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright (C) 2008 Happy Fish / YuQing
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* FastDFS may be copied only under the terms of the GNU General
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* Public License V3, which may be found in the FastDFS source kit.
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
@ -36,133 +21,6 @@
|
||||||
#include "sockopt.h"
|
#include "sockopt.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "shared_func.h"
|
#include "shared_func.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "http_func.h"
|
|
||||||
|
|
||||||
#ifdef USE_LIBCURL
|
|
||||||
#include <curl/curl.h>
|
|
||||||
|
|
||||||
static bool curl_inited = false;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *buff;
|
|
||||||
int length;
|
|
||||||
int alloc_size;
|
|
||||||
bool dynamic_alloc;
|
|
||||||
} CurlCallbackArg;
|
|
||||||
|
|
||||||
static size_t curl_write_data(void *ptr, size_t size,
|
|
||||||
size_t nmemb, void *userdata)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
int alloc_size;
|
|
||||||
char *new_buff;
|
|
||||||
CurlCallbackArg *cbarg;
|
|
||||||
|
|
||||||
cbarg = (CurlCallbackArg *)userdata;
|
|
||||||
len = size * nmemb;
|
|
||||||
if ((cbarg->alloc_size - cbarg->length) < len) {
|
|
||||||
if (!cbarg->dynamic_alloc) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
alloc_size = 2 * cbarg->alloc_size;
|
|
||||||
while ((alloc_size - cbarg->length) < len) {
|
|
||||||
alloc_size *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_buff = (char *)fc_malloc(alloc_size);
|
|
||||||
if (new_buff == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbarg->length > 0) {
|
|
||||||
memcpy(new_buff, cbarg->buff, cbarg->length);
|
|
||||||
}
|
|
||||||
free(cbarg->buff);
|
|
||||||
|
|
||||||
cbarg->buff = new_buff;
|
|
||||||
cbarg->alloc_size = alloc_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(cbarg->buff + cbarg->length, ptr, len);
|
|
||||||
cbarg->length += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_url_content_ex(const char *url, const int url_len,
|
|
||||||
const int connect_timeout, const int network_timeout,
|
|
||||||
int *http_status, char **content, int *content_len,
|
|
||||||
char *error_info)
|
|
||||||
{
|
|
||||||
CURLcode result;
|
|
||||||
long response_code;
|
|
||||||
CURL *curl;
|
|
||||||
CurlCallbackArg cbarg;
|
|
||||||
|
|
||||||
*error_info = '\0';
|
|
||||||
*http_status = 0;
|
|
||||||
if (!curl_inited) {
|
|
||||||
if ((result=curl_global_init(CURL_GLOBAL_ALL)) != 0) {
|
|
||||||
sprintf(error_info, "curl_global_init fail "
|
|
||||||
"with code: %d", result);
|
|
||||||
return errno != 0 ? errno : EBUSY;
|
|
||||||
}
|
|
||||||
curl_inited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((curl=curl_easy_init()) == NULL) {
|
|
||||||
sprintf(error_info, "curl_easy_init fail");
|
|
||||||
return errno != 0 ? errno : EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*content == NULL) {
|
|
||||||
cbarg.dynamic_alloc = true;
|
|
||||||
cbarg.alloc_size = 16 * 1024;
|
|
||||||
cbarg.buff = (char *)fc_malloc(cbarg.alloc_size);
|
|
||||||
if (cbarg.buff == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cbarg.dynamic_alloc = false;
|
|
||||||
cbarg.alloc_size = *content_len;
|
|
||||||
cbarg.buff = *content;
|
|
||||||
}
|
|
||||||
cbarg.length = 0;
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, connect_timeout);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, connect_timeout + network_timeout);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &cbarg);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
|
||||||
|
|
||||||
result = curl_easy_perform(curl);
|
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
|
|
||||||
*http_status = response_code;
|
|
||||||
if (result == CURLE_OK) {
|
|
||||||
if (cbarg.dynamic_alloc) {
|
|
||||||
*content = cbarg.buff;
|
|
||||||
}
|
|
||||||
*content_len = cbarg.length;
|
|
||||||
*(*content + *content_len) = '\0';
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
sprintf(error_info, "curl_easy_perform fail with code: %d, %s",
|
|
||||||
result, curl_easy_strerror(result));
|
|
||||||
if (cbarg.dynamic_alloc && cbarg.buff != NULL) {
|
|
||||||
free(cbarg.buff);
|
|
||||||
}
|
|
||||||
*content_len = 0;
|
|
||||||
return EACCES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
int get_url_content_ex(const char *url, const int url_len,
|
int get_url_content_ex(const char *url, const int url_len,
|
||||||
const int connect_timeout, const int network_timeout,
|
const int connect_timeout, const int network_timeout,
|
||||||
|
|
@ -185,7 +43,6 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
char *pPort;
|
char *pPort;
|
||||||
char *pSpace;
|
char *pSpace;
|
||||||
|
|
||||||
*error_info = '\0';
|
|
||||||
*http_status = 0;
|
*http_status = 0;
|
||||||
if (*content == NULL)
|
if (*content == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -272,7 +129,7 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
"connect to %s:%u fail, errno: %d, " \
|
"connect to %s:%d fail, errno: %d, " \
|
||||||
"error info: %s", __LINE__, domain_name, \
|
"error info: %s", __LINE__, domain_name, \
|
||||||
port, result, STRERROR(result));
|
port, result, STRERROR(result));
|
||||||
|
|
||||||
|
|
@ -281,7 +138,7 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
|
|
||||||
out_len = snprintf(out_buff, sizeof(out_buff), \
|
out_len = snprintf(out_buff, sizeof(out_buff), \
|
||||||
"GET %s HTTP/1.0\r\n" \
|
"GET %s HTTP/1.0\r\n" \
|
||||||
"Host: %s:%u\r\n" \
|
"Host: %s:%d\r\n" \
|
||||||
"Connection: close\r\n" \
|
"Connection: close\r\n" \
|
||||||
"\r\n", pURI, domain_name, port);
|
"\r\n", pURI, domain_name, port);
|
||||||
if ((result=tcpsenddata(sock, out_buff, out_len, network_timeout)) != 0)
|
if ((result=tcpsenddata(sock, out_buff, out_len, network_timeout)) != 0)
|
||||||
|
|
@ -289,7 +146,7 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
"send data to %s:%u fail, errno: %d, " \
|
"send data to %s:%d fail, errno: %d, " \
|
||||||
"error info: %s", __LINE__, domain_name, \
|
"error info: %s", __LINE__, domain_name, \
|
||||||
port, result, STRERROR(result));
|
port, result, STRERROR(result));
|
||||||
|
|
||||||
|
|
@ -298,11 +155,18 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
|
|
||||||
if (bNeedAlloc)
|
if (bNeedAlloc)
|
||||||
{
|
{
|
||||||
*content = (char *)fc_malloc(alloc_size + 1);
|
*content = (char *)malloc(alloc_size + 1);
|
||||||
if (*content == NULL)
|
if (*content == NULL)
|
||||||
{
|
{
|
||||||
close(sock);
|
close(sock);
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, alloc_size + 1, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,12 +178,20 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
if (bNeedAlloc)
|
if (bNeedAlloc)
|
||||||
{
|
{
|
||||||
alloc_size *= 2;
|
alloc_size *= 2;
|
||||||
*content = (char *)fc_realloc(*content, alloc_size + 1);
|
*content = (char *)realloc(*content, alloc_size + 1);
|
||||||
if (*content == NULL)
|
if (*content == NULL)
|
||||||
{
|
{
|
||||||
*content_len = 0;
|
*content_len = 0;
|
||||||
close(sock);
|
close(sock);
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"realloc %d bytes fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, \
|
||||||
|
alloc_size + 1, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
recv_bytes = alloc_size - *content_len;
|
recv_bytes = alloc_size - *content_len;
|
||||||
|
|
@ -347,7 +219,7 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
"recv data from %s:%u fail, errno: %d, " \
|
"recv data from %s:%d fail, errno: %d, " \
|
||||||
"error info: %s", __LINE__, domain_name, \
|
"error info: %s", __LINE__, domain_name, \
|
||||||
port, result, STRERROR(result));
|
port, result, STRERROR(result));
|
||||||
|
|
||||||
|
|
@ -359,7 +231,7 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
if (pContent == NULL)
|
if (pContent == NULL)
|
||||||
{
|
{
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
"response data from %s:%u is invalid", \
|
"response data from %s:%d is invalid", \
|
||||||
__LINE__, domain_name, port);
|
__LINE__, domain_name, port);
|
||||||
|
|
||||||
result = EINVAL;
|
result = EINVAL;
|
||||||
|
|
@ -371,7 +243,7 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
if (pSpace == NULL || pSpace >= pContent)
|
if (pSpace == NULL || pSpace >= pContent)
|
||||||
{
|
{
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
"response data from %s:%u is invalid", \
|
"response data from %s:%d is invalid", \
|
||||||
__LINE__, domain_name, port);
|
__LINE__, domain_name, port);
|
||||||
|
|
||||||
result = EINVAL;
|
result = EINVAL;
|
||||||
|
|
@ -380,8 +252,9 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
|
|
||||||
*http_status = atoi(pSpace + 1);
|
*http_status = atoi(pSpace + 1);
|
||||||
*content_len -= pContent - *content;
|
*content_len -= pContent - *content;
|
||||||
memmove(*content, pContent, *content_len);
|
memcpy(*content, pContent, *content_len);
|
||||||
*(*content + *content_len) = '\0';
|
*(*content + *content_len) = '\0';
|
||||||
|
*error_info = '\0';
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
close(sock);
|
close(sock);
|
||||||
|
|
@ -395,8 +268,6 @@ int get_url_content_ex(const char *url, const int url_len,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int get_url_content(const char *url, const int connect_timeout, \
|
int get_url_content(const char *url, const int connect_timeout, \
|
||||||
const int network_timeout, int *http_status, \
|
const int network_timeout, int *http_status, \
|
||||||
char **content, int *content_len, char *error_info)
|
char **content, int *content_len, char *error_info)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HTTP_FUNC_H
|
#ifndef _HTTP_FUNC_H
|
||||||
#define _HTTP_FUNC_H
|
#define _HTTP_FUNC_H
|
||||||
|
|
@ -23,14 +16,6 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
|
|
||||||
#define IS_URL_RESOURCE(str) \
|
|
||||||
((strncasecmp(str, "http://", 7) == 0) || \
|
|
||||||
(strncasecmp(str, "https://", 8) == 0))
|
|
||||||
|
|
||||||
#define IS_URL_RESOURCE_EX(s) \
|
|
||||||
((s)->len >= 8 && ((memcmp((s)->str, "http://", 7) == 0) || \
|
|
||||||
(memcmp((s)->str, "https://", 8) == 0)))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -84,7 +77,6 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
|
||||||
const char *local_ip;
|
const char *local_ip;
|
||||||
const char *private_ip;
|
const char *private_ip;
|
||||||
struct in_addr ip_addr;
|
struct in_addr ip_addr;
|
||||||
struct in6_addr ip6_addr;
|
|
||||||
|
|
||||||
private_ip = get_first_local_private_ip();
|
private_ip = get_first_local_private_ip();
|
||||||
if (private_ip != NULL)
|
if (private_ip != NULL)
|
||||||
|
|
@ -101,28 +93,16 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
|
||||||
context->fd = -1;
|
context->fd = -1;
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
else if (strcmp(local_ip, LOCAL_LOOPBACK_IPv4) == 0)
|
else if (strcmp(local_ip, LOCAL_LOOPBACK_IP) == 0)
|
||||||
{
|
{
|
||||||
/* 注意,当系统存在IPv6回环地址时,为了简化系统的改动,
|
|
||||||
会将IPv6回环地址修改成IPv4回环地址返回
|
|
||||||
此处错误打印时,需要带上IPv6回环地址
|
|
||||||
*/
|
|
||||||
logWarning("file: "__FILE__", line: %d, "
|
logWarning("file: "__FILE__", line: %d, "
|
||||||
"can't get local ip address, set to %s or %s",
|
"can't get local ip address, set to %s",
|
||||||
__LINE__, LOCAL_LOOPBACK_IPv4, LOCAL_LOOPBACK_IPv6);
|
__LINE__, LOCAL_LOOPBACK_IP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inet_pton(AF_INET, local_ip, &ip_addr) == 1)
|
if (inet_pton(AF_INET, local_ip, &ip_addr) != 1)
|
||||||
{
|
{
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
else if(inet_pton(AF_INET6, local_ip, &ip6_addr) == 1)
|
|
||||||
{
|
|
||||||
ip_addr.s_addr = *((in_addr_64_t *)&ip6_addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"invalid local ip address: %s",
|
"invalid local ip address: %s",
|
||||||
__LINE__, local_ip);
|
__LINE__, local_ip);
|
||||||
|
|
@ -136,14 +116,13 @@ int id_generator_init_extra_ex(struct idg_context *context, const char *filename
|
||||||
mid = ntohl(ip_addr.s_addr) & ((1 << mid_bits) - 1);
|
mid = ntohl(ip_addr.s_addr) & ((1 << mid_bits) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((context->fd = open(filename, O_RDWR | O_CLOEXEC)) < 0)
|
if ((context->fd = open(filename, O_RDWR)) < 0)
|
||||||
{
|
{
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
{
|
{
|
||||||
mode_t old_mode;
|
mode_t old_mode;
|
||||||
old_mode = umask(0);
|
old_mode = umask(0);
|
||||||
if ((context->fd=open(filename, O_RDWR | O_CREAT |
|
if ((context->fd=open(filename, O_RDWR | O_CREAT, mode)) < 0)
|
||||||
O_CLOEXEC, mode)) < 0)
|
|
||||||
{
|
{
|
||||||
result = errno != 0 ? errno : EACCES;
|
result = errno != 0 ? errno : EACCES;
|
||||||
}
|
}
|
||||||
|
|
@ -203,13 +182,12 @@ void id_generator_destroy(struct idg_context *context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int id_generator_next_extra_ptr(struct idg_context *context,
|
int id_generator_next_extra(struct idg_context *context, const int extra,
|
||||||
const int *extra, int64_t *id)
|
int64_t *id)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int len;
|
int len;
|
||||||
int bytes;
|
int bytes;
|
||||||
int new_extra;
|
|
||||||
int64_t sn;
|
int64_t sn;
|
||||||
char buff[32];
|
char buff[32];
|
||||||
char *endptr;
|
char *endptr;
|
||||||
|
|
@ -272,18 +250,9 @@ int id_generator_next_extra_ptr(struct idg_context *context,
|
||||||
|
|
||||||
file_unlock(context->fd);
|
file_unlock(context->fd);
|
||||||
|
|
||||||
if (extra == NULL)
|
|
||||||
{
|
|
||||||
new_extra = sn % (1 << context->extra_bits);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
new_extra = *extra;
|
|
||||||
}
|
|
||||||
|
|
||||||
*id = (((int64_t)time(NULL)) << context->mes_bits_sum) |
|
*id = (((int64_t)time(NULL)) << context->mes_bits_sum) |
|
||||||
context->masked_mid |
|
context->masked_mid | ((extra << context->sn_bits) & context->extra_mask) |
|
||||||
((new_extra << context->sn_bits) & context->extra_mask) |
|
|
||||||
(sn & context->sn_mask);
|
(sn & context->sn_mask);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2016 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
64 bits id generator for multi processes, the generated id format:
|
64 bits id generator for multi processes, the generated id format:
|
||||||
|
|
@ -26,6 +19,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
|
|
@ -128,42 +122,15 @@ static inline int id_generator_init(struct idg_context *context, const char *fil
|
||||||
void id_generator_destroy(struct idg_context *context);
|
void id_generator_destroy(struct idg_context *context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate next id with extra pointer
|
* generate next id ex
|
||||||
* parameter:
|
|
||||||
* context: the id generator context
|
|
||||||
* extra: the extra data pointer, NULL for set extra data to sn % (1 << extra_bits)
|
|
||||||
* id: store the id
|
|
||||||
* return error no, 0 for success, none zero for fail
|
|
||||||
*/
|
|
||||||
int id_generator_next_extra_ptr(struct idg_context *context,
|
|
||||||
const int *extra, int64_t *id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generate next id with extra data
|
|
||||||
* parameter:
|
* parameter:
|
||||||
* context: the id generator context
|
* context: the id generator context
|
||||||
* extra: the extra data
|
* extra: the extra data
|
||||||
* id: store the id
|
* id: store the id
|
||||||
* return error no, 0 for success, none zero for fail
|
* return error no, 0 for success, none zero for fail
|
||||||
*/
|
*/
|
||||||
static inline int id_generator_next_extra(struct idg_context *context,
|
int id_generator_next_extra(struct idg_context *context, const int extra,
|
||||||
const int extra, int64_t *id)
|
int64_t *id);
|
||||||
{
|
|
||||||
return id_generator_next_extra_ptr(context, &extra, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generate next id, set extra data to sn % (1 << extra_bits)
|
|
||||||
* parameter:
|
|
||||||
* context: the id generator context
|
|
||||||
* id: store the id
|
|
||||||
* return error no, 0 for success, none zero for fail
|
|
||||||
*/
|
|
||||||
static inline int id_generator_next_extra_by_mod(struct idg_context *context,
|
|
||||||
int64_t *id)
|
|
||||||
{
|
|
||||||
return id_generator_next_extra_ptr(context, NULL, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generate next id
|
* generate next id
|
||||||
|
|
@ -174,8 +141,7 @@ static inline int id_generator_next_extra_by_mod(struct idg_context *context,
|
||||||
*/
|
*/
|
||||||
static inline int id_generator_next(struct idg_context *context, int64_t *id)
|
static inline int id_generator_next(struct idg_context *context, int64_t *id)
|
||||||
{
|
{
|
||||||
const int extra = 0;
|
return id_generator_next_extra(context, 0, id);
|
||||||
return id_generator_next_extra_ptr(context, &extra, id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//ini_file_reader.h
|
//ini_file_reader.h
|
||||||
#ifndef INI_FILE_READER_H
|
#ifndef INI_FILE_READER_H
|
||||||
|
|
@ -23,8 +16,8 @@
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
#define FAST_INI_ITEM_NAME_LEN 63
|
#define FAST_INI_ITEM_NAME_LEN 64
|
||||||
#define FAST_INI_ITEM_VALUE_LEN 255
|
#define FAST_INI_ITEM_VALUE_LEN 256
|
||||||
#define FAST_INI_ITEM_NAME_SIZE (FAST_INI_ITEM_NAME_LEN + 1)
|
#define FAST_INI_ITEM_NAME_SIZE (FAST_INI_ITEM_NAME_LEN + 1)
|
||||||
#define FAST_INI_ITEM_VALUE_SIZE (FAST_INI_ITEM_VALUE_LEN + 1)
|
#define FAST_INI_ITEM_VALUE_SIZE (FAST_INI_ITEM_VALUE_LEN + 1)
|
||||||
|
|
||||||
|
|
@ -33,22 +26,8 @@
|
||||||
#define FAST_INI_ANNOTATION_WITH_BUILTIN 2
|
#define FAST_INI_ANNOTATION_WITH_BUILTIN 2
|
||||||
#define FAST_INI_ANNOTATION_NONE FAST_INI_ANNOTATION_DISABLE
|
#define FAST_INI_ANNOTATION_NONE FAST_INI_ANNOTATION_DISABLE
|
||||||
|
|
||||||
#define FAST_INI_FLAGS_NONE 0
|
#define FAST_INI_FLAGS_NONE 0
|
||||||
#define FAST_INI_FLAGS_SHELL_EXECUTE 1
|
#define FAST_INI_FLAGS_SHELL_EXECUTE 1
|
||||||
#define FAST_INI_FLAGS_DISABLE_SAME_SECTION_MERGE 2
|
|
||||||
|
|
||||||
typedef bool (*IniSectionNameFilterFunc)(const char *section_name,
|
|
||||||
const int name_len, void *args);
|
|
||||||
|
|
||||||
#define FAST_INI_SET_FULL_CTX_EX(ctx, config_file, sname, ini_context) \
|
|
||||||
do { \
|
|
||||||
ctx.filename = config_file; \
|
|
||||||
ctx.section_name = sname; \
|
|
||||||
ctx.context = ini_context; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define FAST_INI_SET_FULL_CTX(ctx, config_file, sname) \
|
|
||||||
FAST_INI_SET_FULL_CTX_EX(ctx, config_file, sname, NULL)
|
|
||||||
|
|
||||||
typedef struct ini_item
|
typedef struct ini_item
|
||||||
{
|
{
|
||||||
|
|
@ -60,7 +39,7 @@ typedef struct ini_section
|
||||||
{
|
{
|
||||||
IniItem *items;
|
IniItem *items;
|
||||||
int count; //item count
|
int count; //item count
|
||||||
int alloc;
|
int alloc_count;
|
||||||
} IniSection;
|
} IniSection;
|
||||||
|
|
||||||
typedef struct ini_section_info
|
typedef struct ini_section_info
|
||||||
|
|
@ -79,30 +58,13 @@ typedef struct ini_context
|
||||||
char flags;
|
char flags;
|
||||||
} IniContext;
|
} IniContext;
|
||||||
|
|
||||||
typedef struct ini_full_context
|
typedef struct ini_annotation_map {
|
||||||
{
|
|
||||||
const char *filename;
|
|
||||||
const char *section_name;
|
|
||||||
IniContext *context;
|
|
||||||
} IniFullContext;
|
|
||||||
|
|
||||||
typedef struct ini_annotation_entry {
|
|
||||||
char *func_name;
|
char *func_name;
|
||||||
void *arg;
|
int (*func_init) ();
|
||||||
void *dlhandle;
|
void (*func_destroy) ();
|
||||||
|
int (*func_get) (IniContext *context, char *param, char **pOutValue, int max_values);
|
||||||
int (*func_init) (struct ini_annotation_entry *annotation);
|
void (*func_free) (char **values, const int count);
|
||||||
void (*func_destroy) (struct ini_annotation_entry *annotation);
|
} AnnotationMap;
|
||||||
int (*func_get) (IniContext *context,
|
|
||||||
struct ini_annotation_entry *annotation,
|
|
||||||
const IniItem *item,
|
|
||||||
char **pOutValue, int max_values);
|
|
||||||
|
|
||||||
void (*func_free) (struct ini_annotation_entry *annotation,
|
|
||||||
char **values, const int count);
|
|
||||||
|
|
||||||
bool inited;
|
|
||||||
} AnnotationEntry;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
@ -114,67 +76,9 @@ extern "C" {
|
||||||
strcasecmp(pValue, "on") == 0 || \
|
strcasecmp(pValue, "on") == 0 || \
|
||||||
strcmp(pValue, "1") == 0)
|
strcmp(pValue, "1") == 0)
|
||||||
|
|
||||||
#define iniGetStrValue(szSectionName, szItemName, pContext) \
|
int iniSetAnnotationCallBack(AnnotationMap *map, int count);
|
||||||
iniGetStrValueEx(szSectionName, szItemName, pContext, false)
|
|
||||||
|
|
||||||
#define iniGetCharValue(szSectionName, szItemName, pContext, cDefaultValue) \
|
|
||||||
iniGetCharValueEx(szSectionName, szItemName, \
|
|
||||||
pContext, cDefaultValue, false)
|
|
||||||
|
|
||||||
#define iniGetIntValue(szSectionName, szItemName, pContext, nDefaultValue) \
|
|
||||||
iniGetIntValueEx(szSectionName, szItemName, \
|
|
||||||
pContext, nDefaultValue, false)
|
|
||||||
|
|
||||||
#define iniGetInt64Value(szSectionName, szItemName, pContext, nDefaultValue) \
|
|
||||||
iniGetInt64ValueEx(szSectionName, szItemName, \
|
|
||||||
pContext, nDefaultValue, false)
|
|
||||||
|
|
||||||
#define iniGetDoubleValue(szSectionName, szItemName, pContext, dbDefaultValue) \
|
|
||||||
iniGetDoubleValueEx(szSectionName, szItemName, \
|
|
||||||
pContext, dbDefaultValue, false)
|
|
||||||
|
|
||||||
#define iniGetBoolValue(szSectionName, szItemName, pContext, bDefaultValue) \
|
|
||||||
iniGetBoolValueEx(szSectionName, szItemName, \
|
|
||||||
pContext, bDefaultValue, false)
|
|
||||||
|
|
||||||
#define iniGetPercentValue(ini_ctx, item_name, item_value, default_value) \
|
|
||||||
iniGetPercentValueEx(ini_ctx, item_name, item_value, default_value, false)
|
|
||||||
|
|
||||||
#define iniGetByteValue(szSectionName, szItemName, pContext, nDefaultValue) \
|
|
||||||
iniGetByteValueEx(szSectionName, szItemName, \
|
|
||||||
pContext, nDefaultValue, 1, false)
|
|
||||||
|
|
||||||
#define iniGetIntCorrectValue(ini_ctx, item_name, \
|
|
||||||
default_value, min_value, max_value) \
|
|
||||||
iniGetIntCorrectValueEx(ini_ctx, item_name, \
|
|
||||||
default_value, min_value, max_value, false)
|
|
||||||
|
|
||||||
#define iniGetInt64CorrectValue(ini_ctx, item_name, \
|
|
||||||
default_value, min_value, max_value) \
|
|
||||||
iniGetInt64CorrectValueEx(ini_ctx, item_name, \
|
|
||||||
default_value, min_value, max_value, false)
|
|
||||||
|
|
||||||
#define iniGetByteCorrectValue(ini_ctx, item_name, \
|
|
||||||
default_value, min_value, max_value) \
|
|
||||||
iniGetByteCorrectValueEx(ini_ctx, item_name, \
|
|
||||||
default_value, 1, min_value, max_value, false)
|
|
||||||
|
|
||||||
#define iniGetDoubleCorrectValue(ini_ctx, item_name, \
|
|
||||||
default_value, min_value, max_value) \
|
|
||||||
iniGetDoubleCorrectValueEx(ini_ctx, item_name, \
|
|
||||||
default_value, 1, min_value, max_value, false)
|
|
||||||
|
|
||||||
#define iniGetPercentCorrectValue(ini_ctx, item_name, \
|
|
||||||
item_value, default_value, min_value, max_value) \
|
|
||||||
iniGetPercentCorrectValueEx(ini_ctx, item_name, item_value, \
|
|
||||||
default_value, min_value, max_value, false)
|
|
||||||
|
|
||||||
int iniSetAnnotationCallBack(AnnotationEntry *annotations, int count);
|
|
||||||
void iniDestroyAnnotationCallBack();
|
void iniDestroyAnnotationCallBack();
|
||||||
|
|
||||||
void iniAnnotationFreeValues(struct ini_annotation_entry *annotation,
|
|
||||||
char **values, const int count);
|
|
||||||
|
|
||||||
/** load ini items from file
|
/** load ini items from file
|
||||||
* parameters:
|
* parameters:
|
||||||
* szFilename: the filename, can be an URL
|
* szFilename: the filename, can be an URL
|
||||||
|
|
@ -183,16 +87,6 @@ void iniAnnotationFreeValues(struct ini_annotation_entry *annotation,
|
||||||
*/
|
*/
|
||||||
int iniLoadFromFile(const char *szFilename, IniContext *pContext);
|
int iniLoadFromFile(const char *szFilename, IniContext *pContext);
|
||||||
|
|
||||||
/** load ini items from file with flags
|
|
||||||
* parameters:
|
|
||||||
* szFilename: the filename, can be an URL
|
|
||||||
* pContext: the ini context
|
|
||||||
* flags: the flags
|
|
||||||
* return: error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int iniLoadFromFile1(const char *szFilename,
|
|
||||||
IniContext *pContext, const char flags);
|
|
||||||
|
|
||||||
/** load ini items from file
|
/** load ini items from file
|
||||||
* parameters:
|
* parameters:
|
||||||
* szFilename: the filename, can be an URL
|
* szFilename: the filename, can be an URL
|
||||||
|
|
@ -204,7 +98,7 @@ int iniLoadFromFile1(const char *szFilename,
|
||||||
* return: error no, 0 for success, != 0 fail
|
* return: error no, 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
|
int iniLoadFromFileEx(const char *szFilename, IniContext *pContext,
|
||||||
const char annotation_type, AnnotationEntry *annotations, const int count,
|
const char annotation_type, AnnotationMap *annotations, const int count,
|
||||||
const char flags);
|
const char flags);
|
||||||
|
|
||||||
/** load ini items from string buffer
|
/** load ini items from string buffer
|
||||||
|
|
@ -226,18 +120,9 @@ int iniLoadFromBuffer(char *content, IniContext *pContext);
|
||||||
* return: error no, 0 for success, != 0 fail
|
* return: error no, 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int iniLoadFromBufferEx(char *content, IniContext *pContext,
|
int iniLoadFromBufferEx(char *content, IniContext *pContext,
|
||||||
const char annotation_type, AnnotationEntry *annotations, const int count,
|
const char annotation_type, AnnotationMap *annotations, const int count,
|
||||||
const char flags);
|
const char flags);
|
||||||
|
|
||||||
/** load ini items from string buffer with flags
|
|
||||||
* parameters:
|
|
||||||
* content: the string buffer to parse
|
|
||||||
* pContext: the ini context
|
|
||||||
* flags: the flags
|
|
||||||
* return: error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int iniLoadFromBuffer1(char *content, IniContext *pContext, const char flags);
|
|
||||||
|
|
||||||
/** free ini context
|
/** free ini context
|
||||||
* parameters:
|
* parameters:
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
|
|
@ -251,25 +136,10 @@ void iniFreeContext(IniContext *pContext);
|
||||||
* global section
|
* global section
|
||||||
* szItemName: the item name
|
* szItemName: the item name
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: item value, return NULL when the item not exist
|
* return: item value, return NULL when the item not exist
|
||||||
*/
|
*/
|
||||||
char *iniGetStrValueEx(const char *szSectionName, const char *szItemName,
|
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
|
||||||
IniContext *pContext, const bool bRetryGlobal);
|
IniContext *pContext);
|
||||||
|
|
||||||
/** get the first charactor
|
|
||||||
* parameters:
|
|
||||||
* szSectionName: the section name, NULL or empty string for
|
|
||||||
* global section
|
|
||||||
* szItemName: the item name
|
|
||||||
* pContext: the ini context
|
|
||||||
* cDefaultValue: the default value
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: item value, return default value when the item not exist
|
|
||||||
*/
|
|
||||||
char iniGetCharValueEx(const char *szSectionName, const char *szItemName,
|
|
||||||
IniContext *pContext, const char cDefaultValue,
|
|
||||||
const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item string value
|
/** get item string value
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
@ -291,65 +161,10 @@ int iniGetValues(const char *szSectionName, const char *szItemName, \
|
||||||
* szItemName: the item name
|
* szItemName: the item name
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
* nDefaultValue: the default value
|
* nDefaultValue: the default value
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: item value, return nDefaultValue when the item not exist
|
* return: item value, return nDefaultValue when the item not exist
|
||||||
*/
|
*/
|
||||||
int iniGetIntValueEx(const char *szSectionName,
|
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
|
||||||
const char *szItemName, IniContext *pContext,
|
IniContext *pContext, const int nDefaultValue);
|
||||||
const int nDefaultValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** check and correct int value
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* nValue: the item value
|
|
||||||
* nMinValue: the min value to check (including)
|
|
||||||
* nMaxValue: the max value to check (including)
|
|
||||||
* return: corrected value
|
|
||||||
*/
|
|
||||||
int64_t iniCheckAndCorrectIntValue(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const int64_t nValue,
|
|
||||||
const int64_t nMinValue, const int64_t nMaxValue);
|
|
||||||
|
|
||||||
/** check and correct double value
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* dValue: the item value
|
|
||||||
* dMinValue: the min value to check (including)
|
|
||||||
* dMaxValue: the max value to check (including)
|
|
||||||
* return: corrected value
|
|
||||||
*/
|
|
||||||
double iniCheckAndCorrectDoubleValue(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const double dValue,
|
|
||||||
const double dMinValue, const double dMaxValue);
|
|
||||||
|
|
||||||
/** check and correct double value (show as percentage)
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* dValue: the item value
|
|
||||||
* dMinValue: the min value to check (including)
|
|
||||||
* dMaxValue: the max value to check (including)
|
|
||||||
* return: corrected value
|
|
||||||
*/
|
|
||||||
double iniCheckAndCorrectPercentValue(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const double dValue,
|
|
||||||
const double dMinValue, const double dMaxValue);
|
|
||||||
|
|
||||||
/** get item correct value (32 bits integer)
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* nDefaultValue: the default value
|
|
||||||
* nMinValue: the min value to check (including)
|
|
||||||
* nMaxValue: the max value to check (including)
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: item value, return nDefaultValue when the item not exist
|
|
||||||
*/
|
|
||||||
int iniGetIntCorrectValueEx(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const int nDefaultValue,
|
|
||||||
const int nMinValue, const int nMaxValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item string value array
|
/** get item string value array
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
@ -360,69 +175,20 @@ int iniGetIntCorrectValueEx(IniFullContext *pIniContext,
|
||||||
* nTargetCount: store the item value count
|
* nTargetCount: store the item value count
|
||||||
* return: item value array, return NULL when the item not exist
|
* return: item value array, return NULL when the item not exist
|
||||||
*/
|
*/
|
||||||
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName,
|
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
|
||||||
IniContext *pContext, int *nTargetCount);
|
IniContext *pContext, int *nTargetCount);
|
||||||
|
|
||||||
/** get item value (64 bits integer)
|
/** get item int64 value (64 bits)
|
||||||
* parameters:
|
* parameters:
|
||||||
* szSectionName: the section name, NULL or empty string for
|
* szSectionName: the section name, NULL or empty string for
|
||||||
* global section
|
* global section
|
||||||
* szItemName: the item name
|
* szItemName: the item name
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
* nDefaultValue: the default value
|
* nDefaultValue: the default value
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: int64 value, return nDefaultValue when the item not exist
|
* return: int64 value, return nDefaultValue when the item not exist
|
||||||
*/
|
*/
|
||||||
int64_t iniGetInt64ValueEx(const char *szSectionName,
|
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
|
||||||
const char *szItemName, IniContext *pContext,
|
IniContext *pContext, const int64_t nDefaultValue);
|
||||||
const int64_t nDefaultValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item correct value (64 bits integer)
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* nDefaultValue: the default value
|
|
||||||
* nMinValue: the min value to check (including)
|
|
||||||
* nMaxValue: the max value to check (including)
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: int64 value, return nDefaultValue when the item not exist
|
|
||||||
*/
|
|
||||||
int64_t iniGetInt64CorrectValueEx(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const int64_t nDefaultValue,
|
|
||||||
const int64_t nMinValue, const int64_t nMaxValue,
|
|
||||||
const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item byte value (64 bits integer)
|
|
||||||
* parameters:
|
|
||||||
* szSectionName: the section name, NULL or empty string for
|
|
||||||
* global section
|
|
||||||
* szItemName: the item name
|
|
||||||
* pContext: the ini context
|
|
||||||
* nDefaultValue: the default value
|
|
||||||
* nDefaultUnitBytes: the default byte unit, such as 1 for byte, 1024 for KB
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: int64 value, return nDefaultValue when the item not exist
|
|
||||||
*/
|
|
||||||
int64_t iniGetByteValueEx(const char *szSectionName,
|
|
||||||
const char *szItemName, IniContext *pContext,
|
|
||||||
const int64_t nDefaultValue, const int nDefaultUnitBytes,
|
|
||||||
const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item correct byte value (64 bits integer)
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* nDefaultValue: the default value
|
|
||||||
* nDefaultUnitBytes: the default byte unit, such as 1 for byte, 1024 for KB
|
|
||||||
* nMinValue: the min value to check (including)
|
|
||||||
* nMaxValue: the max value to check (including)
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: int64 value, return nDefaultValue when the item not exist
|
|
||||||
*/
|
|
||||||
int64_t iniGetByteCorrectValueEx(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const int64_t nDefaultValue,
|
|
||||||
const int nDefaultUnitBytes, const int64_t nMinValue,
|
|
||||||
const int64_t nMaxValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item boolean value
|
/** get item boolean value
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
@ -431,12 +197,10 @@ int64_t iniGetByteCorrectValueEx(IniFullContext *pIniContext,
|
||||||
* szItemName: the item name
|
* szItemName: the item name
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
* bDefaultValue: the default value
|
* bDefaultValue: the default value
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: item boolean value, return bDefaultValue when the item not exist
|
* return: item boolean value, return bDefaultValue when the item not exist
|
||||||
*/
|
*/
|
||||||
bool iniGetBoolValueEx(const char *szSectionName,
|
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
|
||||||
const char *szItemName, IniContext *pContext,
|
IniContext *pContext, const bool bDefaultValue);
|
||||||
const bool bDefaultValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item double value
|
/** get item double value
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
@ -445,56 +209,10 @@ bool iniGetBoolValueEx(const char *szSectionName,
|
||||||
* szItemName: the item name
|
* szItemName: the item name
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
* dbDefaultValue: the default value
|
* dbDefaultValue: the default value
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: item value, return dbDefaultValue when the item not exist
|
* return: item value, return dbDefaultValue when the item not exist
|
||||||
*/
|
*/
|
||||||
double iniGetDoubleValueEx(const char *szSectionName,
|
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
|
||||||
const char *szItemName, IniContext *pContext,
|
IniContext *pContext, const double dbDefaultValue);
|
||||||
const double dbDefaultValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item correct double value
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* dbDefaultValue: the default value
|
|
||||||
* dbMinValue: the min value to check (including)
|
|
||||||
* dbMaxValue: the max value to check (including)
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: double value, return dbDefaultValue when the item not exist
|
|
||||||
*/
|
|
||||||
double iniGetDoubleCorrectValueEx(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, const double dbDefaultValue,
|
|
||||||
const double dbMinValue, const double dbMaxValue,
|
|
||||||
const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** get item percent double value
|
|
||||||
* parameters:
|
|
||||||
* ini_ctx: the full context
|
|
||||||
* item_name: the item name
|
|
||||||
* item_value: store the item value
|
|
||||||
* default_value: the default value
|
|
||||||
* retry_global: if fetch from global section when the item not exist
|
|
||||||
* return: error no, 0 for success, != 0 for fail
|
|
||||||
*/
|
|
||||||
int iniGetPercentValueEx(IniFullContext *ini_ctx,
|
|
||||||
const char *item_name, double *item_value,
|
|
||||||
const double default_value, const bool retry_global);
|
|
||||||
|
|
||||||
/** get item correct double value (show as percentage)
|
|
||||||
* parameters:
|
|
||||||
* pIniContext: the full ini context
|
|
||||||
* szItemName: the item name
|
|
||||||
* dbItemValue: store the item value
|
|
||||||
* dbDefaultValue: the default value
|
|
||||||
* dbMinValue: the min value to check (including)
|
|
||||||
* dbMaxValue: the max value to check (including)
|
|
||||||
* bRetryGlobal: if fetch from global section when the item not exist
|
|
||||||
* return: error no, 0 for success, != 0 for fail
|
|
||||||
*/
|
|
||||||
int iniGetPercentCorrectValueEx(IniFullContext *pIniContext,
|
|
||||||
const char *szItemName, double *dbItemValue,
|
|
||||||
const double dbDefaultValue, const double dbMinValue,
|
|
||||||
const double dbMaxValue, const bool bRetryGlobal);
|
|
||||||
|
|
||||||
/** print all items
|
/** print all items
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
@ -513,7 +231,7 @@ static inline const char *iniGetConfigPath(IniContext *pContext)
|
||||||
return pContext->config_path;
|
return pContext->config_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return the section names
|
/** return the items of global section
|
||||||
* parameters:
|
* parameters:
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
* sections: the section array
|
* sections: the section array
|
||||||
|
|
@ -524,60 +242,6 @@ static inline const char *iniGetConfigPath(IniContext *pContext)
|
||||||
int iniGetSectionNames(IniContext *pContext, IniSectionInfo *sections,
|
int iniGetSectionNames(IniContext *pContext, IniSectionInfo *sections,
|
||||||
const int max_size, int *nCount);
|
const int max_size, int *nCount);
|
||||||
|
|
||||||
/** return the section names
|
|
||||||
* parameters:
|
|
||||||
* pContext: the ini context
|
|
||||||
* prefix: the prefix of section name
|
|
||||||
* sections: the section array
|
|
||||||
* max_size: the max size of sections
|
|
||||||
* nCount: return the section count
|
|
||||||
* return: errno, 0 for success, != 0 for fail
|
|
||||||
*/
|
|
||||||
int iniGetSectionNamesByPrefix(IniContext *pContext, const char *szPrefix,
|
|
||||||
IniSectionInfo *sections, const int max_size, int *nCount);
|
|
||||||
|
|
||||||
/** return the section names
|
|
||||||
* parameters:
|
|
||||||
* pContext: the ini context
|
|
||||||
* filter_func: the section name filter function
|
|
||||||
* args: the extra data pointer
|
|
||||||
* sections: the section array
|
|
||||||
* max_size: the max size of sections
|
|
||||||
* nCount: return the section count
|
|
||||||
* return: errno, 0 for success, != 0 for fail
|
|
||||||
*/
|
|
||||||
int iniGetSectionNamesEx(IniContext *pContext, IniSectionNameFilterFunc
|
|
||||||
filter_func, void *args, IniSectionInfo *sections,
|
|
||||||
const int max_size, int *nCount);
|
|
||||||
|
|
||||||
/** get matched section count
|
|
||||||
* parameters:
|
|
||||||
* pContext: the ini context
|
|
||||||
* filter_func: the section name filter function
|
|
||||||
* args: the extra data pointer
|
|
||||||
* return: matched section count
|
|
||||||
*/
|
|
||||||
int iniGetSectionCountEx(IniContext *pContext, IniSectionNameFilterFunc
|
|
||||||
filter_func, void *args);
|
|
||||||
|
|
||||||
/** get matched section count
|
|
||||||
* parameters:
|
|
||||||
* pContext: the ini context
|
|
||||||
* prefix: the prefix of section name
|
|
||||||
* return: matched section count
|
|
||||||
*/
|
|
||||||
int iniGetSectionCountByPrefix(IniContext *pContext, const char *szPrefix);
|
|
||||||
|
|
||||||
/** get section count
|
|
||||||
* parameters:
|
|
||||||
* pContext: the ini context
|
|
||||||
* return: section count
|
|
||||||
*/
|
|
||||||
static inline int iniGetSectionCount(IniContext *pContext)
|
|
||||||
{
|
|
||||||
return pContext->sections.item_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** return the items of global section
|
/** return the items of global section
|
||||||
* parameters:
|
* parameters:
|
||||||
* pContext: the ini context
|
* pContext: the ini context
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
#ifndef IO_OPT_H_
|
#ifndef IO_OPT_H_
|
||||||
#define IO_OPT_H_
|
#define IO_OPT_H_
|
||||||
|
|
||||||
|
|
|
||||||
243
src/ioevent.c
243
src/ioevent.c
|
|
@ -1,24 +1,8 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "ioevent.h"
|
#include "ioevent.h"
|
||||||
|
|
||||||
#if IOEVENT_USE_KQUEUE
|
#if IOEVENT_USE_KQUEUE
|
||||||
|
|
@ -45,119 +29,71 @@ int kqueue_ev_convert(int16_t event, uint16_t flags)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ioevent_init(IOEventPoller *ioevent, const char *service_name,
|
int ioevent_init(IOEventPoller *ioevent, const int size,
|
||||||
const bool use_io_uring, const int size, const int timeout_ms,
|
const int timeout_ms, const int extra_events)
|
||||||
const int extra_events)
|
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
ioevent->iterator.index = 0;
|
ioevent->size = size;
|
||||||
ioevent->iterator.count = 0;
|
ioevent->extra_events = extra_events;
|
||||||
ioevent->service_name = service_name;
|
ioevent->iterator.index = 0;
|
||||||
ioevent->size = size;
|
ioevent->iterator.count = 0;
|
||||||
ioevent->extra_events = extra_events;
|
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#if IOEVENT_USE_URING
|
ioevent->poll_fd = epoll_create(ioevent->size);
|
||||||
ioevent->use_io_uring = use_io_uring;
|
if (ioevent->poll_fd < 0) {
|
||||||
if (use_io_uring) {
|
return errno != 0 ? errno : ENOMEM;
|
||||||
int result;
|
}
|
||||||
if ((result=io_uring_queue_init(size, &ioevent->ring, 0)) < 0) {
|
bytes = sizeof(struct epoll_event) * size;
|
||||||
return -result;
|
ioevent->events = (struct epoll_event *)malloc(bytes);
|
||||||
}
|
|
||||||
ioevent->cqe = NULL;
|
|
||||||
ioevent->submit_count = 0;
|
|
||||||
ioevent->send_zc_logged = false;
|
|
||||||
ioevent->send_zc_done_notify = false;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
ioevent->poll_fd = epoll_create(ioevent->size);
|
|
||||||
if (ioevent->poll_fd < 0) {
|
|
||||||
return errno != 0 ? errno : ENOMEM;
|
|
||||||
}
|
|
||||||
bytes = sizeof(struct epoll_event) * size;
|
|
||||||
ioevent->events = (struct epoll_event *)fc_malloc(bytes);
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
ioevent->poll_fd = kqueue();
|
ioevent->poll_fd = kqueue();
|
||||||
if (ioevent->poll_fd < 0) {
|
if (ioevent->poll_fd < 0) {
|
||||||
return errno != 0 ? errno : ENOMEM;
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
bytes = sizeof(struct kevent) * size;
|
bytes = sizeof(struct kevent) * size;
|
||||||
ioevent->events = (struct kevent *)fc_malloc(bytes);
|
ioevent->events = (struct kevent *)malloc(bytes);
|
||||||
#elif IOEVENT_USE_PORT
|
#elif IOEVENT_USE_PORT
|
||||||
ioevent->poll_fd = port_create();
|
ioevent->poll_fd = port_create();
|
||||||
if (ioevent->poll_fd < 0) {
|
if (ioevent->poll_fd < 0) {
|
||||||
return errno != 0 ? errno : ENOMEM;
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
bytes = sizeof(port_event_t) * size;
|
bytes = sizeof(port_event_t) * size;
|
||||||
ioevent->events = (port_event_t *)fc_malloc(bytes);
|
ioevent->events = (port_event_t *)malloc(bytes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
if (ioevent->events == NULL) {
|
||||||
if (!ioevent->use_io_uring) {
|
close(ioevent->poll_fd);
|
||||||
#endif
|
ioevent->poll_fd = -1;
|
||||||
if (ioevent->events == NULL) {
|
return ENOMEM;
|
||||||
close(ioevent->poll_fd);
|
}
|
||||||
ioevent->poll_fd = -1;
|
ioevent_set_timeout(ioevent, timeout_ms);
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ioevent_set_timeout(ioevent, timeout_ms);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ioevent_destroy(IOEventPoller *ioevent)
|
void ioevent_destroy(IOEventPoller *ioevent)
|
||||||
{
|
{
|
||||||
#if IOEVENT_USE_URING
|
if (ioevent->events != NULL) {
|
||||||
if (ioevent->use_io_uring) {
|
free(ioevent->events);
|
||||||
io_uring_queue_exit(&ioevent->ring);
|
ioevent->events = NULL;
|
||||||
} else {
|
}
|
||||||
#endif
|
|
||||||
if (ioevent->events != NULL) {
|
|
||||||
free(ioevent->events);
|
|
||||||
ioevent->events = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioevent->poll_fd >= 0) {
|
if (ioevent->poll_fd >= 0) {
|
||||||
close(ioevent->poll_fd);
|
close(ioevent->poll_fd);
|
||||||
ioevent->poll_fd = -1;
|
ioevent->poll_fd = -1;
|
||||||
}
|
}
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ioevent_attach(IOEventPoller *ioevent, const int fd,
|
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
const int e, void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#if IOEVENT_USE_URING
|
struct epoll_event ev;
|
||||||
if (ioevent->use_io_uring) {
|
memset(&ev, 0, sizeof(ev));
|
||||||
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
|
ev.events = e | ioevent->extra_events;
|
||||||
if (sqe == NULL) {
|
ev.data.ptr = data;
|
||||||
return ENOSPC;
|
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||||
}
|
|
||||||
io_uring_prep_poll_multishot(sqe, fd, e | ioevent->extra_events);
|
|
||||||
sqe->user_data = (long)data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
struct epoll_event ev;
|
|
||||||
memset(&ev, 0, sizeof(ev));
|
|
||||||
ev.events = e | ioevent->extra_events;
|
|
||||||
ev.data.ptr = data;
|
|
||||||
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
struct kevent ev[2];
|
struct kevent ev[2];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
@ -176,32 +112,15 @@ int ioevent_attach(IOEventPoller *ioevent, const int fd,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int ioevent_modify(IOEventPoller *ioevent, const int fd,
|
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
const int e, void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#if IOEVENT_USE_URING
|
struct epoll_event ev;
|
||||||
if (ioevent->use_io_uring) {
|
memset(&ev, 0, sizeof(ev));
|
||||||
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
|
ev.events = e | ioevent->extra_events;
|
||||||
if (sqe == NULL) {
|
ev.data.ptr = data;
|
||||||
return ENOSPC;
|
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
|
||||||
}
|
|
||||||
io_uring_prep_poll_update(sqe, sqe->user_data, sqe->user_data,
|
|
||||||
e | ioevent->extra_events, IORING_POLL_UPDATE_EVENTS);
|
|
||||||
sqe->user_data = (long)data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
struct epoll_event ev;
|
|
||||||
memset(&ev, 0, sizeof(ev));
|
|
||||||
ev.events = e | ioevent->extra_events;
|
|
||||||
ev.data.ptr = data;
|
|
||||||
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
struct kevent ev[2];
|
struct kevent ev[2];
|
||||||
int result;
|
int result;
|
||||||
|
|
@ -236,25 +155,8 @@ int ioevent_modify(IOEventPoller *ioevent, const int fd,
|
||||||
|
|
||||||
int ioevent_detach(IOEventPoller *ioevent, const int fd)
|
int ioevent_detach(IOEventPoller *ioevent, const int fd)
|
||||||
{
|
{
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#if IOEVENT_USE_URING
|
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||||
if (ioevent->use_io_uring) {
|
|
||||||
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
|
|
||||||
if (sqe == NULL) {
|
|
||||||
return ENOSPC;
|
|
||||||
}
|
|
||||||
io_uring_prep_cancel_fd(sqe, fd, 0);
|
|
||||||
/* set sqe->flags MUST after io_uring_prep_xxx */
|
|
||||||
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
struct kevent ev[1];
|
struct kevent ev[1];
|
||||||
int r, w;
|
int r, w;
|
||||||
|
|
@ -273,33 +175,15 @@ int ioevent_detach(IOEventPoller *ioevent, const int fd)
|
||||||
|
|
||||||
int ioevent_poll(IOEventPoller *ioevent)
|
int ioevent_poll(IOEventPoller *ioevent)
|
||||||
{
|
{
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#if IOEVENT_USE_URING
|
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
|
||||||
if (ioevent->use_io_uring) {
|
|
||||||
int result;
|
|
||||||
result = io_uring_wait_cqe_timeout(&ioevent->ring,
|
|
||||||
&ioevent->cqe, &ioevent->timeout);
|
|
||||||
if (result < 0) {
|
|
||||||
errno = -result;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
return epoll_wait(ioevent->poll_fd, ioevent->events,
|
|
||||||
ioevent->size, ioevent->timeout_ms);
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events,
|
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events, ioevent->size, &ioevent->timeout);
|
||||||
ioevent->size, &ioevent->timeout);
|
|
||||||
#elif IOEVENT_USE_PORT
|
#elif IOEVENT_USE_PORT
|
||||||
int result;
|
int result;
|
||||||
int retval;
|
int retval;
|
||||||
unsigned int nget = 1;
|
unsigned int nget = 1;
|
||||||
if((retval=port_getn(ioevent->poll_fd, ioevent->events,
|
if((retval = port_getn(ioevent->poll_fd, ioevent->events,
|
||||||
ioevent->size, &nget, &ioevent->timeout)) == 0)
|
ioevent->size, &nget, &ioevent->timeout)) == 0)
|
||||||
{
|
{
|
||||||
result = (int)nget;
|
result = (int)nget;
|
||||||
|
|
@ -325,3 +209,4 @@ int ioevent_poll(IOEventPoller *ioevent)
|
||||||
#error port me
|
#error port me
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
205
src/ioevent.h
205
src/ioevent.h
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __IOEVENT_H__
|
#ifndef __IOEVENT_H__
|
||||||
#define __IOEVENT_H__
|
#define __IOEVENT_H__
|
||||||
|
|
||||||
|
|
@ -20,28 +5,17 @@
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include "_os_define.h"
|
#include "_os_define.h"
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#define IOEVENT_TIMEOUT (1 << 20)
|
#define IOEVENT_TIMEOUT 0x8000
|
||||||
#define IOEVENT_NOTIFY (1 << 21) //for io_uring send_zc done callback
|
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
#include <sys/epoll.h>
|
|
||||||
#define IOEVENT_EDGE_TRIGGER EPOLLET
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IOEVENT_USE_EPOLL
|
#if IOEVENT_USE_EPOLL
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#define IOEVENT_EDGE_TRIGGER EPOLLET
|
||||||
|
|
||||||
#define IOEVENT_READ EPOLLIN
|
#define IOEVENT_READ EPOLLIN
|
||||||
#define IOEVENT_WRITE EPOLLOUT
|
#define IOEVENT_WRITE EPOLLOUT
|
||||||
#define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP)
|
#define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP)
|
||||||
|
|
||||||
#elif IOEVENT_USE_URING
|
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <liburing.h>
|
|
||||||
#define IOEVENT_READ POLLIN
|
|
||||||
#define IOEVENT_WRITE POLLOUT
|
|
||||||
#define IOEVENT_ERROR (POLLERR | POLLPRI | POLLHUP)
|
|
||||||
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
#include <sys/event.h>
|
#include <sys/event.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
|
@ -76,33 +50,18 @@ int kqueue_ev_convert(int16_t event, uint16_t flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct ioevent_puller {
|
typedef struct ioevent_puller {
|
||||||
const char *service_name;
|
|
||||||
int size; //max events (fd)
|
int size; //max events (fd)
|
||||||
int extra_events;
|
int extra_events;
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
struct io_uring ring;
|
|
||||||
int submit_count;
|
|
||||||
bool send_zc_logged;
|
|
||||||
bool send_zc_done_notify; //if callback when send_zc done
|
|
||||||
bool use_io_uring;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int poll_fd;
|
int poll_fd;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int index;
|
int index;
|
||||||
int count;
|
int count;
|
||||||
} iterator; //for deal event loop
|
} iterator; //for deal event loop
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
struct epoll_event *events;
|
struct epoll_event *events;
|
||||||
int timeout_ms; //for epoll
|
int timeout;
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
struct io_uring_cqe *cqe;
|
|
||||||
struct __kernel_timespec timeout;
|
|
||||||
#endif
|
|
||||||
bool zero_timeout;
|
|
||||||
|
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
struct kevent *events;
|
struct kevent *events;
|
||||||
struct timespec timeout;
|
struct timespec timeout;
|
||||||
|
|
@ -110,10 +69,9 @@ typedef struct ioevent_puller {
|
||||||
port_event_t *events;
|
port_event_t *events;
|
||||||
timespec_t timeout;
|
timespec_t timeout;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} IOEventPoller;
|
} IOEventPoller;
|
||||||
|
|
||||||
#if OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#define IOEVENT_GET_EVENTS(ioevent, index) \
|
#define IOEVENT_GET_EVENTS(ioevent, index) \
|
||||||
(ioevent)->events[index].events
|
(ioevent)->events[index].events
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
|
@ -126,7 +84,7 @@ typedef struct ioevent_puller {
|
||||||
#error port me
|
#error port me
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#define IOEVENT_GET_DATA(ioevent, index) \
|
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||||
(ioevent)->events[index].data.ptr
|
(ioevent)->events[index].data.ptr
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
|
@ -139,7 +97,7 @@ typedef struct ioevent_puller {
|
||||||
#error port me
|
#error port me
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
#if IOEVENT_USE_EPOLL
|
||||||
#define IOEVENT_CLEAR_DATA(ioevent, index) \
|
#define IOEVENT_CLEAR_DATA(ioevent, index) \
|
||||||
(ioevent)->events[index].data.ptr = NULL
|
(ioevent)->events[index].data.ptr = NULL
|
||||||
#elif IOEVENT_USE_KQUEUE
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
|
@ -156,39 +114,24 @@ typedef struct ioevent_puller {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ioevent_init(IOEventPoller *ioevent, const char *service_name,
|
int ioevent_init(IOEventPoller *ioevent, const int size,
|
||||||
const bool use_io_uring, const int size, const int timeout_ms,
|
const int timeout_ms, const int extra_events);
|
||||||
const int extra_events);
|
|
||||||
void ioevent_destroy(IOEventPoller *ioevent);
|
void ioevent_destroy(IOEventPoller *ioevent);
|
||||||
|
|
||||||
int ioevent_attach(IOEventPoller *ioevent, const int fd,
|
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
const int e, void *data);
|
void *data);
|
||||||
int ioevent_modify(IOEventPoller *ioevent, const int fd,
|
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
const int e, void *data);
|
void *data);
|
||||||
int ioevent_detach(IOEventPoller *ioevent, const int fd);
|
int ioevent_detach(IOEventPoller *ioevent, const int fd);
|
||||||
int ioevent_poll(IOEventPoller *ioevent);
|
int ioevent_poll(IOEventPoller *ioevent);
|
||||||
|
|
||||||
static inline void ioevent_set_timeout(IOEventPoller *ioevent,
|
static inline void ioevent_set_timeout(IOEventPoller *ioevent, const int timeout_ms)
|
||||||
const int timeout_ms)
|
|
||||||
{
|
{
|
||||||
#if IOEVENT_USE_EPOLL
|
#if IOEVENT_USE_EPOLL
|
||||||
ioevent->timeout_ms = timeout_ms;
|
ioevent->timeout = timeout_ms;
|
||||||
#else
|
#else
|
||||||
#if IOEVENT_USE_URING
|
ioevent->timeout.tv_sec = timeout_ms / 1000;
|
||||||
if (!ioevent->use_io_uring) {
|
ioevent->timeout.tv_nsec = 1000000 * (timeout_ms % 1000);
|
||||||
ioevent->timeout_ms = timeout_ms;
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
ioevent->timeout.tv_sec = timeout_ms / 1000;
|
|
||||||
ioevent->timeout.tv_nsec = 1000000 * (timeout_ms % 1000);
|
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
ioevent->zero_timeout = (timeout_ms == 0);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,114 +141,6 @@ static inline int ioevent_poll_ex(IOEventPoller *ioevent, const int timeout_ms)
|
||||||
return ioevent_poll(ioevent);
|
return ioevent_poll(ioevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
static inline void ioevent_set_send_zc_done_notify(
|
|
||||||
IOEventPoller *ioevent, const bool need_notify)
|
|
||||||
{
|
|
||||||
ioevent->send_zc_done_notify = need_notify;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ioevent_uring_submit(IOEventPoller *ioevent)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
ioevent->submit_count = 0;
|
|
||||||
while (1) {
|
|
||||||
result = io_uring_submit(&ioevent->ring);
|
|
||||||
if (result < 0) {
|
|
||||||
if (result != -EINTR) {
|
|
||||||
return -result;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct io_uring_sqe *ioevent_uring_get_sqe(IOEventPoller *ioevent)
|
|
||||||
{
|
|
||||||
struct io_uring_sqe *sqe = io_uring_get_sqe(&ioevent->ring);
|
|
||||||
if (sqe == NULL) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"io_uring_get_sqe fail", __LINE__);
|
|
||||||
}
|
|
||||||
return sqe;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_recv(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, int sockfd,
|
|
||||||
void *buf, size_t size, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_recv(sqe, sockfd, buf, size, 0);
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_send(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, int sockfd,
|
|
||||||
void *buf, size_t len, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_send(sqe, sockfd, buf, len, 0);
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_writev(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, int sockfd, const struct iovec *iovecs,
|
|
||||||
unsigned nr_vecs, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_writev(sqe, sockfd, iovecs, nr_vecs, 0);
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_send_zc(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, int sockfd,
|
|
||||||
void *buf, size_t len, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_send_zc(sqe, sockfd, buf, len, 0,
|
|
||||||
#ifdef IORING_SEND_ZC_REPORT_USAGE
|
|
||||||
IORING_SEND_ZC_REPORT_USAGE
|
|
||||||
#else
|
|
||||||
0
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_close(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, int fd, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_close(sqe, fd);
|
|
||||||
if (user_data == NULL) {
|
|
||||||
/* set sqe->flags MUST after io_uring_prep_xxx */
|
|
||||||
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
|
|
||||||
} else {
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
}
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_cancel(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_cancel(sqe, user_data, 0);
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void ioevent_uring_prep_connect(IOEventPoller *ioevent,
|
|
||||||
struct io_uring_sqe *sqe, int fd, const struct sockaddr *addr,
|
|
||||||
socklen_t addrlen, void *user_data)
|
|
||||||
{
|
|
||||||
io_uring_prep_connect(sqe, fd, addr, addrlen);
|
|
||||||
sqe->user_data = (long)user_data;
|
|
||||||
ioevent->submit_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,133 +1,57 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sched_thread.h"
|
#include "sched_thread.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "ioevent_loop.h"
|
#include "ioevent_loop.h"
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
static int ioevent_process_by_uring(IOEventPoller *ioevent)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
unsigned head;
|
|
||||||
unsigned count = 0;
|
|
||||||
IOEventEntry *pEntry;
|
|
||||||
|
|
||||||
result = io_uring_wait_cqe_timeout(&ioevent->ring,
|
|
||||||
&ioevent->cqe, &ioevent->timeout);
|
|
||||||
switch (result) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case -ETIME:
|
|
||||||
case -EINTR:
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
result *= -1;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"io_uring_wait_cqe fail, errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_uring_for_each_cqe(&ioevent->ring, head, ioevent->cqe) {
|
|
||||||
count++;
|
|
||||||
pEntry = (IOEventEntry *)ioevent->cqe->user_data;
|
|
||||||
if (pEntry != NULL) {
|
|
||||||
if (ioevent->cqe->flags & IORING_CQE_F_NOTIF) {
|
|
||||||
if (ioevent->send_zc_done_notify) {
|
|
||||||
pEntry->callback(pEntry->fd, IOEVENT_NOTIFY, pEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef IORING_NOTIF_USAGE_ZC_COPIED
|
|
||||||
if (!ioevent->send_zc_logged) {
|
|
||||||
struct fast_task_info *task;
|
|
||||||
|
|
||||||
task = (struct fast_task_info *)pEntry;
|
|
||||||
ioevent->send_zc_logged = true;
|
|
||||||
if (ioevent->cqe->res & IORING_NOTIF_USAGE_ZC_COPIED) {
|
|
||||||
logWarning("file: "__FILE__", line: %d, %s "
|
|
||||||
"client %s:%u, io_uring send_zc: memory "
|
|
||||||
"copy instead of zero copy!", __LINE__,
|
|
||||||
ioevent->service_name, task->client_ip,
|
|
||||||
task->port);
|
|
||||||
} else {
|
|
||||||
logInfo("file: "__FILE__", line: %d, %s "
|
|
||||||
"client %s:%u, io_uring send_zc: zero "
|
|
||||||
"copy OK.", __LINE__, ioevent->service_name,
|
|
||||||
task->client_ip, task->port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
pEntry->res = ioevent->cqe->res;
|
|
||||||
pEntry->callback(pEntry->fd, 0, pEntry);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logWarning("file: "__FILE__", line: %d, "
|
|
||||||
"io_uring unexpected flags: %d, result: %d", __LINE__,
|
|
||||||
ioevent->cqe->flags, ioevent->cqe->res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
io_uring_cq_advance(&ioevent->ring, count);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void deal_ioevents(IOEventPoller *ioevent)
|
static void deal_ioevents(IOEventPoller *ioevent)
|
||||||
{
|
{
|
||||||
int event;
|
int event;
|
||||||
IOEventEntry *pEntry;
|
IOEventEntry *pEntry;
|
||||||
|
|
||||||
for (ioevent->iterator.index=0; ioevent->iterator.index < ioevent->
|
for (ioevent->iterator.index=0; ioevent->iterator.index < ioevent->iterator.
|
||||||
iterator.count; ioevent->iterator.index++)
|
count; ioevent->iterator.index++)
|
||||||
{
|
{
|
||||||
event = IOEVENT_GET_EVENTS(ioevent, ioevent->iterator.index);
|
event = IOEVENT_GET_EVENTS(ioevent, ioevent->iterator.index);
|
||||||
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
|
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
|
||||||
ioevent->iterator.index);
|
ioevent->iterator.index);
|
||||||
if (pEntry != NULL) {
|
if (pEntry != NULL) {
|
||||||
pEntry->callback(pEntry->fd, event, pEntry);
|
pEntry->callback(pEntry->fd, event, pEntry->timer.data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
logDebug("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
"ignore ioevent : %d, index: %d",
|
"ignore iovent : %d, index: %d", __LINE__, event, ioevent->iterator.index);
|
||||||
__LINE__, event, ioevent->iterator.index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioevent_process_by_poll(IOEventPoller *ioevent)
|
int ioevent_remove(IOEventPoller *ioevent, void *data)
|
||||||
{
|
{
|
||||||
int result;
|
IOEventEntry *pEntry;
|
||||||
|
int index;
|
||||||
|
|
||||||
ioevent->iterator.count = ioevent_poll(ioevent);
|
if (ioevent->iterator.index >= ioevent->iterator.count)
|
||||||
if (ioevent->iterator.count > 0) {
|
{
|
||||||
deal_ioevents(ioevent);
|
return ENOENT;
|
||||||
}
|
}
|
||||||
else if (ioevent->iterator.count < 0) {
|
|
||||||
result = errno != 0 ? errno : EINVAL;
|
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
|
||||||
if (result != EINTR) {
|
ioevent->iterator.index);
|
||||||
logError("file: "__FILE__", line: %d, "
|
if (pEntry != NULL && pEntry->timer.data == data) {
|
||||||
"ioevent_poll fail, errno: %d, error info: %s",
|
return 0; //do NOT clear current entry
|
||||||
__LINE__, result, STRERROR(result));
|
}
|
||||||
return result;
|
|
||||||
|
for (index=ioevent->iterator.index + 1; index < ioevent->iterator.count;
|
||||||
|
index++)
|
||||||
|
{
|
||||||
|
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, index);
|
||||||
|
if (pEntry != NULL && pEntry->timer.data == data) {
|
||||||
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
|
"clear iovent data: %p", __LINE__, data);
|
||||||
|
IOEVENT_CLEAR_DATA(ioevent, index);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deal_timeouts(FastTimerEntry *head)
|
static void deal_timeouts(FastTimerEntry *head)
|
||||||
|
|
@ -142,214 +66,138 @@ static void deal_timeouts(FastTimerEntry *head)
|
||||||
current = entry;
|
current = entry;
|
||||||
entry = entry->next;
|
entry = entry->next;
|
||||||
|
|
||||||
/* must set NULL because NOT in time wheel */
|
current->prev = current->next = NULL; //must set NULL because NOT in time wheel
|
||||||
current->prev = current->next = NULL;
|
pEventEntry = (IOEventEntry *)current->data;
|
||||||
pEventEntry = (IOEventEntry *)current;
|
if (pEventEntry != NULL)
|
||||||
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT, current);
|
{
|
||||||
|
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
|
||||||
|
current->data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ioevent_loop(struct nio_thread_data *thread_data,
|
void iovent_add_to_deleted_list(struct fast_task_info *pTask)
|
||||||
|
{
|
||||||
|
if (pTask->thread_data == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask->next = pTask->thread_data->deleted_list;
|
||||||
|
pTask->thread_data->deleted_list = pTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_loop(struct nio_thread_data *pThreadData,
|
||||||
IOEventCallback recv_notify_callback, TaskCleanUpCallback
|
IOEventCallback recv_notify_callback, TaskCleanUpCallback
|
||||||
clean_up_callback, volatile bool *continue_flag)
|
clean_up_callback, volatile bool *continue_flag)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct ioevent_notify_entry ev_notify;
|
IOEventEntry ev_notify;
|
||||||
FastTimerEntry head;
|
FastTimerEntry head;
|
||||||
struct fast_task_info *task;
|
struct fast_task_info *pTask;
|
||||||
time_t last_check_time;
|
time_t last_check_time;
|
||||||
int save_extra_events;
|
|
||||||
int count;
|
int count;
|
||||||
#ifdef OS_LINUX
|
|
||||||
uint32_t sched_counter;
|
|
||||||
#endif
|
|
||||||
bool sched_pull;
|
|
||||||
|
|
||||||
memset(&ev_notify, 0, sizeof(ev_notify));
|
memset(&ev_notify, 0, sizeof(ev_notify));
|
||||||
ev_notify.event.fd = FC_NOTIFY_READ_FD(thread_data);
|
ev_notify.fd = pThreadData->pipe_fds[0];
|
||||||
ev_notify.event.callback = recv_notify_callback;
|
ev_notify.callback = recv_notify_callback;
|
||||||
ev_notify.thread_data = thread_data;
|
if (ioevent_attach(&pThreadData->ev_puller,
|
||||||
|
pThreadData->pipe_fds[0], IOEVENT_READ,
|
||||||
save_extra_events = thread_data->ev_puller.extra_events;
|
&ev_notify) != 0)
|
||||||
thread_data->ev_puller.extra_events = 0; //disable edge trigger temporarily
|
|
||||||
if (ioevent_attach(&thread_data->ev_puller, ev_notify.
|
|
||||||
event.fd, IOEVENT_READ, &ev_notify) != 0)
|
|
||||||
{
|
{
|
||||||
result = errno != 0 ? errno : ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
logCrit("file: "__FILE__", line: %d, "
|
logCrit("file: "__FILE__", line: %d, " \
|
||||||
"ioevent_attach fail, errno: %d, error info: %s",
|
"ioevent_attach fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
thread_data->ev_puller.extra_events = save_extra_events; //restore
|
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
pThreadData->deleted_list = NULL;
|
||||||
sched_counter = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
thread_data->deleted_list = NULL;
|
|
||||||
last_check_time = g_current_time;
|
last_check_time = g_current_time;
|
||||||
while (*continue_flag) {
|
while (*continue_flag)
|
||||||
#ifdef OS_LINUX
|
{
|
||||||
if (thread_data->ev_puller.zero_timeout) {
|
pThreadData->ev_puller.iterator.count = ioevent_poll(&pThreadData->ev_puller);
|
||||||
sched_pull = (sched_counter++ & 8) != 0;
|
if (pThreadData->ev_puller.iterator.count > 0)
|
||||||
} else {
|
{
|
||||||
sched_pull = true;
|
deal_ioevents(&pThreadData->ev_puller);
|
||||||
}
|
}
|
||||||
#else
|
else if (pThreadData->ev_puller.iterator.count < 0)
|
||||||
sched_pull = true;
|
{
|
||||||
#endif
|
result = errno != 0 ? errno : EINVAL;
|
||||||
|
if (result != EINTR)
|
||||||
#if IOEVENT_USE_URING
|
{
|
||||||
if (thread_data->ev_puller.use_io_uring) {
|
logError("file: "__FILE__", line: %d, " \
|
||||||
if (thread_data->ev_puller.submit_count > 0) {
|
"ioevent_poll fail, " \
|
||||||
if ((result=ioevent_uring_submit(&thread_data->
|
"errno: %d, error info: %s", \
|
||||||
ev_puller)) != 0)
|
__LINE__, result, STRERROR(result));
|
||||||
{
|
return result;
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"io_uring_submit fail, errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (sched_pull) {
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
if (thread_data->ev_puller.use_io_uring) {
|
|
||||||
if ((result=ioevent_process_by_uring(&thread_data->
|
|
||||||
ev_puller)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
if ((result=ioevent_process_by_poll(&thread_data->
|
|
||||||
ev_puller)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread_data->busy_polling_callback != NULL) {
|
|
||||||
thread_data->busy_polling_callback(thread_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread_data->deleted_list != NULL) {
|
|
||||||
//count = 0;
|
|
||||||
while (thread_data->deleted_list != NULL) {
|
|
||||||
task = thread_data->deleted_list;
|
|
||||||
thread_data->deleted_list = task->next;
|
|
||||||
|
|
||||||
if (task->polling.in_queue) {
|
|
||||||
fc_list_del_init(&task->polling.dlink);
|
|
||||||
task->polling.in_queue = false;
|
|
||||||
if (fc_list_empty(&task->thread_data->polling_queue)) {
|
|
||||||
ioevent_set_timeout(&task->thread_data->ev_puller,
|
|
||||||
task->thread_data->timeout_ms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clean_up_callback(task);
|
|
||||||
//count++;
|
|
||||||
}
|
}
|
||||||
//logInfo("cleanup task count: %d", count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_current_time - last_check_time > 0) {
|
if (pThreadData->deleted_list != NULL)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
while (pThreadData->deleted_list != NULL)
|
||||||
|
{
|
||||||
|
pTask = pThreadData->deleted_list;
|
||||||
|
pThreadData->deleted_list = pTask->next;
|
||||||
|
|
||||||
|
clean_up_callback(pTask);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
logDebug("cleanup task count: %d", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_current_time - last_check_time > 0)
|
||||||
|
{
|
||||||
last_check_time = g_current_time;
|
last_check_time = g_current_time;
|
||||||
count = fast_timer_timeouts_get(
|
count = fast_timer_timeouts_get(
|
||||||
&thread_data->timer, g_current_time, &head);
|
&pThreadData->timer, g_current_time, &head);
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
deal_timeouts(&head);
|
deal_timeouts(&head);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread_data->notify.enabled) {
|
if (pThreadData->thread_loop_callback != NULL) {
|
||||||
int64_t n;
|
pThreadData->thread_loop_callback(pThreadData);
|
||||||
if ((n=__sync_fetch_and_add(&thread_data->notify.counter, 0)) != 0)
|
|
||||||
{
|
|
||||||
__sync_fetch_and_sub(&thread_data->notify.counter, n);
|
|
||||||
/*
|
|
||||||
logInfo("file: "__FILE__", line: %d, "
|
|
||||||
"n ==== %"PRId64", now: %"PRId64,
|
|
||||||
__LINE__, n, __sync_fetch_and_add(
|
|
||||||
&thread_data->notify.counter, 0));
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread_data->thread_loop_callback != NULL) {
|
|
||||||
thread_data->thread_loop_callback(thread_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
|
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
|
||||||
int sock, short event, IOEventCallback callback,
|
int sock, short event, IOEventCallback callback, const int timeout)
|
||||||
const int timeout)
|
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
task->thread_data = pThread;
|
pTask->thread_data = pThread;
|
||||||
task->event.fd = sock;
|
pTask->event.fd = sock;
|
||||||
task->event.callback = callback;
|
pTask->event.callback = callback;
|
||||||
#if IOEVENT_USE_URING
|
if (ioevent_attach(&pThread->ev_puller,
|
||||||
if (pThread->ev_puller.use_io_uring) {
|
sock, event, pTask) < 0)
|
||||||
if (FC_URING_OP_TYPE(task) == IORING_OP_NOP) {
|
{
|
||||||
if ((result=uring_prep_first_recv(task)) != 0) {
|
result = errno != 0 ? errno : ENOENT;
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"uring_prep_recv fail, fd: %d, "
|
"ioevent_attach fail, " \
|
||||||
"errno: %d, error info: %s",
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, sock, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/*
|
pTask->event.timer.data = pTask;
|
||||||
logWarning("file: "__FILE__", line: %d, "
|
pTask->event.timer.expires = g_current_time + timeout;
|
||||||
"skip uring_prep_recv, fd: %d, port: %d, "
|
result = fast_timer_add(&pThread->timer, &pTask->event.timer);
|
||||||
"in progress op type: %d, timeout: %"PRId64,
|
if (result != 0)
|
||||||
__LINE__, sock, task->port, FC_URING_OP_TYPE(task),
|
{
|
||||||
task->event.timer.expires);
|
logError("file: "__FILE__", line: %d, " \
|
||||||
*/
|
"fast_timer_add fail, " \
|
||||||
}
|
"errno: %d, error info: %s", \
|
||||||
} else {
|
__LINE__, result, STRERROR(result));
|
||||||
#endif
|
return result;
|
||||||
if (ioevent_attach(&pThread->ev_puller, sock, event, task) < 0) {
|
}
|
||||||
result = errno != 0 ? errno : ENOENT;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"ioevent_attach fail, fd: %d, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, sock, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
task->event.timer.expires = g_current_time + timeout;
|
|
||||||
fast_timer_add(&pThread->timer, &task->event.timer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ioevent_reset(struct fast_task_info *task, int new_fd, short event)
|
|
||||||
{
|
|
||||||
if (task->event.fd == new_fd)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task->event.fd >= 0)
|
|
||||||
{
|
|
||||||
ioevent_detach(&task->thread_data->ev_puller, task->event.fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
task->event.fd = new_fd;
|
|
||||||
return ioevent_attach(&task->thread_data->ev_puller, new_fd, event, task);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,250 +1,27 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _IOEVENT_LOOP_H
|
#ifndef _IOEVENT_LOOP_H
|
||||||
#define _IOEVENT_LOOP_H
|
#define _IOEVENT_LOOP_H
|
||||||
|
|
||||||
#include "fast_task_queue.h"
|
#include "fast_task_queue.h"
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
#include "sockopt.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define fc_hold_task_ex(task, inc_count) __sync_add_and_fetch( \
|
|
||||||
&task->reffer_count, inc_count)
|
|
||||||
|
|
||||||
#define fc_hold_task(task) fc_hold_task_ex(task, 1)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ioevent_loop(struct nio_thread_data *thread_data,
|
int ioevent_loop(struct nio_thread_data *pThreadData,
|
||||||
IOEventCallback recv_notify_callback, TaskCleanUpCallback
|
IOEventCallback recv_notify_callback, TaskCleanUpCallback
|
||||||
clean_up_callback, volatile bool *continue_flag);
|
clean_up_callback, volatile bool *continue_flag);
|
||||||
|
|
||||||
int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
|
//remove entry from ready list
|
||||||
int sock, short event, IOEventCallback callback,
|
int ioevent_remove(IOEventPoller *ioevent, void *data);
|
||||||
const int timeout);
|
|
||||||
|
|
||||||
int ioevent_reset(struct fast_task_info *task, int new_fd, short event);
|
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
|
||||||
|
int sock, short event, IOEventCallback callback, const int timeout);
|
||||||
|
|
||||||
static inline bool ioevent_is_canceled(struct fast_task_info *task)
|
void iovent_add_to_deleted_list(struct fast_task_info *pTask);
|
||||||
{
|
|
||||||
return __sync_fetch_and_add(&task->canceled, 0) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//only called by the nio thread
|
|
||||||
static inline void ioevent_add_to_deleted_list(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
if (!__sync_bool_compare_and_swap(&task->canceled, 0, 1))
|
|
||||||
{
|
|
||||||
logWarning("file: "__FILE__", line: %d, "
|
|
||||||
"task %p already canceled", __LINE__, task);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
task->next = task->thread_data->deleted_list;
|
|
||||||
task->thread_data->deleted_list = task;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ioevent_notify_thread(struct nio_thread_data *thread_data)
|
|
||||||
{
|
|
||||||
int64_t n;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (__sync_fetch_and_add(&thread_data->notify.counter, 1) == 0)
|
|
||||||
{
|
|
||||||
n = 1;
|
|
||||||
if (write(FC_NOTIFY_WRITE_FD(thread_data), &n, sizeof(n)) != sizeof(n))
|
|
||||||
{
|
|
||||||
result = errno != 0 ? errno : EIO;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"write to fd %d fail, errno: %d, error info: %s",
|
|
||||||
__LINE__, FC_NOTIFY_WRITE_FD(thread_data),
|
|
||||||
result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
|
|
||||||
#define SET_OP_TYPE_AND_HOLD_TASK(task, _op_type) \
|
|
||||||
struct io_uring_sqe *sqe; \
|
|
||||||
if ((sqe=ioevent_uring_get_sqe(&task->thread_data->ev_puller)) == NULL) { \
|
|
||||||
return ENOSPC; \
|
|
||||||
} \
|
|
||||||
FC_URING_OP_TYPE(task) = _op_type; \
|
|
||||||
fc_hold_task(task)
|
|
||||||
|
|
||||||
static inline int uring_prep_recv_data(struct fast_task_info *task,
|
|
||||||
char *buff, const int len)
|
|
||||||
{
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_RECV);
|
|
||||||
ioevent_uring_prep_recv(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, buff, len, task);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_first_recv(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_RECV);
|
|
||||||
ioevent_uring_prep_recv(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->recv.ptr->data,
|
|
||||||
task->recv.ptr->size, task);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_next_recv(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_RECV);
|
|
||||||
ioevent_uring_prep_recv(&task->thread_data->ev_puller, sqe,
|
|
||||||
task->event.fd, task->recv.ptr->data + task->recv.ptr->offset,
|
|
||||||
task->recv.ptr->length - task->recv.ptr->offset, task);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_first_send(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
if (task->iovec_array.iovs != NULL) {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
|
|
||||||
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->iovec_array.iovs,
|
|
||||||
FC_MIN(task->iovec_array.count, IOV_MAX),
|
|
||||||
task);
|
|
||||||
} else {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
|
|
||||||
ioevent_uring_prep_send(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->send.ptr->data,
|
|
||||||
task->send.ptr->length, task);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_next_send(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
if (task->iovec_array.iovs != NULL) {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
|
|
||||||
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->iovec_array.iovs,
|
|
||||||
FC_MIN(task->iovec_array.count, IOV_MAX),
|
|
||||||
task);
|
|
||||||
} else {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
|
|
||||||
ioevent_uring_prep_send(&task->thread_data->ev_puller, sqe,
|
|
||||||
task->event.fd, task->send.ptr->data + task->send.ptr->offset,
|
|
||||||
task->send.ptr->length - task->send.ptr->offset, task);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_first_send_zc(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
if (task->iovec_array.iovs != NULL) {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
|
|
||||||
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->iovec_array.iovs,
|
|
||||||
FC_MIN(task->iovec_array.count, IOV_MAX),
|
|
||||||
task);
|
|
||||||
} else if (task->send.ptr->length < 4096) {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
|
|
||||||
ioevent_uring_prep_send(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->send.ptr->data,
|
|
||||||
task->send.ptr->length, task);
|
|
||||||
} else {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND_ZC);
|
|
||||||
ioevent_uring_prep_send_zc(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->send.ptr->data,
|
|
||||||
task->send.ptr->length, task);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_next_send_zc(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
if (task->iovec_array.iovs != NULL) {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_WRITEV);
|
|
||||||
ioevent_uring_prep_writev(&task->thread_data->ev_puller,
|
|
||||||
sqe, task->event.fd, task->iovec_array.iovs,
|
|
||||||
FC_MIN(task->iovec_array.count, IOV_MAX),
|
|
||||||
task);
|
|
||||||
} else if (task->send.ptr->length - task->send.ptr->offset < 4096) {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND);
|
|
||||||
ioevent_uring_prep_send(&task->thread_data->ev_puller, sqe,
|
|
||||||
task->event.fd, task->send.ptr->data + task->send.ptr->offset,
|
|
||||||
task->send.ptr->length - task->send.ptr->offset, task);
|
|
||||||
} else {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_SEND_ZC);
|
|
||||||
ioevent_uring_prep_send_zc(&task->thread_data->ev_puller, sqe,
|
|
||||||
task->event.fd, task->send.ptr->data + task->send.ptr->offset,
|
|
||||||
task->send.ptr->length - task->send.ptr->offset, task);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_close_fd(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
struct io_uring_sqe *sqe;
|
|
||||||
|
|
||||||
if ((sqe=ioevent_uring_get_sqe(&task->thread_data->ev_puller)) == NULL) {
|
|
||||||
return ENOSPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do NOT need callback */
|
|
||||||
ioevent_uring_prep_close(&task->thread_data->
|
|
||||||
ev_puller, sqe, task->event.fd, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_cancel(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_ASYNC_CANCEL);
|
|
||||||
ioevent_uring_prep_cancel(&task->thread_data->ev_puller, sqe, task);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int uring_prep_connect(struct fast_task_info *task)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
sockaddr_convert_t *convert;
|
|
||||||
|
|
||||||
if ((task->event.fd=socketCreateEx2(AF_UNSPEC, task->server_ip,
|
|
||||||
O_NONBLOCK, NULL, &result)) < 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert = (sockaddr_convert_t *)(task->send.ptr->data +
|
|
||||||
task->send.ptr->size - 2 * sizeof(sockaddr_convert_t));
|
|
||||||
if ((result=setsockaddrbyip(task->server_ip, task->port, convert)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
SET_OP_TYPE_AND_HOLD_TASK(task, IORING_OP_CONNECT);
|
|
||||||
ioevent_uring_prep_connect(&task->thread_data->ev_puller, sqe,
|
|
||||||
task->event.fd, &convert->sa.addr, convert->len, task);
|
|
||||||
} while (0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,564 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "json_parser.h"
|
|
||||||
|
|
||||||
#define EXPECT_STR_LEN 80
|
|
||||||
|
|
||||||
#define JSON_SPACE(ch) \
|
|
||||||
(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
|
|
||||||
|
|
||||||
#define JSON_TOKEN(ch) \
|
|
||||||
((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || \
|
|
||||||
(ch >= '0' && ch <= '9') || (ch == '_' || ch == '-' || \
|
|
||||||
ch == '.'))
|
|
||||||
|
|
||||||
int fc_detect_json_type(const string_t *input)
|
|
||||||
{
|
|
||||||
if (input->len < 2) {
|
|
||||||
return FC_JSON_TYPE_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input->str[0] == '[' && input->str[input->len - 1] == ']') {
|
|
||||||
return FC_JSON_TYPE_ARRAY;
|
|
||||||
}
|
|
||||||
if (input->str[0] == '{' && input->str[input->len - 1] == '}') {
|
|
||||||
return FC_JSON_TYPE_MAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FC_JSON_TYPE_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_parse_error(const char *str, const char *current,
|
|
||||||
const int expect_len, const char *front,
|
|
||||||
string_t *error_info, const int error_size)
|
|
||||||
{
|
|
||||||
const char *show_str;
|
|
||||||
int show_len;
|
|
||||||
|
|
||||||
show_len = current - str;
|
|
||||||
if (show_len > expect_len) {
|
|
||||||
show_len = expect_len;
|
|
||||||
}
|
|
||||||
show_str = current - show_len;
|
|
||||||
error_info->len = snprintf(error_info->str, error_size,
|
|
||||||
"%s, input: %.*s", front, show_len, show_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int json_escape_string(fc_json_context_t *context,
|
|
||||||
const string_t *input, char *output)
|
|
||||||
{
|
|
||||||
const char *src;
|
|
||||||
const char *end;
|
|
||||||
char *dest;
|
|
||||||
|
|
||||||
dest = output;
|
|
||||||
end = input->str + input->len;
|
|
||||||
for (src=input->str; src<end; src++) {
|
|
||||||
switch (*src) {
|
|
||||||
case '\\':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = '\\';
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 't';
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'r';
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'n';
|
|
||||||
break;
|
|
||||||
case '\b':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'b';
|
|
||||||
break;
|
|
||||||
case '\f':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'f';
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = '\"';
|
|
||||||
break;
|
|
||||||
case '\0':
|
|
||||||
*dest++ = '\\';
|
|
||||||
*dest++ = 'u';
|
|
||||||
*dest++ = '0';
|
|
||||||
*dest++ = '0';
|
|
||||||
*dest++ = '0';
|
|
||||||
*dest++ = '0';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*dest++ = *src;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest - output;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int next_json_element(fc_json_context_t *context)
|
|
||||||
{
|
|
||||||
char *dest;
|
|
||||||
const char *start;
|
|
||||||
char buff[128];
|
|
||||||
char quote_ch;
|
|
||||||
int unicode;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
dest = context->decode.element.str;
|
|
||||||
quote_ch = *context->p;
|
|
||||||
if (quote_ch == '\"' || quote_ch == '\'') {
|
|
||||||
context->p++;
|
|
||||||
while (context->p < context->end && *context->p != quote_ch) {
|
|
||||||
if (*context->p == '\\') {
|
|
||||||
if (++context->p == context->end) {
|
|
||||||
set_parse_error(context->str, context->p,
|
|
||||||
EXPECT_STR_LEN, "expect a character after \\",
|
|
||||||
&context->error_info, context->error_size);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*context->p == 'u') { //unicode
|
|
||||||
start = ++context->p; //skip charator 'u'
|
|
||||||
i = 0;
|
|
||||||
while (i < 4 && context->p < context->end &&
|
|
||||||
IS_HEX_CHAR(*context->p))
|
|
||||||
{
|
|
||||||
buff[i++] = *context->p;
|
|
||||||
++context->p;
|
|
||||||
}
|
|
||||||
if (i != 4) {
|
|
||||||
set_parse_error(context->str, start,
|
|
||||||
EXPECT_STR_LEN, "expect 4 hex characters "
|
|
||||||
"after \\u", &context->error_info,
|
|
||||||
context->error_size);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
buff[i] = '\0';
|
|
||||||
unicode = strtol(buff, NULL, 16);
|
|
||||||
if (unicode < 0x80) {
|
|
||||||
*dest++ = unicode;
|
|
||||||
} else if (unicode < 0x800) {
|
|
||||||
*dest++ = 0xC0 | ((unicode >> 6) & 0x1F);
|
|
||||||
*dest++ = 0x80 | (unicode & 0x3F);
|
|
||||||
} else {
|
|
||||||
*dest++ = 0xE0 | ((unicode >> 12) & 0x0F);
|
|
||||||
*dest++ = 0x80 | ((unicode >> 6) & 0x3F);
|
|
||||||
*dest++ = 0x80 | (unicode & 0x3F);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (*context->p) {
|
|
||||||
case '\\':
|
|
||||||
*dest++ = '\\';
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
*dest++ = '/';
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
*dest++ = '\t';
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
*dest++ = '\r';
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
*dest++ = '\n';
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
*dest++ = '\f';
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
*dest++ = '\b';
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
*dest++ = '\"';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sprintf(buff, "invalid escaped character: %c(0x%x)",
|
|
||||||
*context->p, (unsigned char)*context->p);
|
|
||||||
set_parse_error(context->str, context->p + 1,
|
|
||||||
EXPECT_STR_LEN, buff, &context->error_info,
|
|
||||||
context->error_size);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
context->p++;
|
|
||||||
} else {
|
|
||||||
*dest++ = *context->p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->p == context->end) {
|
|
||||||
sprintf(buff, "expect closed character: %c", quote_ch);
|
|
||||||
set_parse_error(context->str, context->p, EXPECT_STR_LEN,
|
|
||||||
buff, &context->error_info, context->error_size);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
context->p++; //skip quote char
|
|
||||||
} else {
|
|
||||||
while (context->p < context->end && JSON_TOKEN(*context->p)) {
|
|
||||||
*dest++ = *context->p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*dest = '\0';
|
|
||||||
context->decode.element.len = dest - context->decode.element.str;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_alloc_array(fc_json_context_t *context,
|
|
||||||
fc_common_array_t *array)
|
|
||||||
{
|
|
||||||
int bytes;
|
|
||||||
if (array->count < array->alloc) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array->alloc == 0) {
|
|
||||||
array->alloc = 32;
|
|
||||||
} else {
|
|
||||||
array->alloc *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = array->element_size * array->alloc;
|
|
||||||
array->elements = fc_realloc(array->elements, bytes);
|
|
||||||
if (array->elements == NULL) {
|
|
||||||
context->error_info.len = snprintf(context->error_info.str,
|
|
||||||
context->error_size, "realloc %d bytes fail", bytes);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int prepare_json_parse(fc_json_context_t *context,
|
|
||||||
const string_t *input, const char lquote,
|
|
||||||
const char rquote)
|
|
||||||
{
|
|
||||||
int expect_size;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (input->len < 2) {
|
|
||||||
context->error_info.len = snprintf(context->error_info.str,
|
|
||||||
context->error_size, "json string is too short");
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input->str[0] != lquote) {
|
|
||||||
context->error_info.len = snprintf(context->error_info.str, context->
|
|
||||||
error_size, "json array must start with \"%c\"", lquote);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
if (input->str[input->len - 1] != rquote) {
|
|
||||||
context->error_info.len = snprintf(context->error_info.str, context->
|
|
||||||
error_size, "json array must end with \"%c\"", rquote);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_size = input->len;
|
|
||||||
if (context->output.alloc_size < expect_size) {
|
|
||||||
if ((result=fc_realloc_buffer(&context->output, context->
|
|
||||||
init_buff_size, expect_size)) != 0)
|
|
||||||
{
|
|
||||||
context->error_info.len = snprintf(context->error_info.str,
|
|
||||||
context->error_size, "realloc buffer fail");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context->decode.element.str = context->output.buff;
|
|
||||||
context->decode.element.len = 0;
|
|
||||||
context->str = input->str;
|
|
||||||
context->p = input->str + 1;
|
|
||||||
context->end = input->str + input->len - 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void json_quote_string(fc_json_context_t
|
|
||||||
*context, const string_t *input, char **buff)
|
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
p = *buff;
|
|
||||||
*p++ = '"';
|
|
||||||
p += json_escape_string(context, input, p);
|
|
||||||
*p++ = '"';
|
|
||||||
*buff = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_encode_json_array_ex(fc_json_context_t *context,
|
|
||||||
const string_t *elements, const int count,
|
|
||||||
BufferInfo *buffer)
|
|
||||||
{
|
|
||||||
const string_t *el;
|
|
||||||
const string_t *end;
|
|
||||||
char *p;
|
|
||||||
int expect_size;
|
|
||||||
|
|
||||||
expect_size = 3;
|
|
||||||
end = elements + count;
|
|
||||||
for (el=elements; el<end; el++) {
|
|
||||||
expect_size += 6 * el->len + 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer->alloc_size < expect_size) {
|
|
||||||
if ((context->error_no=fc_realloc_buffer(buffer, context->
|
|
||||||
init_buff_size, expect_size)) != 0)
|
|
||||||
{
|
|
||||||
context->error_info.len = snprintf(context->error_info.str,
|
|
||||||
context->error_size, "realloc buffer fail");
|
|
||||||
return context->error_no;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p = buffer->buff;
|
|
||||||
*p++ = '[';
|
|
||||||
for (el=elements; el<end; el++) {
|
|
||||||
if (el > elements) {
|
|
||||||
*p++ = ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
json_quote_string(context, el, &p);
|
|
||||||
}
|
|
||||||
|
|
||||||
*p++ = ']';
|
|
||||||
*p = '\0';
|
|
||||||
buffer->length = p - buffer->buff;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_encode_json_map_ex(fc_json_context_t *context,
|
|
||||||
const key_value_pair_t *elements, const int count,
|
|
||||||
BufferInfo *buffer)
|
|
||||||
{
|
|
||||||
const key_value_pair_t *pair;
|
|
||||||
const key_value_pair_t *end;
|
|
||||||
char *p;
|
|
||||||
int expect_size;
|
|
||||||
|
|
||||||
expect_size = 3;
|
|
||||||
end = elements + count;
|
|
||||||
for (pair=elements; pair<end; pair++) {
|
|
||||||
expect_size += 6 * (pair->key.len + pair->value.len) + 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer->alloc_size < expect_size) {
|
|
||||||
if ((context->error_no=fc_realloc_buffer(buffer, context->
|
|
||||||
init_buff_size, expect_size)) != 0)
|
|
||||||
{
|
|
||||||
context->error_info.len = snprintf(context->error_info.str,
|
|
||||||
context->error_size, "realloc buffer fail");
|
|
||||||
return context->error_no;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p = buffer->buff;
|
|
||||||
*p++ = '{';
|
|
||||||
for (pair=elements; pair<end; pair++) {
|
|
||||||
if (pair > elements) {
|
|
||||||
*p++ = ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
json_quote_string(context, &pair->key, &p);
|
|
||||||
*p++ = ':';
|
|
||||||
json_quote_string(context, &pair->value, &p);
|
|
||||||
}
|
|
||||||
|
|
||||||
*p++ = '}';
|
|
||||||
*p = '\0';
|
|
||||||
buffer->length = p - buffer->buff;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define JSON_DECODE_COPY_STRING(ctx, input, dest, src) \
|
|
||||||
do { \
|
|
||||||
if ((context->error_no=fast_mpool_alloc_string_ex2( \
|
|
||||||
&ctx->decode.mpool, dest, src)) != 0) \
|
|
||||||
{ \
|
|
||||||
set_parse_error(input->str, ctx->p, EXPECT_STR_LEN, \
|
|
||||||
"out of memory", &ctx->error_info, ctx->error_size); \
|
|
||||||
return NULL; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
|
|
||||||
*context, const string_t *input)
|
|
||||||
{
|
|
||||||
if ((context->error_no=prepare_json_parse(context,
|
|
||||||
input, '[', ']')) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->jarray.count = 0;
|
|
||||||
while (context->p < context->end) {
|
|
||||||
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
|
||||||
context->p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->p == context->end) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*context->p == ',') {
|
|
||||||
set_parse_error(input->str, context->p + 1,
|
|
||||||
EXPECT_STR_LEN, "unexpect comma \",\"",
|
|
||||||
&context->error_info, context->error_size);
|
|
||||||
context->error_no = EINVAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((context->error_no=next_json_element(context)) != 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
|
||||||
context->p++;
|
|
||||||
}
|
|
||||||
if (context->p < context->end) {
|
|
||||||
if (*context->p == ',') {
|
|
||||||
context->p++; //skip comma
|
|
||||||
} else {
|
|
||||||
set_parse_error(input->str, context->p,
|
|
||||||
EXPECT_STR_LEN, "expect comma \",\"",
|
|
||||||
&context->error_info, context->error_size);
|
|
||||||
context->error_no = EINVAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((context->error_no=check_alloc_array(context,
|
|
||||||
(fc_common_array_t *)
|
|
||||||
&context->jarray)) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->decode.use_mpool) {
|
|
||||||
JSON_DECODE_COPY_STRING(context, input, context->jarray.elements +
|
|
||||||
context->jarray.count++, &context->decode.element);
|
|
||||||
} else {
|
|
||||||
context->jarray.elements[context->jarray.count++] =
|
|
||||||
context->decode.element;
|
|
||||||
}
|
|
||||||
context->decode.element.str += context->decode.element.len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &context->jarray;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
|
|
||||||
*context, const string_t *input)
|
|
||||||
{
|
|
||||||
key_value_pair_t kv_pair;
|
|
||||||
|
|
||||||
if ((context->error_no=prepare_json_parse(context,
|
|
||||||
input, '{', '}')) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->jmap.count = 0;
|
|
||||||
while (context->p < context->end) {
|
|
||||||
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
|
||||||
context->p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->p == context->end) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*context->p == ',') {
|
|
||||||
set_parse_error(input->str, context->p + 1,
|
|
||||||
EXPECT_STR_LEN, "unexpect comma \",\"",
|
|
||||||
&context->error_info, context->error_size);
|
|
||||||
context->error_no = EINVAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((context->error_no=next_json_element(context)) != 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
|
||||||
context->p++;
|
|
||||||
}
|
|
||||||
if (!(context->p < context->end && *context->p == ':')) {
|
|
||||||
set_parse_error(input->str, context->p,
|
|
||||||
EXPECT_STR_LEN, "expect colon \":\"",
|
|
||||||
&context->error_info, context->error_size);
|
|
||||||
context->error_no = EINVAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
context->p++; //skip colon
|
|
||||||
|
|
||||||
kv_pair.key = context->decode.element;
|
|
||||||
context->decode.element.str += context->decode.element.len + 1;
|
|
||||||
|
|
||||||
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
|
||||||
context->p++;
|
|
||||||
}
|
|
||||||
if ((context->error_no=next_json_element(context)) != 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
while (context->p < context->end && JSON_SPACE(*context->p)) {
|
|
||||||
context->p++;
|
|
||||||
}
|
|
||||||
if (context->p < context->end) {
|
|
||||||
if (*context->p == ',') {
|
|
||||||
context->p++; //skip comma
|
|
||||||
} else {
|
|
||||||
set_parse_error(input->str, context->p,
|
|
||||||
EXPECT_STR_LEN, "expect comma \",\"",
|
|
||||||
&context->error_info, context->error_size);
|
|
||||||
context->error_no = EINVAL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kv_pair.value = context->decode.element;
|
|
||||||
context->decode.element.str += context->decode.element.len + 1;
|
|
||||||
|
|
||||||
if ((context->error_no=check_alloc_array(context,
|
|
||||||
(fc_common_array_t *)
|
|
||||||
&context->jmap)) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->decode.use_mpool) {
|
|
||||||
key_value_pair_t *dest;
|
|
||||||
dest = context->jmap.elements + context->jmap.count++;
|
|
||||||
JSON_DECODE_COPY_STRING(context, input,
|
|
||||||
&dest->key, &kv_pair.key);
|
|
||||||
JSON_DECODE_COPY_STRING(context, input,
|
|
||||||
&dest->value, &kv_pair.value);
|
|
||||||
} else {
|
|
||||||
context->jmap.elements[context->jmap.count++] = kv_pair;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &context->jmap;
|
|
||||||
}
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//json_parser.h
|
|
||||||
|
|
||||||
#ifndef _FC_JSON_PARSER_H
|
|
||||||
#define _FC_JSON_PARSER_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "common_define.h"
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "fast_mpool.h"
|
|
||||||
|
|
||||||
#define FC_JSON_TYPE_STRING 1
|
|
||||||
#define FC_JSON_TYPE_ARRAY 2
|
|
||||||
#define FC_JSON_TYPE_MAP 3
|
|
||||||
|
|
||||||
#define DEFINE_ARRAY_STRUCT(ELEMENT_TYPE, ARRAY_TYPE) \
|
|
||||||
typedef struct { \
|
|
||||||
ELEMENT_TYPE *elements; \
|
|
||||||
int count; \
|
|
||||||
\
|
|
||||||
/* for internal use */ \
|
|
||||||
int element_size; \
|
|
||||||
int alloc; \
|
|
||||||
} ARRAY_TYPE
|
|
||||||
|
|
||||||
DEFINE_ARRAY_STRUCT(void, fc_common_array_t);
|
|
||||||
DEFINE_ARRAY_STRUCT(string_t, fc_json_array_t);
|
|
||||||
DEFINE_ARRAY_STRUCT(key_value_pair_t, fc_json_map_t);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BufferInfo output; //for json encode/decode
|
|
||||||
struct {
|
|
||||||
struct fast_mpool_man mpool;
|
|
||||||
string_t element; //string allocator use output buffer
|
|
||||||
bool use_mpool;
|
|
||||||
} decode;
|
|
||||||
int init_buff_size;
|
|
||||||
int error_no;
|
|
||||||
int error_size;
|
|
||||||
char error_holder[256];
|
|
||||||
string_t error_info;
|
|
||||||
|
|
||||||
fc_json_array_t jarray;
|
|
||||||
fc_json_map_t jmap;
|
|
||||||
|
|
||||||
/* for internal use */
|
|
||||||
const char *str; //input string
|
|
||||||
const char *p; //current
|
|
||||||
const char *end;
|
|
||||||
} fc_json_context_t;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void fc_init_common_array(fc_common_array_t *array,
|
|
||||||
const int element_size)
|
|
||||||
{
|
|
||||||
array->elements = NULL;
|
|
||||||
array->element_size = element_size;
|
|
||||||
array->count = array->alloc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_init_json_array(fc_json_array_t *array)
|
|
||||||
{
|
|
||||||
fc_init_common_array((fc_common_array_t *)array, sizeof(string_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_init_json_map(fc_json_map_t *array)
|
|
||||||
{
|
|
||||||
fc_init_common_array((fc_common_array_t *)array,
|
|
||||||
sizeof(key_value_pair_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_free_common_array(fc_common_array_t *array)
|
|
||||||
{
|
|
||||||
if (array->elements != NULL) {
|
|
||||||
free(array->elements);
|
|
||||||
array->elements = NULL;
|
|
||||||
array->count = array->alloc = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_free_json_array(fc_json_array_t *array)
|
|
||||||
{
|
|
||||||
fc_free_common_array((fc_common_array_t *)array);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_free_json_map(fc_json_map_t *array)
|
|
||||||
{
|
|
||||||
fc_free_common_array((fc_common_array_t *)array);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_set_json_error_buffer(fc_json_context_t *ctx,
|
|
||||||
char *error_info, const int error_size)
|
|
||||||
{
|
|
||||||
if (error_info != NULL && error_size > 0) {
|
|
||||||
ctx->error_info.str = error_info;
|
|
||||||
ctx->error_size = error_size;
|
|
||||||
} else {
|
|
||||||
ctx->error_info.str = ctx->error_holder;
|
|
||||||
ctx->error_size = sizeof(ctx->error_holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->error_info.len = 0;
|
|
||||||
*ctx->error_info.str = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_init_json_context_ex(fc_json_context_t *ctx,
|
|
||||||
const bool decode_use_mpool, const int alloc_size_once,
|
|
||||||
const int init_buff_size, char *error_info,
|
|
||||||
const int error_size)
|
|
||||||
{
|
|
||||||
const int discard_size = 0;
|
|
||||||
|
|
||||||
ctx->output.buff = NULL;
|
|
||||||
ctx->output.alloc_size = ctx->output.length = 0;
|
|
||||||
FC_SET_STRING_NULL(ctx->decode.element);
|
|
||||||
if (init_buff_size > 0) {
|
|
||||||
ctx->init_buff_size = init_buff_size;
|
|
||||||
} else {
|
|
||||||
ctx->init_buff_size = 1024;
|
|
||||||
}
|
|
||||||
fc_init_json_array(&ctx->jarray);
|
|
||||||
fc_init_json_map(&ctx->jmap);
|
|
||||||
|
|
||||||
ctx->error_no = 0;
|
|
||||||
fc_set_json_error_buffer(ctx, error_info, error_size);
|
|
||||||
ctx->decode.use_mpool = decode_use_mpool;
|
|
||||||
if (decode_use_mpool) {
|
|
||||||
return fast_mpool_init(&ctx->decode.mpool,
|
|
||||||
alloc_size_once, discard_size);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_init_json_context(fc_json_context_t *ctx)
|
|
||||||
{
|
|
||||||
const bool decode_use_mpool = false;
|
|
||||||
const int alloc_size_once = 0;
|
|
||||||
const int init_buff_size = 0;
|
|
||||||
|
|
||||||
return fc_init_json_context_ex(ctx, decode_use_mpool,
|
|
||||||
alloc_size_once, init_buff_size, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_reset_json_context(fc_json_context_t *ctx)
|
|
||||||
{
|
|
||||||
if (ctx->decode.use_mpool) {
|
|
||||||
fast_mpool_reset(&ctx->decode.mpool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_destroy_json_context(fc_json_context_t *ctx)
|
|
||||||
{
|
|
||||||
fc_free_buffer(&ctx->output);
|
|
||||||
fc_free_json_array(&ctx->jarray);
|
|
||||||
fc_free_json_map(&ctx->jmap);
|
|
||||||
if (ctx->decode.use_mpool) {
|
|
||||||
fast_mpool_destroy(&ctx->decode.mpool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_json_parser_get_error_no(fc_json_context_t *ctx)
|
|
||||||
{
|
|
||||||
return ctx->error_no;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const string_t *fc_json_parser_get_error_info(
|
|
||||||
fc_json_context_t *ctx)
|
|
||||||
{
|
|
||||||
return &ctx->error_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fc_detect_json_type(const string_t *input);
|
|
||||||
|
|
||||||
int fc_encode_json_array_ex(fc_json_context_t *context,
|
|
||||||
const string_t *elements, const int count,
|
|
||||||
BufferInfo *buffer);
|
|
||||||
|
|
||||||
int fc_encode_json_map_ex(fc_json_context_t *context,
|
|
||||||
const key_value_pair_t *elements, const int count,
|
|
||||||
BufferInfo *buffer);
|
|
||||||
|
|
||||||
static inline const BufferInfo *fc_encode_json_array(fc_json_context_t
|
|
||||||
*context, const string_t *elements, const int count)
|
|
||||||
{
|
|
||||||
if (fc_encode_json_array_ex(context, elements, count,
|
|
||||||
&context->output) == 0)
|
|
||||||
{
|
|
||||||
return &context->output;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const BufferInfo *fc_encode_json_map(fc_json_context_t
|
|
||||||
*context, const key_value_pair_t *elements, const int count)
|
|
||||||
{
|
|
||||||
if (fc_encode_json_map_ex(context, elements, count,
|
|
||||||
&context->output) == 0)
|
|
||||||
{
|
|
||||||
return &context->output;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fc_json_array_t *fc_decode_json_array(fc_json_context_t
|
|
||||||
*context, const string_t *input);
|
|
||||||
|
|
||||||
const fc_json_map_t *fc_decode_json_map(fc_json_context_t
|
|
||||||
*context, const string_t *input);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -31,7 +24,7 @@ bool is_local_host_ip(const char *client_ip)
|
||||||
char *p;
|
char *p;
|
||||||
char *pEnd;
|
char *pEnd;
|
||||||
|
|
||||||
pEnd = g_local_host_ip_addrs +
|
pEnd = g_local_host_ip_addrs + \
|
||||||
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||||
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||||
{
|
{
|
||||||
|
|
@ -56,34 +49,29 @@ int insert_into_local_host_ip(const char *client_ip)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(g_local_host_ip_addrs + IP_ADDRESS_SIZE *
|
strcpy(g_local_host_ip_addrs + \
|
||||||
g_local_host_ip_count, client_ip);
|
IP_ADDRESS_SIZE * g_local_host_ip_count, \
|
||||||
|
client_ip);
|
||||||
g_local_host_ip_count++;
|
g_local_host_ip_count++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *local_host_ip_addrs_to_string(char *buff, const int size)
|
void log_local_host_ip_addrs()
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
char *pEnd;
|
char *pEnd;
|
||||||
|
char buff[512];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = snprintf(buff, size, "local_host_ip_count: %d,",
|
len = sprintf(buff, "local_host_ip_count: %d,", g_local_host_ip_count);
|
||||||
g_local_host_ip_count);
|
pEnd = g_local_host_ip_addrs + \
|
||||||
pEnd = g_local_host_ip_addrs +
|
|
||||||
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||||
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||||
{
|
{
|
||||||
len += snprintf(buff + len, size - len, " %s", p);
|
len += sprintf(buff + len, " %s", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buff;
|
logInfo("%s", buff);
|
||||||
}
|
|
||||||
|
|
||||||
void log_local_host_ip_addrs()
|
|
||||||
{
|
|
||||||
char buff[1024];
|
|
||||||
logInfo("%s", local_host_ip_addrs_to_string(buff, sizeof(buff)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_local_host_ip_addrs()
|
void load_local_host_ip_addrs()
|
||||||
|
|
@ -95,7 +83,7 @@ void load_local_host_ip_addrs()
|
||||||
char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT];
|
char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT];
|
||||||
int alias_count;
|
int alias_count;
|
||||||
|
|
||||||
insert_into_local_host_ip(LOCAL_LOOPBACK_IPv4);
|
insert_into_local_host_ip(LOCAL_LOOPBACK_IP);
|
||||||
|
|
||||||
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
|
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
|
||||||
if (*g_if_alias_prefix == '\0')
|
if (*g_if_alias_prefix == '\0')
|
||||||
|
|
@ -159,8 +147,8 @@ const char *get_next_local_ip(const char *previous_ip)
|
||||||
pEnd = g_local_host_ip_addrs + \
|
pEnd = g_local_host_ip_addrs + \
|
||||||
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||||
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||||
{
|
{
|
||||||
if (!is_loopback_ip(p))
|
if (strcmp(p, LOCAL_LOOPBACK_IP) != 0)
|
||||||
{
|
{
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
|
|
@ -171,7 +159,7 @@ const char *get_next_local_ip(const char *previous_ip)
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -186,10 +174,7 @@ const char *get_first_local_ip()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* 注意,当系统存在IPv6回环地址时,为了简化系统的改动,
|
return LOCAL_LOOPBACK_IP;
|
||||||
会将IPv6回环地址修改成IPv4回环地址返回
|
|
||||||
*/
|
|
||||||
return LOCAL_LOOPBACK_IPv4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,17 +199,3 @@ const char *get_first_local_private_ip()
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stat_local_host_ip(int *ipv4_count, int *ipv6_count)
|
|
||||||
{
|
|
||||||
const char *ip_addr;
|
|
||||||
|
|
||||||
*ipv4_count = *ipv6_count = 0;
|
|
||||||
ip_addr = NULL;
|
|
||||||
while ((ip_addr=get_next_local_ip(ip_addr)) != NULL) {
|
|
||||||
if (is_ipv6_addr(ip_addr)) {
|
|
||||||
++(*ipv6_count);
|
|
||||||
} else {
|
|
||||||
++(*ipv4_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//local_ip_func.h
|
//local_ip_func.h
|
||||||
|
|
||||||
|
|
@ -25,32 +18,22 @@
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
|
|
||||||
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
|
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
|
||||||
#define FAST_MAX_LOCAL_IP_ADDRS 32
|
#define FAST_MAX_LOCAL_IP_ADDRS 16
|
||||||
|
|
||||||
#define LOCAL_LOOPBACK_IPv4 "127.0.0.1"
|
#define LOCAL_LOOPBACK_IP "127.0.0.1"
|
||||||
#define LOCAL_LOOPBACK_IPv6 "::1"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int g_local_host_ip_count;
|
extern int g_local_host_ip_count;
|
||||||
extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS *
|
extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
|
||||||
IP_ADDRESS_SIZE];
|
IP_ADDRESS_SIZE];
|
||||||
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
|
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
|
||||||
|
|
||||||
void load_local_host_ip_addrs();
|
void load_local_host_ip_addrs();
|
||||||
bool is_local_host_ip(const char *client_ip);
|
bool is_local_host_ip(const char *client_ip);
|
||||||
|
|
||||||
static inline bool is_loopback_ip(const char *ip_addr)
|
|
||||||
{
|
|
||||||
return (strcmp(ip_addr, LOCAL_LOOPBACK_IPv4) == 0 ||
|
|
||||||
strcmp(ip_addr, LOCAL_LOOPBACK_IPv6) == 0 ||
|
|
||||||
strcasecmp(ip_addr, "fe80::1") == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stat_local_host_ip(int *ipv4_count, int *ipv6_count);
|
|
||||||
|
|
||||||
const char *get_first_local_ip();
|
const char *get_first_local_ip();
|
||||||
const char *get_next_local_ip(const char *previous_ip);
|
const char *get_next_local_ip(const char *previous_ip);
|
||||||
|
|
||||||
|
|
@ -59,7 +42,6 @@ const char *get_first_local_private_ip();
|
||||||
int insert_into_local_host_ip(const char *client_ip);
|
int insert_into_local_host_ip(const char *client_ip);
|
||||||
void log_local_host_ip_addrs();
|
void log_local_host_ip_addrs();
|
||||||
void print_local_host_ip_addrs();
|
void print_local_host_ip_addrs();
|
||||||
const char *local_host_ip_addrs_to_string(char *buff, const int size);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
#ifndef _LOCKED_LIST_H
|
|
||||||
#define _LOCKED_LIST_H
|
|
||||||
|
|
||||||
#include "fc_list.h"
|
|
||||||
#include "pthread_func.h"
|
|
||||||
|
|
||||||
typedef struct fc_locked_list {
|
|
||||||
struct fc_list_head head;
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
} FCLockedList;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOCKED_LIST_LOCK(list) PTHREAD_MUTEX_LOCK(&(list)->lock)
|
|
||||||
#define LOCKED_LIST_UNLOCK(list) PTHREAD_MUTEX_UNLOCK(&(list)->lock)
|
|
||||||
|
|
||||||
static inline int locked_list_init(FCLockedList *list)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if ((result=init_pthread_lock(&list->lock)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
FC_INIT_LIST_HEAD(&list->head);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void locked_list_destroy(FCLockedList *list)
|
|
||||||
{
|
|
||||||
pthread_mutex_destroy(&list->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void locked_list_add(struct fc_list_head *_new,
|
|
||||||
FCLockedList *list)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
fc_list_add(_new, &list->head);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void locked_list_add_tail(struct fc_list_head *_new,
|
|
||||||
FCLockedList *list)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
fc_list_add_tail(_new, &list->head);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void locked_list_move(struct fc_list_head *obj,
|
|
||||||
FCLockedList *list)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
fc_list_move(obj, &list->head);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void locked_list_move_tail(struct fc_list_head *obj,
|
|
||||||
FCLockedList *list)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
fc_list_move_tail(obj, &list->head);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void locked_list_del(struct fc_list_head *old,
|
|
||||||
FCLockedList *list)
|
|
||||||
{
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
fc_list_del_init(old);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int locked_list_empty(FCLockedList *list)
|
|
||||||
{
|
|
||||||
int empty;
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
empty = fc_list_empty(&list->head);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int locked_list_count(FCLockedList *list)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
PTHREAD_MUTEX_LOCK(&list->lock);
|
|
||||||
count = fc_list_count(&list->head);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&list->lock);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define locked_list_first_entry(list, type, member, var) \
|
|
||||||
PTHREAD_MUTEX_LOCK(&(list)->lock); \
|
|
||||||
var = fc_list_first_entry(&(list)->head, type, member); \
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&(list)->lock)
|
|
||||||
|
|
||||||
#define locked_list_last_entry(list, type, member, var) \
|
|
||||||
PTHREAD_MUTEX_LOCK(&(list)->lock); \
|
|
||||||
var = fc_list_last_entry(&(list)->head, type, member); \
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&(list)->lock)
|
|
||||||
|
|
||||||
#define locked_list_pop(list, type, member, var) \
|
|
||||||
PTHREAD_MUTEX_LOCK(&(list)->lock); \
|
|
||||||
var = fc_list_first_entry(&(list)->head, type, member); \
|
|
||||||
if (var != NULL) { \
|
|
||||||
fc_list_del_init(&var->member); \
|
|
||||||
} \
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&(list)->lock)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,353 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include "logger.h"
|
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "pthread_func.h"
|
|
||||||
#include "locked_timer.h"
|
|
||||||
|
|
||||||
static int locked_timer_init_slots(LockedTimer *timer)
|
|
||||||
{
|
|
||||||
int bytes;
|
|
||||||
int result;
|
|
||||||
LockedTimerSlot *slot;
|
|
||||||
LockedTimerSlot *send;
|
|
||||||
pthread_mutex_t *lock;
|
|
||||||
pthread_mutex_t *lend;
|
|
||||||
|
|
||||||
bytes = sizeof(LockedTimerSlot) * timer->slot_count;
|
|
||||||
timer->slots = (LockedTimerSlot *)fc_malloc(bytes);
|
|
||||||
if (timer->slots == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
memset(timer->slots, 0, bytes);
|
|
||||||
|
|
||||||
send = timer->slots + timer->slot_count;
|
|
||||||
for (slot=timer->slots; slot<send; slot++) {
|
|
||||||
if ((result=init_pthread_lock(&slot->lock)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
FC_INIT_LIST_HEAD(&slot->head);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer->entry_shares.locks = (pthread_mutex_t *)fc_malloc(
|
|
||||||
sizeof(pthread_mutex_t) * timer->entry_shares.count);
|
|
||||||
if (timer->entry_shares.locks == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
lend = timer->entry_shares.locks + timer->entry_shares.count;
|
|
||||||
for (lock=timer->entry_shares.locks; lock<lend; lock++) {
|
|
||||||
if ((result=init_pthread_lock(lock)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int locked_timer_init_ex(LockedTimer *timer, const int slot_count,
|
|
||||||
const int64_t current_time, const int shared_lock_count,
|
|
||||||
const bool set_lock_index)
|
|
||||||
{
|
|
||||||
if (slot_count <= 0 || current_time <= 0) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer->slot_count = slot_count;
|
|
||||||
timer->entry_shares.count = shared_lock_count;
|
|
||||||
timer->entry_shares.set_lock_index = set_lock_index;
|
|
||||||
timer->base_time = current_time; //base time for slot 0
|
|
||||||
timer->current_time = current_time;
|
|
||||||
return locked_timer_init_slots(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void locked_timer_destroy(LockedTimer *timer)
|
|
||||||
{
|
|
||||||
LockedTimerSlot *slot;
|
|
||||||
LockedTimerSlot *send;
|
|
||||||
pthread_mutex_t *lock;
|
|
||||||
pthread_mutex_t *lend;
|
|
||||||
|
|
||||||
if (timer->slots == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
send = timer->slots + timer->slot_count;
|
|
||||||
for (slot=timer->slots; slot<send; slot++) {
|
|
||||||
pthread_mutex_destroy(&slot->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
lend = timer->entry_shares.locks + timer->entry_shares.count;
|
|
||||||
for (lock=timer->entry_shares.locks; lock<lend; lock++) {
|
|
||||||
pthread_mutex_destroy(lock);
|
|
||||||
}
|
|
||||||
free(timer->entry_shares.locks);
|
|
||||||
timer->entry_shares.locks = NULL;
|
|
||||||
timer->entry_shares.count = 0;
|
|
||||||
|
|
||||||
free(timer->slots);
|
|
||||||
timer->slots = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
|
||||||
(((expires) - timer->base_time) % timer->slot_count)
|
|
||||||
|
|
||||||
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
|
||||||
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
|
||||||
|
|
||||||
#define TIMER_ENTRY_LOCK(timer, lock_index) \
|
|
||||||
PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index)
|
|
||||||
|
|
||||||
#define TIMER_ENTRY_UNLOCK(timer, lock_index) \
|
|
||||||
PTHREAD_MUTEX_UNLOCK(timer->entry_shares.locks + lock_index)
|
|
||||||
|
|
||||||
#define TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry) \
|
|
||||||
(timer->entry_shares.set_lock_index ? \
|
|
||||||
__sync_add_and_fetch(&entry->lock_index, 0) : entry->lock_index)
|
|
||||||
|
|
||||||
#define TIMER_ENTRY_FETCH_AND_LOCK(timer, entry) \
|
|
||||||
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry); \
|
|
||||||
PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index)
|
|
||||||
|
|
||||||
#define TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index) \
|
|
||||||
do { \
|
|
||||||
TIMER_ENTRY_LOCK(timer, lock_index); \
|
|
||||||
entry->status = FAST_TIMER_STATUS_NORMAL; \
|
|
||||||
entry->slot_index = slot - timer->slots; \
|
|
||||||
TIMER_ENTRY_UNLOCK(timer, lock_index); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static inline void add_entry(LockedTimer *timer, LockedTimerSlot *slot,
|
|
||||||
LockedTimerEntry *entry, const int64_t expires, const int flags)
|
|
||||||
{
|
|
||||||
int lock_index;
|
|
||||||
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) != 0) {
|
|
||||||
if (timer->entry_shares.set_lock_index) {
|
|
||||||
int old_index;
|
|
||||||
/* init the entry on the first call */
|
|
||||||
lock_index = ((unsigned long)entry) % timer->entry_shares.count;
|
|
||||||
old_index = entry->lock_index;
|
|
||||||
while (!__sync_bool_compare_and_swap(&entry->lock_index,
|
|
||||||
old_index, lock_index))
|
|
||||||
{
|
|
||||||
old_index = __sync_add_and_fetch(&entry->lock_index, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lock_index = entry->lock_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index);
|
|
||||||
} else {
|
|
||||||
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&slot->lock);
|
|
||||||
if ((flags & FAST_TIMER_FLAGS_SET_EXPIRES) != 0) {
|
|
||||||
entry->expires = expires;
|
|
||||||
}
|
|
||||||
fc_list_add_tail(&entry->dlink, &slot->head);
|
|
||||||
entry->rehash = false;
|
|
||||||
|
|
||||||
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) == 0) {
|
|
||||||
/* MUST set entry status and slot index in the end when entry move */
|
|
||||||
TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index);
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&slot->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define check_entry_status(timer, entry, slot_index) \
|
|
||||||
check_set_entry_status(timer, entry, slot_index, \
|
|
||||||
FAST_TIMER_STATUS_NONE)
|
|
||||||
|
|
||||||
static inline int check_set_entry_status(LockedTimer *timer,
|
|
||||||
LockedTimerEntry *entry, int *slot_index, const int new_status)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int lock_index;
|
|
||||||
|
|
||||||
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry);
|
|
||||||
while (1) {
|
|
||||||
TIMER_ENTRY_LOCK(timer, lock_index);
|
|
||||||
switch (entry->status) {
|
|
||||||
case FAST_TIMER_STATUS_CLEARED:
|
|
||||||
result = ECANCELED;
|
|
||||||
break;
|
|
||||||
case FAST_TIMER_STATUS_TIMEOUT:
|
|
||||||
result = ETIMEDOUT;
|
|
||||||
break;
|
|
||||||
case FAST_TIMER_STATUS_MOVING:
|
|
||||||
result = EAGAIN;
|
|
||||||
break;
|
|
||||||
case FAST_TIMER_STATUS_NORMAL:
|
|
||||||
result = 0;
|
|
||||||
if (new_status != FAST_TIMER_STATUS_NONE) {
|
|
||||||
entry->status = new_status;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*slot_index = entry->slot_index;
|
|
||||||
TIMER_ENTRY_UNLOCK(timer, lock_index);
|
|
||||||
|
|
||||||
if (result != EAGAIN) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
fc_sleep_ms(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void locked_timer_add_ex(LockedTimer *timer, LockedTimerEntry *entry,
|
|
||||||
const int64_t expires, const int flags)
|
|
||||||
{
|
|
||||||
LockedTimerSlot *slot;
|
|
||||||
int64_t new_expires;
|
|
||||||
bool new_flags;
|
|
||||||
|
|
||||||
if (expires > timer->current_time) {
|
|
||||||
new_expires = expires;
|
|
||||||
new_flags = flags;
|
|
||||||
} else {
|
|
||||||
new_expires = timer->current_time + 1; //plus 1 for rare case
|
|
||||||
new_flags = flags | FAST_TIMER_FLAGS_SET_EXPIRES;
|
|
||||||
}
|
|
||||||
slot = TIMER_GET_SLOT_POINTER(timer, new_expires);
|
|
||||||
add_entry(timer, slot, entry, new_expires, new_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int locked_timer_modify(LockedTimer *timer, LockedTimerEntry *entry,
|
|
||||||
const int64_t new_expires)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int slot_index;
|
|
||||||
|
|
||||||
if (new_expires > entry->expires) {
|
|
||||||
if ((result=check_entry_status(timer, entry, &slot_index)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&(timer->slots + slot_index)->lock);
|
|
||||||
entry->rehash = TIMER_GET_SLOT_INDEX(timer,
|
|
||||||
new_expires) != slot_index;
|
|
||||||
entry->expires = new_expires; //lazy move
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&(timer->slots + slot_index)->lock);
|
|
||||||
} else if (new_expires < entry->expires) {
|
|
||||||
if ((result=locked_timer_remove_ex(timer, entry,
|
|
||||||
FAST_TIMER_STATUS_MOVING)) == 0)
|
|
||||||
{
|
|
||||||
locked_timer_add_ex(timer, entry, new_expires,
|
|
||||||
FAST_TIMER_FLAGS_SET_EXPIRES);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int locked_timer_remove_ex(LockedTimer *timer, LockedTimerEntry *entry,
|
|
||||||
const int new_status)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int slot_index;
|
|
||||||
|
|
||||||
if ((result=check_set_entry_status(timer, entry,
|
|
||||||
&slot_index, new_status)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&(timer->slots + slot_index)->lock);
|
|
||||||
fc_list_del_init(&entry->dlink);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&(timer->slots + slot_index)->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time,
|
|
||||||
LockedTimerEntry *head)
|
|
||||||
{
|
|
||||||
LockedTimerSlot *slot;
|
|
||||||
LockedTimerSlot *new_slot;
|
|
||||||
LockedTimerEntry *entry;
|
|
||||||
LockedTimerEntry *tmp;
|
|
||||||
LockedTimerEntry *tail;
|
|
||||||
bool is_valid;
|
|
||||||
int lock_index;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
if (timer->current_time >= current_time) {
|
|
||||||
head->next = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tail = head;
|
|
||||||
count = 0;
|
|
||||||
while (timer->current_time < current_time) {
|
|
||||||
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
|
||||||
PTHREAD_MUTEX_LOCK(&slot->lock);
|
|
||||||
fc_list_for_each_entry_safe(entry, tmp, &slot->head, dlink) {
|
|
||||||
if (entry->expires >= current_time) { //not expired
|
|
||||||
if (entry->rehash) {
|
|
||||||
new_slot = TIMER_GET_SLOT_POINTER(timer, entry->expires);
|
|
||||||
if (new_slot != slot) { //check to avoid deadlock
|
|
||||||
TIMER_ENTRY_FETCH_AND_LOCK(timer, entry);
|
|
||||||
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
|
|
||||||
entry->status = FAST_TIMER_STATUS_MOVING;
|
|
||||||
is_valid = true;
|
|
||||||
} else {
|
|
||||||
is_valid = false;
|
|
||||||
}
|
|
||||||
TIMER_ENTRY_UNLOCK(timer, lock_index);
|
|
||||||
|
|
||||||
if (is_valid) {
|
|
||||||
fc_list_del_init(&entry->dlink);
|
|
||||||
add_entry(timer, new_slot, entry, entry->expires,
|
|
||||||
FAST_TIMER_FLAGS_SET_NOTHING);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entry->rehash = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { //expired
|
|
||||||
TIMER_ENTRY_FETCH_AND_LOCK(timer, entry);
|
|
||||||
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
|
|
||||||
entry->status = FAST_TIMER_STATUS_TIMEOUT;
|
|
||||||
is_valid = true;
|
|
||||||
} else {
|
|
||||||
is_valid = false;
|
|
||||||
}
|
|
||||||
TIMER_ENTRY_UNLOCK(timer, lock_index);
|
|
||||||
|
|
||||||
if (is_valid) {
|
|
||||||
fc_list_del_init(&entry->dlink);
|
|
||||||
tail->next = entry;
|
|
||||||
tail = entry;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&slot->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
tail->next = NULL;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LOCKED_TIMER_H__
|
|
||||||
#define __LOCKED_TIMER_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "common_define.h"
|
|
||||||
#include "fc_list.h"
|
|
||||||
|
|
||||||
#define FAST_TIMER_STATUS_NONE 0
|
|
||||||
#define FAST_TIMER_STATUS_NORMAL 1
|
|
||||||
#define FAST_TIMER_STATUS_MOVING 2
|
|
||||||
#define FAST_TIMER_STATUS_TIMEOUT 3
|
|
||||||
#define FAST_TIMER_STATUS_CLEARED 4
|
|
||||||
|
|
||||||
#define FAST_TIMER_FLAGS_SET_NOTHING 0
|
|
||||||
#define FAST_TIMER_FLAGS_SET_EXPIRES 1
|
|
||||||
#define FAST_TIMER_FLAGS_SET_ENTRY_LOCK 2
|
|
||||||
#define FAST_TIMER_FLAGS_SET_ALL (FAST_TIMER_FLAGS_SET_EXPIRES | \
|
|
||||||
FAST_TIMER_FLAGS_SET_ENTRY_LOCK)
|
|
||||||
|
|
||||||
typedef struct locked_timer_entry {
|
|
||||||
int64_t expires;
|
|
||||||
struct fc_list_head dlink; //for timer slot
|
|
||||||
struct locked_timer_entry *next; //for timeout chain
|
|
||||||
uint32_t slot_index; //for slot lock
|
|
||||||
volatile uint16_t lock_index; //for entry lock
|
|
||||||
uint8_t status;
|
|
||||||
bool rehash;
|
|
||||||
} LockedTimerEntry;
|
|
||||||
|
|
||||||
typedef struct locked_timer_slot {
|
|
||||||
struct fc_list_head head;
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
} LockedTimerSlot;
|
|
||||||
|
|
||||||
typedef struct locked_timer_shared_locks {
|
|
||||||
bool set_lock_index;
|
|
||||||
uint16_t count;
|
|
||||||
pthread_mutex_t *locks;
|
|
||||||
} LockedTimerSharedLocks;
|
|
||||||
|
|
||||||
typedef struct locked_timer {
|
|
||||||
int slot_count; //time wheel slot count
|
|
||||||
LockedTimerSharedLocks entry_shares; //shared locks for entry
|
|
||||||
int64_t base_time; //base time for slot 0
|
|
||||||
volatile int64_t current_time;
|
|
||||||
LockedTimerSlot *slots;
|
|
||||||
} LockedTimer;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define locked_timer_init(timer, slot_count, current_time, shared_lock_count) \
|
|
||||||
locked_timer_init_ex(timer, slot_count, current_time, shared_lock_count, \
|
|
||||||
true)
|
|
||||||
|
|
||||||
#define locked_timer_add(timer, entry) \
|
|
||||||
locked_timer_add_ex(timer, entry, (entry)->expires, \
|
|
||||||
FAST_TIMER_FLAGS_SET_ENTRY_LOCK)
|
|
||||||
|
|
||||||
#define locked_timer_remove(timer, entry) \
|
|
||||||
locked_timer_remove_ex(timer, entry, FAST_TIMER_STATUS_CLEARED)
|
|
||||||
|
|
||||||
int locked_timer_init_ex(LockedTimer *timer, const int slot_count,
|
|
||||||
const int64_t current_time, const int shared_lock_count,
|
|
||||||
const bool set_lock_index);
|
|
||||||
|
|
||||||
void locked_timer_destroy(LockedTimer *timer);
|
|
||||||
|
|
||||||
void locked_timer_add_ex(LockedTimer *timer, LockedTimerEntry *entry,
|
|
||||||
const int64_t expires, const int flags);
|
|
||||||
|
|
||||||
int locked_timer_remove_ex(LockedTimer *timer, LockedTimerEntry *entry,
|
|
||||||
const int new_status);
|
|
||||||
|
|
||||||
int locked_timer_modify(LockedTimer *timer, LockedTimerEntry *entry,
|
|
||||||
const int64_t new_expires);
|
|
||||||
|
|
||||||
int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time,
|
|
||||||
LockedTimerEntry *head);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
283
src/logger.c
283
src/logger.c
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
@ -50,21 +43,21 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock);
|
||||||
|
|
||||||
static int check_and_mk_log_dir(const char *base_path)
|
static int check_and_mk_log_dir(const char *base_path)
|
||||||
{
|
{
|
||||||
char log_path[MAX_PATH_SIZE];
|
char data_path[MAX_PATH_SIZE];
|
||||||
|
|
||||||
fc_combine_full_filename(base_path, "logs", log_path);
|
snprintf(data_path, sizeof(data_path), "%s/logs", base_path);
|
||||||
if (!fileExists(log_path))
|
if (!fileExists(data_path))
|
||||||
{
|
{
|
||||||
if (mkdir(log_path, 0755) != 0)
|
if (mkdir(data_path, 0755) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "mkdir \"%s\" fail, "
|
fprintf(stderr, "mkdir \"%s\" fail, " \
|
||||||
"errno: %d, error info: %s\n",
|
"errno: %d, error info: %s\n", \
|
||||||
log_path, errno, STRERROR(errno));
|
data_path, errno, STRERROR(errno));
|
||||||
return errno != 0 ? errno : EPERM;
|
return errno != 0 ? errno : EPERM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_init()
|
int log_init()
|
||||||
|
|
@ -99,7 +92,6 @@ int log_init_ex(LogContext *pContext)
|
||||||
pContext->log_level = LOG_INFO;
|
pContext->log_level = LOG_INFO;
|
||||||
pContext->log_fd = STDERR_FILENO;
|
pContext->log_fd = STDERR_FILENO;
|
||||||
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
|
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
|
||||||
pContext->compress_log_days_before = 1;
|
|
||||||
strcpy(pContext->rotate_time_format, "%Y%m%d_%H%M%S");
|
strcpy(pContext->rotate_time_format, "%Y%m%d_%H%M%S");
|
||||||
|
|
||||||
pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE);
|
pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE);
|
||||||
|
|
@ -112,7 +104,7 @@ int log_init_ex(LogContext *pContext)
|
||||||
}
|
}
|
||||||
pContext->pcurrent_buff = pContext->log_buff;
|
pContext->pcurrent_buff = pContext->log_buff;
|
||||||
|
|
||||||
if ((result=init_pthread_lock(&(pContext->lock))) != 0)
|
if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -136,8 +128,8 @@ static int log_print_header(LogContext *pContext)
|
||||||
if (pContext->current_size < 0)
|
if (pContext->current_size < 0)
|
||||||
{
|
{
|
||||||
result = errno != 0 ? errno : EACCES;
|
result = errno != 0 ? errno : EACCES;
|
||||||
fprintf(stderr, "lseek file \"%s\" fail, "
|
fprintf(stderr, "lseek file \"%s\" fail, " \
|
||||||
"errno: %d, error info: %s\n",
|
"errno: %d, error info: %s\n", \
|
||||||
pContext->log_filename, result, STRERROR(result));
|
pContext->log_filename, result, STRERROR(result));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -158,8 +150,8 @@ static int log_print_header(LogContext *pContext)
|
||||||
static int log_open(LogContext *pContext)
|
static int log_open(LogContext *pContext)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | O_CREAT |
|
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | \
|
||||||
O_APPEND | O_CLOEXEC | pContext->fd_flags, 0644)) < 0)
|
O_CREAT | O_APPEND | pContext->fd_flags, 0644)) < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "open log file \"%s\" to write fail, " \
|
fprintf(stderr, "open log file \"%s\" to write fail, " \
|
||||||
"errno: %d, error info: %s\n", \
|
"errno: %d, error info: %s\n", \
|
||||||
|
|
@ -222,44 +214,31 @@ int log_reopen_ex(LogContext *pContext)
|
||||||
return log_open(pContext);
|
return log_open(pContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_set_prefix_ex(LogContext *pContext, const char *base_path,
|
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
|
||||||
const char *filename_prefix)
|
const char *filename_prefix)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
char log_filename[MAX_PATH_SIZE];
|
|
||||||
|
|
||||||
if ((result=check_and_mk_log_dir(base_path)) != 0)
|
if ((result=check_and_mk_log_dir(base_path)) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(log_filename, MAX_PATH_SIZE, "%s/logs/%s.log",
|
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", \
|
||||||
base_path, filename_prefix);
|
base_path, filename_prefix);
|
||||||
return log_set_filename_ex(pContext, log_filename);
|
|
||||||
|
return log_open(pContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
|
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
|
||||||
{
|
{
|
||||||
if (log_filename == NULL || *log_filename == '\0')
|
if (log_filename == NULL) {
|
||||||
{
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
"log_filename is NULL!\n", __LINE__);
|
||||||
"log_filename is NULL or empty!\n", __LINE__);
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename);
|
||||||
if (*(pContext->log_filename) == '\0')
|
return log_open(pContext);
|
||||||
{
|
|
||||||
fc_strlcpy(pContext->log_filename, log_filename, MAX_PATH_SIZE);
|
|
||||||
return log_open(pContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(log_filename, pContext->log_filename) == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fc_strlcpy(pContext->log_filename, log_filename, MAX_PATH_SIZE);
|
|
||||||
return log_reopen_ex(pContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
|
void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
|
||||||
|
|
@ -296,9 +275,9 @@ void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_call
|
||||||
{
|
{
|
||||||
int64_t current_size;
|
int64_t current_size;
|
||||||
|
|
||||||
pthread_mutex_lock(&(pContext->lock));
|
pthread_mutex_lock(&(pContext->log_thread_lock));
|
||||||
current_size = pContext->current_size;
|
current_size = pContext->current_size;
|
||||||
pthread_mutex_unlock(&(pContext->lock));
|
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||||
if (current_size == 0)
|
if (current_size == 0)
|
||||||
{
|
{
|
||||||
log_print_header(pContext);
|
log_print_header(pContext);
|
||||||
|
|
@ -323,14 +302,7 @@ void log_set_compress_log_flags_ex(LogContext *pContext, const short flags)
|
||||||
|
|
||||||
void log_set_compress_log_days_before_ex(LogContext *pContext, const int days_before)
|
void log_set_compress_log_days_before_ex(LogContext *pContext, const int days_before)
|
||||||
{
|
{
|
||||||
if (days_before > 0)
|
pContext->compress_log_days_before = days_before;
|
||||||
{
|
|
||||||
pContext->compress_log_days_before = days_before;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pContext->compress_log_days_before = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_set_fd_flags(LogContext *pContext, const int flags)
|
void log_set_fd_flags(LogContext *pContext, const int flags)
|
||||||
|
|
@ -347,7 +319,7 @@ void log_destroy_ex(LogContext *pContext)
|
||||||
close(pContext->log_fd);
|
close(pContext->log_fd);
|
||||||
pContext->log_fd = STDERR_FILENO;
|
pContext->log_fd = STDERR_FILENO;
|
||||||
|
|
||||||
pthread_mutex_destroy(&pContext->lock);
|
pthread_mutex_destroy(&pContext->log_thread_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pContext->log_buff != NULL)
|
if (pContext->log_buff != NULL)
|
||||||
|
|
@ -385,11 +357,12 @@ static int log_delete_old_file(LogContext *pContext,
|
||||||
char full_filename[MAX_PATH_SIZE + 128];
|
char full_filename[MAX_PATH_SIZE + 128];
|
||||||
if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
|
if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
|
||||||
{
|
{
|
||||||
fc_concat_two_strings(old_filename, GZIP_EXT_NAME_STR, full_filename);
|
snprintf(full_filename, sizeof(full_filename), "%s%s",
|
||||||
|
old_filename, GZIP_EXT_NAME_STR);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fc_safe_strcpy(full_filename, old_filename);
|
snprintf(full_filename, sizeof(full_filename), "%s", old_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlink(full_filename) != 0)
|
if (unlink(full_filename) != 0)
|
||||||
|
|
@ -400,10 +373,6 @@ static int log_delete_old_file(LogContext *pContext,
|
||||||
"unlink %s fail, errno: %d, error info: %s\n", \
|
"unlink %s fail, errno: %d, error info: %s\n", \
|
||||||
__LINE__, full_filename, errno, STRERROR(errno));
|
__LINE__, full_filename, errno, STRERROR(errno));
|
||||||
}
|
}
|
||||||
else if (NEED_COMPRESS_LOG(pContext->compress_log_flags))
|
|
||||||
{
|
|
||||||
unlink(old_filename);
|
|
||||||
}
|
|
||||||
return errno != 0 ? errno : EPERM;
|
return errno != 0 ? errno : EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -545,9 +514,7 @@ static int log_get_matched_files(LogContext *pContext,
|
||||||
char *log_filename;
|
char *log_filename;
|
||||||
char *filename;
|
char *filename;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
#ifndef OS_LINUX
|
|
||||||
struct dirent ent;
|
struct dirent ent;
|
||||||
#endif
|
|
||||||
struct dirent *pEntry;
|
struct dirent *pEntry;
|
||||||
time_t the_time;
|
time_t the_time;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
@ -589,18 +556,11 @@ static int log_get_matched_files(LogContext *pContext,
|
||||||
the_time = get_current_time() - days_before * 86400;
|
the_time = get_current_time() - days_before * 86400;
|
||||||
localtime_r(&the_time, &tm);
|
localtime_r(&the_time, &tm);
|
||||||
memset(filename_prefix, 0, sizeof(filename_prefix));
|
memset(filename_prefix, 0, sizeof(filename_prefix));
|
||||||
len = strlen(log_filename);
|
len = sprintf(filename_prefix, "%s.", log_filename);
|
||||||
memcpy(filename_prefix, log_filename, len);
|
|
||||||
*(filename_prefix + len++) = '.';
|
|
||||||
strftime(filename_prefix + len, sizeof(filename_prefix) - len,
|
strftime(filename_prefix + len, sizeof(filename_prefix) - len,
|
||||||
rotate_time_format_prefix, &tm);
|
rotate_time_format_prefix, &tm);
|
||||||
prefix_filename_len = strlen(filename_prefix);
|
prefix_filename_len = strlen(filename_prefix);
|
||||||
|
|
||||||
#ifndef OS_LINUX
|
|
||||||
while (readdir_r(dir, &ent, &pEntry) == 0)
|
while (readdir_r(dir, &ent, &pEntry) == 0)
|
||||||
#else
|
|
||||||
while ((pEntry=readdir(dir)) != NULL)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
if (pEntry == NULL)
|
if (pEntry == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -652,8 +612,8 @@ static int log_delete_matched_old_files(LogContext *pContext,
|
||||||
log_get_file_path(pContext, log_filepath);
|
log_get_file_path(pContext, log_filepath);
|
||||||
for (i=0; i<filename_array.count; i++)
|
for (i=0; i<filename_array.count; i++)
|
||||||
{
|
{
|
||||||
fc_concat_two_strings(log_filepath, filename_array.
|
snprintf(full_filename, sizeof(full_filename), "%s%s",
|
||||||
filenames[i], full_filename);
|
log_filepath, filename_array.filenames[i]);
|
||||||
if (unlink(full_filename) != 0)
|
if (unlink(full_filename) != 0)
|
||||||
{
|
{
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
|
|
@ -704,9 +664,7 @@ int log_delete_old_files(void *args)
|
||||||
the_time -= 86400;
|
the_time -= 86400;
|
||||||
localtime_r(&the_time, &tm);
|
localtime_r(&the_time, &tm);
|
||||||
memset(old_filename, 0, sizeof(old_filename));
|
memset(old_filename, 0, sizeof(old_filename));
|
||||||
len = strlen(pContext->log_filename);
|
len = sprintf(old_filename, "%s.", pContext->log_filename);
|
||||||
memcpy(old_filename, pContext->log_filename, len);
|
|
||||||
*(old_filename + len++) = '.';
|
|
||||||
strftime(old_filename + len, sizeof(old_filename) - len,
|
strftime(old_filename + len, sizeof(old_filename) - len,
|
||||||
pContext->rotate_time_format, &tm);
|
pContext->rotate_time_format, &tm);
|
||||||
if ((result=log_delete_old_file(pContext, old_filename)) != 0)
|
if ((result=log_delete_old_file(pContext, old_filename)) != 0)
|
||||||
|
|
@ -728,20 +686,31 @@ int log_delete_old_files(void *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *log_gzip_func(void *args)
|
static void* log_gzip_func(void *args)
|
||||||
{
|
{
|
||||||
LogContext *pContext;
|
LogContext *pContext;
|
||||||
|
char *gzip;
|
||||||
char cmd[MAX_PATH_SIZE + 128];
|
char cmd[MAX_PATH_SIZE + 128];
|
||||||
struct log_filename_array filename_array;
|
struct log_filename_array filename_array;
|
||||||
char log_filepath[MAX_PATH_SIZE];
|
char log_filepath[MAX_PATH_SIZE];
|
||||||
char full_filename[MAX_PATH_SIZE + 32];
|
char full_filename[MAX_PATH_SIZE + 32];
|
||||||
char output[512];
|
|
||||||
const char *gzip_cmd_filename;
|
|
||||||
int prefix_len;
|
int prefix_len;
|
||||||
int result;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
pContext = (LogContext *)args;
|
pContext = (LogContext *)args;
|
||||||
|
if (access("/bin/gzip", F_OK) == 0)
|
||||||
|
{
|
||||||
|
gzip = "/bin/gzip";
|
||||||
|
}
|
||||||
|
else if (access("/usr/bin/gzip", F_OK) == 0)
|
||||||
|
{
|
||||||
|
gzip = "/usr/bin/gzip";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gzip = "gzip";
|
||||||
|
}
|
||||||
|
|
||||||
if (log_get_prefix_len(pContext, &prefix_len) != 0)
|
if (log_get_prefix_len(pContext, &prefix_len) != 0)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -764,25 +733,13 @@ static void *log_gzip_func(void *args)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
gzip_cmd_filename = get_gzip_command_filename();
|
snprintf(full_filename, sizeof(full_filename), "%s%s",
|
||||||
fc_concat_two_strings(log_filepath, filename_array.
|
log_filepath, filename_array.filenames[i]);
|
||||||
filenames[i], full_filename);
|
snprintf(cmd, sizeof(cmd), "%s %s", gzip, full_filename);
|
||||||
fc_combine_two_strings(gzip_cmd_filename, full_filename, ' ', cmd);
|
if (system(cmd) == -1)
|
||||||
result = getExecResult(cmd, output, sizeof(output));
|
{
|
||||||
if (result != 0)
|
fprintf(stderr, "execute %s fail\n", cmd);
|
||||||
{
|
}
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
|
||||||
"exec command \"%s\" fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, cmd, result, STRERROR(result));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (*output != '\0')
|
|
||||||
{
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
|
||||||
"exec command \"%s\", output: %s",
|
|
||||||
__LINE__, cmd, output);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_free_filename_array(&filename_array);
|
log_free_filename_array(&filename_array);
|
||||||
|
|
@ -833,7 +790,8 @@ int log_rotate(LogContext *pContext)
|
||||||
|
|
||||||
close(pContext->log_fd);
|
close(pContext->log_fd);
|
||||||
|
|
||||||
current_time = get_current_time();
|
current_time = get_current_time();
|
||||||
|
localtime_r(¤t_time, &tm);
|
||||||
if (tm.tm_hour == 0 && tm.tm_min <= 1)
|
if (tm.tm_hour == 0 && tm.tm_min <= 1)
|
||||||
{
|
{
|
||||||
if (strstr(pContext->rotate_time_format, "%H") == NULL
|
if (strstr(pContext->rotate_time_format, "%H") == NULL
|
||||||
|
|
@ -841,14 +799,12 @@ int log_rotate(LogContext *pContext)
|
||||||
&& strstr(pContext->rotate_time_format, "%S") == NULL)
|
&& strstr(pContext->rotate_time_format, "%S") == NULL)
|
||||||
{
|
{
|
||||||
current_time -= 120;
|
current_time -= 120;
|
||||||
|
localtime_r(¤t_time, &tm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
localtime_r(¤t_time, &tm);
|
|
||||||
|
|
||||||
memset(old_filename, 0, sizeof(old_filename));
|
memset(old_filename, 0, sizeof(old_filename));
|
||||||
len = strlen(pContext->log_filename);
|
len = sprintf(old_filename, "%s.", pContext->log_filename);
|
||||||
memcpy(old_filename, pContext->log_filename, len);
|
|
||||||
*(old_filename + len++) = '.';
|
|
||||||
strftime(old_filename + len, sizeof(old_filename) - len,
|
strftime(old_filename + len, sizeof(old_filename) - len,
|
||||||
pContext->rotate_time_format, &tm);
|
pContext->rotate_time_format, &tm);
|
||||||
if (access(old_filename, F_OK) == 0)
|
if (access(old_filename, F_OK) == 0)
|
||||||
|
|
@ -918,19 +874,19 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
|
||||||
{
|
{
|
||||||
if (bNeedLock)
|
if (bNeedLock)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&(pContext->lock));
|
pthread_mutex_lock(&(pContext->log_thread_lock));
|
||||||
}
|
}
|
||||||
result = log_check_rotate(pContext);
|
result = log_check_rotate(pContext);
|
||||||
if (bNeedLock)
|
if (bNeedLock)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&(pContext->lock));
|
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
|
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
|
||||||
&(pContext->lock))) != 0))
|
&(pContext->log_thread_lock))) != 0))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_lock fail, " \
|
"call pthread_mutex_lock fail, " \
|
||||||
|
|
@ -955,10 +911,10 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
|
||||||
if (written != write_bytes)
|
if (written != write_bytes)
|
||||||
{
|
{
|
||||||
result = errno != 0 ? errno : EIO;
|
result = errno != 0 ? errno : EIO;
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
"pid: %d, call write fail, fd: %d, errno: %d, error info: %s\n",
|
"call write fail, errno: %d, error info: %s\n",\
|
||||||
__LINE__, getpid(), pContext->log_fd, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pContext->rotate_immediately)
|
if (pContext->rotate_immediately)
|
||||||
{
|
{
|
||||||
|
|
@ -966,7 +922,7 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
|
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
|
||||||
&(pContext->lock))) != 0))
|
&(pContext->log_thread_lock))) != 0))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_unlock fail, " \
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
|
@ -977,8 +933,8 @@ static int log_fsync(LogContext *pContext, const bool bNeedLock)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
static void doLogEx(LogContext *pContext, struct timeval *tv, \
|
||||||
const char *caption, const char *text, const int text_len,
|
const char *caption, const char *text, const int text_len, \
|
||||||
const bool bNeedSync, const bool bNeedLock)
|
const bool bNeedSync, const bool bNeedLock)
|
||||||
{
|
{
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
@ -1003,7 +959,7 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bNeedLock && (result=pthread_mutex_lock(&pContext->lock)) != 0)
|
if (bNeedLock && (result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_lock fail, " \
|
"call pthread_mutex_lock fail, " \
|
||||||
|
|
@ -1018,12 +974,12 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
||||||
__LINE__, LOG_BUFF_SIZE, text_len + 64);
|
__LINE__, LOG_BUFF_SIZE, text_len + 64);
|
||||||
if (bNeedLock)
|
if (bNeedLock)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&(pContext->lock));
|
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64
|
if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64 \
|
||||||
> LOG_BUFF_SIZE)
|
> LOG_BUFF_SIZE)
|
||||||
{
|
{
|
||||||
log_fsync(pContext, false);
|
log_fsync(pContext, false);
|
||||||
|
|
@ -1050,14 +1006,10 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (caption != NULL)
|
if (caption != NULL)
|
||||||
{
|
{
|
||||||
buff_len = strlen(caption);
|
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption);
|
||||||
memcpy(pContext->pcurrent_buff, caption, buff_len);
|
pContext->pcurrent_buff += buff_len;
|
||||||
pContext->pcurrent_buff += buff_len;
|
}
|
||||||
*pContext->pcurrent_buff++ = ' ';
|
|
||||||
*pContext->pcurrent_buff++ = '-';
|
|
||||||
*pContext->pcurrent_buff++ = ' ';
|
|
||||||
}
|
|
||||||
memcpy(pContext->pcurrent_buff, text, text_len);
|
memcpy(pContext->pcurrent_buff, text, text_len);
|
||||||
pContext->pcurrent_buff += text_len;
|
pContext->pcurrent_buff += text_len;
|
||||||
*pContext->pcurrent_buff++ = '\n';
|
*pContext->pcurrent_buff++ = '\n';
|
||||||
|
|
@ -1067,7 +1019,7 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
||||||
log_fsync(pContext, false);
|
log_fsync(pContext, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->lock))) != 0)
|
if (bNeedLock && (result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutex_unlock fail, " \
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
|
@ -1076,8 +1028,8 @@ void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_it_ex2(LogContext *pContext, const char *caption,
|
void log_it_ex2(LogContext *pContext, const char *caption, \
|
||||||
const char *text, const int text_len,
|
const char *text, const int text_len, \
|
||||||
const bool bNeedSync, const bool bNeedLock)
|
const bool bNeedSync, const bool bNeedLock)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
@ -1092,10 +1044,10 @@ void log_it_ex2(LogContext *pContext, const char *caption,
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_it_ex3(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock);
|
doLogEx(pContext, &tv, caption, text, text_len, bNeedSync, bNeedLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void log_it_ex1(LogContext *pContext, const int priority,
|
void log_it_ex1(LogContext *pContext, const int priority, \
|
||||||
const char *text, const int text_len)
|
const char *text, const int text_len)
|
||||||
{
|
{
|
||||||
bool bNeedSync;
|
bool bNeedSync;
|
||||||
|
|
@ -1291,12 +1243,45 @@ void logAccess(LogContext *pContext, struct timeval *tvStart, \
|
||||||
{
|
{
|
||||||
len = sizeof(text) - 1;
|
len = sizeof(text) - 1;
|
||||||
}
|
}
|
||||||
log_it_ex3(pContext, tvStart, NULL, text, len, false, true);
|
doLogEx(pContext, tvStart, NULL, text, len, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *log_get_level_caption_ex(LogContext *pContext)
|
const char *log_get_level_caption_ex(LogContext *pContext)
|
||||||
{
|
{
|
||||||
return get_log_level_caption(pContext->log_level);
|
const char *caption;
|
||||||
|
|
||||||
|
switch (pContext->log_level)
|
||||||
|
{
|
||||||
|
case LOG_DEBUG:
|
||||||
|
caption = "DEBUG";
|
||||||
|
break;
|
||||||
|
case LOG_INFO:
|
||||||
|
caption = "INFO";
|
||||||
|
break;
|
||||||
|
case LOG_NOTICE:
|
||||||
|
caption = "NOTICE";
|
||||||
|
break;
|
||||||
|
case LOG_WARNING:
|
||||||
|
caption = "WARNING";
|
||||||
|
break;
|
||||||
|
case LOG_ERR:
|
||||||
|
caption = "ERROR";
|
||||||
|
break;
|
||||||
|
case LOG_CRIT:
|
||||||
|
caption = "CRIT";
|
||||||
|
break;
|
||||||
|
case LOG_ALERT:
|
||||||
|
caption = "ALERT";
|
||||||
|
break;
|
||||||
|
case LOG_EMERG:
|
||||||
|
caption = "EMERG";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
caption = "UNKOWN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return caption;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef LOG_FORMAT_CHECK
|
#ifndef LOG_FORMAT_CHECK
|
||||||
|
|
|
||||||
78
src/logger.h
78
src/logger.h
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//logger.h
|
//logger.h
|
||||||
#ifndef LOGGER_H
|
#ifndef LOGGER_H
|
||||||
|
|
@ -36,16 +29,11 @@ extern "C" {
|
||||||
#define LOG_COMPRESS_FLAGS_ENABLED 1
|
#define LOG_COMPRESS_FLAGS_ENABLED 1
|
||||||
#define LOG_COMPRESS_FLAGS_NEW_THREAD 2
|
#define LOG_COMPRESS_FLAGS_NEW_THREAD 2
|
||||||
|
|
||||||
#define LOG_NOTHING (LOG_DEBUG + 10)
|
|
||||||
|
|
||||||
struct log_context;
|
struct log_context;
|
||||||
|
|
||||||
//log header line callback
|
//log header line callback
|
||||||
typedef void (*LogHeaderCallback)(struct log_context *pContext);
|
typedef void (*LogHeaderCallback)(struct log_context *pContext);
|
||||||
|
|
||||||
#define FC_LOG_BY_LEVEL(level) \
|
|
||||||
(level <= g_log_context.log_level)
|
|
||||||
|
|
||||||
typedef struct log_context
|
typedef struct log_context
|
||||||
{
|
{
|
||||||
/* log level value please see: sys/syslog.h
|
/* log level value please see: sys/syslog.h
|
||||||
|
|
@ -62,7 +50,7 @@ typedef struct log_context
|
||||||
char *pcurrent_buff;
|
char *pcurrent_buff;
|
||||||
|
|
||||||
/* mutext lock */
|
/* mutext lock */
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t log_thread_lock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
rotate the log when the log file exceeds this parameter
|
rotate the log when the log file exceeds this parameter
|
||||||
|
|
@ -127,25 +115,11 @@ extern LogContext g_log_context;
|
||||||
*/
|
*/
|
||||||
int log_init();
|
int log_init();
|
||||||
|
|
||||||
/** init function using global log context
|
|
||||||
* do nothing when already inited
|
|
||||||
* return: 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
static inline int log_try_init()
|
|
||||||
{
|
|
||||||
if (g_log_context.log_buff != NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return log_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** init function using global log context, take over stderr and stdout
|
/** init function using global log context, take over stderr and stdout
|
||||||
* return: 0 for success, != 0 fail
|
* return: 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int log_init2();
|
int log_init2();
|
||||||
|
|
||||||
|
|
||||||
#define log_reopen() log_reopen_ex(&g_log_context)
|
#define log_reopen() log_reopen_ex(&g_log_context)
|
||||||
|
|
||||||
#define log_set_prefix(base_path, filename_prefix) \
|
#define log_set_prefix(base_path, filename_prefix) \
|
||||||
|
|
@ -172,13 +146,6 @@ int log_init2();
|
||||||
|
|
||||||
#define log_destroy() log_destroy_ex(&g_log_context)
|
#define log_destroy() log_destroy_ex(&g_log_context)
|
||||||
|
|
||||||
#define log_it1(priority, text, text_len) \
|
|
||||||
log_it_ex1(&g_log_context, priority, text, text_len)
|
|
||||||
|
|
||||||
#define log_it2(caption, text, text_len, bNeedSync, bNeedLock) \
|
|
||||||
log_it_ex2(&g_log_context, caption, text, text_len, bNeedSync, bNeedLock)
|
|
||||||
|
|
||||||
|
|
||||||
/** init function, use stderr for output by default
|
/** init function, use stderr for output by default
|
||||||
* parameters:
|
* parameters:
|
||||||
* pContext: the log context
|
* pContext: the log context
|
||||||
|
|
@ -201,7 +168,7 @@ int log_reopen_ex(LogContext *pContext);
|
||||||
* filename_prefix: log filename prefix
|
* filename_prefix: log filename prefix
|
||||||
* return: 0 for success, != 0 fail
|
* return: 0 for success, != 0 fail
|
||||||
*/
|
*/
|
||||||
int log_set_prefix_ex(LogContext *pContext, const char *base_path,
|
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
|
||||||
const char *filename_prefix);
|
const char *filename_prefix);
|
||||||
|
|
||||||
/** set log filename
|
/** set log filename
|
||||||
|
|
@ -274,24 +241,6 @@ void log_take_over_stderr_ex(LogContext *pContext);
|
||||||
*/
|
*/
|
||||||
void log_take_over_stdout_ex(LogContext *pContext);
|
void log_take_over_stdout_ex(LogContext *pContext);
|
||||||
|
|
||||||
|
|
||||||
/** init function using global log context
|
|
||||||
* do nothing when already inited
|
|
||||||
* return: 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
static inline int log_try_init2()
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if ((result=log_try_init()) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_take_over_stderr();
|
|
||||||
log_take_over_stdout();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** set compress_log_flags to true
|
/** set compress_log_flags to true
|
||||||
* parameters:
|
* parameters:
|
||||||
* pContext: the log context
|
* pContext: the log context
|
||||||
|
|
@ -343,7 +292,7 @@ void log_it_ex(LogContext *pContext, const int priority, \
|
||||||
* text_len: text string length (bytes)
|
* text_len: text string length (bytes)
|
||||||
* return: none
|
* return: none
|
||||||
*/
|
*/
|
||||||
void log_it_ex1(LogContext *pContext, const int priority,
|
void log_it_ex1(LogContext *pContext, const int priority, \
|
||||||
const char *text, const int text_len);
|
const char *text, const int text_len);
|
||||||
|
|
||||||
/** log to file
|
/** log to file
|
||||||
|
|
@ -355,13 +304,10 @@ void log_it_ex1(LogContext *pContext, const int priority,
|
||||||
* bNeedSync: if sync to file immediatelly
|
* bNeedSync: if sync to file immediatelly
|
||||||
* return: none
|
* return: none
|
||||||
*/
|
*/
|
||||||
void log_it_ex2(LogContext *pContext, const char *caption,
|
void log_it_ex2(LogContext *pContext, const char *caption, \
|
||||||
const char *text, const int text_len,
|
const char *text, const int text_len, \
|
||||||
const bool bNeedSync, const bool bNeedLock);
|
const bool bNeedSync, const bool bNeedLock);
|
||||||
|
|
||||||
void log_it_ex3(LogContext *pContext, struct timeval *tv,
|
|
||||||
const char *caption, const char *text, const int text_len,
|
|
||||||
const bool bNeedSync, const bool bNeedLock);
|
|
||||||
|
|
||||||
/** sync log buffer to log file
|
/** sync log buffer to log file
|
||||||
* parameters:
|
* parameters:
|
||||||
|
|
|
||||||
27
src/md5.c
27
src/md5.c
|
|
@ -311,7 +311,7 @@ MD5_memset(POINTER output, int value, unsigned int len)
|
||||||
/*
|
/*
|
||||||
* Digests a string
|
* Digests a string
|
||||||
*/
|
*/
|
||||||
int my_md5_string(char *string, unsigned char digest[16])
|
int my_md5_string(char *string,unsigned char digest[16])
|
||||||
{
|
{
|
||||||
MD5_CTX context;
|
MD5_CTX context;
|
||||||
unsigned int len = strlen(string);
|
unsigned int len = strlen(string);
|
||||||
|
|
@ -332,22 +332,25 @@ int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int my_md5_file(char *filename, unsigned char digest[16])
|
int my_md5_file(char *filename,unsigned char digest[16])
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
MD5_CTX context;
|
MD5_CTX context;
|
||||||
int len;
|
int len;
|
||||||
unsigned char buff[16 * 1024];
|
unsigned char buffer[1024];
|
||||||
|
|
||||||
if ((file = fopen(filename, "rb")) == NULL) {
|
if ((file = fopen(filename, "rb")) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
else {
|
||||||
|
my_md5_init(&context);
|
||||||
|
while ((len = fread(buffer, 1, 1024, file)) > 0)
|
||||||
|
{
|
||||||
|
my_md5_update(&context, buffer, len);
|
||||||
|
}
|
||||||
|
my_md5_final(digest, &context);
|
||||||
|
|
||||||
my_md5_init(&context);
|
fclose(file);
|
||||||
while ((len = fread(buff, 1, sizeof(buff), file)) > 0) {
|
}
|
||||||
my_md5_update(&context, buff, len);
|
return 0;
|
||||||
}
|
|
||||||
my_md5_final(digest, &context);
|
|
||||||
fclose(file);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,11 @@ int my_md5_file(char *filename, unsigned char digest[16]);
|
||||||
*/
|
*/
|
||||||
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16]);
|
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16]);
|
||||||
|
|
||||||
void my_md5_init(MD5_CTX *context);
|
void my_md5_init (MD5_CTX *);
|
||||||
|
|
||||||
void my_md5_update(MD5_CTX *context, unsigned char *input,
|
void my_md5_update (MD5_CTX *, unsigned char *, unsigned int);
|
||||||
unsigned int inputLen);
|
|
||||||
|
|
||||||
void my_md5_final(unsigned char digest[16], MD5_CTX *context);
|
void my_md5_final (unsigned char [16], MD5_CTX *);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2015 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* libfastcommon may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//multi_skiplist.c
|
//multi_skiplist.c
|
||||||
|
|
||||||
|
|
@ -22,7 +15,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "multi_skiplist.h"
|
#include "multi_skiplist.h"
|
||||||
|
|
||||||
int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
||||||
|
|
@ -30,8 +22,6 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
||||||
skiplist_free_func free_func,
|
skiplist_free_func free_func,
|
||||||
const int min_alloc_elements_once)
|
const int min_alloc_elements_once)
|
||||||
{
|
{
|
||||||
const int64_t alloc_elements_limit = 0;
|
|
||||||
char name[64];
|
|
||||||
int bytes;
|
int bytes;
|
||||||
int element_size;
|
int element_size;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -54,15 +44,21 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(MultiSkiplistNode *) * level_count;
|
bytes = sizeof(MultiSkiplistNode *) * level_count;
|
||||||
sl->tmp_previous = (MultiSkiplistNode **)fc_malloc(bytes);
|
sl->tmp_previous = (MultiSkiplistNode **)malloc(bytes);
|
||||||
if (sl->tmp_previous == NULL) {
|
if (sl->tmp_previous == NULL) {
|
||||||
return ENOMEM;
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(struct fast_mblock_man) * level_count;
|
bytes = sizeof(struct fast_mblock_man) * level_count;
|
||||||
sl->mblocks = (struct fast_mblock_man *)fc_malloc(bytes);
|
sl->mblocks = (struct fast_mblock_man *)malloc(bytes);
|
||||||
if (sl->mblocks == NULL) {
|
if (sl->mblocks == NULL) {
|
||||||
return ENOMEM;
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
"malloc %d bytes fail, errno: %d, error info: %s",
|
||||||
|
__LINE__, bytes, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
}
|
}
|
||||||
memset(sl->mblocks, 0, bytes);
|
memset(sl->mblocks, 0, bytes);
|
||||||
|
|
||||||
|
|
@ -75,12 +71,9 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=level_count-1; i>=0; i--) {
|
for (i=level_count-1; i>=0; i--) {
|
||||||
sprintf(name, "multi-sl-level%02d", i);
|
element_size = sizeof(MultiSkiplistNode) + sizeof(MultiSkiplistNode *) * (i + 1);
|
||||||
element_size = sizeof(MultiSkiplistNode) +
|
if ((result=fast_mblock_init_ex(sl->mblocks + i,
|
||||||
sizeof(MultiSkiplistNode *) * (i + 1);
|
element_size, alloc_elements_once, NULL, false)) != 0)
|
||||||
if ((result=fast_mblock_init_ex1(sl->mblocks + i, name,
|
|
||||||
element_size, alloc_elements_once, alloc_elements_limit,
|
|
||||||
NULL, NULL, false)) != 0)
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -103,9 +96,9 @@ int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count,
|
||||||
}
|
}
|
||||||
memset(sl->tail, 0, sl->mblocks[0].info.element_size);
|
memset(sl->tail, 0, sl->mblocks[0].info.element_size);
|
||||||
|
|
||||||
if ((result=fast_mblock_init_ex1(&sl->data_mblock, "multi-sl-data",
|
if ((result=fast_mblock_init_ex(&sl->data_mblock,
|
||||||
sizeof(MultiSkiplistData), alloc_elements_once,
|
sizeof(MultiSkiplistData), alloc_elements_once,
|
||||||
alloc_elements_limit, NULL, NULL, false)) != 0)
|
NULL, false)) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -412,16 +405,6 @@ int multi_skiplist_find_all(MultiSkiplist *sl, void *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *multi_skiplist_find_ge(MultiSkiplist *sl, void *data)
|
|
||||||
{
|
|
||||||
MultiSkiplistNode *node;
|
|
||||||
node = multi_skiplist_get_first_larger_or_equal(sl, data);
|
|
||||||
if (node == sl->tail) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return node->head->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int multi_skiplist_find_range(MultiSkiplist *sl, void *start_data, void *end_data,
|
int multi_skiplist_find_range(MultiSkiplist *sl, void *start_data, void *end_data,
|
||||||
MultiSkiplistIterator *iterator)
|
MultiSkiplistIterator *iterator)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2015 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* libfastcommon may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//multi_skiplist.h, support duplicated entries, and support stable sort :)
|
//multi_skiplist.h, support duplicated entries, and support stable sort :)
|
||||||
|
|
||||||
|
|
@ -82,7 +75,6 @@ int multi_skiplist_find_all(MultiSkiplist *sl, void *data,
|
||||||
MultiSkiplistIterator *iterator);
|
MultiSkiplistIterator *iterator);
|
||||||
int multi_skiplist_find_range(MultiSkiplist *sl, void *start_data, void *end_data,
|
int multi_skiplist_find_range(MultiSkiplist *sl, void *start_data, void *end_data,
|
||||||
MultiSkiplistIterator *iterator);
|
MultiSkiplistIterator *iterator);
|
||||||
void *multi_skiplist_find_ge(MultiSkiplist *sl, void *data);
|
|
||||||
|
|
||||||
static inline void multi_skiplist_iterator(MultiSkiplist *sl,
|
static inline void multi_skiplist_iterator(MultiSkiplist *sl,
|
||||||
MultiSkiplistIterator *iterator)
|
MultiSkiplistIterator *iterator)
|
||||||
|
|
@ -117,15 +109,6 @@ static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *multi_skiplist_get_first(MultiSkiplist *sl)
|
|
||||||
{
|
|
||||||
if (sl->top->links[0] != sl->tail) {
|
|
||||||
return sl->top->links[0]->head->data;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool multi_skiplist_empty(MultiSkiplist *sl)
|
static inline bool multi_skiplist_empty(MultiSkiplist *sl)
|
||||||
{
|
{
|
||||||
return sl->top->links[0] == sl->tail;
|
return sl->top->links[0] == sl->tail;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -34,19 +19,12 @@
|
||||||
static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
||||||
FastMultiSockEntry *entry);
|
FastMultiSockEntry *entry);
|
||||||
|
|
||||||
static int64_t fms_get_current_time_ms()
|
int fast_multi_sock_client_init(FastMultiSockClient *client,
|
||||||
{
|
|
||||||
return (int64_t)get_current_time() * 1000LL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
|
|
||||||
FastMultiSockEntry *entries, const int entry_count,
|
FastMultiSockEntry *entries, const int entry_count,
|
||||||
const int header_length,
|
const int header_length,
|
||||||
fms_client_get_body_length_func get_body_length_func,
|
fast_multi_sock_client_get_body_length_func get_body_length_func,
|
||||||
fms_client_get_current_time_ms_func get_current_time_ms_func,
|
const int init_recv_buffer_size, const int timeout)
|
||||||
const int init_recv_buffer_size, const int timeout_ms)
|
|
||||||
{
|
{
|
||||||
const bool use_io_uring = false;
|
|
||||||
int result;
|
int result;
|
||||||
int new_init_recv_buffer_size;
|
int new_init_recv_buffer_size;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -66,8 +44,8 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=ioevent_init(&client->ioevent, "client",
|
if ((result=ioevent_init(&client->ioevent, entry_count,
|
||||||
use_io_uring, entry_count, timeout_ms, 0)) != 0)
|
timeout * 1000, 0)) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"ioevent_init fail, errno: %d, error info: %s",
|
"ioevent_init fail, errno: %d, error info: %s",
|
||||||
|
|
@ -86,7 +64,7 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<entry_count; i++) {
|
for (i=0; i<entry_count; i++) {
|
||||||
if ((result=fast_buffer_init1(&entries[i].recv_buffer,
|
if ((result=fast_buffer_init_ex(&entries[i].recv_buffer,
|
||||||
new_init_recv_buffer_size)) != 0)
|
new_init_recv_buffer_size)) != 0)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -96,24 +74,12 @@ int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
|
||||||
client->entry_count = entry_count;
|
client->entry_count = entry_count;
|
||||||
client->header_length = header_length;
|
client->header_length = header_length;
|
||||||
client->get_body_length_func = get_body_length_func;
|
client->get_body_length_func = get_body_length_func;
|
||||||
client->get_current_time_ms_func = get_current_time_ms_func;
|
|
||||||
client->entries = entries;
|
client->entries = entries;
|
||||||
client->timeout_ms = timeout_ms;
|
client->timeout = timeout;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_multi_sock_client_init(FastMultiSockClient *client,
|
|
||||||
FastMultiSockEntry *entries, const int entry_count,
|
|
||||||
const int header_length,
|
|
||||||
fms_client_get_body_length_func get_body_length_func,
|
|
||||||
const int init_recv_buffer_size, const int timeout)
|
|
||||||
{
|
|
||||||
return fast_multi_sock_client_init_ex(client, entries, entry_count,
|
|
||||||
header_length, get_body_length_func, fms_get_current_time_ms,
|
|
||||||
init_recv_buffer_size, timeout * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fast_multi_sock_client_destroy(FastMultiSockClient *client)
|
void fast_multi_sock_client_destroy(FastMultiSockClient *client)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -129,7 +95,6 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
int result;
|
int result;
|
||||||
char formatted_ip[FORMATTED_IP_SIZE];
|
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
while (entry->remain > 0) {
|
while (entry->remain > 0) {
|
||||||
|
|
@ -139,28 +104,32 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
break;
|
break;
|
||||||
} else if (errno == EINTR) { //should retry
|
}
|
||||||
|
else if (errno == EINTR) { //should retry
|
||||||
logDebug("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
"server: %s:%u, ignore interupt signal", __LINE__,
|
"server: %s:%d, ignore interupt signal",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr,
|
||||||
entry->conn->port);
|
entry->conn->port);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = errno != 0 ? errno : ECONNRESET;
|
result = errno != 0 ? errno : ECONNRESET;
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"send to server %s:%u fail, "
|
"send to server %s:%d fail, "
|
||||||
"errno: %d, error info: %s", __LINE__,
|
"errno: %d, error info: %s",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr,
|
||||||
entry->conn->port, result, strerror(result));
|
entry->conn->port,
|
||||||
|
result, strerror(result));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (bytes == 0) {
|
}
|
||||||
|
else if (bytes == 0) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"send to server %s:%u, sock: %d fail, "
|
"send to server %s:%d, sock: %d fail, "
|
||||||
"connection disconnected", __LINE__,
|
"connection disconnected",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr, entry->conn->port,
|
||||||
entry->conn->port, entry->conn->sock);
|
entry->conn->sock);
|
||||||
|
|
||||||
result = ECONNRESET;
|
result = ECONNRESET;
|
||||||
break;
|
break;
|
||||||
|
|
@ -169,7 +138,6 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
|
||||||
entry->remain -= bytes;
|
entry->remain -= bytes;
|
||||||
if (entry->remain == 0) {
|
if (entry->remain == 0) {
|
||||||
entry->remain = client->header_length; //to recv pkg header
|
entry->remain = client->header_length; //to recv pkg header
|
||||||
entry->recv_stage = fms_stage_recv_header;
|
|
||||||
entry->io_callback = fast_multi_sock_client_do_recv;
|
entry->io_callback = fast_multi_sock_client_do_recv;
|
||||||
if (ioevent_modify(&client->ioevent, entry->conn->sock,
|
if (ioevent_modify(&client->ioevent, entry->conn->sock,
|
||||||
IOEVENT_READ, entry) != 0)
|
IOEVENT_READ, entry) != 0)
|
||||||
|
|
@ -191,7 +159,6 @@ static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int result;
|
int result;
|
||||||
char formatted_ip[FORMATTED_IP_SIZE];
|
|
||||||
|
|
||||||
for (i=0; i<client->entry_count; i++) {
|
for (i=0; i<client->entry_count; i++) {
|
||||||
client->entries[i].remain = send_buffer->length;
|
client->entries[i].remain = send_buffer->length;
|
||||||
|
|
@ -204,9 +171,9 @@ static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
|
||||||
client->entries[i].error_no = ENOTCONN;
|
client->entries[i].error_no = ENOTCONN;
|
||||||
client->entries[i].done = true;
|
client->entries[i].done = true;
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"NOT connected to %s:%u", __LINE__,
|
"NOT connected to %s:%d",
|
||||||
format_ip_address(client->entries[i].conn->ip_addr,
|
__LINE__, client->entries[i].conn->ip_addr,
|
||||||
formatted_ip), client->entries[i].conn->port);
|
client->entries[i].conn->port);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,7 +213,6 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
||||||
{
|
{
|
||||||
int bytes;
|
int bytes;
|
||||||
int result;
|
int result;
|
||||||
char formatted_ip[FORMATTED_IP_SIZE];
|
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
while (entry->remain > 0) {
|
while (entry->remain > 0) {
|
||||||
|
|
@ -255,28 +221,32 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
break;
|
break;
|
||||||
} else if (errno == EINTR) { //should retry
|
}
|
||||||
|
else if (errno == EINTR) { //should retry
|
||||||
logDebug("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
"server: %s:%u, ignore interupt signal", __LINE__,
|
"server: %s:%d, ignore interupt signal",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr,
|
||||||
entry->conn->port);
|
entry->conn->port);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = errno != 0 ? errno : ECONNRESET;
|
result = errno != 0 ? errno : ECONNRESET;
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"server: %s:%u, recv failed, "
|
"server: %s:%d, recv failed, "
|
||||||
"errno: %d, error info: %s", __LINE__,
|
"errno: %d, error info: %s",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr,
|
||||||
entry->conn->port, result, strerror(result));
|
entry->conn->port,
|
||||||
|
result, strerror(result));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (bytes == 0) {
|
}
|
||||||
|
else if (bytes == 0) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"server: %s:%u, sock: %d, recv failed, "
|
"server: %s:%d, sock: %d, recv failed, "
|
||||||
"connection disconnected", __LINE__,
|
"connection disconnected",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr, entry->conn->port,
|
||||||
entry->conn->port, entry->conn->sock);
|
entry->conn->sock);
|
||||||
|
|
||||||
result = ECONNRESET;
|
result = ECONNRESET;
|
||||||
break;
|
break;
|
||||||
|
|
@ -284,25 +254,18 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
||||||
|
|
||||||
entry->recv_buffer.length += bytes;
|
entry->recv_buffer.length += bytes;
|
||||||
entry->remain -= bytes;
|
entry->remain -= bytes;
|
||||||
if (entry->remain == 0 && entry->recv_stage == fms_stage_recv_header) {
|
if (entry->remain == 0 && entry->recv_buffer.length == client->header_length) {
|
||||||
int body_length;
|
int body_length;
|
||||||
|
|
||||||
entry->recv_stage = fms_stage_recv_body;
|
|
||||||
body_length = client->get_body_length_func(&entry->recv_buffer);
|
body_length = client->get_body_length_func(&entry->recv_buffer);
|
||||||
if (body_length < 0) {
|
if (body_length < 0) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"server: %s:%u, body_length: %d < 0", __LINE__,
|
"server: %s:%d, body_length: %d < 0",
|
||||||
format_ip_address(entry->conn->ip_addr, formatted_ip),
|
__LINE__, entry->conn->ip_addr,
|
||||||
entry->conn->port, body_length);
|
entry->conn->port, body_length);
|
||||||
result = EPIPE;
|
result = EINVAL;
|
||||||
break;
|
|
||||||
} else if (body_length == 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if ((result=fast_buffer_check(&entry->recv_buffer, body_length)) != 0) {
|
||||||
if ((result=fast_buffer_check(&entry->recv_buffer,
|
|
||||||
body_length)) != 0)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
entry->remain = body_length; //to recv body
|
entry->remain = body_length; //to recv body
|
||||||
|
|
@ -317,80 +280,41 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
|
||||||
static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
|
static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int count;
|
|
||||||
#if IOEVENT_USE_URING
|
|
||||||
unsigned head;
|
|
||||||
#else
|
|
||||||
int event;
|
int event;
|
||||||
|
int count;
|
||||||
int index;
|
int index;
|
||||||
#endif
|
time_t remain_timeout;
|
||||||
int remain_timeout;
|
|
||||||
FastMultiSockEntry *entry;
|
FastMultiSockEntry *entry;
|
||||||
char formatted_ip[FORMATTED_IP_SIZE];
|
|
||||||
|
|
||||||
while (client->pulling_count > 0) {
|
while (client->pulling_count > 0) {
|
||||||
remain_timeout = client->deadline_time_ms -
|
remain_timeout = client->deadline_time - get_current_time();
|
||||||
client->get_current_time_ms_func();
|
if (remain_timeout <= 0) { //timeout
|
||||||
if (remain_timeout < 0) { //timeout
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IOEVENT_USE_URING
|
count = ioevent_poll_ex(&client->ioevent, remain_timeout * 1000);
|
||||||
result = io_uring_wait_cqe_timeout(&client->ioevent.ring,
|
logInfo("poll count: %d\n", count);
|
||||||
&client->ioevent.cqe, &client->ioevent.timeout);
|
|
||||||
switch (result) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case -ETIME:
|
|
||||||
case -EAGAIN:
|
|
||||||
case -EINTR:
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
result *= -1;
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"io_uring_wait_cqe fail, errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
io_uring_for_each_cqe(&client->ioevent.ring, head, client->ioevent.cqe) {
|
|
||||||
count++;
|
|
||||||
entry = (FastMultiSockEntry *)client->ioevent.cqe->user_data;
|
|
||||||
//logInfo("sock: %d, event: %d", entry->conn->sock, event);
|
|
||||||
result = entry->io_callback(client, entry);
|
|
||||||
if (result != 0 || entry->remain == 0) {
|
|
||||||
fast_multi_sock_client_finish(client, entry, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
io_uring_cq_advance(&client->ioevent.ring, count);
|
|
||||||
|
|
||||||
#else
|
|
||||||
count = ioevent_poll_ex(&client->ioevent, remain_timeout);
|
|
||||||
//logInfo("poll count: %d\n", count);
|
|
||||||
for (index=0; index<count; index++) {
|
for (index=0; index<count; index++) {
|
||||||
event = IOEVENT_GET_EVENTS(&client->ioevent, index);
|
event = IOEVENT_GET_EVENTS(&client->ioevent, index);
|
||||||
entry = (FastMultiSockEntry *)IOEVENT_GET_DATA(
|
entry = (FastMultiSockEntry *)IOEVENT_GET_DATA(&client->ioevent, index);
|
||||||
&client->ioevent, index);
|
|
||||||
|
|
||||||
if (event & IOEVENT_ERROR) {
|
if (event & IOEVENT_ERROR) {
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"server: %s:%u, recv error event: %d, connection "
|
"server: %s:%d, recv error event: %d, "
|
||||||
"reset", __LINE__, format_ip_address(entry->conn->
|
"connection reset", __LINE__,
|
||||||
ip_addr, formatted_ip), entry->conn->port, event);
|
entry->conn->ip_addr, entry->conn->port, event);
|
||||||
|
|
||||||
fast_multi_sock_client_finish(client, entry, ECONNRESET);
|
fast_multi_sock_client_finish(client, entry, ECONNRESET);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//logInfo("sock: %d, event: %d", entry->conn->sock, event);
|
logInfo("sock: %d, event: %d", entry->conn->sock, event);
|
||||||
|
|
||||||
result = entry->io_callback(client, entry);
|
result = entry->io_callback(client, entry);
|
||||||
if (result != 0 || entry->remain == 0) {
|
if (result != 0 || entry->remain == 0) {
|
||||||
fast_multi_sock_client_finish(client, entry, result);
|
fast_multi_sock_client_finish(client, entry, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -402,12 +326,11 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<client->entry_count; i++) {
|
for (i=0; i<client->entry_count; i++) {
|
||||||
if (!client->entries[i].done) {
|
if (!client->entries[i].done) {
|
||||||
fast_multi_sock_client_finish(client,
|
fast_multi_sock_client_finish(client, client->entries + i, ETIMEDOUT);
|
||||||
client->entries + i, ETIMEDOUT);
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
"recv from %s:%u timedout", __LINE__,
|
"recv from %s:%d timedout",
|
||||||
format_ip_address(client->entries[i].conn->ip_addr,
|
__LINE__, client->entries[i].conn->ip_addr,
|
||||||
formatted_ip), client->entries[i].conn->port);
|
client->entries[i].conn->port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -415,8 +338,7 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
|
||||||
logInfo("file: "__FILE__", line: %d, pulling_count: %d, "
|
logInfo("file: "__FILE__", line: %d, pulling_count: %d, "
|
||||||
"success_count: %d\n", __LINE__,
|
"success_count: %d\n", __LINE__,
|
||||||
client->pulling_count, client->success_count);
|
client->pulling_count, client->success_count);
|
||||||
return client->success_count > 0 ? 0 :
|
return client->success_count > 0 ? 0 : (remain_timeout > 0 ? ENOENT : ETIMEDOUT);
|
||||||
(remain_timeout > 0 ? ENOENT : ETIMEDOUT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fast_multi_sock_client_request(FastMultiSockClient *client,
|
int fast_multi_sock_client_request(FastMultiSockClient *client,
|
||||||
|
|
@ -424,8 +346,7 @@ int fast_multi_sock_client_request(FastMultiSockClient *client,
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
client->deadline_time_ms = client->get_current_time_ms_func() +
|
client->deadline_time = get_current_time() + client->timeout;
|
||||||
client->timeout_ms;
|
|
||||||
client->pulling_count = 0;
|
client->pulling_count = 0;
|
||||||
client->success_count = 0;
|
client->success_count = 0;
|
||||||
if ((result=fast_multi_sock_client_send_data(client, send_buffer)) != 0) {
|
if ((result=fast_multi_sock_client_send_data(client, send_buffer)) != 0) {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2018 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//multi_socket_client.h
|
//multi_socket_client.h
|
||||||
|
|
||||||
|
|
@ -21,6 +14,7 @@
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include "connection_pool.h"
|
#include "connection_pool.h"
|
||||||
|
|
@ -28,30 +22,27 @@
|
||||||
#include "ioevent.h"
|
#include "ioevent.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
fms_stage_recv_header = 'H',
|
fast_multi_sock_stage_send = 'S',
|
||||||
fms_stage_recv_body = 'B'
|
fast_multi_sock_stage_recv = 'R'
|
||||||
} FastMultiSockRecvStage;
|
} FastMultiSockStage;
|
||||||
|
|
||||||
struct fast_multi_sock_client;
|
struct fast_multi_sock_client;
|
||||||
struct fast_multi_sock_entry;
|
struct fast_multi_sock_entry;
|
||||||
|
|
||||||
typedef int64_t (*fms_client_get_current_time_ms_func)();
|
|
||||||
|
|
||||||
//return the body length
|
//return the body length
|
||||||
typedef int (*fms_client_get_body_length_func)(const FastBuffer *recv_buffer);
|
typedef int (*fast_multi_sock_client_get_body_length_func)(const FastBuffer *recv_buffer);
|
||||||
|
|
||||||
//IO deal fucntion
|
//IO deal fucntion
|
||||||
typedef int (*fast_multi_sock_client_io_func)(struct fast_multi_sock_client *
|
typedef int (*fast_multi_sock_client_io_func)(struct fast_multi_sock_client *client,
|
||||||
client, struct fast_multi_sock_entry *entry);
|
struct fast_multi_sock_entry *entry);
|
||||||
|
|
||||||
typedef struct fast_multi_sock_entry {
|
typedef struct fast_multi_sock_entry {
|
||||||
ConnectionInfo *conn; //the connected socket must be non-block socket
|
ConnectionInfo *conn; //the socket must be non-block socket
|
||||||
FastBuffer *send_buffer; //send buffer for internal use
|
FastBuffer *send_buffer; //send buffer for internal use
|
||||||
fast_multi_sock_client_io_func io_callback; //for internal use
|
fast_multi_sock_client_io_func io_callback; //for internal use
|
||||||
FastBuffer recv_buffer; //recv buffer for response package
|
FastBuffer recv_buffer; //recv buffer
|
||||||
int error_no; //0 for success, != 0 fail
|
int error_no; //0 for success, != 0 fail
|
||||||
int remain; //remain bytes, for internal use
|
int remain; //remain bytes, for internal use
|
||||||
FastMultiSockRecvStage recv_stage; //for internal use
|
|
||||||
bool done; //for internal use
|
bool done; //for internal use
|
||||||
} FastMultiSockEntry;
|
} FastMultiSockEntry;
|
||||||
|
|
||||||
|
|
@ -60,11 +51,10 @@ typedef struct fast_multi_sock_client {
|
||||||
int header_length; //package header size
|
int header_length; //package header size
|
||||||
int pulling_count;
|
int pulling_count;
|
||||||
int success_count;
|
int success_count;
|
||||||
int timeout_ms;
|
int timeout;
|
||||||
int64_t deadline_time_ms;
|
time_t deadline_time;
|
||||||
FastMultiSockEntry *entries;
|
FastMultiSockEntry *entries;
|
||||||
fms_client_get_current_time_ms_func get_current_time_ms_func;
|
fast_multi_sock_client_get_body_length_func get_body_length_func;
|
||||||
fms_client_get_body_length_func get_body_length_func;
|
|
||||||
IOEventPoller ioevent;
|
IOEventPoller ioevent;
|
||||||
} FastMultiSockClient;
|
} FastMultiSockClient;
|
||||||
|
|
||||||
|
|
@ -73,25 +63,6 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
init function
|
|
||||||
@param client the client context
|
|
||||||
@param entries the socket entries
|
|
||||||
@param entry_count the count of socket entries
|
|
||||||
@param header_length the header length of a package
|
|
||||||
@param get_body_length_func the get body length function
|
|
||||||
@param get_current_time_ms_func the get current time in ms function
|
|
||||||
@param init_recv_buffer_size the initial size of response buffer
|
|
||||||
@param timeout_ms the timeout in milliseconds
|
|
||||||
@return error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int fast_multi_sock_client_init_ex(FastMultiSockClient *client,
|
|
||||||
FastMultiSockEntry *entries, const int entry_count,
|
|
||||||
const int header_length,
|
|
||||||
fms_client_get_body_length_func get_body_length_func,
|
|
||||||
fms_client_get_current_time_ms_func get_current_time_ms_func,
|
|
||||||
const int init_recv_buffer_size, const int timeout_ms);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
init function
|
init function
|
||||||
@param client the client context
|
@param client the client context
|
||||||
|
|
@ -106,7 +77,7 @@ extern "C" {
|
||||||
int fast_multi_sock_client_init(FastMultiSockClient *client,
|
int fast_multi_sock_client_init(FastMultiSockClient *client,
|
||||||
FastMultiSockEntry *entries, const int entry_count,
|
FastMultiSockEntry *entries, const int entry_count,
|
||||||
const int header_length,
|
const int header_length,
|
||||||
fms_client_get_body_length_func get_body_length_func,
|
fast_multi_sock_client_get_body_length_func get_body_length_func,
|
||||||
const int init_recv_buffer_size, const int timeout);
|
const int init_recv_buffer_size, const int timeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* php7 extension wrapper
|
/* php7 extension wrapper
|
||||||
* for compatibility, these wrapper functions are designed for old php version.
|
* for compatibility, these wrapper functions are designed for old php version.
|
||||||
*/
|
*/
|
||||||
|
|
@ -34,22 +19,6 @@
|
||||||
#include <SAPI.h>
|
#include <SAPI.h>
|
||||||
#include <php_ini.h>
|
#include <php_ini.h>
|
||||||
|
|
||||||
#ifndef TSRMLS_DC
|
|
||||||
#define TSRMLS_DC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TSRMLS_C
|
|
||||||
#define TSRMLS_C
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TSRMLS_CC
|
|
||||||
#define TSRMLS_CC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TSRMLS_FETCH
|
|
||||||
#define TSRMLS_FETCH()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PHP_MAJOR_VERSION < 7
|
#if PHP_MAJOR_VERSION < 7
|
||||||
typedef int zend_size_t;
|
typedef int zend_size_t;
|
||||||
#define ZEND_RETURN_STRING(s, dup) RETURN_STRING(s, dup)
|
#define ZEND_RETURN_STRING(s, dup) RETURN_STRING(s, dup)
|
||||||
|
|
@ -63,8 +32,7 @@ typedef int zend_size_t;
|
||||||
|
|
||||||
#define ZEND_TYPE_OF(z) (z)->type
|
#define ZEND_TYPE_OF(z) (z)->type
|
||||||
#define ZEND_IS_BOOL(z) (ZEND_TYPE_OF(z) == IS_BOOL)
|
#define ZEND_IS_BOOL(z) (ZEND_TYPE_OF(z) == IS_BOOL)
|
||||||
#define ZEND_IS_TRUE(z) (ZEND_IS_BOOL(z) && (z)->value.lval != 0)
|
#define ZEND_IS_TRUE(z) ((z)->value.lval != 0)
|
||||||
#define ZEND_IS_FALSE(z) (ZEND_IS_BOOL(z) && (z)->value.lval == 0)
|
|
||||||
#define Z_CE_P(z) ((zend_class_entry *)(z))
|
#define Z_CE_P(z) ((zend_class_entry *)(z))
|
||||||
#define ZEND_ZVAL_STRINGL ZVAL_STRINGL
|
#define ZEND_ZVAL_STRINGL ZVAL_STRINGL
|
||||||
//#define zend_get_object_wrapper(obj) zend_object_store_get_object(obj)
|
//#define zend_get_object_wrapper(obj) zend_object_store_get_object(obj)
|
||||||
|
|
@ -157,7 +125,6 @@ typedef size_t zend_size_t;
|
||||||
#define ZEND_TYPE_OF(z) Z_TYPE_P(z)
|
#define ZEND_TYPE_OF(z) Z_TYPE_P(z)
|
||||||
#define ZEND_IS_BOOL(z) (Z_TYPE_P(z) == IS_TRUE || Z_TYPE_P(z) == IS_FALSE)
|
#define ZEND_IS_BOOL(z) (Z_TYPE_P(z) == IS_TRUE || Z_TYPE_P(z) == IS_FALSE)
|
||||||
#define ZEND_IS_TRUE(z) (Z_TYPE_P(z) == IS_TRUE)
|
#define ZEND_IS_TRUE(z) (Z_TYPE_P(z) == IS_TRUE)
|
||||||
#define ZEND_IS_FALSE(z) (Z_TYPE_P(z) == IS_FALSE)
|
|
||||||
#define Z_STRVAL_PP(s) Z_STRVAL_P(*s)
|
#define Z_STRVAL_PP(s) Z_STRVAL_P(*s)
|
||||||
#define Z_STRLEN_PP(s) Z_STRLEN_P(*s)
|
#define Z_STRLEN_PP(s) Z_STRLEN_P(*s)
|
||||||
#define ZEND_ZVAL_STRINGL(z, s, l, dup) ZVAL_STRINGL(z, s, l)
|
#define ZEND_ZVAL_STRINGL(z, s, l, dup) ZVAL_STRINGL(z, s, l)
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -50,14 +35,14 @@ int write_to_pid_file(const char *pidFilename)
|
||||||
char buff[32];
|
char buff[32];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = fc_itoa(getpid(), buff);
|
len = sprintf(buff, "%d", (int)getpid());
|
||||||
return writeToFile(pidFilename, buff, len);
|
return writeToFile(pidFilename, buff, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int delete_pid_file(const char *pidFilename)
|
int delete_pid_file(const char *pidFilename)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
pid_t pid = 0;
|
pid_t pid;
|
||||||
|
|
||||||
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -112,59 +97,43 @@ static int do_stop(const char *pidFilename, const bool bShowError, pid_t *pid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_stop_ex(const char *pidFilename,
|
int process_stop(const char *pidFilename)
|
||||||
const bool bShowError, bool *force)
|
|
||||||
{
|
{
|
||||||
#define MAX_WAIT_COUNT 300
|
pid_t pid;
|
||||||
pid_t pid = 0;
|
|
||||||
int result;
|
int result;
|
||||||
int sig;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
*force = false;
|
result = do_stop(pidFilename, true, &pid);
|
||||||
if ((result=do_stop(pidFilename, bShowError, &pid)) != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
||||||
for (i=0; i<MAX_WAIT_COUNT; i++) {
|
do {
|
||||||
sig = (i % 10 == 0) ? SIGTERM : 0;
|
sleep(1);
|
||||||
if (kill(pid, sig) != 0) {
|
} while (kill(pid, SIGTERM) == 0);
|
||||||
break;
|
fprintf(stderr, "pid [%d] exit.\n", (int)pid);
|
||||||
}
|
|
||||||
|
|
||||||
fc_sleep_ms(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == MAX_WAIT_COUNT) {
|
|
||||||
if (kill(pid, SIGKILL) == 0) {
|
|
||||||
fprintf(stderr, "waiting for pid [%d] exit timeout, "
|
|
||||||
"force kill!\n", (int)pid);
|
|
||||||
*force = true;
|
|
||||||
fc_sleep_ms(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "pid [%d] exit.\n\n", (int)pid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_restart(const char *pidFilename)
|
int process_restart(const char *pidFilename)
|
||||||
{
|
{
|
||||||
const bool bShowError = false;
|
|
||||||
bool force;
|
|
||||||
int result;
|
int result;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
result = process_stop_ex(pidFilename, bShowError, &force);
|
result = do_stop(pidFilename, false, &pid);
|
||||||
if (result == ENOENT || result == ESRCH) {
|
if (result == 0) {
|
||||||
result = 0;
|
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
||||||
} else if (result == 0) {
|
do {
|
||||||
if (force) {
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
} while (kill(pid, SIGTERM) == 0);
|
||||||
fprintf(stderr, "starting ...\n");
|
fprintf(stderr, "starting ...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result == ENOENT || result == ESRCH) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,7 +168,7 @@ static const char *get_exename_by_pid(const pid_t pid, char *buff,
|
||||||
|
|
||||||
int process_start(const char* pidFilename)
|
int process_start(const char* pidFilename)
|
||||||
{
|
{
|
||||||
pid_t pid = 0;
|
pid_t pid;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
||||||
|
|
@ -251,41 +220,40 @@ int process_start(const char* pidFilename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int process_exist(const char *pidFilename, pid_t *pid)
|
int process_exist(const char *pidFilename)
|
||||||
{
|
{
|
||||||
|
pid_t pid;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result=get_pid_from_file(pidFilename, pid)) != 0) {
|
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
||||||
if (result == ENOENT) {
|
if (result == ENOENT) {
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "get pid from file: %s fail, " \
|
fprintf(stderr, "get pid from file: %s fail, " \
|
||||||
"errno: %d, error info: %s\n",
|
"errno: %d, error info: %s\n",
|
||||||
pidFilename, result, strerror(result));
|
pidFilename, result, strerror(result));
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kill(*pid, 0) == 0) {
|
if (kill(pid, 0) == 0) {
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
else if (errno == ENOENT || errno == ESRCH) {
|
else if (errno == ENOENT || errno == ESRCH) {
|
||||||
return ENOENT;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = errno != 0 ? errno : EPERM;
|
|
||||||
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
|
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
|
||||||
(int)*pid, result, strerror(result));
|
(int)pid, errno, strerror(errno));
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
|
int get_base_path_from_conf_file(const char *filename, char *base_path,
|
||||||
const int path_size, const int noent_log_level)
|
const int path_size)
|
||||||
{
|
{
|
||||||
char *pBasePath;
|
char *pBasePath;
|
||||||
string_t path_string;
|
|
||||||
IniContext iniContext;
|
IniContext iniContext;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
|
@ -302,7 +270,7 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
|
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
|
||||||
if (pBasePath == NULL || *pBasePath == '\0')
|
if (pBasePath == NULL)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"conf file \"%s\" must have item " \
|
"conf file \"%s\" must have item " \
|
||||||
|
|
@ -311,18 +279,16 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FC_SET_STRING(path_string, pBasePath);
|
snprintf(base_path, path_size, "%s", pBasePath);
|
||||||
normalize_path(NULL, &path_string, base_path, path_size);
|
|
||||||
chopPath(base_path);
|
chopPath(base_path);
|
||||||
if (!fileExists(base_path))
|
if (!fileExists(base_path))
|
||||||
{
|
{
|
||||||
result = errno != 0 ? errno : ENOENT;
|
logError("file: "__FILE__", line: %d, " \
|
||||||
log_it_ex(&g_log_context, noent_log_level,
|
"\"%s\" can't be accessed, error info: %s", \
|
||||||
"file: "__FILE__", line: %d, "
|
__LINE__, base_path, STRERROR(errno));
|
||||||
"\"%s\" can't be accessed, error info: %s",
|
result = errno != 0 ? errno : ENOENT;
|
||||||
__LINE__, base_path, STRERROR(result));
|
break;
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
if (!isDir(base_path))
|
if (!isDir(base_path))
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
|
@ -339,9 +305,6 @@ int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
|
||||||
|
|
||||||
int process_action(const char *pidFilename, const char *action, bool *stop)
|
int process_action(const char *pidFilename, const char *action, bool *stop)
|
||||||
{
|
{
|
||||||
int result;
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
*stop = false;
|
*stop = false;
|
||||||
if (action == NULL)
|
if (action == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -353,23 +316,6 @@ int process_action(const char *pidFilename, const char *action, bool *stop)
|
||||||
*stop = true;
|
*stop = true;
|
||||||
return process_stop(pidFilename);
|
return process_stop(pidFilename);
|
||||||
}
|
}
|
||||||
else if (strcmp(action, "status") == 0)
|
|
||||||
{
|
|
||||||
*stop = true;
|
|
||||||
result = process_exist(pidFilename, &pid);
|
|
||||||
switch (result) {
|
|
||||||
case 0:
|
|
||||||
printf("Running, pid: %d\n", (int)pid);
|
|
||||||
break;
|
|
||||||
case ENOENT:
|
|
||||||
printf("NOT running\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Unkown status\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else if (strcmp(action, "restart") == 0)
|
else if (strcmp(action, "restart") == 0)
|
||||||
{
|
{
|
||||||
return process_restart(pidFilename);
|
return process_restart(pidFilename);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef PROCESS_CTRL_H
|
#ifndef PROCESS_CTRL_H
|
||||||
#define PROCESS_CTRL_H
|
#define PROCESS_CTRL_H
|
||||||
|
|
@ -27,11 +12,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int get_base_path_from_conf_file_ex(const char *filename, char *base_path,
|
int get_base_path_from_conf_file(const char *filename, char *base_path,
|
||||||
const int path_size, const int noent_log_level);
|
const int path_size);
|
||||||
|
|
||||||
#define get_base_path_from_conf_file(filename, base_path, path_size) \
|
|
||||||
get_base_path_from_conf_file_ex(filename, base_path, path_size, LOG_ERR)
|
|
||||||
|
|
||||||
int get_pid_from_file(const char *pidFilename, pid_t *pid);
|
int get_pid_from_file(const char *pidFilename, pid_t *pid);
|
||||||
|
|
||||||
|
|
@ -39,19 +21,11 @@ int write_to_pid_file(const char *pidFilename);
|
||||||
|
|
||||||
int delete_pid_file(const char *pidFilename);
|
int delete_pid_file(const char *pidFilename);
|
||||||
|
|
||||||
int process_stop_ex(const char *pidFilename,
|
int process_stop(const char *pidFilename);
|
||||||
const bool bShowError, bool *force);
|
|
||||||
|
|
||||||
static inline int process_stop(const char *pidFilename)
|
|
||||||
{
|
|
||||||
const bool bShowError = true;
|
|
||||||
bool force;
|
|
||||||
return process_stop_ex(pidFilename, bShowError, &force);
|
|
||||||
}
|
|
||||||
|
|
||||||
int process_restart(const char *pidFilename);
|
int process_restart(const char *pidFilename);
|
||||||
|
|
||||||
int process_exist(const char *pidFilename, pid_t *pid);
|
int process_exist(const char *pidFilename);
|
||||||
|
|
||||||
int process_action(const char *pidFilename, const char *action, bool *stop);
|
int process_action(const char *pidFilename, const char *action, bool *stop);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -28,42 +21,44 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "pthread_func.h"
|
#include "pthread_func.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
int init_pthread_lock(pthread_mutex_t *pthread_lock)
|
int init_pthread_lock(pthread_mutex_t *pthread_lock)
|
||||||
{
|
{
|
||||||
pthread_mutexattr_t mat;
|
pthread_mutexattr_t mat;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result=pthread_mutexattr_init(&mat)) != 0) {
|
if ((result=pthread_mutexattr_init(&mat)) != 0)
|
||||||
logError("file: "__FILE__", line: %d, "
|
{
|
||||||
"call pthread_mutexattr_init fail, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"call pthread_mutexattr_init fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if ((result=pthread_mutexattr_settype(&mat,
|
if ((result=pthread_mutexattr_settype(&mat, \
|
||||||
PTHREAD_MUTEX_ERRORCHECK)) != 0)
|
PTHREAD_MUTEX_ERRORCHECK)) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"call pthread_mutexattr_settype fail, "
|
"call pthread_mutexattr_settype fail, " \
|
||||||
"errno: %d, error info: %s",
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if ((result=pthread_mutex_init(pthread_lock, &mat)) != 0) {
|
if ((result=pthread_mutex_init(pthread_lock, &mat)) != 0)
|
||||||
logError("file: "__FILE__", line: %d, "
|
{
|
||||||
"call pthread_mutex_init fail, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"call pthread_mutex_init fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if ((result=pthread_mutexattr_destroy(&mat)) != 0) {
|
if ((result=pthread_mutexattr_destroy(&mat)) != 0)
|
||||||
logError("file: "__FILE__", line: %d, "
|
{
|
||||||
"call thread_mutexattr_destroy fail, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"call thread_mutexattr_destroy fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -71,93 +66,52 @@ int init_pthread_lock(pthread_mutex_t *pthread_lock)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_pthread_rwlock(pthread_rwlock_t *rwlock)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
pthread_rwlockattr_t holder;
|
|
||||||
pthread_rwlockattr_t *ptr;
|
|
||||||
} attr;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WITH_PTHREAD_RWLOCKATTR_SETKIND_NP
|
|
||||||
attr.ptr = &attr.holder;
|
|
||||||
if ((result=pthread_rwlockattr_init(attr.ptr)) != 0) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_rwlockattr_init fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=pthread_rwlockattr_setkind_np(attr.ptr,
|
|
||||||
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_rwlockattr_settype fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
attr.ptr = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((result=pthread_rwlock_init(rwlock, attr.ptr)) != 0) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call pthread_rwlock_init fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (attr.ptr != NULL) {
|
|
||||||
if ((result=pthread_rwlockattr_destroy(attr.ptr)) != 0) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"call thread_rwlockattr_destroy fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
|
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
|
||||||
{
|
{
|
||||||
size_t old_stack_size;
|
size_t old_stack_size;
|
||||||
size_t new_stack_size;
|
size_t new_stack_size;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ((result=pthread_attr_init(pattr)) != 0) {
|
if ((result=pthread_attr_init(pattr)) != 0)
|
||||||
logError("file: "__FILE__", line: %d, "
|
{
|
||||||
"call pthread_attr_init fail, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"call pthread_attr_init fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=pthread_attr_getstacksize(pattr, &old_stack_size)) != 0) {
|
if ((result=pthread_attr_getstacksize(pattr, &old_stack_size)) != 0)
|
||||||
logError("file: "__FILE__", line: %d, "
|
{
|
||||||
"call pthread_attr_getstacksize fail, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"call pthread_attr_getstacksize fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack_size > 0) {
|
if (stack_size > 0)
|
||||||
if (old_stack_size != stack_size) {
|
{
|
||||||
|
if (old_stack_size != stack_size)
|
||||||
|
{
|
||||||
new_stack_size = stack_size;
|
new_stack_size = stack_size;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
new_stack_size = 0;
|
new_stack_size = 0;
|
||||||
}
|
}
|
||||||
} else if (old_stack_size < 1 * 1024 * 1024) {
|
}
|
||||||
|
else if (old_stack_size < 1 * 1024 * 1024)
|
||||||
|
{
|
||||||
new_stack_size = 1 * 1024 * 1024;
|
new_stack_size = 1 * 1024 * 1024;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
new_stack_size = 0;
|
new_stack_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_stack_size > 0) {
|
if (new_stack_size > 0)
|
||||||
|
{
|
||||||
if ((result=pthread_attr_setstacksize(pattr,
|
if ((result=pthread_attr_setstacksize(pattr,
|
||||||
new_stack_size)) != 0)
|
new_stack_size)) != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -169,12 +123,12 @@ int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=pthread_attr_setdetachstate(pattr,
|
if ((result=pthread_attr_setdetachstate(pattr, \
|
||||||
PTHREAD_CREATE_DETACHED)) != 0)
|
PTHREAD_CREATE_DETACHED)) != 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"call pthread_attr_setdetachstate fail, "
|
"call pthread_attr_setdetachstate fail, " \
|
||||||
"errno: %d, error info: %s",
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -182,101 +136,40 @@ int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_work_threads(int *count, void *(*start_func)(void *),
|
int create_work_threads(int *count, void *(*start_func)(void *), \
|
||||||
void **args, pthread_t *tids, const int stack_size)
|
void *arg, pthread_t *tids, const int stack_size)
|
||||||
{
|
{
|
||||||
#define FIXED_TID_COUNT 256
|
|
||||||
|
|
||||||
int result;
|
int result;
|
||||||
pthread_attr_t thread_attr;
|
pthread_attr_t thread_attr;
|
||||||
void **current_arg;
|
|
||||||
pthread_t fixed_tids[FIXED_TID_COUNT];
|
|
||||||
pthread_t *the_tids;
|
|
||||||
pthread_t *ptid;
|
pthread_t *ptid;
|
||||||
pthread_t *ptid_end;
|
pthread_t *ptid_end;
|
||||||
|
|
||||||
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0) {
|
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
||||||
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tids != NULL) {
|
|
||||||
the_tids = tids;
|
|
||||||
} else {
|
|
||||||
if (*count <= FIXED_TID_COUNT) {
|
|
||||||
the_tids = fixed_tids;
|
|
||||||
} else {
|
|
||||||
int bytes;
|
|
||||||
bytes = sizeof(pthread_t) * *count;
|
|
||||||
the_tids = (pthread_t *)fc_malloc(bytes);
|
|
||||||
if (the_tids == NULL) {
|
|
||||||
pthread_attr_destroy(&thread_attr);
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
ptid_end = the_tids + (*count);
|
ptid_end = tids + (*count);
|
||||||
for (ptid=the_tids,current_arg=args; ptid<ptid_end;
|
for (ptid=tids; ptid<ptid_end; ptid++)
|
||||||
ptid++,current_arg++)
|
{
|
||||||
{
|
if ((result=pthread_create(ptid, &thread_attr, \
|
||||||
if ((result=pthread_create(ptid, &thread_attr,
|
start_func, arg)) != 0)
|
||||||
start_func, *current_arg)) != 0)
|
|
||||||
{
|
{
|
||||||
*count = ptid - the_tids;
|
*count = ptid - tids;
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"create threads #%d fail, "
|
"create thread failed, startup threads: %d, " \
|
||||||
"errno: %d, error info: %s",
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, *count,
|
__LINE__, *count, \
|
||||||
result, STRERROR(result));
|
result, STRERROR(result));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (the_tids != tids && the_tids != fixed_tids) {
|
|
||||||
free(the_tids);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_attr_destroy(&thread_attr);
|
pthread_attr_destroy(&thread_attr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_work_threads_ex(int *count, void *(*start_func)(void *),
|
|
||||||
void *args, const int elment_size, pthread_t *tids,
|
|
||||||
const int stack_size)
|
|
||||||
{
|
|
||||||
#define FIXED_ARG_COUNT 256
|
|
||||||
|
|
||||||
void *fixed_args[FIXED_ARG_COUNT];
|
|
||||||
void **pp_args;
|
|
||||||
char *p;
|
|
||||||
int result;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (*count <= FIXED_ARG_COUNT) {
|
|
||||||
pp_args = fixed_args;
|
|
||||||
} else {
|
|
||||||
int bytes;
|
|
||||||
bytes = sizeof(void *) * (*count);
|
|
||||||
pp_args = (void **)fc_malloc(bytes);
|
|
||||||
if (pp_args == NULL) {
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p = (char *)args;
|
|
||||||
for (i=0; i<*count; i++) {
|
|
||||||
pp_args[i] = p;
|
|
||||||
p += elment_size;
|
|
||||||
}
|
|
||||||
result = create_work_threads(count, start_func,
|
|
||||||
pp_args, tids, stack_size);
|
|
||||||
if (pp_args != fixed_args) {
|
|
||||||
free(pp_args);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kill_work_threads(pthread_t *tids, const int count)
|
int kill_work_threads(pthread_t *tids, const int count)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
@ -284,11 +177,13 @@ int kill_work_threads(pthread_t *tids, const int count)
|
||||||
pthread_t *ptid_end;
|
pthread_t *ptid_end;
|
||||||
|
|
||||||
ptid_end = tids + count;
|
ptid_end = tids + count;
|
||||||
for (ptid=tids; ptid<ptid_end; ptid++) {
|
for (ptid=tids; ptid<ptid_end; ptid++)
|
||||||
if ((result=pthread_kill(*ptid, SIGINT)) != 0) {
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
if ((result=pthread_kill(*ptid, SIGINT)) != 0)
|
||||||
"kill thread failed, "
|
{
|
||||||
"errno: %d, error info: %s",
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"kill thread failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -296,53 +191,3 @@ int kill_work_threads(pthread_t *tids, const int count)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fc_create_thread(pthread_t *tid, void *(*start_func)(void *),
|
|
||||||
void *args, const int stack_size)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
pthread_attr_t thread_attr;
|
|
||||||
|
|
||||||
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=pthread_create(tid, &thread_attr, start_func, args)) != 0) {
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"create thread fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_attr_destroy(&thread_attr);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_pthread_lock_cond_pair(pthread_lock_cond_pair_t *lcp)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=init_pthread_lock(&lcp->lock)) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"init_pthread_lock fail, errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=pthread_cond_init(&lcp->cond, NULL)) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"pthread_cond_init fail, "
|
|
||||||
"errno: %d, error info: %s",
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_pthread_lock_cond_pair(pthread_lock_cond_pair_t *lcp)
|
|
||||||
{
|
|
||||||
pthread_cond_destroy(&lcp->cond);
|
|
||||||
pthread_mutex_destroy(&lcp->lock);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PTHREAD_FUNC_H
|
#ifndef PTHREAD_FUNC_H
|
||||||
#define PTHREAD_FUNC_H
|
#define PTHREAD_FUNC_H
|
||||||
|
|
@ -23,184 +16,18 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include "common_define.h"
|
#include "common_define.h"
|
||||||
#include "shared_func.h"
|
|
||||||
#include "sched_thread.h"
|
|
||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int init_pthread_lock(pthread_mutex_t *pthread_lock);
|
int init_pthread_lock(pthread_mutex_t *pthread_lock);
|
||||||
int init_pthread_rwlock(pthread_rwlock_t *rwlock);
|
|
||||||
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size);
|
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size);
|
||||||
|
|
||||||
int init_pthread_lock_cond_pair(pthread_lock_cond_pair_t *lcp);
|
int create_work_threads(int *count, void *(*start_func)(void *), \
|
||||||
void destroy_pthread_lock_cond_pair(pthread_lock_cond_pair_t *lcp);
|
void *arg, pthread_t *tids, const int stack_size);
|
||||||
|
|
||||||
#define PTHREAD_MUTEX_LOCK(lock) \
|
|
||||||
do { \
|
|
||||||
int lock_res; \
|
|
||||||
if ((lock_res=pthread_mutex_lock(lock)) != 0) \
|
|
||||||
{ \
|
|
||||||
logWarning("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_lock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, lock_res, STRERROR(lock_res)); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define PTHREAD_MUTEX_UNLOCK(lock) \
|
|
||||||
do { \
|
|
||||||
int unlock_res; \
|
|
||||||
if ((unlock_res=pthread_mutex_unlock(lock)) != 0) \
|
|
||||||
{ \
|
|
||||||
logWarning("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_unlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, unlock_res, STRERROR(unlock_res)); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define PTHREAD_RWLOCK_WRLOCK(rwlock) \
|
|
||||||
do { \
|
|
||||||
int rwlock_res; \
|
|
||||||
if ((rwlock_res=pthread_rwlock_wrlock(rwlock)) != 0) \
|
|
||||||
{ \
|
|
||||||
logWarning("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_rwlock_wrlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, rwlock_res, STRERROR(rwlock_res)); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define PTHREAD_RWLOCK_RDLOCK(rwlock) \
|
|
||||||
do { \
|
|
||||||
int rwlock_res; \
|
|
||||||
if ((rwlock_res=pthread_rwlock_rdlock(rwlock)) != 0) \
|
|
||||||
{ \
|
|
||||||
logWarning("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_rwlock_rdlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, rwlock_res, STRERROR(rwlock_res)); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define PTHREAD_RWLOCK_UNLOCK(rwlock) \
|
|
||||||
do { \
|
|
||||||
int unlock_res; \
|
|
||||||
if ((unlock_res=pthread_rwlock_unlock(rwlock)) != 0) \
|
|
||||||
{ \
|
|
||||||
logWarning("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_rwlock_unlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, unlock_res, STRERROR(unlock_res)); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define lcp_timedwait_sec(lcp, timeout) \
|
|
||||||
fc_timedwait_sec(&(lcp)->lock, &(lcp)->cond, timeout)
|
|
||||||
|
|
||||||
#define lcp_timedwait_ms(lcp, timeout_ms) \
|
|
||||||
fc_timedwait_ms(&(lcp)->lock, &(lcp)->cond, timeout_ms)
|
|
||||||
|
|
||||||
static inline void fc_timedwait_sec(pthread_mutex_t *lock,
|
|
||||||
pthread_cond_t *cond, const int timeout)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
|
|
||||||
ts.tv_sec = get_current_time() + timeout;
|
|
||||||
ts.tv_nsec = 0;
|
|
||||||
PTHREAD_MUTEX_LOCK(lock);
|
|
||||||
pthread_cond_timedwait(cond, lock, &ts);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void fc_timedwait_ms(pthread_mutex_t *lock,
|
|
||||||
pthread_cond_t *cond, const int timeout_ms)
|
|
||||||
{
|
|
||||||
int64_t expires_ms;
|
|
||||||
struct timespec ts;
|
|
||||||
|
|
||||||
expires_ms = get_current_time_ms() + timeout_ms;
|
|
||||||
ts.tv_sec = expires_ms / 1000;
|
|
||||||
ts.tv_nsec = (expires_ms % 1000) * (1000 * 1000);
|
|
||||||
PTHREAD_MUTEX_LOCK(lock);
|
|
||||||
pthread_cond_timedwait(cond, lock, &ts);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_timeout_to_timespec(const int timeout,
|
|
||||||
const int time_unit, struct timespec *ts)
|
|
||||||
{
|
|
||||||
int seconds;
|
|
||||||
|
|
||||||
switch (time_unit) {
|
|
||||||
case FC_TIME_UNIT_SECOND:
|
|
||||||
seconds = timeout;
|
|
||||||
ts->tv_nsec = 0;
|
|
||||||
break;
|
|
||||||
case FC_TIME_UNIT_MSECOND:
|
|
||||||
seconds = timeout / 1000;
|
|
||||||
ts->tv_nsec = (timeout % 1000) * (1000 * 1000);
|
|
||||||
break;
|
|
||||||
case FC_TIME_UNIT_USECOND:
|
|
||||||
seconds = timeout / (1000 * 1000);
|
|
||||||
ts->tv_nsec = (timeout % (1000 * 1000)) * 1000;
|
|
||||||
break;
|
|
||||||
case FC_TIME_UNIT_NSECOND:
|
|
||||||
seconds = timeout / (1000 * 1000 * 1000);
|
|
||||||
ts->tv_nsec = timeout % (1000 * 1000 * 1000);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logError("file: "__FILE__", line: %d, "
|
|
||||||
"invalid time unit: %d", __LINE__, time_unit);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ts->tv_sec = get_current_time() + seconds;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fc_cond_timedwait(pthread_lock_cond_pair_t *lcp,
|
|
||||||
const int timeout, const int time_unit)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=fc_timeout_to_timespec(timeout, time_unit, &ts)) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return pthread_cond_timedwait(&lcp->cond, &lcp->lock, &ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define fc_cond_timedwait_sec(lcp, timeout) \
|
|
||||||
fc_cond_timedwait(lcp, timeout, FC_TIME_UNIT_SECOND)
|
|
||||||
|
|
||||||
#define fc_cond_timedwait_ms(lcp, timeout_ms) \
|
|
||||||
fc_cond_timedwait(lcp, timeout_ms, FC_TIME_UNIT_MSECOND)
|
|
||||||
|
|
||||||
#define fc_cond_timedwait_us(lcp, timeout_us) \
|
|
||||||
fc_cond_timedwait(lcp, timeout_us, FC_TIME_UNIT_USECOND)
|
|
||||||
|
|
||||||
|
|
||||||
int create_work_threads(int *count, void *(*start_func)(void *),
|
|
||||||
void **args, pthread_t *tids, const int stack_size);
|
|
||||||
|
|
||||||
int create_work_threads_ex(int *count, void *(*start_func)(void *),
|
|
||||||
void *args, const int elment_size, pthread_t *tids,
|
|
||||||
const int stack_size);
|
|
||||||
|
|
||||||
int kill_work_threads(pthread_t *tids, const int count);
|
int kill_work_threads(pthread_t *tids, const int count);
|
||||||
|
|
||||||
int fc_create_thread(pthread_t *tid, void *(*start_func)(void *),
|
|
||||||
void *args, const int stack_size);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "pthread_pool.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
*the thread pool
|
||||||
|
*/
|
||||||
|
// global varalibale declared
|
||||||
|
static threadpool_info_t *pool;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the thread callback function proxy
|
||||||
|
* parameters:
|
||||||
|
* arg:the thread callback function parameter
|
||||||
|
*/
|
||||||
|
static void *callback_proxy(void *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* push the thread into the pool
|
||||||
|
* parameters:
|
||||||
|
* thread:the thread will push into the poolbool
|
||||||
|
* return:
|
||||||
|
* 0:success
|
||||||
|
* >0 : fail
|
||||||
|
*/
|
||||||
|
static int push2pool(thread_info_t *thread);
|
||||||
|
|
||||||
|
// proxy the thread running, use pthread_cond_wait to wait for arg to be update by
|
||||||
|
// other users that need to use this thread
|
||||||
|
static void *callback_proxy(void *arg)
|
||||||
|
{
|
||||||
|
thread_info_t* thread = (thread_info_t *) arg;
|
||||||
|
// runs only when the pool->state is initialized
|
||||||
|
while(initialized == pool->state)
|
||||||
|
{
|
||||||
|
// run what the caller want to do
|
||||||
|
thread->func(thread->arg);
|
||||||
|
|
||||||
|
// if the state of thread pool is changed
|
||||||
|
// we termiate the execution of this thread by returning the result
|
||||||
|
if(pool == NULL || initialized != pool->state) break;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&thread->mutex_locker);
|
||||||
|
|
||||||
|
if(0 == push2pool(thread))
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&thread->run_locker,&thread->mutex_locker);
|
||||||
|
pthread_mutex_unlock(&thread->mutex_locker);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock( &thread->mutex_locker );
|
||||||
|
pthread_cond_destroy( &thread->run_locker );
|
||||||
|
pthread_mutex_destroy( &thread->mutex_locker );
|
||||||
|
|
||||||
|
free( thread );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&pool->mutex_locker);
|
||||||
|
pool->current_size --;
|
||||||
|
if(0 >= pool->current_size) pthread_cond_signal(&pool->empty_locker);
|
||||||
|
pthread_mutex_unlock(&pool->mutex_locker);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push the free thread_info_t back to the thread pool
|
||||||
|
static int push2pool(thread_info_t *thread)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&pool->mutex_locker);
|
||||||
|
if( pool->current_index < pool->total_size )
|
||||||
|
{
|
||||||
|
pool->list[ pool->current_index ] = thread;
|
||||||
|
pool->current_index++;
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
// there is new thread for use, call phtread_cond_signal to
|
||||||
|
// notice the caller
|
||||||
|
pthread_cond_signal( &pool->run_locker);
|
||||||
|
|
||||||
|
if( pool->current_index >= pool->current_size )
|
||||||
|
{
|
||||||
|
// current_index reach the max
|
||||||
|
// notice other thread that I am full
|
||||||
|
pthread_cond_signal( &pool->full_locker );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}while(0);
|
||||||
|
pthread_mutex_unlock(&pool->mutex_locker);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize a thread pool of [size] for later use
|
||||||
|
int threadpool_init(int size)
|
||||||
|
{
|
||||||
|
if(0 >= size)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = (threadpool_info_t *) malloc(sizeof(threadpool_info_t));
|
||||||
|
if(NULL == pool)
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
memset(pool,0,sizeof(threadpool_info_t));
|
||||||
|
pool->state = initializing;
|
||||||
|
pool->total_size = size;
|
||||||
|
pool->current_size = 0;
|
||||||
|
pool->current_index = 0;
|
||||||
|
// initialize sync data structures
|
||||||
|
pthread_mutex_init(&pool->mutex_locker,NULL);
|
||||||
|
pthread_cond_init(&pool->run_locker,NULL);
|
||||||
|
pthread_cond_init(&pool->empty_locker,NULL);
|
||||||
|
pthread_cond_init(&pool->full_locker,NULL);
|
||||||
|
// initialize a list of thread_info_t structs
|
||||||
|
pool->list = (thread_info_t **) malloc(sizeof(thread_info_t*) * size);
|
||||||
|
if(NULL == pool->list)
|
||||||
|
{
|
||||||
|
pthread_cond_destroy(&pool->run_locker);
|
||||||
|
pthread_cond_destroy(&pool->empty_locker);
|
||||||
|
pthread_cond_destroy(&pool->full_locker);
|
||||||
|
pthread_mutex_destroy(&pool->mutex_locker);
|
||||||
|
// free the memory pointed by pool pointer
|
||||||
|
free(pool);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->state = initialized;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the callback within the thread pool, arg is its var
|
||||||
|
int threadpool_run(callback func,void *arg)
|
||||||
|
{
|
||||||
|
if(NULL == pool)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&pool->mutex_locker);
|
||||||
|
if(NULL == pool || initialized != pool->state) //the pool cannot use
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//current size is >= the max pool size and all thread are busy now
|
||||||
|
while(pool->current_index <= 0 && pool->current_size >= pool->total_size)
|
||||||
|
{
|
||||||
|
// wait on the run locker when there is no spare thread for the caller to use
|
||||||
|
pthread_cond_wait(&pool->run_locker,&pool->mutex_locker);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0 >= pool->current_index)
|
||||||
|
{
|
||||||
|
// when the current_index is smaler or equal to 0
|
||||||
|
// we create a new thread_info_t data structure and put it into the pool later
|
||||||
|
thread_info_t * thread = (thread_info_t *) malloc(sizeof(thread_info_t));
|
||||||
|
if(NULL == thread)
|
||||||
|
{
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memset(thread,0,sizeof(thread_info_t));
|
||||||
|
|
||||||
|
// create thread and set it to detached mode(it will end by itself when it finishes)
|
||||||
|
pthread_mutex_init(&thread->mutex_locker,NULL);
|
||||||
|
pthread_cond_init(&thread->run_locker,NULL);
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
||||||
|
|
||||||
|
thread->arg = arg;
|
||||||
|
thread->func = func;
|
||||||
|
|
||||||
|
if(0 == pthread_create(&thread->id,&attr,callback_proxy,thread))
|
||||||
|
{
|
||||||
|
pool->current_size ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = -3;
|
||||||
|
pthread_mutex_destroy(&thread->mutex_locker);
|
||||||
|
pthread_cond_destroy(&thread->run_locker);
|
||||||
|
free(thread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pool->current_index --;//because the array begin with 0
|
||||||
|
thread_info_t *thread = pool->list[ pool->current_index ];
|
||||||
|
pool->list[ pool->current_index ] = NULL;
|
||||||
|
|
||||||
|
thread->func = func;
|
||||||
|
thread->arg = arg;
|
||||||
|
|
||||||
|
pthread_mutex_lock( &thread->mutex_locker );
|
||||||
|
pthread_cond_signal( &thread->run_locker ) ;
|
||||||
|
pthread_mutex_unlock ( &thread->mutex_locker );
|
||||||
|
}
|
||||||
|
}while(0);
|
||||||
|
pthread_mutex_unlock(&pool->mutex_locker);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destory the thread pool
|
||||||
|
int threadpool_destroy()
|
||||||
|
{
|
||||||
|
if(NULL == pool) return 0;
|
||||||
|
|
||||||
|
pthread_mutex_lock( &pool->mutex_locker);
|
||||||
|
|
||||||
|
// when current_index is biger or equals to current_size
|
||||||
|
// this means all the job in the thread pool is finished
|
||||||
|
// which means we can do the free related jobs
|
||||||
|
if( pool->current_index < pool->current_size )
|
||||||
|
{
|
||||||
|
// if current_index < current_size, wait for current_index to reach current_size
|
||||||
|
// then change the state of the pool, thus stopping the caller to put more task
|
||||||
|
// into the thread pool, then it use pthread_cond_signal to cause all worker thread
|
||||||
|
// to exit.
|
||||||
|
pthread_cond_wait( &pool->full_locker, &pool->mutex_locker );
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->state = uninstalling;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// cause all the thread to run to its end
|
||||||
|
for( i = 0; i < pool->current_index; i++ )
|
||||||
|
{
|
||||||
|
thread_info_t *thread = pool->list[i];
|
||||||
|
|
||||||
|
pthread_mutex_lock( &thread->mutex_locker );
|
||||||
|
pthread_cond_signal( &thread->run_locker ) ;
|
||||||
|
pthread_mutex_unlock ( &thread->mutex_locker );
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for all threads to exit, when all threads exit, it will
|
||||||
|
// issue a signal of empty_locker
|
||||||
|
if(0 < pool->current_size)
|
||||||
|
{
|
||||||
|
pthread_cond_wait( &pool->empty_locker, &pool->mutex_locker);
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < pool->current_index; i++ )
|
||||||
|
{
|
||||||
|
free( pool->list[ i ] );
|
||||||
|
pool->list[ i ] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock( &pool->mutex_locker );
|
||||||
|
|
||||||
|
pool->current_index = 0;
|
||||||
|
|
||||||
|
pthread_mutex_destroy( &pool->mutex_locker );
|
||||||
|
pthread_cond_destroy( &pool->run_locker );
|
||||||
|
pthread_cond_destroy( &pool->full_locker );
|
||||||
|
pthread_cond_destroy( &pool->empty_locker );
|
||||||
|
|
||||||
|
free( pool->list );
|
||||||
|
pool->list = NULL;
|
||||||
|
free( pool);
|
||||||
|
pool = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef PTHREAD_POOL_H_
|
||||||
|
#define PTHREAD_POOL_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* define the callback function type of thread
|
||||||
|
*/
|
||||||
|
typedef void (*callback)(void *);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the thread pool state
|
||||||
|
* member:
|
||||||
|
* uninitialized : not initialize the thread pool.
|
||||||
|
* initializing : initializing the thread pool.
|
||||||
|
* initialized : the pool can use.
|
||||||
|
* uninstalling : uninstalling the thread pool.
|
||||||
|
* uninstalled : uninstall the thread pool is over.
|
||||||
|
*/
|
||||||
|
typedef enum threadpool_state
|
||||||
|
{
|
||||||
|
uninitialized,
|
||||||
|
initializing,
|
||||||
|
initialized,
|
||||||
|
uninstalling,
|
||||||
|
uninstalled,
|
||||||
|
}thread_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* define the thread type which in the pool
|
||||||
|
* members:
|
||||||
|
* id : the thread id
|
||||||
|
* mutex_locker : the mutext locker
|
||||||
|
* run_locker : the locker for noticing the thread do running or waitting
|
||||||
|
* func : the callback function for thread
|
||||||
|
* arg : the callback parameter
|
||||||
|
*/
|
||||||
|
typedef struct thread_info
|
||||||
|
{
|
||||||
|
pthread_t id;
|
||||||
|
pthread_mutex_t mutex_locker;
|
||||||
|
pthread_cond_t run_locker;
|
||||||
|
callback func;
|
||||||
|
void *arg;
|
||||||
|
}thread_info_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the structure for the thread pool
|
||||||
|
* member:
|
||||||
|
* list : the initialazed thread list
|
||||||
|
* mutex_locker : the mutex locker for the thread operation.
|
||||||
|
* run_locker : the locker for noticing the thread do running or waitting.
|
||||||
|
* full_locker : the locker notice the thread is stoping when free the thread pool and the pool is not full .
|
||||||
|
* empty_Locker : the locker notice the thread waitting for the busy thread work over,then do with the thread.
|
||||||
|
* state : the pool's current state.
|
||||||
|
* total_size : the pool max size;
|
||||||
|
* current_size : the thread count for the current pool ;
|
||||||
|
* current_index : the busy thread in the pool index.
|
||||||
|
*/
|
||||||
|
typedef struct threadpool_info
|
||||||
|
{
|
||||||
|
thread_info_t **list;
|
||||||
|
pthread_mutex_t mutex_locker;
|
||||||
|
pthread_cond_t run_locker;
|
||||||
|
pthread_cond_t full_locker;
|
||||||
|
pthread_cond_t empty_locker;
|
||||||
|
thread_state_t state;
|
||||||
|
int total_size;
|
||||||
|
int current_size;
|
||||||
|
int current_index;
|
||||||
|
}threadpool_info_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize the thread pool
|
||||||
|
* parameters:
|
||||||
|
* size : thread pool max size
|
||||||
|
* return:
|
||||||
|
* 0:initialize pool success;
|
||||||
|
* -1:the size parameter is less 0;
|
||||||
|
* -2:initialize pool is fail,malloc memory for pool or pool->list is error;
|
||||||
|
*/
|
||||||
|
int threadpool_init(int size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* run the function with the thread from pool
|
||||||
|
* parameter:
|
||||||
|
* func:the thread callback function
|
||||||
|
* arg:the parameter of callback function
|
||||||
|
* return:
|
||||||
|
* 0 : success
|
||||||
|
* -1: the pool is NULL;
|
||||||
|
* -2 : malloc memory for thread is error;
|
||||||
|
* -3 : create thread is error;
|
||||||
|
*/
|
||||||
|
int threadpool_run(callback func,void *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* free and destroy the thread pool memory
|
||||||
|
* return:
|
||||||
|
* 0 : success
|
||||||
|
* less 0 : fail
|
||||||
|
*/
|
||||||
|
int threadpool_destroy();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PTHREAD_POOL_H_ */
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
/*
|
/**
|
||||||
* Copyright (c) 2020 YuQing <384681@qq.com>
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
*
|
*
|
||||||
* This program is free software: you can use, redistribute, and/or modify
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
* it under the terms of the Lesser GNU General Public License, version 3
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
* or later ("LGPL"), as published by the Free Software Foundation.
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
*
|
**/
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the Lesser GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -20,10 +13,9 @@
|
||||||
#include "shared_func.h"
|
#include "shared_func.h"
|
||||||
#include "pthread_func.h"
|
#include "pthread_func.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "fc_memory.h"
|
|
||||||
#include "sched_thread.h"
|
#include "sched_thread.h"
|
||||||
|
|
||||||
volatile int g_schedule_flag = false;
|
volatile bool g_schedule_flag = false;
|
||||||
volatile time_t g_current_time = 0;
|
volatile time_t g_current_time = 0;
|
||||||
|
|
||||||
static ScheduleArray waiting_schedule_array = {NULL, 0};
|
static ScheduleArray waiting_schedule_array = {NULL, 0};
|
||||||
|
|
@ -41,84 +33,36 @@ static int sched_dup_array(const ScheduleArray *pSrcArray,
|
||||||
|
|
||||||
static int sched_cmp_by_next_call_time(const void *p1, const void *p2)
|
static int sched_cmp_by_next_call_time(const void *p1, const void *p2)
|
||||||
{
|
{
|
||||||
return ((ScheduleEntry *)p1)->next_call_time -
|
return ((ScheduleEntry *)p1)->next_call_time - \
|
||||||
((ScheduleEntry *)p2)->next_call_time;
|
((ScheduleEntry *)p2)->next_call_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t sched_make_first_call_time(struct tm *tm_current,
|
static int sched_init_entries(ScheduleArray *pScheduleArray)
|
||||||
const TimeInfo *time_base, const int interval)
|
|
||||||
{
|
|
||||||
int remain;
|
|
||||||
struct {
|
|
||||||
time_t time;
|
|
||||||
struct tm tm;
|
|
||||||
} base;
|
|
||||||
|
|
||||||
if (time_base->hour == TIME_NONE)
|
|
||||||
{
|
|
||||||
return g_current_time + interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tm_current->tm_hour > time_base->hour ||
|
|
||||||
(tm_current->tm_hour == time_base->hour
|
|
||||||
&& tm_current->tm_min >= time_base->minute))
|
|
||||||
{
|
|
||||||
base.tm = *tm_current;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base.time = g_current_time - 24 * 3600;
|
|
||||||
localtime_r(&base.time, &base.tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.tm.tm_hour = time_base->hour;
|
|
||||||
base.tm.tm_min = time_base->minute;
|
|
||||||
if (time_base->second >= 0 && time_base->second <= 59)
|
|
||||||
{
|
|
||||||
base.tm.tm_sec = time_base->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base.tm.tm_sec = 0;
|
|
||||||
}
|
|
||||||
base.time = mktime(&base.tm);
|
|
||||||
remain = g_current_time - base.time;
|
|
||||||
if (remain > 0)
|
|
||||||
{
|
|
||||||
return g_current_time + interval - remain % interval;
|
|
||||||
}
|
|
||||||
else if (remain < 0)
|
|
||||||
{
|
|
||||||
return g_current_time + (-1 * remain) % interval;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return g_current_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sched_init_entries(ScheduleEntry *entries, const int count)
|
|
||||||
{
|
{
|
||||||
ScheduleEntry *pEntry;
|
ScheduleEntry *pEntry;
|
||||||
ScheduleEntry *pEnd;
|
ScheduleEntry *pEnd;
|
||||||
|
time_t time_base;
|
||||||
struct tm tm_current;
|
struct tm tm_current;
|
||||||
|
struct tm tm_base;
|
||||||
|
int remain;
|
||||||
|
int interval;
|
||||||
|
|
||||||
if (count < 0)
|
if (pScheduleArray->count < 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, " \
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"schedule count %d < 0", \
|
"schedule count %d < 0", \
|
||||||
__LINE__, count);
|
__LINE__, pScheduleArray->count);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (count == 0)
|
if (pScheduleArray->count == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_current_time = time(NULL);
|
g_current_time = time(NULL);
|
||||||
localtime_r((time_t *)&g_current_time, &tm_current);
|
localtime_r((time_t *)&g_current_time, &tm_current);
|
||||||
pEnd = entries + count;
|
pEnd = pScheduleArray->entries + pScheduleArray->count;
|
||||||
for (pEntry=entries; pEntry<pEnd; pEntry++)
|
for (pEntry=pScheduleArray->entries; pEntry<pEnd; pEntry++)
|
||||||
{
|
{
|
||||||
if (next_id < pEntry->id)
|
if (next_id < pEntry->id)
|
||||||
{
|
{
|
||||||
|
|
@ -127,26 +71,70 @@ static int sched_init_entries(ScheduleEntry *entries, const int count)
|
||||||
|
|
||||||
if (pEntry->interval <= 0)
|
if (pEntry->interval <= 0)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, " \
|
||||||
"shedule id: %d, interval %d <= 0",
|
"shedule interval %d <= 0", \
|
||||||
__LINE__, pEntry->id, pEntry->interval);
|
__LINE__, pEntry->interval);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pEntry->next_call_time = sched_make_first_call_time(
|
if (pEntry->time_base.hour == TIME_NONE)
|
||||||
&tm_current, &pEntry->time_base, pEntry->interval);
|
{
|
||||||
|
pEntry->next_call_time = g_current_time + \
|
||||||
|
pEntry->interval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tm_current.tm_hour > pEntry->time_base.hour || \
|
||||||
|
(tm_current.tm_hour == pEntry->time_base.hour \
|
||||||
|
&& tm_current.tm_min >= pEntry->time_base.minute))
|
||||||
|
{
|
||||||
|
memcpy(&tm_base, &tm_current, sizeof(struct tm));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_base = g_current_time - 24 * 3600;
|
||||||
|
localtime_r(&time_base, &tm_base);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
tm_base.tm_hour = pEntry->time_base.hour;
|
||||||
|
tm_base.tm_min = pEntry->time_base.minute;
|
||||||
|
if (pEntry->time_base.second >= 0 && pEntry->time_base.second <= 59)
|
||||||
|
{
|
||||||
|
tm_base.tm_sec = pEntry->time_base.second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tm_base.tm_sec = 0;
|
||||||
|
}
|
||||||
|
time_base = mktime(&tm_base);
|
||||||
|
remain = g_current_time - time_base;
|
||||||
|
if (remain > 0)
|
||||||
|
{
|
||||||
|
interval = pEntry->interval - remain % pEntry->interval;
|
||||||
|
}
|
||||||
|
else if (remain < 0)
|
||||||
|
{
|
||||||
|
interval = (-1 * remain) % pEntry->interval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEntry->next_call_time = g_current_time + interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
char buff1[32];
|
char buff1[32];
|
||||||
char buff2[32];
|
char buff2[32];
|
||||||
logInfo("id=%d, current time=%s, first call time=%s",
|
logInfo("id=%d, current time=%s, first call time=%s\n", \
|
||||||
pEntry->id, formatDatetime(g_current_time,
|
pEntry->id, formatDatetime(g_current_time, \
|
||||||
"%Y-%m-%d %H:%M:%S", buff1, sizeof(buff1)),
|
"%Y-%m-%d %H:%M:%S", buff1, sizeof(buff1)), \
|
||||||
formatDatetime(pEntry->next_call_time,
|
formatDatetime(pEntry->next_call_time, \
|
||||||
"%Y-%m-%d %H:%M:%S", buff2, sizeof(buff2)));
|
"%Y-%m-%d %H:%M:%S", buff2, sizeof(buff2)));
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -165,7 +153,7 @@ static void sched_make_chain(ScheduleContext *pContext)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(pScheduleArray->entries, pScheduleArray->count,
|
qsort(pScheduleArray->entries, pScheduleArray->count, \
|
||||||
sizeof(ScheduleEntry), sched_cmp_by_next_call_time);
|
sizeof(ScheduleEntry), sched_cmp_by_next_call_time);
|
||||||
|
|
||||||
pContext->head = pScheduleArray->entries;
|
pContext->head = pScheduleArray->entries;
|
||||||
|
|
@ -222,11 +210,10 @@ static int print_all_sched_entries(ScheduleArray *pScheduleArray)
|
||||||
pEntry->time_base.minute, pEntry->time_base.second);
|
pEntry->time_base.minute, pEntry->time_base.second);
|
||||||
}
|
}
|
||||||
logInfo("id: %u, time_base: %s, interval: %d, "
|
logInfo("id: %u, time_base: %s, interval: %d, "
|
||||||
"new_thread: %s, task_func: %p, args: %p, "
|
"new_thread: %s, task_func: %p, args: %p",
|
||||||
"next_call_time: %d", pEntry->id, timebase,
|
pEntry->id, timebase, pEntry->interval,
|
||||||
pEntry->interval, pEntry->new_thread ? "true" : "false",
|
pEntry->new_thread ? "true" : "false",
|
||||||
pEntry->task_func, pEntry->func_args,
|
pEntry->task_func, pEntry->func_args);
|
||||||
(int)pEntry->next_call_time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(sortedByIdArray.entries);
|
free(sortedByIdArray.entries);
|
||||||
|
|
@ -236,7 +223,6 @@ static int print_all_sched_entries(ScheduleArray *pScheduleArray)
|
||||||
static int do_check_waiting(ScheduleContext *pContext)
|
static int do_check_waiting(ScheduleContext *pContext)
|
||||||
{
|
{
|
||||||
ScheduleArray *pScheduleArray;
|
ScheduleArray *pScheduleArray;
|
||||||
ScheduleEntry *waitingEntries;
|
|
||||||
ScheduleEntry *newEntries;
|
ScheduleEntry *newEntries;
|
||||||
ScheduleEntry *pWaitingEntry;
|
ScheduleEntry *pWaitingEntry;
|
||||||
ScheduleEntry *pWaitingEnd;
|
ScheduleEntry *pWaitingEnd;
|
||||||
|
|
@ -244,8 +230,8 @@ static int do_check_waiting(ScheduleContext *pContext)
|
||||||
ScheduleEntry *pSchedEnd;
|
ScheduleEntry *pSchedEnd;
|
||||||
int allocCount;
|
int allocCount;
|
||||||
int newCount;
|
int newCount;
|
||||||
|
int result;
|
||||||
int deleteCount;
|
int deleteCount;
|
||||||
int waitingCount;
|
|
||||||
|
|
||||||
pScheduleArray = &(pContext->scheduleArray);
|
pScheduleArray = &(pContext->scheduleArray);
|
||||||
deleteCount = 0;
|
deleteCount = 0;
|
||||||
|
|
@ -283,17 +269,7 @@ static int do_check_waiting(ScheduleContext *pContext)
|
||||||
waiting_del_id = -1;
|
waiting_del_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&schedule_context->lock);
|
if (waiting_schedule_array.count == 0)
|
||||||
waitingCount = waiting_schedule_array.count;
|
|
||||||
waitingEntries = waiting_schedule_array.entries;
|
|
||||||
if (waiting_schedule_array.entries != NULL)
|
|
||||||
{
|
|
||||||
waiting_schedule_array.count = 0;
|
|
||||||
waiting_schedule_array.entries = NULL;
|
|
||||||
}
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&schedule_context->lock);
|
|
||||||
|
|
||||||
if (waitingCount == 0)
|
|
||||||
{
|
{
|
||||||
if (deleteCount > 0)
|
if (deleteCount > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -304,41 +280,50 @@ static int do_check_waiting(ScheduleContext *pContext)
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
allocCount = pScheduleArray->count + waitingCount;
|
allocCount = pScheduleArray->count + waiting_schedule_array.count;
|
||||||
newEntries = (ScheduleEntry *)fc_malloc(sizeof(ScheduleEntry) * allocCount);
|
newEntries = (ScheduleEntry *)malloc(sizeof(ScheduleEntry) * allocCount);
|
||||||
if (newEntries == NULL)
|
if (newEntries == NULL)
|
||||||
{
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, (int)sizeof(ScheduleEntry) * allocCount, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
if (deleteCount > 0)
|
if (deleteCount > 0)
|
||||||
{
|
{
|
||||||
sched_make_chain(pContext);
|
sched_make_chain(pContext);
|
||||||
}
|
}
|
||||||
return ENOMEM;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pScheduleArray->count > 0)
|
if (pScheduleArray->count > 0)
|
||||||
{
|
{
|
||||||
memcpy(newEntries, pScheduleArray->entries,
|
memcpy(newEntries, pScheduleArray->entries, \
|
||||||
sizeof(ScheduleEntry) * pScheduleArray->count);
|
sizeof(ScheduleEntry) * pScheduleArray->count);
|
||||||
}
|
}
|
||||||
newCount = pScheduleArray->count;
|
newCount = pScheduleArray->count;
|
||||||
pWaitingEnd = waitingEntries + waitingCount;
|
pWaitingEnd = waiting_schedule_array.entries + waiting_schedule_array.count;
|
||||||
for (pWaitingEntry=waitingEntries; pWaitingEntry<pWaitingEnd;
|
for (pWaitingEntry=waiting_schedule_array.entries; \
|
||||||
pWaitingEntry++)
|
pWaitingEntry<pWaitingEnd; pWaitingEntry++)
|
||||||
{
|
{
|
||||||
pSchedEnd = newEntries + newCount;
|
pSchedEnd = newEntries + newCount;
|
||||||
for (pSchedEntry=newEntries; pSchedEntry<pSchedEnd; \
|
for (pSchedEntry=newEntries; pSchedEntry<pSchedEnd; \
|
||||||
pSchedEntry++)
|
pSchedEntry++)
|
||||||
{
|
{
|
||||||
if (pWaitingEntry->id == pSchedEntry->id)
|
if (pWaitingEntry->id == pSchedEntry->id)
|
||||||
{
|
{
|
||||||
*pSchedEntry = *pWaitingEntry;
|
memcpy(pSchedEntry, pWaitingEntry, \
|
||||||
break;
|
sizeof(ScheduleEntry));
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pSchedEntry == pSchedEnd)
|
if (pSchedEntry == pSchedEnd)
|
||||||
{
|
{
|
||||||
*pSchedEntry = *pWaitingEntry;
|
memcpy(pSchedEntry, pWaitingEntry, \
|
||||||
|
sizeof(ScheduleEntry));
|
||||||
newCount++;
|
newCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +331,7 @@ static int do_check_waiting(ScheduleContext *pContext)
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
"schedule add entries: %d, replace entries: %d",
|
"schedule add entries: %d, replace entries: %d",
|
||||||
__LINE__, newCount - pScheduleArray->count, \
|
__LINE__, newCount - pScheduleArray->count, \
|
||||||
waitingCount - (newCount - pScheduleArray->count));
|
waiting_schedule_array.count - (newCount - pScheduleArray->count));
|
||||||
|
|
||||||
if (pScheduleArray->entries != NULL)
|
if (pScheduleArray->entries != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -354,9 +339,13 @@ static int do_check_waiting(ScheduleContext *pContext)
|
||||||
}
|
}
|
||||||
pScheduleArray->entries = newEntries;
|
pScheduleArray->entries = newEntries;
|
||||||
pScheduleArray->count = newCount;
|
pScheduleArray->count = newCount;
|
||||||
free(waitingEntries);
|
|
||||||
|
free(waiting_schedule_array.entries);
|
||||||
|
waiting_schedule_array.count = 0;
|
||||||
|
waiting_schedule_array.entries = NULL;
|
||||||
|
|
||||||
sched_make_chain(pContext);
|
sched_make_chain(pContext);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,10 +369,6 @@ static void *sched_call_func(void *args)
|
||||||
TaskFunc task_func;
|
TaskFunc task_func;
|
||||||
int task_id;
|
int task_id;
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
prctl(PR_SET_NAME, "sched-call");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pEntry = (ScheduleEntry *)args;
|
pEntry = (ScheduleEntry *)args;
|
||||||
task_func = pEntry->task_func;
|
task_func = pEntry->task_func;
|
||||||
func_args = pEntry->func_args;
|
func_args = pEntry->func_args;
|
||||||
|
|
@ -412,20 +397,15 @@ static void *sched_thread_entrance(void *args)
|
||||||
int exec_count;
|
int exec_count;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
prctl(PR_SET_NAME, "sched");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pContext = (ScheduleContext *)args;
|
pContext = (ScheduleContext *)args;
|
||||||
if (sched_init_entries(pContext->scheduleArray.entries,
|
if (sched_init_entries(&(pContext->scheduleArray)) != 0)
|
||||||
pContext->scheduleArray.count) != 0)
|
|
||||||
{
|
{
|
||||||
free(pContext);
|
free(pContext);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sched_make_chain(pContext);
|
sched_make_chain(pContext);
|
||||||
|
|
||||||
__sync_bool_compare_and_swap(&g_schedule_flag, 0, 1);
|
g_schedule_flag = true;
|
||||||
while (*(pContext->pcontinue_flag))
|
while (*(pContext->pcontinue_flag))
|
||||||
{
|
{
|
||||||
g_current_time = time(NULL);
|
g_current_time = time(NULL);
|
||||||
|
|
@ -438,11 +418,6 @@ static void *sched_thread_entrance(void *args)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
logInfo("task count: %d, next_call_time: %d, g_current_time: %d",
|
|
||||||
pContext->scheduleArray.count,
|
|
||||||
(int)pContext->head->next_call_time, (int)g_current_time);
|
|
||||||
*/
|
|
||||||
while (pContext->head->next_call_time > g_current_time &&
|
while (pContext->head->next_call_time > g_current_time &&
|
||||||
*(pContext->pcontinue_flag))
|
*(pContext->pcontinue_flag))
|
||||||
{
|
{
|
||||||
|
|
@ -463,7 +438,7 @@ static void *sched_thread_entrance(void *args)
|
||||||
|
|
||||||
exec_count = 0;
|
exec_count = 0;
|
||||||
pCurrent = pContext->head;
|
pCurrent = pContext->head;
|
||||||
while (*(pContext->pcontinue_flag) && (pCurrent != NULL
|
while (*(pContext->pcontinue_flag) && (pCurrent != NULL \
|
||||||
&& pCurrent->next_call_time <= g_current_time))
|
&& pCurrent->next_call_time <= g_current_time))
|
||||||
{
|
{
|
||||||
//logInfo("exec task id: %d", pCurrent->id);
|
//logInfo("exec task id: %d", pCurrent->id);
|
||||||
|
|
@ -487,13 +462,13 @@ static void *sched_thread_entrance(void *args)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fc_sleep_ms(1);
|
usleep(1*1000);
|
||||||
for (i=1; !pCurrent->thread_running && i<100; i++)
|
for (i=1; !pCurrent->thread_running && i<100; i++)
|
||||||
{
|
{
|
||||||
logDebug("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
"task_id: %d, waiting thread ready, count %d",
|
"task_id: %d, waiting thread ready, count %d",
|
||||||
__LINE__, pCurrent->id, i);
|
__LINE__, pCurrent->id, i);
|
||||||
fc_sleep_ms(1);
|
usleep(1*1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -554,7 +529,7 @@ static void *sched_thread_entrance(void *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__sync_bool_compare_and_swap(&g_schedule_flag, 1, 0);
|
g_schedule_flag = false;
|
||||||
|
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
"schedule thread exit", __LINE__);
|
"schedule thread exit", __LINE__);
|
||||||
|
|
@ -566,6 +541,7 @@ static void *sched_thread_entrance(void *args)
|
||||||
static int sched_dup_array(const ScheduleArray *pSrcArray, \
|
static int sched_dup_array(const ScheduleArray *pSrcArray, \
|
||||||
ScheduleArray *pDestArray)
|
ScheduleArray *pDestArray)
|
||||||
{
|
{
|
||||||
|
int result;
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
if (pSrcArray->count == 0)
|
if (pSrcArray->count == 0)
|
||||||
|
|
@ -576,10 +552,15 @@ static int sched_dup_array(const ScheduleArray *pSrcArray, \
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = sizeof(ScheduleEntry) * pSrcArray->count;
|
bytes = sizeof(ScheduleEntry) * pSrcArray->count;
|
||||||
pDestArray->entries = (ScheduleEntry *)fc_malloc(bytes);
|
pDestArray->entries = (ScheduleEntry *)malloc(bytes);
|
||||||
if (pDestArray->entries == NULL)
|
if (pDestArray->entries == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, bytes, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(pDestArray->entries, pSrcArray->entries, bytes);
|
memcpy(pDestArray->entries, pSrcArray->entries, bytes);
|
||||||
|
|
@ -587,17 +568,28 @@ static int sched_dup_array(const ScheduleArray *pSrcArray, \
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sched_append_array(const ScheduleArray *pSrcArray,
|
static int sched_append_array(const ScheduleArray *pSrcArray, \
|
||||||
ScheduleArray *pDestArray)
|
ScheduleArray *pDestArray)
|
||||||
{
|
{
|
||||||
|
int result;
|
||||||
int bytes;
|
int bytes;
|
||||||
ScheduleEntry *new_entries;
|
ScheduleEntry *new_entries;
|
||||||
|
|
||||||
|
if (pSrcArray->count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bytes = sizeof(ScheduleEntry) * (pDestArray->count + pSrcArray->count);
|
bytes = sizeof(ScheduleEntry) * (pDestArray->count + pSrcArray->count);
|
||||||
new_entries = (ScheduleEntry *)fc_malloc(bytes);
|
new_entries = (ScheduleEntry *)malloc(bytes);
|
||||||
if (new_entries == NULL)
|
if (new_entries == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, bytes, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pDestArray->entries != NULL)
|
if (pDestArray->entries != NULL)
|
||||||
|
|
@ -614,66 +606,37 @@ static int sched_append_array(const ScheduleArray *pSrcArray,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sched_thread_init_ex(ScheduleContext **ppContext)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
*ppContext = (ScheduleContext *)fc_malloc(sizeof(ScheduleContext));
|
|
||||||
if (*ppContext == NULL)
|
|
||||||
{
|
|
||||||
return ENOMEM;
|
|
||||||
}
|
|
||||||
memset(*ppContext, 0, sizeof(ScheduleContext));
|
|
||||||
|
|
||||||
if ((result=init_pthread_lock(&(*ppContext)->lock)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sched_add_entries(const ScheduleArray *pScheduleArray)
|
int sched_add_entries(const ScheduleArray *pScheduleArray)
|
||||||
{
|
{
|
||||||
ScheduleEntry *newStart;
|
int result;
|
||||||
int old_count;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (pScheduleArray->count <= 0)
|
if (pScheduleArray->count == 0)
|
||||||
{
|
{
|
||||||
logWarning("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
"no schedule entry", __LINE__);
|
"no schedule entry", __LINE__);
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schedule_context == NULL)
|
if (waiting_schedule_array.entries != NULL)
|
||||||
{
|
{
|
||||||
if ((result=sched_thread_init_ex(&schedule_context)) != 0)
|
if (g_schedule_flag)
|
||||||
{
|
{
|
||||||
return result;
|
while (waiting_schedule_array.entries != NULL)
|
||||||
|
{
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"waiting for schedule array ready ...", __LINE__);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PTHREAD_MUTEX_LOCK(&schedule_context->lock);
|
if ((result=sched_append_array(pScheduleArray,
|
||||||
do {
|
&waiting_schedule_array)) != 0)
|
||||||
old_count = waiting_schedule_array.count;
|
{
|
||||||
if ((result=sched_append_array(pScheduleArray,
|
return result;
|
||||||
&waiting_schedule_array)) != 0)
|
}
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
newStart = waiting_schedule_array.entries + old_count;
|
return sched_init_entries(&waiting_schedule_array);
|
||||||
if ((result=sched_init_entries(newStart, pScheduleArray->count)) != 0)
|
|
||||||
{
|
|
||||||
waiting_schedule_array.count = newStart -
|
|
||||||
waiting_schedule_array.entries; //rollback
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (0);
|
|
||||||
PTHREAD_MUTEX_UNLOCK(&schedule_context->lock);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sched_del_entry(const int id)
|
int sched_del_entry(const int id)
|
||||||
|
|
@ -698,10 +661,24 @@ int sched_del_entry(const int id)
|
||||||
|
|
||||||
int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
const int stack_size, bool * volatile pcontinue_flag,
|
const int stack_size, bool * volatile pcontinue_flag,
|
||||||
ScheduleContext *pContext)
|
ScheduleContext **ppContext)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
pthread_attr_t thread_attr;
|
pthread_attr_t thread_attr;
|
||||||
|
ScheduleContext *pContext;
|
||||||
|
|
||||||
|
pContext = (ScheduleContext *)malloc(sizeof(ScheduleContext));
|
||||||
|
if (pContext == NULL)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, (int)sizeof(ScheduleContext), \
|
||||||
|
result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
memset(pContext, 0, sizeof(ScheduleContext));
|
||||||
|
|
||||||
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -709,7 +686,7 @@ int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((result=sched_dup_array(pScheduleArray,
|
if ((result=sched_dup_array(pScheduleArray, \
|
||||||
&(pContext->scheduleArray))) != 0)
|
&(pContext->scheduleArray))) != 0)
|
||||||
{
|
{
|
||||||
free(pContext);
|
free(pContext);
|
||||||
|
|
@ -718,9 +695,8 @@ int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
|
|
||||||
if (timer_slot_count > 0)
|
if (timer_slot_count > 0)
|
||||||
{
|
{
|
||||||
if ((result=fast_mblock_init_ex1(&pContext->delay_task_allocator,
|
if ((result=fast_mblock_init(&pContext->mblock,
|
||||||
"sched-delay-task", sizeof(FastDelayTask),
|
sizeof(FastDelayTask), mblock_alloc_once)) != 0)
|
||||||
mblock_alloc_once, 0, NULL, NULL, true)) != 0)
|
|
||||||
{
|
{
|
||||||
free(pContext);
|
free(pContext);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -733,9 +709,7 @@ int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
free(pContext);
|
free(pContext);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if ((result=init_pthread_lock(&pContext->delay_queue.lock)) != 0)
|
||||||
if ((result=fc_queue_init(&pContext->delay_queue, (long)
|
|
||||||
(&((FastDelayTask *)NULL)->next))) != 0)
|
|
||||||
{
|
{
|
||||||
free(pContext);
|
free(pContext);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -754,6 +728,7 @@ int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
__LINE__, result, STRERROR(result));
|
__LINE__, result, STRERROR(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ppContext = pContext;
|
||||||
pthread_attr_destroy(&thread_attr);
|
pthread_attr_destroy(&thread_attr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -761,16 +736,8 @@ int sched_start_ex(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid,
|
||||||
const int stack_size, bool * volatile pcontinue_flag)
|
const int stack_size, bool * volatile pcontinue_flag)
|
||||||
{
|
{
|
||||||
int result;
|
|
||||||
if (schedule_context == NULL)
|
|
||||||
{
|
|
||||||
if ((result=sched_thread_init_ex(&schedule_context)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sched_start_ex(pScheduleArray, ptid, stack_size,
|
return sched_start_ex(pScheduleArray, ptid, stack_size,
|
||||||
pcontinue_flag, schedule_context);
|
pcontinue_flag, &schedule_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_set_delay_params(const int slot_count, const int alloc_once)
|
void sched_set_delay_params(const int slot_count, const int alloc_once)
|
||||||
|
|
@ -798,8 +765,6 @@ int sched_add_delay_task_ex(ScheduleContext *pContext, TaskFunc task_func,
|
||||||
void *func_args, const int delay_seconds, const bool new_thread)
|
void *func_args, const int delay_seconds, const bool new_thread)
|
||||||
{
|
{
|
||||||
FastDelayTask *task;
|
FastDelayTask *task;
|
||||||
bool notify;
|
|
||||||
|
|
||||||
if (!pContext->timer_init)
|
if (!pContext->timer_init)
|
||||||
{
|
{
|
||||||
logError("file: "__FILE__", line: %d, "
|
logError("file: "__FILE__", line: %d, "
|
||||||
|
|
@ -808,8 +773,7 @@ int sched_add_delay_task_ex(ScheduleContext *pContext, TaskFunc task_func,
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
task = (FastDelayTask *)fast_mblock_alloc_object(
|
task = (FastDelayTask *)fast_mblock_alloc_object(&pContext->mblock);
|
||||||
&pContext->delay_task_allocator);
|
|
||||||
if (task == NULL)
|
if (task == NULL)
|
||||||
{
|
{
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
@ -827,7 +791,18 @@ int sched_add_delay_task_ex(ScheduleContext *pContext, TaskFunc task_func,
|
||||||
task->timer.expires = g_current_time;
|
task->timer.expires = g_current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
fc_queue_push_ex(&pContext->delay_queue, task, ¬ify);
|
pthread_mutex_lock(&pContext->delay_queue.lock);
|
||||||
|
if (pContext->delay_queue.head == NULL)
|
||||||
|
{
|
||||||
|
pContext->delay_queue.head = task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pContext->delay_queue.tail->next = task;
|
||||||
|
}
|
||||||
|
pContext->delay_queue.tail = task;
|
||||||
|
pthread_mutex_unlock(&pContext->delay_queue.lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -841,10 +816,18 @@ int sched_add_delay_task(TaskFunc task_func, void *func_args,
|
||||||
static void sched_deal_task_queue(ScheduleContext *pContext)
|
static void sched_deal_task_queue(ScheduleContext *pContext)
|
||||||
{
|
{
|
||||||
FastDelayTask *task;
|
FastDelayTask *task;
|
||||||
struct fc_queue_info qinfo;
|
|
||||||
|
|
||||||
fc_queue_try_pop_to_queue(&pContext->delay_queue, &qinfo);
|
pthread_mutex_lock(&pContext->delay_queue.lock);
|
||||||
task = qinfo.head;
|
if (pContext->delay_queue.head == NULL)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&pContext->delay_queue.lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task = pContext->delay_queue.head;
|
||||||
|
pContext->delay_queue.head = NULL;
|
||||||
|
pContext->delay_queue.tail = NULL;
|
||||||
|
pthread_mutex_unlock(&pContext->delay_queue.lock);
|
||||||
|
|
||||||
while (task != NULL)
|
while (task != NULL)
|
||||||
{
|
{
|
||||||
fast_timer_add(&pContext->timer, (FastTimerEntry *)task);
|
fast_timer_add(&pContext->timer, (FastTimerEntry *)task);
|
||||||
|
|
@ -863,10 +846,6 @@ static void *sched_call_delay_func(void *args)
|
||||||
ScheduleContext *pContext;
|
ScheduleContext *pContext;
|
||||||
FastDelayTask *task;
|
FastDelayTask *task;
|
||||||
|
|
||||||
#ifdef OS_LINUX
|
|
||||||
prctl(PR_SET_NAME, "sched-delay");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
delay_context = (struct delay_thread_context *)args;
|
delay_context = (struct delay_thread_context *)args;
|
||||||
task = delay_context->task;
|
task = delay_context->task;
|
||||||
pContext = delay_context->schedule_context;
|
pContext = delay_context->schedule_context;
|
||||||
|
|
@ -880,7 +859,7 @@ static void *sched_call_delay_func(void *args)
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
"delay thread exit, task args: %p", __LINE__, task->func_args);
|
"delay thread exit, task args: %p", __LINE__, task->func_args);
|
||||||
|
|
||||||
fast_mblock_free_object(&pContext->delay_task_allocator, task);
|
fast_mblock_free_object(&pContext->mblock, task);
|
||||||
pthread_detach(pthread_self());
|
pthread_detach(pthread_self());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -904,7 +883,7 @@ static void deal_timeout_tasks(ScheduleContext *pContext, FastTimerEntry *head)
|
||||||
if (!task->new_thread)
|
if (!task->new_thread)
|
||||||
{
|
{
|
||||||
task->task_func(task->func_args);
|
task->task_func(task->func_args);
|
||||||
fast_mblock_free_object(&pContext->delay_task_allocator, task);
|
fast_mblock_free_object(&pContext->mblock, task);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -926,13 +905,13 @@ static void deal_timeout_tasks(ScheduleContext *pContext, FastTimerEntry *head)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fc_sleep_ms(1);
|
usleep(1*1000);
|
||||||
for (i=1; !task->thread_running && i<100; i++)
|
for (i=1; !task->thread_running && i<100; i++)
|
||||||
{
|
{
|
||||||
logDebug("file: "__FILE__", line: %d, "
|
logDebug("file: "__FILE__", line: %d, "
|
||||||
"task args: %p, waiting thread ready, count %d",
|
"task args: %p, waiting thread ready, count %d",
|
||||||
__LINE__, task->func_args, i);
|
__LINE__, task->func_args, i);
|
||||||
fc_sleep_ms(1);
|
usleep(1*1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -963,16 +942,3 @@ uint32_t sched_generate_next_id()
|
||||||
{
|
{
|
||||||
return ++next_id;
|
return ++next_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sched_free_ptr_func(void *ptr)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sched_delay_free_ptr(void *ptr, const int delay_seconds)
|
|
||||||
{
|
|
||||||
const bool new_thread = false;
|
|
||||||
return sched_add_delay_task_ex(schedule_context, sched_free_ptr_func,
|
|
||||||
ptr, delay_seconds, new_thread);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue