Software /
code /
prosody
File
util/prosodyctl.lua @ 12201:e5e0ab93d7f4 0.11
util.xml: Break reference to help the GC (fix #1711)
LuaExpat uses a registry reference to track handlers, which makes
it so that an upvalue like this creates a reference loop that keeps the
parser and its handlers from being garbage collected. The same issue has
affected util.xmppstream in the past.
Code for checking:
local xml_parse = require"util.xml".parse;
for i = 1, 10000 do xml_parse("<root/>") end
collectgarbage(); collectgarbage();
print(collectgarbage("count"), "KiB");
A future release of LuaExpat may fix the underlying issue there.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 20 Jan 2022 09:57:20 +0100 |
parent | 10720:6e46fefe956c |
child | 10722:3ddc7c9f35dc |
line wrap: on
line source
-- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- local config = require "core.configmanager"; local encodings = require "util.encodings"; local stringprep = encodings.stringprep; local storagemanager = require "core.storagemanager"; local usermanager = require "core.usermanager"; local signal = require "util.signal"; local set = require "util.set"; local lfs = require "lfs"; local pcall = pcall; local type = type; local nodeprep, nameprep = stringprep.nodeprep, stringprep.nameprep; local io, os = io, os; local print = print; local tonumber = tonumber; local _G = _G; local prosody = prosody; -- UI helpers local function show_message(msg, ...) print(msg:format(...)); end local function show_usage(usage, desc) print("Usage: ".._G.arg[0].." "..usage); if desc then print(" "..desc); end end local function getchar(n) local stty_ret = os.execute("stty raw -echo 2>/dev/null"); local ok, char; if stty_ret == true or stty_ret == 0 then ok, char = pcall(io.read, n or 1); os.execute("stty sane"); else ok, char = pcall(io.read, "*l"); if ok then char = char:sub(1, n or 1); end end if ok then return char; end end local function getline() local ok, line = pcall(io.read, "*l"); if ok then return line; end end local function getpass() local stty_ret, _, status_code = os.execute("stty -echo 2>/dev/null"); if status_code then -- COMPAT w/ Lua 5.1 stty_ret = status_code; end if stty_ret ~= 0 then io.write("\027[08m"); -- ANSI 'hidden' text attribute end local ok, pass = pcall(io.read, "*l"); if stty_ret == 0 then os.execute("stty sane"); else io.write("\027[00m"); end io.write("\n"); if ok then return pass; end end local function show_yesno(prompt) io.write(prompt, " "); local choice = getchar():lower(); io.write("\n"); if not choice:match("%a") then choice = prompt:match("%[.-(%U).-%]$"); if not choice then return nil; end end return (choice == "y"); end local function read_password() local password; while true do io.write("Enter new password: "); password = getpass(); if not password then show_message("No password - cancelled"); return; end io.write("Retype new password: "); if getpass() ~= password then if not show_yesno [=[Passwords did not match, try again? [Y/n]]=] then return; end else break; end end return password; end local function show_prompt(prompt) io.write(prompt, " "); local line = getline(); line = line and line:gsub("\n$",""); return (line and #line > 0) and line or nil; end -- Server control local function adduser(params) local user, host, password = nodeprep(params.user), nameprep(params.host), params.password; if not user then return false, "invalid-username"; elseif not host then return false, "invalid-hostname"; end local host_session = prosody.hosts[host]; if not host_session then return false, "no-such-host"; end storagemanager.initialize_host(host); local provider = host_session.users; if not(provider) or provider.name == "null" then usermanager.initialize_host(host); end local ok, errmsg = usermanager.create_user(user, password, host); if not ok then return false, errmsg or "creating-user-failed"; end return true; end local function user_exists(params) local user, host = nodeprep(params.user), nameprep(params.host); storagemanager.initialize_host(host); local provider = prosody.hosts[host].users; if not(provider) or provider.name == "null" then usermanager.initialize_host(host); end return usermanager.user_exists(user, host); end local function passwd(params) if not user_exists(params) then return false, "no-such-user"; end return adduser(params); end local function deluser(params) if not user_exists(params) then return false, "no-such-user"; end local user, host = nodeprep(params.user), nameprep(params.host); return usermanager.delete_user(user, host); end local function getpid() local pidfile = config.get("*", "pidfile"); if not pidfile then return false, "no-pidfile"; end if type(pidfile) ~= "string" then return false, "invalid-pidfile"; end pidfile = config.resolve_relative_path(prosody.paths.data, pidfile); local modules_disabled = set.new(config.get("*", "modules_disabled")); if prosody.platform ~= "posix" or modules_disabled:contains("posix") then return false, "no-posix"; end local file, err = io.open(pidfile, "r+"); if not file then return false, "pidfile-read-failed", err; end local locked, err = lfs.lock(file, "w"); if locked then file:close(); return false, "pidfile-not-locked"; end local pid = tonumber(file:read("*a")); file:close(); if not pid then return false, "invalid-pid"; end return true, pid; end local function isrunning() local ok, pid, err = getpid(); if not ok then if pid == "pidfile-read-failed" or pid == "pidfile-not-locked" then -- Report as not running, since we can't open the pidfile -- (it probably doesn't exist) return true, false; end return ok, pid; end return true, signal.kill(pid, 0) == 0; end local function start(source_dir) local ok, ret = isrunning(); if not ok then return ok, ret; end if ret then return false, "already-running"; end if not source_dir then os.execute("./prosody -D"); else os.execute(source_dir.."/../../bin/prosody -D"); end return true; end local function stop() local ok, ret = isrunning(); if not ok then return ok, ret; end if not ret then return false, "not-running"; end local ok, pid = getpid() if not ok then return false, pid; end signal.kill(pid, signal.SIGTERM); return true; end local function reload() local ok, ret = isrunning(); if not ok then return ok, ret; end if not ret then return false, "not-running"; end local ok, pid = getpid() if not ok then return false, pid; end signal.kill(pid, signal.SIGHUP); return true; end return { show_message = show_message; show_warning = show_message; show_usage = show_usage; getchar = getchar; getline = getline; getpass = getpass; show_yesno = show_yesno; read_password = read_password; show_prompt = show_prompt; adduser = adduser; user_exists = user_exists; passwd = passwd; deluser = deluser; getpid = getpid; isrunning = isrunning; start = start; stop = stop; reload = reload; };