Class: Expect::SessionResources
- Inherits:
-
Object
- Object
- Expect::SessionResources
- Defined in:
- lib/expect/session_resources.rb
Overview
独立保存句柄、PID 和日志所有权,让终结器无需直接捕获会话即可清理遗弃资源。 IO 是否关闭与子进程是否退出分别记录;不能仅凭句柄状态清空 PID 或伪造退出状态。
Instance Attribute Summary collapse
-
#own ⇒ Object
readonly
Returns the value of attribute own.
-
#owned_log ⇒ Object
owned_log 只保存库打开的文件;借用的 IO/日志回调留在会话中,不能成为终结器的引用根。.
-
#owner ⇒ Object
readonly
Returns the value of attribute owner.
-
#pid ⇒ Object
owned_log 只保存库打开的文件;借用的 IO/日志回调留在会话中,不能成为终结器的引用根。.
-
#reader ⇒ Object
readonly
Returns the value of attribute reader.
-
#slave ⇒ Object
readonly
Returns the value of attribute slave.
-
#status ⇒ Object
owned_log 只保存库打开的文件;借用的 IO/日志回调留在会话中,不能成为终结器的引用根。.
-
#writer ⇒ Object
readonly
Returns the value of attribute writer.
Class Method Summary collapse
-
.close_handles(*handles) ⇒ Object
账本尚未建立时也能释放局部 IO;不依赖完整会话,也不调用无效参数上的用户方法。.
-
.finalizer(resources) ⇒ Object
构造只持有资源对象的终结回调,避免闭包中的 self 绑定到会话而妨碍回收。.
Instance Method Summary collapse
-
#close_handles ⇒ Object
只关闭由本库拥有的 IO;借用的 reader、writer 由调用方管理。 常规关闭错误延后到所有句柄尝试完再抛出,失败句柄仍留在账本内供下一次关闭重试。.
-
#finalize ⇒ Object
GC 兜底关闭所属句柄和日志,并强制终止尚存活的子进程;不执行软关闭等待。.
-
#initialize(reader, writer:, slave: nil, own: false) ⇒ SessionResources
constructor
记录创建资源的进程;fork 后的副本不能向父进程拥有的子进程发信号。.
-
#reap ⇒ Object
非阻塞回收直属子进程,缓存 Process::Status,成功后清空 PID 以支持重复查询。.
Constructor Details
#initialize(reader, writer:, slave: nil, own: false) ⇒ SessionResources
记录创建资源的进程;fork 后的副本不能向父进程拥有的子进程发信号。
12 13 14 15 16 17 18 |
# File 'lib/expect/session_resources.rb', line 12 def initialize(reader, writer:, slave: nil, own: false) @reader = reader @writer = writer @slave = slave @own = own @owner = Process.pid end |
Instance Attribute Details
#own ⇒ Object (readonly)
Returns the value of attribute own.
9 10 11 |
# File 'lib/expect/session_resources.rb', line 9 def own @own end |
#owned_log ⇒ Object
owned_log 只保存库打开的文件;借用的 IO/日志回调留在会话中,不能成为终结器的引用根。
8 9 10 |
# File 'lib/expect/session_resources.rb', line 8 def owned_log @owned_log end |
#owner ⇒ Object (readonly)
Returns the value of attribute owner.
9 10 11 |
# File 'lib/expect/session_resources.rb', line 9 def owner @owner end |
#pid ⇒ Object
owned_log 只保存库打开的文件;借用的 IO/日志回调留在会话中,不能成为终结器的引用根。
8 9 10 |
# File 'lib/expect/session_resources.rb', line 8 def pid @pid end |
#reader ⇒ Object (readonly)
Returns the value of attribute reader.
9 10 11 |
# File 'lib/expect/session_resources.rb', line 9 def reader @reader end |
#slave ⇒ Object (readonly)
Returns the value of attribute slave.
9 10 11 |
# File 'lib/expect/session_resources.rb', line 9 def slave @slave end |
#status ⇒ Object
owned_log 只保存库打开的文件;借用的 IO/日志回调留在会话中,不能成为终结器的引用根。
8 9 10 |
# File 'lib/expect/session_resources.rb', line 8 def status @status end |
#writer ⇒ Object (readonly)
Returns the value of attribute writer.
9 10 11 |
# File 'lib/expect/session_resources.rb', line 9 def writer @writer end |
Class Method Details
.close_handles(*handles) ⇒ Object
账本尚未建立时也能释放局部 IO;不依赖完整会话,也不调用无效参数上的用户方法。
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/expect/session_resources.rb', line 27 def self.close_handles(*handles) # 初始化校验失败时可能含无效参数,只关闭真实 IO;PTY 读写端也需要去重。 failure = nil handles.grep(IO).uniq(&:object_id).each do |io| io.close unless io.closed? rescue IOError, SystemCallError => error failure ||= error end raise failure if failure end |
.finalizer(resources) ⇒ Object
构造只持有资源对象的终结回调,避免闭包中的 self 绑定到会话而妨碍回收。
73 74 75 |
# File 'lib/expect/session_resources.rb', line 73 def self.finalizer(resources) proc { resources.finalize } end |
Instance Method Details
#close_handles ⇒ Object
只关闭由本库拥有的 IO;借用的 reader、writer 由调用方管理。 常规关闭错误延后到所有句柄尝试完再抛出,失败句柄仍留在账本内供下一次关闭重试。
22 23 24 |
# File 'lib/expect/session_resources.rb', line 22 def close_handles self.class.close_handles(reader, writer, slave) if own end |
#finalize ⇒ Object
GC 兜底关闭所属句柄和日志,并强制终止尚存活的子进程;不执行软关闭等待。
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/expect/session_resources.rb', line 55 def finalize return unless owner == Process.pid begin close_handles ensure begin owned_log.close if owned_log && !owned_log.closed? ensure # 每个阶段独立收尾;句柄或日志关闭失败不能跳过进程回收。 finalize_child end end rescue IOError, SystemCallError nil end |
#reap ⇒ Object
非阻塞回收直属子进程,缓存 Process::Status,成功后清空 PID 以支持重复查询。
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/expect/session_resources.rb', line 39 def reap return status unless pid && owner == Process.pid if (reaped = Process.waitpid2(pid, Process::WNOHANG)) @status = reaped.last @pid = nil end status rescue Errno::ECHILD # 子进程可能已被调用方或其他线程回收,不再保留可能被系统复用的 PID。 # 无法获取别人已取走的 Process::Status,保留未知状态而不是推断成功或失败。 @pid = nil status end |