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

Tasks and exceptions #12485

Closed
Keno opened this issue Aug 6, 2015 · 11 comments · Fixed by #28878
Closed

Tasks and exceptions #12485

Keno opened this issue Aug 6, 2015 · 11 comments · Fixed by #28878
Assignees
Labels
domain:error handling Handling of exceptions by Julia or the user kind:bug Indicates an unexpected problem or unintended behavior

Comments

@Keno
Copy link
Member

Keno commented Aug 6, 2015

Working with exceptions in the presence of tasks can be a little frustrating. Two concrete issues I encountered:

julia> t = @schedule try
       while true; sleep(1); end
       catch e
       isa(e,InterruptException) || rethrow(e)
       end
Task (waiting) @0x00000001116c6cb0

julia> try
       error("You will never see me")
       catch e
       rethrow(e)
       finally
       Base.throwto(t,InterruptException)
       end
ERROR: InterruptException
 in throwto at ./task.jl:29
 in anonymous at ./no file:6

This is because exception in transit is not task local.

The other problem is that stack traces are pretty bad when waiting on a task:

julia> foo() = error("Foo")
foo (generic function with 1 method)

julia> foo()
ERROR: Foo
 in foo at ./none:1

julia> wait(@schedule foo())
ERROR: Foo
 in yieldto at ./task.jl:24
 in wait at ./task.jl:313
 in wait at ./task.jl:228
 in wait at ./task.jl:61

The backtrace from the task is not shown anywhere. Ideally it would be displayed somehow.

@tkelman tkelman added the domain:error handling Handling of exceptions by Julia or the user label Aug 6, 2015
@amitmurthy
Copy link
Contributor

In the second case, "handled" tasks do not print their backtraces. However, it can still be accessed if you have a reference to the task object.

t=@schedule foo(); wait(t);
Base.show_backtrace(STDOUT, t.backtrace)

@amitmurthy
Copy link
Contributor

In the first case, backtrace of t can be accessed by

julia> Base.show_backtrace(STDOUT, t.backtrace)

 in yieldto at ./task.jl:75
 in wait at ./task.jl:371
 in wait at ./task.jl:286
 in sleep at stream.jl:616
 in anonymous at task.jl:2

The Base.throwto seems to hide the local rethrown exception.

 try
              error("You will never see me")
              catch e
              rethrow(e)
              finally
              1
              end
ERROR: You will never see me
 in anonymous at no file:2

@amitmurthy
Copy link
Contributor

Probably indirectly related - #1784

I have also seen a segfault triggered from code within a finally block - trying to get a reduced case for the same.

@amitmurthy
Copy link
Contributor

Also, show of a task in error now prints its backtrace.

julia> t=@schedule foo(); wait(t);
ERROR: Foo
 in yieldto at ./task.jl:75
 in wait at ./task.jl:371
 in wait at ./task.jl:286
 in wait at ./task.jl:112

julia> t
Task (failed) @0x00007f36d4160010
ErrorException("Foo")
 in foo at none:1
 in anonymous at task.jl:67

@vtjnash
Copy link
Sponsor Member

vtjnash commented Aug 7, 2015

possible solution idea https://gist.github.com/vtjnash/9cd53434cc7f7e2f7a29

@JeffBezanson JeffBezanson added the kind:bug Indicates an unexpected problem or unintended behavior label Aug 10, 2015
@JeffBezanson JeffBezanson self-assigned this Aug 10, 2015
@JeffBezanson
Copy link
Sponsor Member

Yes, something like that should work. It can mostly be fixed in the front end by saving the exception data around the finally block. jl_exception_in_transit was intended to be very short-lived, and shouldn't have to be task local.

@JeffBezanson
Copy link
Sponsor Member

Also, need parens at the end of Base.throwto(t,InterruptException()).

JeffBezanson added a commit that referenced this issue Aug 10, 2015
- save the exception to be rethrown around the code in a finally block
- set bt_size=0 on task switch. since we don't remember which task the
  backtrace came from, it must be associated with the current task or else
  not exist.
JeffBezanson added a commit that referenced this issue Aug 21, 2015
improve interaction of task switches and finally blocks (#12485)
@sbchisholm
Copy link

Is this similar? I found that rethrow() (no arguments) will throw the last thrown exception even if it is not the exception that was caught in the catch statement:

type IgnoredException <: Exception end
type HandledException <: Exception end

try
    @async begin
        sleep(1.0)
        try 
            throw(IgnoredException())
        catch ex
            println("Task threw and caught $ex")
            !isa(ex, IgnoredException) && rethrow()
        end 
    end 

    println("Throwing HandledException")
    throw(HandledException())
catch ex
    if isa(ex, HandledException)
        println("Caught: $ex")
    end 
    sleep(2.0)
    println("Rethrowing...")
    rethrow(ex) # throws HandledException()
    # rethrow()  # throws IgnoredException()
end

If I don't pass ex to rethrow, it will throw the IgnoredException() that was caught and ignored by the asynchronous task. I was expecting that rethrow() would throw the exception that was caught by the catch statement.

@JeffBezanson
Copy link
Sponsor Member

Yes that looks like the same issue to me.

@sbchisholm
Copy link

Thanks @JeffBezanson.

@c42f c42f mentioned this issue Aug 24, 2018
10 tasks
@c42f
Copy link
Member

c42f commented Aug 24, 2018

Experimental PR which fixes this: #28878

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:error handling Handling of exceptions by Julia or the user kind:bug Indicates an unexpected problem or unintended behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants