mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-10 04:40:25 +01:00
Prevent exit callback instance leaks
De-references pty_baton's exit callback after it is called so it can be automatically released, preventing leaked instances. Adds basic implementation for Pipe's get_status() method and forces PTY to wait for child process to exit to ensure exit callback is cleaned up. Adds a test to check that exit callback is still called as usual.
This commit is contained in:
parent
38927e0a3e
commit
0ae1d80abb
5 changed files with 24 additions and 4 deletions
|
@ -31,6 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
`pipe.close()` method of the gdnative library is now registered.
|
||||
- Fixed 'Condition "!obj" is true.' error that would often print to console when
|
||||
closing terminals in the Terminal panel of the editor plugin.
|
||||
- Fixed leaked instances that would occur when PTY exited but child process was still
|
||||
running.
|
||||
|
||||
|
||||
## [v2.0.0](https://github.com/lihop/godot-xterm/compare/v1.2.1...v2.0.0) - 2021-07-25
|
||||
|
|
|
@ -445,8 +445,10 @@ static void pty_after_waitpid(uv_async_t *async) {
|
|||
|
||||
Array argv = Array::make(baton->exit_code, baton->signal_code);
|
||||
|
||||
if (baton->cb != nullptr && baton->cb->is_valid())
|
||||
if (baton->cb != nullptr && baton->cb->is_valid()) {
|
||||
baton->cb->call_funcv(argv);
|
||||
baton->cb = (Ref<FuncRef>)nullptr;
|
||||
}
|
||||
|
||||
uv_close((uv_handle_t *)async, pty_after_close);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ void Pipe::_register_methods() {
|
|||
register_method("poll", &Pipe::_poll_connection);
|
||||
register_method("open", &Pipe::open);
|
||||
register_method("write", &Pipe::write);
|
||||
register_method("get_status", &Pipe::get_status);
|
||||
register_method("close", &Pipe::close);
|
||||
|
||||
register_signal<Pipe>("data_received", "data",
|
||||
|
@ -56,11 +57,12 @@ godot_error Pipe::open(int fd, bool ipc = false) {
|
|||
RETURN_IF_UV_ERR(
|
||||
uv_read_start((uv_stream_t *)&handle, _alloc_buffer, _read_cb));
|
||||
|
||||
status = 1;
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
void Pipe::close() {
|
||||
uv_close((uv_handle_t *)&handle, NULL);
|
||||
uv_close((uv_handle_t *)&handle, _close_cb);
|
||||
uv_run(uv_default_loop(), UV_RUN_NOWAIT);
|
||||
}
|
||||
|
||||
|
@ -84,6 +86,8 @@ godot_error Pipe::write(String p_data) {
|
|||
}
|
||||
|
||||
int Pipe::get_status() {
|
||||
if (!uv_is_active((uv_handle_t *)&handle))
|
||||
status = 0;
|
||||
_poll_connection();
|
||||
return status;
|
||||
}
|
||||
|
@ -120,3 +124,8 @@ void _alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
|
|||
buf->base = (char *)malloc(suggested_size);
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
void _close_cb(uv_handle_t *handle) {
|
||||
Pipe *pipe = static_cast<Pipe *>(handle->data);
|
||||
pipe->status = 0;
|
||||
}
|
|
@ -96,9 +96,10 @@ func open(cols: int = DEFAULT_COLS, rows: int = DEFAULT_ROWS) -> Array:
|
|||
|
||||
|
||||
func _exit_tree():
|
||||
_exit_cb = null
|
||||
if _pid > 1:
|
||||
LibuvUtils.kill(_pid, Signal.SIGHUP)
|
||||
while _pipe.get_status() != 0:
|
||||
continue
|
||||
|
||||
|
||||
func _on_pipe_data_received(data):
|
||||
|
|
|
@ -73,6 +73,12 @@ func test_closes_pty_on_exit():
|
|||
assert_eq(new_num_pts, num_pts)
|
||||
|
||||
|
||||
func test_emits_exited_signal_when_child_process_exits():
|
||||
pty.call_deferred("fork", "exit")
|
||||
yield(yield_to(pty, "exited", 1), YIELD)
|
||||
assert_signal_emitted(pty, "exited")
|
||||
|
||||
|
||||
class Helper:
|
||||
static func _get_pts() -> Array:
|
||||
assert(false, "Abstract method")
|
||||
|
|
Loading…
Reference in a new issue