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

trap ctrl-C in the repl #26

Closed
StefanKarpinski opened this issue May 29, 2011 · 14 comments
Closed

trap ctrl-C in the repl #26

StefanKarpinski opened this issue May 29, 2011 · 14 comments
Assignees

Comments

@StefanKarpinski
Copy link
Member

Ctrl-C currently kills the repl, which is very annoying. It should abort the current computation as quickly as possible.

@ghost ghost assigned StefanKarpinski May 29, 2011
@JeffBezanson
Copy link
Member

Is there an efficient and reliable way to do this? Continuing after handling an asynchronous signal can leave the system in an inconsistent state.

@JeffBezanson
Copy link
Member

OK, the only thing I can think of is to block SIGINT around anything that temporarily violates invariants.

@StefanKarpinski
Copy link
Member Author

Either that or set a flag and check it at various safe checkpoints. This is not just a repl issue: any "real" programming langage needs to be able to trap and handle signals reliably. Maybe we can look into how other languages handle this.

@JeffBezanson
Copy link
Member

There is no shortage of debate around asynchronous signals (e.g. FPE, SEGV, INT). Everybody wants to trap them and handle them gracefully but POSIX simply won't let you do it. Of course everybody does it anyway and it usually works.
Setting a flag is one of the safer approaches, but it isn't good enough. If we want to be able to break out of "while true end" then we have to check the flag before every backward branch.

@StefanKarpinski
Copy link
Member Author

Would blocking signals during the critical sections (i.e. when the process could be left in an incoherent state) solve the problem? Doing some reading, it seems that POSIX signals sent while signals are blocked should be delivered immediately after the signals become unblocked.

@JeffBezanson
Copy link
Member

Maybe. We have relatively few places that do non-atomic updates to global state, but I would worry about library calls like malloc().
This technique looks like a good way to deal with this with low overhead:
http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_21.html#SEC375
We could wrap malloc with this, but a user might still call the native malloc.
We could at least protect julia's internal state to avoid serious corruption. And we could provide a macro like @sigatomic for user code. I think we'd have to use it in several places in multi.j since the scheduler has global state.
Ultimately these things can't really be left up to the language, because users need to decide if and how they will handle signals, and what kind of overhead they are willing to accept.

@StefanKarpinski
Copy link
Member Author

Can we provide our own malloc so that users and libraries can't call libc malloc directly?

Agreed that you have to let users decide ultimately, but the default should be safe first, and hopefully also with relatively little overhead. The @sigatomic macro is an excellent addition. Most people will never have to use it, but we can provide the ability, which is key.

@JeffBezanson
Copy link
Member

Safe yes, but against what? Handling signals is not part of most applications' normal operation. I hate to add overhead just for the 1 time a week you want to hit ctrl-C, but I guess it can't be helped and hopefully won't even be measurable.
I don't think we should bother much about what external native code does, since realistically you're not going to be able to make everything safe.
I glanced at the ruby source, and it seems to use the same trick I linked to above, with critical sections around various things in the code.

@StefanKarpinski
Copy link
Member Author

Ruby handles these things well, whereas Perl, for example is notoriously bad at it (although fast).

@ViralBShah
Copy link
Member

I think it is important to architect the system for ctrl-c. It's a real pain in the cloud environment, if you are in a native code computation, and ctrl-c just doesn't become effective. I would even be ok with leaking memory, as a user. I used to frequently want to hit ctrl-c when using Star-P, and it was really painful as it just didn't do anything useful.

Also, I don't think ctrl-c should quit the client. That is what ctrl-d does.

@JeffBezanson
Copy link
Member

Agree --- even though I don't really believe in ctrl-c, it's one of those perceptual things that people expect and just feels nice.
Parallel ctrl-c is certainly interesting. We could use ssh to remotely run kill -SIGINT of a hung julia process.

@ghost ghost assigned JeffBezanson Jun 28, 2011
JeffBezanson added a commit that referenced this issue Jul 10, 2011
a few more things probably need to be made signal safe, but it is usable
now with the caveat that you shouldn't trust the system too much after
hitting ctrl-C.
@StefanKarpinski
Copy link
Member Author

This issue seems adequately addressed to me at this point. Can we close it?

@JeffBezanson
Copy link
Member

We probably need more signal-atomic sections. I haven't dealt with malloc, free, and realloc, and task switching, and who knows, maybe more. It's annoying though because all those sigatomic sections are like lisa simpson's tiger-repelling rock; you can't really be sure it's working.

@StefanKarpinski
Copy link
Member Author

It's annoying though because all those sigatomic sections are like lisa simpson's tiger-repelling rock; you can't really be sure it's working.

