Skip to content

Lazy initialize process redirection channels - #576

Open
Guest0x0 wants to merge 3 commits into
mainfrom
lazy-init-process-redirect-pipe
Open

Lazy initialize process redirection channels#576
Guest0x0 wants to merge 3 commits into
mainfrom
lazy-init-process-redirect-pipe

Conversation

@Guest0x0

Copy link
Copy Markdown
Collaborator

Previously, redirection pipes created by @process.read_from_process, @process.redirect_to_file etc. are initialized immediately on creation time. As a result, if the program fail before passing the pipes to a child process, the pipes will leak. So users often need to manually insert errdefer pipe.close() to avoid leak.

This PR modifies the semantic by lazy-initialize the pipes inside @process.run/@process.spawn. This way, if the program fail or jump away before using the pipe, the pipe is not created yet and hence will not leak. Under this new semantic, the child end of a read_from_process(shared=false)/write_to_process pipe never need manual closing. @process.redirect_to_file(shared=false) and @process.redirect_from_file work similarly.

@process.pipe() is way more trickier, though. There are two children process involved in @process.pipe(). So the full sequence is:

@process.pipe()
other setup #1
spawn child #1
other setup #2
spawn child #2

In this PR, pipe initialization is delayed to spawn child #1, so failure in other setup #1 will not result in resource leak. However, if other setup #2 failed, there is no way to close the pipe automatically. So the user need to either avoid other setup #2 by reordering code, or handle failure in other setup #2 manually. Failure in spawn child #1 also has special handling for @pipe.pipe(). If spawn child #1 failed, both ends of the pipe will be closed.

Under the new semantic, code in @shell can be simplified, eliminating unnecessary cleanup and book-keeping.

I am not sure if this PR should be merged, though. The lazy initialization logic is quite complex, especially in the sharing case. For example, users may read from/write to/close the pipe before it is initialized, and the redirection logic need to handle various kinds of race condition properly. I think this reveals a real weakness in current @process API design. When we merge moonbitlang/async into moonbitlang/core in the future, perhaps we can re-design the process API to avoid these lifetime problems. No concrete plan yet, though.

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 1098

Coverage decreased (-0.3%) to 77.967%

Details

  • Coverage decreased (-0.3%) from the base build.
  • Patch coverage: 35 uncovered changes across 3 files (110 of 145 lines covered, 75.86%).
  • 1 coverage regression across 1 file.

Uncovered Changes

File Changed Covered %
src/process/redirect.mbt 103 70 67.96%
src/lazy_init.mbt 4 3 75.0%
src/os_error/error.mbt 4 3 75.0%
Total (6 files) 145 110 75.86%

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
src/tls/transport.mbt 1 83.33%

Coverage Stats

Coverage Status
Relevant Lines: 5410
Covered Lines: 4218
Line Coverage: 77.97%
Coverage Strength: 11089.76 hits per line

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants