-
Notifications
You must be signed in to change notification settings - Fork 40
Minimal subprocess API #1146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Minimal subprocess API #1146
Conversation
76e0e94 to
2987f2a
Compare
7af7036 to
3d62f32
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
11d05e8 to
76c9863
Compare
jiribenes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot attest to the LLVM version, but I think I sort-of understand the JS version and it looks alright.
I am fine with this being merged as-is and figuring out a more user-friendly API later (once I actually try to use it, that is). In general, I think it's a good idea to merge stdlib stuff earlier, so that we (and the students) can use it and see what's good and what's not good. :)
jiribenes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's just my general questions / comments for the JS version
| let old = ${opts}; | ||
| old.stdio[1] = 'pipe'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks mutable to me.
Couldn't there be an issue when we try to reuse existing SpawnOptions?
Should we instead copy opts here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is mutable. I'm still unsure how an API that is both safe and does not extensively copy things on the C/JS side.
Having SpawnOptions be a extern interface (and then explicitly mutated) would be more ideal but I'm not sure how to pass extern interfaces over the FFI boundary.
I.e. something like spawn(...){ options: {SpawnOptions} => Unit }: ...
| old.onSpawn = function(p) { | ||
| oldSpawn(p); | ||
| p.stdout.on('data', (chunk) => { | ||
| $effekt.runToplevel((ks, k) => (${callback})(chunk, ks, k)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this runTopLevel or run? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a callback called from the JS side, so from somewhere in the event loop.
AFAICT, this means runToplevel
| p.on('spawn', () => { | ||
| $effekt.runToplevel((ks, k) => (${callback})(p.stdin, ks, k)); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the process fail to spawn at all? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might. This is not currently handeled (but could, and probably should, be)
| ret %Pos %opts | ||
| """ | ||
| extern def write(to: WritableStream, s: String) at io: Unit = | ||
| jsNode """${to}.write(${s})""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This likely works now, but NodeJS can (and will) sometimes return false, and then we should be more async and wait for the 'drain' event.
https://nodejs.org/api/stream.html#writablewritechunk-encoding-callback
| jsNode """$effekt.capture(k => { | ||
| let p = spawn(${cmd}, ${args}, ${options}); | ||
| ${options}.onSpawn(p); | ||
| p.on('close', (exitcode, sig) => { k(exitcode) }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ignores situations in which the child process is terminated.
I thought we had a string->number map for this somewhere in io/error, but I couldn't find it...
Anyways, here's something like what could be there (but I don't like the implementation)
p.on('close', (exitcode, sig) => {
if (sig) {
const sigMap = {
'SIGHUP':1, 'SIGINT':2, 'SIGQUIT':3, 'SIGILL':4, 'SIGTRAP':5,
'SIGABRT':6, 'SIGBUS':7, 'SIGFPE':8, 'SIGKILL':9, 'SIGUSR1':10,
'SIGSEGV':11, 'SIGUSR2':12, 'SIGPIPE':13, 'SIGALRM':14, 'SIGTERM':15
};
k(128 + (sigMap[sig] || 15)); // '15' is default, this is obviously weird
} else {
k(exitcode || 0); // the `|| 0` is just defensive here
}
});There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can reasonably from FFI, it would also be nice to just do signal('SIGHUP') or sim. instead of encoding it into an int 🤔
Low-level-ish process api. Allows to:
The API uses a (mutable) options object which allows to set those callbacks.
Fixes #1080.