diff options
| author | ruki <[email protected]> | 2020-01-31 23:24:01 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2020-01-31 14:24:07 +0800 |
| commit | 14bb17934b8acf2a0633f8af185c6a024fe37e54 (patch) | |
| tree | f74db3acb5334965c5cdaf4d140f39c817310b8c | |
| parent | ec427567238b5c9302d374c475980c070b42d498 (diff) | |
add pipe lua modules
| -rw-r--r-- | xmake/core/base/io.lua | 6 | ||||
| -rw-r--r-- | xmake/core/base/pipe.lua | 318 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/pipe.lua | 108 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/socket.lua | 4 |
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) |