Brilliant analogy.

cmcaine pushed a commit to cmcaine/julia that referenced this issue Sep 24, 2020
Fix indentation to follow guide rules
topolarity added a commit to topolarity/julia that referenced this issue Jun 27, 2023
It's possible for PiNodes to effectively imply statically the condition
of a Core.ifelse. For example:
```julia
    23 ─ %60  = Core.ifelse(%47, false, true)::Bool
    │    %61  = Core.ifelse(%47, %58, false)::Union{Missing, Bool}
    25 ─        goto JuliaLang#27 if not %60
    26 ─ %65  = π (%61, Bool)
    └───        ...
```

In basic block JuliaLang#26, the PiNode gives us enough information to conclude
that `%47 === false` if control flow reaches that point. The previous
code incorrectly assumed that this kind of pruning would only be done
for PhiNodes.

Resolves JuliaLang#50276.
topolarity added a commit to topolarity/julia that referenced this issue Jun 27, 2023
It's possible for PiNodes to effectively imply statically the condition
of a Core.ifelse. For example:
```julia
    23 ─ %60  = Core.ifelse(%47, false, true)::Bool
    │    %61  = Core.ifelse(%47, %58, false)::Union{Missing, Bool}
    25 ─        goto JuliaLang#27 if not %60
    26 ─ %65  = π (%61, Bool)
    └───        ...
```

In basic block JuliaLang#26, the PiNode gives us enough information to conclude
that `%47 === false` if control flow reaches that point. The previous
code incorrectly assumed that this kind of pruning would only be done
for PhiNodes.

Resolves JuliaLang#50276.
topolarity added a commit to topolarity/julia that referenced this issue Jun 28, 2023
It's possible for PiNodes to effectively imply statically the condition
of a Core.ifelse. For example:
```julia
    23 ─ %60  = Core.ifelse(%47, false, true)::Bool
    │    %61  = Core.ifelse(%47, %58, false)::Union{Missing, Bool}
    25 ─        goto JuliaLang#27 if not %60
    26 ─ %65  = π (%61, Bool)
    └───        ...
```

In basic block JuliaLang#26, the PiNode gives us enough information to conclude
that `%47 === false` if control flow reaches that point. The previous
code incorrectly assumed that this kind of pruning would only be done
for PhiNodes.

Resolves JuliaLang#50276.
topolarity added a commit to topolarity/julia that referenced this issue Jun 28, 2023
It's possible for PiNodes to effectively imply statically the condition
of a Core.ifelse. For example:
```julia
    23 ─ %60  = Core.ifelse(%47, false, true)::Bool
    │    %61  = Core.ifelse(%47, %58, false)::Union{Missing, Bool}
    25 ─        goto JuliaLang#27 if not %60
    26 ─ %65  = π (%61, Bool)
    └───        ...
```

In basic block JuliaLang#26, the PiNode gives us enough information to conclude
that `%47 === false` if control flow reaches that point. The previous
code incorrectly assumed that this kind of pruning would only be done
for PhiNodes.

Resolves JuliaLang#50276.
topolarity added a commit to topolarity/julia that referenced this issue Jun 28, 2023
It's possible for PiNodes to effectively imply statically the condition
of a Core.ifelse. For example:
```julia
    23 ─ %60  = Core.ifelse(%47, false, true)::Bool
    │    %61  = Core.ifelse(%47, %58, false)::Union{Missing, Bool}
    25 ─        goto JuliaLang#27 if not %60
    26 ─ %65  = π (%61, Bool)
    └───        ...
```

In basic block JuliaLang#26, the PiNode gives us enough information to conclude
that `%47 === false` if control flow reaches that point. The previous
code incorrectly assumed that this kind of pruning would only be done
for PhiNodes.

Resolves JuliaLang#50276.
vtjnash pushed a commit that referenced this issue Jun 29, 2023
It's possible for PiNodes to effectively imply statically the condition
of a Core.ifelse. For example:
```julia
    23 ─ %60  = Core.ifelse(%47, false, true)::Bool
    │    %61  = Core.ifelse(%47, %58, false)::Union{Missing, Bool}
    25 ─        goto #27 if not %60
    26 ─ %65  = π (%61, Bool)
    └───        ...
```

In basic block #26, the PiNode gives us enough information to conclude
that `%47 === false` if control flow reaches that point. The previous
code incorrectly assumed that this kind of pruning would only be done
for PhiNodes.

Resolves #50276
Keno pushed a commit that referenced this issue Oct 9, 2023
fix docs for determine_method_for_expr
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

No branches or pull requests

3 participants