build: split into luci and luci-addons packages
[project/luci.git] / libs / lucid / luasrc / lucid.lua
index 4963ccc30485b424c014235f986a35b6e0cfb67e..38b34fde96b34538846c84d7b5874769e6a95f2e 100644 (file)
@@ -43,6 +43,8 @@ local SSTATE = "/tmp/.lucid_store"
 
 --- Starts a new LuCId superprocess.
 function start()
+       state:revert(UCINAME, "main")
+
        prepare()
 
        local detach = cursor:get(UCINAME, "main", "daemonize")
@@ -60,6 +62,12 @@ function start()
        run()
 end
 
+--- Returns the PID of the currently active LuCId process.
+function running()
+       local pid = tonumber(state:get(UCINAME, "main", "pid"))
+       return pid and nixio.kill(pid, 0) and pid
+end
+
 --- Stops any running LuCId superprocess. 
 function stop()
        local pid = tonumber(state:get(UCINAME, "main", "pid"))
@@ -110,22 +118,24 @@ end
 -- This main function of LuCId will wait for events on given file descriptors.
 function run()
        local pollint = tonumber((cursor:get(UCINAME, "main", "pollinterval")))
-       local threadlimit = tonumber(cursor:get(UCINAME, "main", "threadlimit"))
+       local threadlimit = tonumber((cursor:get(UCINAME, "main", "threadlimit")))
 
        while true do
-               if not threadlimit or tcount < threadlimit then
-                       local stat, code = nixio.poll(pollt, pollint)
+               local stat, code = nixio.poll(pollt, pollint)
                
-                       if stat and stat > 0 then
-                               for _, polle in ipairs(pollt) do
-                                       if polle.revents ~= 0 and polle.handler then
-                                               polle.handler(polle)
-                                       end
+               if stat and stat > 0 then
+                       local ok = false
+                       for _, polle in ipairs(pollt) do
+                               if polle.revents ~= 0 and polle.handler then
+                                       ok = ok or polle.handler(polle)
                                end
-                       elseif stat == 0 then
-                               ifaddrs = nixio.getifaddrs()
-                               collectgarbage("collect")
                        end
+                       if not ok then
+                               -- Avoid high CPU usage if thread limit is reached
+                               nixio.nanosleep(0, 100000000)
+                       end
+               elseif stat == 0 then
+                       ifaddrs = nixio.getifaddrs()
                end
                
                for _, cb in ipairs(tickt) do
@@ -134,9 +144,13 @@ function run()
                
                local pid, stat, code = nixio.wait(-1, "nohang")
                while pid and pid > 0 do
-                       tcount = tcount - 1
-                       if tpids[pid] and tpids[pid] ~= true then
-                               tpids[pid](pid, stat, code)
+                       nixio.syslog("info", "Buried thread: " .. pid)
+                       if tpids[pid] then
+                               tcount = tcount - 1
+                               if tpids[pid] ~= true then
+                                       tpids[pid](pid, stat, code)
+                               end
+                               tpids[pid] = nil
                        end
                        pid, stat, code = nixio.wait(-1, "nohang")
                end
@@ -200,6 +214,14 @@ function unregister_tick(cb)
        return false
 end
 
+--- Tests whether a given number of processes can be created.
+-- @oaram num Processes to be created
+-- @return boolean status
+function try_process(num)
+       local threadlimit = tonumber((cursor:get(UCINAME, "main", "threadlimit")))
+       return not threadlimit or (threadlimit - tcount) >= (num or 1)
+end
+
 --- Create a new child process from a Lua function and assign a destructor.
 -- @param threadcb main function of the new process
 -- @param waitcb destructor callback
@@ -209,10 +231,13 @@ function create_process(threadcb, waitcb)
        if threadlimit and tcount >= threadlimit then
                nixio.syslog("warning", "Cannot create thread: process limit reached")
                return nil
+       else
+               collectgarbage("collect")
        end
        local pid, code, err = nixio.fork()
        if pid and pid ~= 0 then
-               tpids[pid] = waitcb
+               nixio.syslog("info", "Created thread: " .. pid)
+               tpids[pid] = waitcb or true
                tcount = tcount + 1
        elseif pid == 0 then
                local code = threadcb()