├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── lib └── resty │ └── signal.lua ├── resty_signal.c ├── t ├── TestKiller.pm ├── kill.t ├── sanity.t └── signum.t └── valgrind.suppress /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | *.swo 4 | t/servroot* 5 | /go 6 | /reindex 7 | /a.lua 8 | *.o 9 | *.so 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: focal 3 | 4 | branches: 5 | only: 6 | - "master" 7 | 8 | os: linux 9 | 10 | language: c 11 | 12 | compiler: 13 | - gcc 14 | 15 | env: 16 | global: 17 | - JOBS=3 18 | - NGX_BUILD_JOBS=$JOBS 19 | - LUAJIT_PREFIX=/opt/luajit21 20 | - LUAJIT_LIB=$LUAJIT_PREFIX/lib 21 | - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 22 | - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH 23 | matrix: 24 | - NGINX_VERSION=1.27.1 25 | 26 | install: 27 | - sudo apt-get install -qq -y cpanminus axel 28 | - sudo cpanm --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1) 29 | - git clone https://github.com/openresty/openresty.git ../openresty 30 | - git clone https://github.com/openresty/nginx-devel-utils.git 31 | - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module 32 | - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module 33 | - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core 34 | - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache 35 | - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx 36 | - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git 37 | 38 | script: 39 | - make 40 | - cd luajit2/ 41 | - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > build.log 2>&1 || (cat build.log && exit 1) 42 | - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) 43 | - cd .. 44 | - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH 45 | - export NGX_BUILD_CC=$CC 46 | - ngx-build $NGINX_VERSION --without-pcre2 --with-http_realip_module --add-module=../ndk-nginx-module --add-module=../lua-nginx-module --with-debug > build.log 2>&1 || (cat build.log && exit 1) 47 | - nginx -V 48 | - ldd `which nginx`|grep -E 'luajit|ssl|pcre' 49 | - prove -I. -r t 50 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OPENRESTY_PREFIX=/usr/local/openresty 2 | 3 | PREFIX ?= /usr/local 4 | LUA_INCLUDE_DIR ?= $(PREFIX)/include 5 | LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) 6 | INSTALL ?= install 7 | 8 | .PHONY: all test install 9 | 10 | SRC := resty_signal.c 11 | OBJ := $(SRC:.c=.o) 12 | 13 | C_SO_NAME := librestysignal.so 14 | 15 | CFLAGS := -O3 -g -Wall -fpic 16 | 17 | LDFLAGS := -shared 18 | # on Mac OS X, one should set instead: 19 | # LDFLAGS := -bundle -undefined dynamic_lookup 20 | 21 | MY_CFLAGS := $(CFLAGS) 22 | MY_LDFLAGS := $(LDFLAGS) -fvisibility=hidden 23 | 24 | test := t 25 | 26 | .PHONY = all test clean install 27 | 28 | all : $(C_SO_NAME) 29 | 30 | ${OBJ} : %.o : %.c 31 | $(CC) $(MY_CFLAGS) -c $< 32 | 33 | ${C_SO_NAME} : ${OBJ} 34 | $(CC) $(MY_LDFLAGS) $^ -o $@ 35 | 36 | #export TEST_NGINX_NO_CLEAN=1 37 | 38 | clean:; rm -f *.o *.so a.out *.d 39 | 40 | install: 41 | $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty 42 | $(INSTALL) lib/resty/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty 43 | $(INSTALL) $(C_SO_NAME) $(DESTDIR)$(LUA_LIB_DIR)/ 44 | 45 | test : all 46 | PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$$PATH prove -I../test-nginx/lib -r $(test) 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Name 2 | ==== 3 | 4 | lua-resty-signal - Lua library for killing or sending signals to Linux processes 5 | 6 | Table of Contents 7 | ================= 8 | 9 | * [Name](#name) 10 | * [Synopsis](#synopsis) 11 | * [Functions](#functions) 12 | * [kill](#kill) 13 | * [signum](#signum) 14 | * [Author](#author) 15 | * [Copyright & Licenses](#copyright--licenses) 16 | 17 | Synopsis 18 | ======== 19 | 20 | ```lua 21 | local resty_signal = require "resty.signal" 22 | local pid = 12345 23 | 24 | local ok, err = resty_signal.kill(pid, "TERM") 25 | if not ok then 26 | ngx.log(ngx.ERR, "failed to kill process of pid ", pid, ": ", err) 27 | return 28 | end 29 | 30 | -- send the signal 0 to check the existence of a process 31 | local ok, err = resty_signal.kill(pid, "NONE") 32 | 33 | local ok, err = resty_signal.kill(pid, "HUP") 34 | 35 | local ok, err = resty_signal.kill(pid, "KILL") 36 | ``` 37 | 38 | Functions 39 | ========= 40 | 41 | kill 42 | ---- 43 | 44 | **syntax:** `ok, err = resty_signal.kill(pid, signal_name_or_num)` 45 | 46 | Sends a signal with its name string or number value to the process of the 47 | specified pid. 48 | 49 | All signal names accepted by [signum](#signum) are supported, like `HUP`, 50 | `KILL`, and `TERM`. 51 | 52 | Signal numbers are also supported when specifying nonportable system-specific 53 | signals is desired. 54 | 55 | [Back to TOC](#table-of-contents) 56 | 57 | signum 58 | ------ 59 | 60 | **syntax:** `num = resty_signal.signum(sig_name)` 61 | 62 | Maps the signal name specified to the system-specific signal number. Returns 63 | `nil` if the signal name is not known. 64 | 65 | All the POSIX and BSD signal names are supported: 66 | 67 | ``` 68 | HUP 69 | INT 70 | QUIT 71 | ILL 72 | TRAP 73 | ABRT 74 | BUS 75 | FPE 76 | KILL 77 | USR1 78 | SEGV 79 | USR2 80 | PIPE 81 | ALRM 82 | TERM 83 | CHLD 84 | CONT 85 | STOP 86 | TSTP 87 | TTIN 88 | TTOU 89 | URG 90 | XCPU 91 | XFSZ 92 | VTALRM 93 | PROF 94 | WINCH 95 | IO 96 | PWR 97 | EMT 98 | SYS 99 | INFO 100 | ``` 101 | 102 | The special signal name `NONE` is also supported, which is mapped to zero (0). 103 | 104 | [Back to TOC](#table-of-contents) 105 | 106 | Author 107 | ====== 108 | 109 | Yichun Zhang (agentzh) 110 | 111 | [Back to TOC](#table-of-contents) 112 | 113 | Copyright & Licenses 114 | ==================== 115 | 116 | This module is licensed under the BSD license. 117 | 118 | Copyright (C) 2018-2019, [OpenResty Inc.](https://openresty.com) 119 | 120 | All rights reserved. 121 | 122 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 123 | 124 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 125 | 126 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 127 | 128 | * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 129 | 130 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 131 | 132 | [Back to TOC](#table-of-contents) 133 | -------------------------------------------------------------------------------- /lib/resty/signal.lua: -------------------------------------------------------------------------------- 1 | local _M = { 2 | version = 0.04 3 | } 4 | 5 | 6 | local ffi = require "ffi" 7 | local base = require "resty.core.base" 8 | 9 | 10 | local C = ffi.C 11 | local ffi_str = ffi.string 12 | local tonumber = tonumber 13 | local assert = assert 14 | local errno = ffi.errno 15 | local type = type 16 | local new_tab = base.new_tab 17 | local error = error 18 | local string_format = string.format 19 | 20 | 21 | local load_shared_lib 22 | do 23 | local string_gmatch = string.gmatch 24 | local string_match = string.match 25 | local io_open = io.open 26 | local io_close = io.close 27 | 28 | local cpath = package.cpath 29 | 30 | function load_shared_lib(so_name) 31 | local tried_paths = new_tab(32, 0) 32 | local i = 1 33 | 34 | for k, _ in string_gmatch(cpath, "[^;]+") do 35 | if k == "?.so" then 36 | k = "./" 37 | end 38 | 39 | local fpath = string_match(k, "(.*/)") 40 | fpath = fpath .. so_name 41 | -- Don't get me wrong, the only way to know if a file exist is 42 | -- trying to open it. 43 | local f = io_open(fpath) 44 | if f ~= nil then 45 | io_close(f) 46 | return ffi.load(fpath) 47 | end 48 | 49 | tried_paths[i] = fpath 50 | i = i + 1 51 | end 52 | 53 | return nil, tried_paths 54 | end -- function 55 | end -- do 56 | 57 | 58 | local resty_signal, tried_paths = load_shared_lib("librestysignal.so") 59 | if not resty_signal then 60 | error("could not load librestysignal.so from the following paths:\n" .. 61 | table.concat(tried_paths, "\n"), 2) 62 | end 63 | 64 | 65 | ffi.cdef[[ 66 | int resty_signal_signum(int num); 67 | ]] 68 | 69 | 70 | if not pcall(function () return C.kill end) then 71 | ffi.cdef("int kill(int32_t pid, int sig);") 72 | end 73 | 74 | 75 | if not pcall(function () return C.strerror end) then 76 | ffi.cdef("char *strerror(int errnum);") 77 | end 78 | 79 | 80 | -- Below is just the ID numbers for each POSIX signal. We map these signal IDs 81 | -- to system-specific signal numbers on the C land (via librestysignal.so). 82 | local signals = { 83 | NONE = 0, 84 | HUP = 1, 85 | INT = 2, 86 | QUIT = 3, 87 | ILL = 4, 88 | TRAP = 5, 89 | ABRT = 6, 90 | BUS = 7, 91 | FPE = 8, 92 | KILL = 9, 93 | USR1 = 10, 94 | SEGV = 11, 95 | USR2 = 12, 96 | PIPE = 13, 97 | ALRM = 14, 98 | TERM = 15, 99 | CHLD = 17, 100 | CONT = 18, 101 | STOP = 19, 102 | TSTP = 20, 103 | TTIN = 21, 104 | TTOU = 22, 105 | URG = 23, 106 | XCPU = 24, 107 | XFSZ = 25, 108 | VTALRM = 26, 109 | PROF = 27, 110 | WINCH = 28, 111 | IO = 29, 112 | PWR = 30, 113 | EMT = 31, 114 | SYS = 32, 115 | INFO = 33 116 | } 117 | 118 | 119 | local function signum(name) 120 | local sig_num 121 | if type(name) == "number" then 122 | sig_num = name 123 | else 124 | local id = signals[name] 125 | if not id then 126 | return nil, "unknown signal name" 127 | end 128 | 129 | sig_num = tonumber(resty_signal.resty_signal_signum(id)) 130 | if sig_num < 0 then 131 | error( 132 | string_format("missing C def for signal %s = %d", name, id), 133 | 2 134 | ) 135 | end 136 | end 137 | return sig_num 138 | end 139 | 140 | 141 | function _M.kill(pid, sig) 142 | assert(sig) 143 | 144 | local sig_num, err = signum(sig) 145 | if err then 146 | return nil, err 147 | end 148 | 149 | local rc = tonumber(C.kill(assert(pid), sig_num)) 150 | if rc == 0 then 151 | return true 152 | end 153 | 154 | local err = ffi_str(C.strerror(errno())) 155 | return nil, err 156 | end 157 | 158 | _M.signum = signum 159 | 160 | return _M 161 | -------------------------------------------------------------------------------- /resty_signal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | enum { 5 | RS_NONE = 0, 6 | RS_HUP = 1, 7 | RS_INT = 2, 8 | RS_QUIT = 3, 9 | RS_ILL = 4, 10 | RS_TRAP = 5, 11 | RS_ABRT = 6, 12 | RS_BUS = 7, 13 | RS_FPE = 8, 14 | RS_KILL = 9, 15 | RS_USR1 = 10, 16 | RS_SEGV = 11, 17 | RS_USR2 = 12, 18 | RS_PIPE = 13, 19 | RS_ALRM = 14, 20 | RS_TERM = 15, 21 | RS_CHLD = 17, 22 | RS_CONT = 18, 23 | RS_STOP = 19, 24 | RS_TSTP = 20, 25 | RS_TTIN = 21, 26 | RS_TTOU = 22, 27 | RS_URG = 23, 28 | RS_XCPU = 24, 29 | RS_XFSZ = 25, 30 | RS_VTALRM = 26, 31 | RS_PROF = 27, 32 | RS_WINCH = 28, 33 | RS_IO = 29, 34 | RS_PWR = 30, 35 | RS_EMT = 31, 36 | RS_SYS = 32, 37 | RS_INFO = 33 38 | }; 39 | 40 | 41 | int 42 | resty_signal_signum(int num) 43 | { 44 | switch (num) { 45 | 46 | case RS_NONE: 47 | return 0; 48 | 49 | case RS_HUP: 50 | return SIGHUP; 51 | 52 | case RS_INT: 53 | return SIGINT; 54 | 55 | case RS_QUIT: 56 | return SIGQUIT; 57 | 58 | case RS_ILL: 59 | return SIGILL; 60 | 61 | case RS_TRAP: 62 | return SIGTRAP; 63 | 64 | case RS_ABRT: 65 | return SIGABRT; 66 | 67 | case RS_BUS: 68 | return SIGBUS; 69 | 70 | case RS_FPE: 71 | return SIGFPE; 72 | 73 | case RS_KILL: 74 | return SIGKILL; 75 | 76 | case RS_SEGV: 77 | return SIGSEGV; 78 | 79 | case RS_PIPE: 80 | return SIGPIPE; 81 | 82 | case RS_ALRM: 83 | return SIGALRM; 84 | 85 | case RS_TERM: 86 | return SIGTERM; 87 | 88 | case RS_CHLD: 89 | return SIGCHLD; 90 | 91 | case RS_CONT: 92 | return SIGCONT; 93 | 94 | case RS_STOP: 95 | return SIGSTOP; 96 | 97 | case RS_TSTP: 98 | return SIGTSTP; 99 | 100 | case RS_TTIN: 101 | return SIGTTIN; 102 | 103 | case RS_TTOU: 104 | return SIGTTOU; 105 | 106 | case RS_XCPU: 107 | return SIGXCPU; 108 | 109 | case RS_XFSZ: 110 | return SIGXFSZ; 111 | 112 | case RS_VTALRM: 113 | return SIGVTALRM; 114 | 115 | case RS_PROF: 116 | return SIGPROF; 117 | 118 | case RS_WINCH: 119 | return SIGWINCH; 120 | 121 | case RS_IO: 122 | return SIGIO; 123 | 124 | #ifdef __linux__ 125 | case RS_PWR: 126 | return SIGPWR; 127 | #endif 128 | 129 | case RS_USR1: 130 | return SIGUSR1; 131 | 132 | case RS_USR2: 133 | return SIGUSR2; 134 | 135 | case RS_URG: 136 | return SIGURG; 137 | 138 | #ifdef __APPLE__ 139 | case RS_EMT: 140 | return SIGEMT; 141 | 142 | case RS_SYS: 143 | return SIGSYS; 144 | 145 | case RS_INFO: 146 | return SIGINFO; 147 | #endif 148 | 149 | default: 150 | return -1; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /t/TestKiller.pm: -------------------------------------------------------------------------------- 1 | package t::TestKiller; 2 | 3 | use v5.10.1; 4 | use Test::Nginx::Socket::Lua -Base; 5 | 6 | add_block_preprocessor(sub { 7 | my $block = shift; 8 | 9 | my $http_config = $block->http_config // ''; 10 | my $init_by_lua_block = $block->init_by_lua_block // 'require "resty.core"'; 11 | 12 | $http_config .= <<_EOC_; 13 | 14 | lua_package_path "./lib/?.lua;../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;"; 15 | lua_package_cpath "./?.so;;"; 16 | init_by_lua_block { 17 | $init_by_lua_block 18 | } 19 | _EOC_ 20 | 21 | $block->set_value("http_config", $http_config); 22 | 23 | if (!defined $block->error_log) { 24 | $block->set_value("no_error_log", "[error]"); 25 | } 26 | 27 | if (!defined $block->request) { 28 | $block->set_value("request", "GET /t"); 29 | } 30 | }); 31 | 32 | 1; 33 | -------------------------------------------------------------------------------- /t/kill.t: -------------------------------------------------------------------------------- 1 | # vi:ft= 2 | 3 | use lib '.'; 4 | use t::TestKiller; 5 | 6 | plan tests => 3 * blocks(); 7 | 8 | no_long_string(); 9 | #no_diff(); 10 | 11 | run_tests(); 12 | 13 | __DATA__ 14 | 15 | === TEST 1: returns an error if signal is unknown 16 | --- config 17 | location = /t { 18 | content_by_lua_block { 19 | local resty_signal = require "resty.signal" 20 | 21 | local ok, err = resty_signal.kill(pid, "FOO") 22 | if not ok then 23 | ngx.say("failed to send FOO signal: ", err) 24 | return 25 | end 26 | ngx.say("ok") 27 | } 28 | } 29 | --- response_body 30 | failed to send FOO signal: unknown signal name 31 | 32 | 33 | 34 | === TEST 2: send NONE to a non-existing process 35 | --- config 36 | location = /t { 37 | content_by_lua_block { 38 | local resty_signal = require "resty.signal" 39 | 40 | local say = ngx.say 41 | local ngx_pipe = require "ngx.pipe" 42 | local proc = assert(ngx_pipe.spawn("echo ok")) 43 | local pid = assert(proc:pid()) 44 | assert(proc:wait()) 45 | 46 | local ok, err = resty_signal.kill(pid, "NONE") 47 | if not ok then 48 | ngx.say("failed to send NONE signal: ", err) 49 | return 50 | end 51 | ngx.say("ok") 52 | } 53 | } 54 | --- response_body 55 | failed to send NONE signal: No such process 56 | 57 | 58 | 59 | === TEST 3: send TERM to a non-existing process 60 | --- config 61 | location = /t { 62 | content_by_lua_block { 63 | local resty_signal = require "resty.signal" 64 | 65 | local say = ngx.say 66 | local ngx_pipe = require "ngx.pipe" 67 | local proc = assert(ngx_pipe.spawn("echo ok")) 68 | local pid = assert(proc:pid()) 69 | assert(proc:wait()) 70 | 71 | local ok, err = resty_signal.kill(pid, "TERM") 72 | if not ok then 73 | ngx.say("failed to send TERM signal: ", err) 74 | return 75 | end 76 | ngx.say("ok") 77 | } 78 | } 79 | --- response_body 80 | failed to send TERM signal: No such process 81 | 82 | 83 | 84 | === TEST 4: send NONE to an existing process 85 | --- config 86 | location = /t { 87 | content_by_lua_block { 88 | local resty_signal = require "resty.signal" 89 | 90 | local say = ngx.say 91 | local ngx_pipe = require "ngx.pipe" 92 | local proc = assert(ngx_pipe.spawn("echo ok")) 93 | local pid = assert(proc:pid()) 94 | -- assert(proc:wait()) 95 | 96 | for i = 1, 2 do 97 | ngx.say("i = ", i) 98 | local ok, err = resty_signal.kill(pid, "NONE") 99 | if not ok then 100 | ngx.say("failed to send NONE signal: ", err) 101 | return 102 | end 103 | end 104 | 105 | ngx.say("ok") 106 | } 107 | } 108 | --- response_body 109 | i = 1 110 | i = 2 111 | ok 112 | 113 | 114 | 115 | === TEST 5: send TERM to an existing process 116 | --- config 117 | location = /t { 118 | content_by_lua_block { 119 | local resty_signal = require "resty.signal" 120 | 121 | local say = ngx.say 122 | local ngx_pipe = require "ngx.pipe" 123 | local proc = assert(ngx_pipe.spawn("echo ok")) 124 | local pid = assert(proc:pid()) 125 | -- assert(proc:wait()) 126 | 127 | for i = 1, 2 do 128 | ngx.say("i = ", i) 129 | local ok, err = resty_signal.kill(pid, "TERM") 130 | if not ok then 131 | ngx.say("failed to send TERM signal: ", err) 132 | return 133 | end 134 | ngx.sleep(0.01) 135 | end 136 | 137 | ngx.say("ok") 138 | } 139 | } 140 | --- response_body 141 | i = 1 142 | i = 2 143 | failed to send TERM signal: No such process 144 | 145 | 146 | 147 | === TEST 6: send KILL to an existing process 148 | --- config 149 | location = /t { 150 | content_by_lua_block { 151 | local resty_signal = require "resty.signal" 152 | 153 | local say = ngx.say 154 | local ngx_pipe = require "ngx.pipe" 155 | local proc = assert(ngx_pipe.spawn("echo ok")) 156 | local pid = assert(proc:pid()) 157 | -- assert(proc:wait()) 158 | 159 | for i = 1, 2 do 160 | ngx.say("i = ", i) 161 | local ok, err = resty_signal.kill(pid, "KILL") 162 | if not ok then 163 | ngx.say("failed to send KILL signal: ", err) 164 | return 165 | end 166 | ngx.sleep(0.01) 167 | end 168 | 169 | ngx.say("ok") 170 | } 171 | } 172 | --- response_body 173 | i = 1 174 | i = 2 175 | failed to send KILL signal: No such process 176 | 177 | 178 | 179 | === TEST 7: send TERM signal value, 15, directly to an existing process 180 | --- config 181 | location = /t { 182 | content_by_lua_block { 183 | local resty_signal = require "resty.signal" 184 | 185 | local say = ngx.say 186 | local ngx_pipe = require "ngx.pipe" 187 | local proc = assert(ngx_pipe.spawn("echo ok")) 188 | local pid = assert(proc:pid()) 189 | -- assert(proc:wait()) 190 | 191 | for i = 1, 2 do 192 | ngx.say("i = ", i) 193 | local ok, err = resty_signal.kill(pid, 15) 194 | if not ok then 195 | ngx.say("failed to send TERM signal: ", err) 196 | return 197 | end 198 | ngx.sleep(0.01) 199 | end 200 | 201 | ngx.say("ok") 202 | } 203 | } 204 | --- response_body 205 | i = 1 206 | i = 2 207 | failed to send TERM signal: No such process 208 | -------------------------------------------------------------------------------- /t/sanity.t: -------------------------------------------------------------------------------- 1 | # vi:ft= 2 | 3 | use lib '.'; 4 | use t::TestKiller; 5 | 6 | plan tests => 3 * blocks(); 7 | 8 | no_long_string(); 9 | #no_diff(); 10 | 11 | run_tests(); 12 | 13 | __DATA__ 14 | 15 | === TEST 1: failure to load librestysignal.so 16 | --- config 17 | location = /t { 18 | content_by_lua_block { 19 | local cpath = package.cpath 20 | package.cpath = "/foo/?.so;/bar/?.so;" 21 | 22 | local ok, perr = pcall(require, "resty.signal") 23 | if not ok then 24 | ngx.say(perr) 25 | end 26 | 27 | package.cpath = cpath 28 | } 29 | } 30 | --- response_body 31 | could not load librestysignal.so from the following paths: 32 | /foo/librestysignal.so 33 | /bar/librestysignal.so 34 | --- no_error_log 35 | [error] 36 | -------------------------------------------------------------------------------- /t/signum.t: -------------------------------------------------------------------------------- 1 | # vi:ft= 2 | 3 | use lib '.'; 4 | use t::TestKiller; 5 | 6 | plan tests => 3 * blocks(); 7 | 8 | no_long_string(); 9 | #no_diff(); 10 | 11 | run_tests(); 12 | 13 | __DATA__ 14 | 15 | === TEST 1: signals whose values are specified by POSIX 16 | --- config 17 | location = /t { 18 | content_by_lua_block { 19 | local resty_signal = require "resty.signal" 20 | local ffi = require "ffi" 21 | local say = ngx.say 22 | local signum = resty_signal.signum 23 | 24 | for i, signame in ipairs{ "ABRT", "ALRM", "HUP", "INT", "KILL", 25 | "QUIT", "TERM", "TRAP", "BLAH" } do 26 | say(signame, ": ", tostring(signum(signame))) 27 | end 28 | 29 | local linux_signals = { 30 | NONE = 0, 31 | HUP = 1, 32 | INT = 2, 33 | QUIT = 3, 34 | ILL = 4, 35 | TRAP = 5, 36 | ABRT = 6, 37 | BUS = 7, 38 | FPE = 8, 39 | KILL = 9, 40 | USR1 = 10, 41 | SEGV = 11, 42 | USR2 = 12, 43 | PIPE = 13, 44 | ALRM = 14, 45 | TERM = 15, 46 | CHLD = 17, 47 | CONT = 18, 48 | STOP = 19, 49 | TSTP = 20, 50 | TTIN = 21, 51 | TTOU = 22, 52 | URG = 23, 53 | XCPU = 24, 54 | XFSZ = 25, 55 | VTALRM = 26, 56 | PROF = 27, 57 | WINCH = 28, 58 | IO = 29, 59 | PWR = 30 60 | } 61 | 62 | local macosx_signals = { 63 | HUP = 1, 64 | INT = 2, 65 | QUIT = 3, 66 | ILL = 4, 67 | TRAP = 5, 68 | ABRT = 6, 69 | EMT = 7, 70 | FPE = 8, 71 | KILL = 9, 72 | BUS = 10, 73 | SEGV = 11, 74 | SYS = 12, 75 | PIPE = 13, 76 | ALRM = 14, 77 | TERM = 15, 78 | URG = 16, 79 | STOP = 17, 80 | TSTP = 18, 81 | CONT = 19, 82 | CHLD = 20, 83 | TTIN = 21, 84 | TTOU = 22, 85 | IO = 23, 86 | XCPU = 24, 87 | XFSZ = 25, 88 | VTALRM = 26, 89 | PROF = 27, 90 | WINCH = 28, 91 | INFO = 29, 92 | USR1 = 30, 93 | USR2 = 31 94 | } 95 | 96 | if ffi.os == "Linux" then 97 | for signame, num in pairs(linux_signals) do 98 | assert(num == tonumber(signum(signame))) 99 | end 100 | elseif ffi.os == "OSX" then 101 | for signame, num in pairs(macosx_signals) do 102 | assert(num == tonumber(signum(signame))) 103 | end 104 | end 105 | } 106 | } 107 | --- response_body 108 | ABRT: 6 109 | ALRM: 14 110 | HUP: 1 111 | INT: 2 112 | KILL: 9 113 | QUIT: 3 114 | TERM: 15 115 | TRAP: 5 116 | BLAH: nil 117 | -------------------------------------------------------------------------------- /valgrind.suppress: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Param 4 | epoll_ctl(event) 5 | fun:epoll_ctl 6 | fun:ngx_epoll_test_rdhup 7 | fun:ngx_epoll_init 8 | fun:ngx_event_process_init 9 | fun:ngx_single_process_cycle 10 | fun:main 11 | } 12 | { 13 | 14 | Memcheck:Leak 15 | match-leak-kinds: definite 16 | fun:malloc 17 | fun:ngx_alloc 18 | fun:ngx_set_environment 19 | fun:ngx_single_process_cycle 20 | fun:main 21 | } 22 | { 23 | 24 | Memcheck:Leak 25 | match-leak-kinds: definite 26 | fun:malloc 27 | fun:ngx_alloc 28 | fun:ngx_set_environment 29 | fun:ngx_worker_process_init 30 | } 31 | --------------------------------------------------------------------------------