-- -- gcsd -- -- gcsd the generic command sequencer daemon can be used to serialize -- commands sent over various paralell communication channels to a -- single command output. It can be seen as a multiplexer for any -- kind of communication between a single resource and various clients -- which want to submit commands to it or query information from it. -- gcsd is written in C and Lua. The goal is to provide an easy to -- understand high level API based on Lua which can be used to -- implement the business logic of the so formed multiplexer daemon. -- -- -- Copyright (C) 2009-2010 Markus Grueneis -- Christian Pointner -- -- This file is part of gcsd. -- -- gcsd is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- any later version. -- -- gcsd 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. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with gcsd. If not, see . -- function get_readables() local readables = {} for _, module in ipairs(module_list.inputs) do for _, fd in ipairs(module:get_read_handles()) do table.insert(readables, fd) end end for _, fd in ipairs(module_list.output:get_read_handles()) do table.insert(readables, fd) end for _, client in ipairs(client_list.clients) do for _, fd in ipairs(client:get_read_handles()) do table.insert(readables, fd) end end return readables end function get_writeables() local writeables = {} for _, module in ipairs(module_list.inputs) do for _, fd in ipairs(module:get_write_handles()) do table.insert(writeables, fd) end end for _, fd in ipairs(module_list.output:get_write_handles()) do table.insert(writeables, fd) end for _, client in ipairs(client_list.clients) do for _, fd in ipairs(client:get_write_handles()) do table.insert(writeables, fd) end end return writeables end function main_loop(opt) log.printf(log.NOTICE, "main_loop started") local sig = signal.init() local return_value = dispatch_tables:load_handler_tables_file(opt.lua_code) if (return_value == defines.KILL_DAEMON) then return_value = -1 else return_value = module_list:init(opt) if(return_value == defines.KILL_DAEMON) then return_value = -1 else return_value = 0 end end while return_value == 0 do local readable, writeable, err = util.select({ sig, unpack(get_readables()) }, get_writeables(), 10) if(err) then if(err == "timeout") then local child, reason, status = util.waitpid() if(child == nil) then if(reason ~= nil) then log.printf(log.DEBUG, "waitpid failed: " .. reason) end else log.printf(log.DEBUG, "child with pid %d stopped, reason: %s, status: %s", child.pid, reason, status) if(child.cleanup ~= nil) then child:cleanup(reason, status) end end elseif(err == "signal") then -- ignore this else log.printf(log.ERROR, "select returned with error: %s", err) return_value = -1 end else for _, reader in ipairs(readable) do if(reader == sig) then return_value = signal.handle() if(return_value == 1) then break end else local ret = reader:read() if(ret == defines.KILL_MODULE_CLASS) then ret = module_list:unregister_by_class(reader.client_instance.module_instance.class) elseif(ret == defines.KILL_MODULE) then ret = module_list:unregister(reader.client_instance.module_instance) elseif(ret == defines.KILL_CLIENT) then client_list:unregister(reader.client_instance) end if(ret == defines.KILL_DAEMON) then return_value = 2 break end end end for _, writer in ipairs(writeable) do local ret = writer:write() if(ret == defines.KILL_MODULE_CLASS) then ret = module_list:unregister_by_class(writer.client_instance.module_instance.class) elseif(ret == defines.KILL_MODULE) then ret = module_list:unregister(writer.client_instance.module_instance) elseif(ret == defines.KILL_CLIENT) then client_list:unregister(writer.client_instance) end if(ret == defines.KILL_DAEMON) then return_value = 2 break end end end command_queue:check_timeout() if(command_queue:command_pending()) then local command = command_queue:get_next_command() log.printf(log.DEBUG, "sending pending command: %s", command) module_list.output:start_command(command) end end if(return_value == 2) then return_value = 0 end module_list:cleanup() signal.stop() return return_value end