Skip to content
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

Initial implementation of general user land signal handling (unix only) #2735

Closed
wants to merge 4 commits into from

Conversation

kevinkassimo
Copy link
Contributor

@kevinkassimo kevinkassimo commented Aug 6, 2019

Implement general signal handling sigaction(signo, handler).

Try it out by pressing Ctrl-C when running this script (wait for TS compiler to finish compile first, since it is not immune to SIGINT):

Deno.sigaction(Deno.Signal.SIGINT, () => {
  console.log(">> SIGINT caught (1)");
});

Deno.sigaction(Deno.Signal.SIGINT, () => {
  console.log(">> SIGINT caught (2)");
});

console.log("sigaction() DEMO starts");

setTimeout(() => {
  console.log("DONE");
}, 5000)

Notice that signal handler would not block script from exiting after timeout, and multiple handlers could be registered.

Achieved by implementing optional Op type which does not prevent process exit.

Code is hacked up so needs much polishing after confirming the approach. API design feedback also needed.

Tests needed. Added basic unit test

@kevinkassimo kevinkassimo changed the title [NEED TESTS] Initial implementation of general user land signal handling [NEED TESTS] Initial implementation of general user land signal handling (unix only) Aug 6, 2019
@ry ry requested a review from piscisaureus August 6, 2019 13:22
@@ -36,6 +36,7 @@ pub type OpAsyncFuture<E> = Box<dyn Future<Item = Buf, Error = E> + Send>;
pub enum Op<E> {
Sync(Buf),
Async(OpAsyncFuture<E>),
AsyncOptional(OpAsyncFuture<E>),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm - what is the purpose of this? I'm not open to adding to this enum...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a marker such that when later registering the op we can tell if the op is optional and should not block event loop exit (by later incrementing optional_ops_count on Isolate). It is used since I don't think there is some easier way to pass this bit of information down other than with a new enum (otherwise we need to change the signature of Async)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The design of signal is by first calling SignalListen to add a signal stream to resources. Then signal is actually handled by repeatedly calling SignalPoll to wait for next poll of signal -- somewhat similar to what we do with TcpStream read. But unlike reading from TcpStream, the task registered by SignalPoll is optional, such that if all other required tasks has finished (pending_ops only contains optional ops), program would exit right away.

@@ -176,6 +176,48 @@ pub fn dispatch_all_legacy(
);
Op::Async(result_fut)
}
Ok(Op::AsyncOptional(fut)) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain? I don't get it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually act almost the same as Op::Async for this part, only that the result wrapping enum is different. I'll see a way if I could avoid duplicate code here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this extra variant?
To make sure the process will exit even when the future is not ready?
I'd suggest to use just Op::Async() and have a separate pending-op count rather than using pending_ops.len().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm misunderstanding, but if both are marked as Op::Async I don't think Isolate will be able to tell if a future is optional when polling?

I kind of want to avoid manipulating Isolate directly from cli (and I'm not quite sure if changing return types of op selectors is a good idea). Also not sure about the counter part since no differentiation between things like enum types mean there is no way I could just decrement for required futures, unless we want to chain another step after the user provided future -- and thus also need to make the counter atomic

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need something like uv_unref ... I’m going to punt on this problem until next week - not sure what the right way to handle this is.

@kevinkassimo kevinkassimo changed the title [NEED TESTS] Initial implementation of general user land signal handling (unix only) Initial implementation of general user land signal handling (unix only) Aug 7, 2019
@kevinkassimo kevinkassimo mentioned this pull request Sep 13, 2019
@kitsonk
Copy link
Contributor

kitsonk commented Sep 13, 2019

My biggest feedback is I am personally not convinced by sigaction. Why wouldn't Deno.signal do? To me the intent would be clear. If not, than something like onSignal.

@kevinkassimo
Copy link
Contributor Author

@kitsonk Deno.Signal is currently the enum of the signal numbers (e.g. Deno.Signal.SIGSEGV). I am worried that introducing another Deno.signal of lowercase would be confusing.

Also Deno.signal sounds more like op to send a signal ("signal a process to handle something") instead of receiving (which we currently have as Deno.kill. I know Python uses the name signal.signal but I still found it quite unintuitive). Both kill and sigaction might be confusing to people with pure frontend background, but they do comply with the Unix traditions...

That being said, except for that I don't think Deno.signal would be good name for registering signal handlers, I am okay with most other names or other API design choices. The interface I showed there is just an POC and for feedback purposes.

@ry
Copy link
Member

ry commented Sep 13, 2019

I think we should just stick with the POSIX names to avoid confusion. Most people should not need to ever look at signal stuff.

That said, the issue with this patch is rather the lack of uv_unref() in tokio...

@ry
Copy link
Member

ry commented Oct 2, 2019

Closing because this is old. We still don't have a solution to uv_unref...

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.

None yet

4 participants