summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2020-01-31 23:24:01 +0800
committerruki <[email protected]>2020-01-31 14:24:07 +0800
commit14bb17934b8acf2a0633f8af185c6a024fe37e54 (patch)
treef74db3acb5334965c5cdaf4d140f39c817310b8c
parentec427567238b5c9302d374c475980c070b42d498 (diff)
add pipe lua modules
-rw-r--r--xmake/core/base/io.lua6
-rw-r--r--xmake/core/base/pipe.lua318
-rw-r--r--xmake/core/sandbox/modules/import/core/base/pipe.lua108
-rw-r--r--xmake/core/sandbox/modules/import/core/base/socket.lua4
4 files changed, 431 insertions, 5 deletions
diff --git a/xmake/core/base/io.lua b/xmake/core/base/io.lua
index 0770436eb..d950c07b0 100644
--- a/xmake/core/base/io.lua
+++ b/xmake/core/base/io.lua
@@ -34,12 +34,12 @@ io._file = _file
io._filelock = _filelock
io._stdfile = io._stdfile or io.stdfile
--- new an file
-function _file.new(filepath, fileref, isstdfile)
+-- new a file
+function _file.new(filepath, cdata, isstdfile)
local file = table.inherit(_file)
file._NAME = path.filename(filepath)
file._PATH = isstdfile and filepath or path.absolute(filepath)
- file._FILE = fileref
+ file._FILE = cdata
setmetatable(file, _file)
return file
end
diff --git a/xmake/core/base/pipe.lua b/xmake/core/base/pipe.lua
new file mode 100644
index 000000000..c16a40bf9
--- /dev/null
+++ b/xmake/core/base/pipe.lua
@@ -0,0 +1,318 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-2020, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file pipe.lua
+--
+
+-- define module
+local pipe = pipe or {}
+local _instance = _instance or {}
+
+-- load modules
+local io = require("base/io")
+local bytes = require("base/bytes")
+local table = require("base/table")
+local string = require("base/string")
+local scheduler = require("base/scheduler")
+
+-- the pipe events, @see tbox/platform/pipe.h
+pipe.EV_READ = 1
+pipe.EV_WRITE = 2
+pipe.EV_CONN = 4
+
+-- new a pipe file
+function _instance.new(cdata, name)
+ local pipefile = table.inherit(_instance)
+ pipefile._NAME = name
+ pipefile._PIPE = cdata
+ setmetatable(pipefile, _instance)
+ return pipefile
+end
+
+-- get the pipe name
+function _instance:name()
+ return self._NAME
+end
+
+-- get poller object type, poller.OT_instance
+function _instance:otype()
+ return 2
+end
+
+-- get cdata of pipe file
+function _instance:cdata()
+ return self._PIPE
+end
+
+-- write data to pipe file
+function _instance:write(data, opt)
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return -1, errors
+ end
+
+ -- data is bytes? unpack the raw address
+ local datasize = #data
+ if type(data) == "table" and data.caddr then
+ datasize = data:size()
+ data = {data = data:caddr(), size = data:size()}
+ end
+
+ -- init start and last
+ opt = opt or {}
+ local start = opt.start or 1
+ local last = opt.last or datasize
+
+ -- check start and last
+ if start > last or start < 1 then
+ return -1, string.format("%s: invalid start(%d) and last(%d)!", self, start, last)
+ end
+
+ -- write it
+ local write = 0
+ local real = 0
+ local wait = false
+ local errors = nil
+ if opt.block then
+ local size = last + 1 - start
+ while start <= last do
+ real, errors = io.pipe_write(self:cdata(), data, start, last)
+ if real > 0 then
+ write = write + real
+ start = start + real
+ wait = false
+ elseif real == 0 and not wait then
+ local events, waiterrs = self:wait(pipe.EV_WRITE, opt.timeout or -1)
+ if events == pipe.EV_WRITE then
+ wait = true
+ else
+ errors = waiterrs
+ break
+ end
+ else
+ break
+ end
+ end
+ if write ~= size then
+ write = -1
+ end
+ else
+ write, errors = io.pipe_write(self:cdata(), data, start, last)
+ if write < 0 and errors then
+ errors = string.format("%s: %s", self, errors)
+ end
+ end
+ return write, errors
+end
+
+-- read data from pipe
+function _instance:read(size, opt)
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return -1, errors
+ end
+
+ -- check size
+ if size == 0 then
+ return 0
+ elseif size == nil or size < 0 then
+ return -1, string.format("%s: invalid size(%d)!", self, size)
+ end
+
+ -- read it
+ opt = opt or {}
+ local read = 0
+ local real = 0
+ local wait = false
+ local data_or_errors = nil
+ if opt.block then
+ local results = {}
+ while read < size do
+ local buff = self:_readbuff()
+ real, data_or_errors = io.pipe_read(self:cdata(), buff:caddr(), math.min(buff:size(), size - read))
+ if real > 0 then
+ read = read + real
+ wait = false
+ table.insert(results, bytes(buff, 1, real))
+ self:_readbuff_clear()
+ elseif real == 0 and not wait then
+ local events, waiterrs = self:wait(pipe.EV_READ, opt.timeout or -1)
+ if events == pipe.EV_READ then
+ wait = true
+ else
+ data_or_errors = waiterrs
+ break
+ end
+ else
+ break
+ end
+ end
+ if read == size then
+ data_or_errors = bytes(results)
+ else
+ read = -1
+ end
+ else
+ local buff = self:_readbuff()
+ read, data_or_errors = io.pipe_read(self:cdata(), buff:caddr(), math.min(buff:size(), size))
+ if read > 0 then
+ data_or_errors = bytes(buff, 1, read)
+ self:_readbuff_clear()
+ end
+ end
+ if read < 0 and data_or_errors then
+ data_or_errors = string.format("%s: %s", self, data_or_errors)
+ end
+ return read, data_or_errors
+end
+
+-- wait pipe events
+function _instance:wait(events, timeout)
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return -1, errors
+ end
+
+ -- wait events
+ local result = -1
+ local errors = nil
+ if scheduler:co_running() then
+ result, errors = scheduler:poller_wait(self, events, timeout or -1)
+ else
+ result, errors = io.pipe_wait(self:cdata(), events, timeout or -1)
+ end
+ if result < 0 and errors then
+ errors = string.format("%s: %s", self, errors)
+ end
+ return result, errors
+end
+
+-- close pipe file
+function _instance:close()
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return false, errors
+ end
+
+ -- cancel pipe events from the scheduler
+ if scheduler:co_running() then
+ ok, errors = scheduler:poller_cancel(self)
+ if not ok then
+ return false, errors
+ end
+ end
+
+ -- close it
+ ok = io.pipe_close(self:cdata())
+ if ok then
+ self._PIPE = nil
+ end
+ return ok
+end
+
+-- get the read buffer
+function _instance:_readbuff()
+ local readbuff = self._READBUFF
+ if not readbuff then
+ readbuff = bytes(8192)
+ self._READBUFF = readbuff
+ end
+ return readbuff
+end
+
+-- clear the read buffer
+function _instance:_readbuff_clear()
+ self._READBUFF = nil
+end
+
+-- ensure the pipe is opened
+function _instance:_ensure_opened()
+ if not self:cdata() then
+ return false, string.format("%s: has been closed!", self)
+ end
+ return true
+end
+
+-- tostring(pipe)
+function _instance:__tostring()
+ return "<pipe: " .. (self:name() or "anonymous") .. ">"
+end
+
+-- gc(pipe)
+function _instance:__gc()
+ if self:cdata() and io.pipe_close(self:cdata()) then
+ self._PIPE = nil
+ end
+end
+
+-- open a named pipe file
+--
+-- 1. named pipe (server-side):
+--
+-- local pipe, errors = pipe.open("xxx")
+-- if pipe then
+-- if pipe:connect() then
+-- pipe:read(...)
+-- end
+-- pipe:close()
+-- end
+--
+-- 2. named pipe (client-side):
+--
+-- local pipe, errors = pipe.open("xxx")
+-- if pipe then
+-- pipe:write(...)
+-- pipe:close()
+-- end
+--
+function pipe.open(name, buffsize)
+
+ local pipefile, errors = io.pipe_open(name, buffsize or 0)
+ if pipefile then
+ return _pipe.new(pipefile, name)
+ else
+ return nil, string.format("failed to open pipe: %s, error: %s", name, errors or "unknown")
+ end
+end
+
+-- open anonymous pipe pair
+--
+-- local rpipe, wpipe, errors = pipe.openpair()
+-- rpipe:read(...)
+-- wpipe:write(...)
+--
+function pipe.openpair(buffsize)
+
+ -- open anonymous pipe pair
+ local rpipefile, wpipefile, errors = io.pipe_openpair(buffsize or 0)
+ if rpipefile and wpipefile then
+ return _pipe.new(rpipefile), _pipe.new(wpipefile)
+ else
+ return nil, nil, string.format("failed to open anonymous pipe pair, error: %s", errors or "unknown")
+ end
+end
+
+-- return module
+return pipe
diff --git a/xmake/core/sandbox/modules/import/core/base/pipe.lua b/xmake/core/sandbox/modules/import/core/base/pipe.lua
new file mode 100644
index 000000000..8b15bec8c
--- /dev/null
+++ b/xmake/core/sandbox/modules/import/core/base/pipe.lua
@@ -0,0 +1,108 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-2020, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file pipe.lua
+--
+
+-- load modules
+local utils = require("base/utils")
+local pipe = require("base/pipe")
+local string = require("base/string")
+local raise = require("sandbox/modules/raise")
+
+-- define module
+local sandbox_core_base_pipe = sandbox_core_base_pipe or {}
+local sandbox_core_base_pipe_instance = sandbox_core_base_pipe_instance or {}
+
+-- export the pipe events
+sandbox_core_base_pipe.EV_READ = pipe.EV_READ
+sandbox_core_base_pipe.EV_WRITE = pipe.EV_WRITE
+sandbox_core_base_pipe.EV_CONN = pipe.EV_CONN
+
+-- wrap pipe file
+function _pipefile_wrap(pipefile)
+
+ -- hook pipe interfaces
+ local hooked = {}
+ for name, func in pairs(sandbox_core_base_pipe_instance) do
+ if not name:startswith("_") and type(func) == "function" then
+ hooked["_" .. name] = pipefile["_" .. name] or pipefile[name]
+ hooked[name] = func
+ end
+ end
+ for name, func in pairs(hooked) do
+ pipefile[name] = func
+ end
+ return pipefile
+end
+
+-- wait pipe events
+function sandbox_core_base_pipe_instance.wait(pipefile, events, timeout)
+ local events, errors = pipefile:_wait(events, timeout)
+ if events < 0 and errors then
+ raise(errors)
+ end
+ return events
+end
+
+-- write data to pipe file
+function sandbox_core_base_pipe_instance.write(pipefile, data, opt)
+ local real, errors = pipefile:_write(data, opt)
+ if real < 0 and errors then
+ raise(errors)
+ end
+ return real
+end
+
+-- read data from pipe file
+function sandbox_core_base_pipe_instance.read(pipefile, size, opt)
+ local real, data_or_errors = pipefile:_read(size, opt)
+ if real < 0 and data_or_errors then
+ raise(data_or_errors)
+ end
+ return real, data_or_errors
+end
+
+-- close pipe file
+function sandbox_core_base_pipe_instance.close(pipefile)
+ local ok, errors = pipefile:_close()
+ if not ok then
+ raise(errors)
+ end
+end
+
+-- open a named pipe file
+function sandbox_core_base_pipe.open(buffsize)
+ local pipefile, errors = pipe.open(buffsize)
+ if not pipefile then
+ raise(errors)
+ end
+ return _pipefile_wrap(pipefile)
+end
+
+-- open a anonymous pipe pair
+function sandbox_core_base_pipe.openpair(buffsize)
+ local rpipefile, wpipefile, errors = pipe.openpair(buffsize)
+ if not rpipefile or not wpipefile then
+ raise(errors)
+ end
+ return _pipefile_wrap(rpipefile), _pipefile_wrap(wpipefile)
+end
+
+-- return module
+return sandbox_core_base_pipe
+
diff --git a/xmake/core/sandbox/modules/import/core/base/socket.lua b/xmake/core/sandbox/modules/import/core/base/socket.lua
index 1198fba55..c7fd0fed5 100644
--- a/xmake/core/sandbox/modules/import/core/base/socket.lua
+++ b/xmake/core/sandbox/modules/import/core/base/socket.lua
@@ -40,8 +40,8 @@ sandbox_core_base_socket.IPV6 = socket.IPV6
-- export the socket events
sandbox_core_base_socket.EV_RECV = socket.EV_RECV
sandbox_core_base_socket.EV_SEND = socket.EV_SEND
-sandbox_core_base_socket.EV_CONN = socket.EV_SEND
-sandbox_core_base_socket.EV_ACPT = socket.EV_RECV
+sandbox_core_base_socket.EV_CONN = socket.EV_CONN
+sandbox_core_base_socket.EV_ACPT = socket.EV_ACPT
-- wrap socket
function _socket_wrap(sock)