summaryrefslogtreecommitdiff
path: root/xmake/core/base/private/pipe_event.lua
blob: 8d12787666bf318bc17496a1e66f20ede3be0d1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
--!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-present, Xmake Open Source Community.
--
-- @author      ruki
-- @file        pipe_event.lua
--

-- define module
local pipe_event = pipe_event or {}
local _instance = _instance or {}

-- load modules
local pipe   = require("base/pipe")
local libc   = require("base/libc")
local bytes  = require("base/bytes")
local table  = require("base/table")

function _instance.new(name)
    local event = table.inherit(_instance)
    event._PIPE_EVENT = true
    event._BUFFER = bytes(2)
    event._NAME = name or "pipe_event"
    local reader, writer, errors = pipe.openpair("AA")
    if not reader or not writer then
        if reader then reader:close() end
        if writer then writer:close() end
        return nil, errors or "failed to open pipe"
    end
    event._READER = reader
    event._WRITER = writer
    event._WRITER_PTR = nil
    return event
end

function _instance:name()
    return self._NAME
end

function _instance:post()
    local writer = self._WRITER
    if not writer then
        return false, "pipe event writer closed"
    end
    local ok, errors = writer:write("1", {block = true})
    if ok < 0 then
        return false, errors or "pipe event post failed"
    end
    writer:close()
    self._WRITER = nil
    self._WRITER_PTR = nil
    return true
end

function _instance:wait(timeout)
    if not self._READER then
        return false, "pipe event reader closed"
    end
    local read, read_errors = self._READER:read(self._BUFFER, 1, {block = true, timeout = timeout})
    if read < 0 then
        return false, read_errors
    end
    return read
end

function _instance:close()
    if self._READER then
        self._READER:close()
    end
    if self._WRITER then
        self._WRITER:close()
    end
    self._READER = nil
    self._WRITER = nil
    self._WRITER_PTR = nil
end

-- return pipe cdata for serialization (writer pointer is stable for passing across threads)
function _instance:cdata()
    if self._WRITER then
        return self._WRITER:cdata()
    end
    return self._WRITER_PTR
end

function _instance:__gc()
    self:close()
end

function _instance:_serialize()
    if not self._WRITER and self._WRITER_PTR then
        return {ptr = self._WRITER_PTR, name = self:name()}
    end
    if not self._WRITER then
        return nil
    end
    local ptr = libc.dataptr(self._WRITER:cdata(), {ffi = false})
    if not ptr then
        return nil
    end
    self._WRITER._PIPE = nil
    self._WRITER = nil
    self._WRITER_PTR = ptr
    return {ptr = ptr, name = self:name()}
end

function _instance:_deserialize(data)
    if not data or not data.ptr then
        return false, "invalid pipe event data"
    end
    self:close()
    local writer = pipe.new(libc.ptraddr(data.ptr, {ffi = false}))
    if not writer then
        return false, "invalid pipe pointer"
    end
    self._NAME = data.name or self._NAME or "pipe_event"
    self._WRITER = writer
    self._WRITER_PTR = data.ptr
    return true
end

function pipe_event.new(name)
    return _instance.new(name)
end

return pipe_event