summaryrefslogtreecommitdiffstats
path: root/include/dnsjit/core/thread.lua
diff options
context:
space:
mode:
Diffstat (limited to 'include/dnsjit/core/thread.lua')
-rw-r--r--include/dnsjit/core/thread.lua141
1 files changed, 141 insertions, 0 deletions
diff --git a/include/dnsjit/core/thread.lua b/include/dnsjit/core/thread.lua
new file mode 100644
index 0000000..f225726
--- /dev/null
+++ b/include/dnsjit/core/thread.lua
@@ -0,0 +1,141 @@
+-- Copyright (c) 2018-2021, OARC, Inc.
+-- All rights reserved.
+--
+-- This file is part of dnsjit.
+--
+-- dnsjit 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
+-- (at your option) any later version.
+--
+-- dnsjit 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 dnsjit. If not, see <http://www.gnu.org/licenses/>.
+
+-- dnsjit.core.thread
+-- POSIX thread with separate Lua state
+-- local thr = require("dnsjit.core.thread").new()
+-- thr:start(function(thr)
+-- print("Hello from thread")
+-- print("got:", thr:pop(), " = ", thr:pop(3))
+-- end)
+-- thr:push("value from main", 1, 2, 3)
+-- thr:stop()
+--
+-- Start a new POSIX thread with it's own Lua state.
+-- Sharable objects can be passed to the thread by pushing and poping them of
+-- the thread stack.
+-- The Thread object and any other objects passed to the thread needs to be
+-- kept alive as long as the thread is running.
+module(...,package.seeall)
+
+require("dnsjit.core.thread_h")
+local ffi = require("ffi")
+local C = ffi.C
+
+local t_name = "core_thread_t"
+local core_thread_t
+local Thread = {
+ _in_thread = function(thr, bytecode)
+ thr = ffi.cast("core_thread_t*", thr)
+ loadstring(bytecode)(thr)
+ end
+}
+
+-- Create a new Thread object.
+function Thread.new()
+ local self = core_thread_t()
+ C.core_thread_init(self)
+ ffi.gc(self, C.core_thread_destroy)
+ return self
+end
+
+-- Return the Log object to control logging of this instance or module.
+function Thread:log()
+ if self == nil then
+ return C.core_thread_log()
+ end
+ return self._log
+end
+
+-- Start the thread and execute the given function in a separate Lua state,
+-- first argument to the function will be the Thread object that created it.
+-- Returns 0 on success.
+function Thread:start(func)
+ local bc = string.dump(func)
+ return C.core_thread_start(self, bc, #bc)
+end
+
+-- Wait for the thread to return.
+-- Returns 0 on success.
+function Thread:stop()
+ return C.core_thread_stop(self)
+end
+
+-- Push string(s), number(s) or sharable object(s) onto the thread stack so
+-- they can be retrieved inside the thread using
+-- .IR pop() .
+-- The sharable object(s) needs to be kept alive as long as the thread is
+-- running, strings and numbers are copied.
+function Thread:push(...)
+ for _, obj in pairs({...}) do
+ local t = type(obj)
+ if t == "string" then
+ C.core_thread_push_string(self, obj, #obj)
+ elseif t == "number" then
+ C.core_thread_push_int64(self, obj)
+ else
+ local ptr, type, module = obj:share()
+ C.core_thread_push(self, ptr, type, #type, module, #module)
+ end
+ end
+end
+
+-- Pop value(s) off the thread stack, should only be called within the thread.
+-- If
+-- .I num
+-- is not given then one value is poped.
+-- Returns nil if no values are left on the stack.
+function Thread:pop(num)
+ if num == nil or num == 1 then
+ local item = C.core_thread_pop(self)
+ if item == nil then
+ return
+ end
+ if item.ptr == nil then
+ if item.str == nil then
+ return tonumber(item.i64)
+ end
+ return ffi.string(item.str)
+ end
+ require(ffi.string(item.module))
+ return ffi.cast(ffi.string(item.type), item.ptr)
+ end
+
+ local ret = {}
+ for n = 1, num do
+ local item = C.core_thread_pop(self)
+ if item == nil then break end
+
+ if item.ptr == nil then
+ if item.str == nil then
+ table.insert(ret, tonumber(item.i64))
+ else
+ table.insert(ret, ffi.string(item.str))
+ end
+ else
+ require(ffi.string(item.module))
+ table.insert(ret, ffi.cast(ffi.string(item.type), item.ptr))
+ end
+ end
+ return unpack(ret)
+end
+
+core_thread_t = ffi.metatype(t_name, { __index = Thread })
+
+-- dnsjit.core.channel (3)
+return Thread