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

callback functions see "old world" in 0.6 #19774

Closed
stevengj opened this issue Dec 30, 2016 · 18 comments
Closed

callback functions see "old world" in 0.6 #19774

stevengj opened this issue Dec 30, 2016 · 18 comments
Assignees
Labels
docs This change adds or pertains to documentation

Comments

@stevengj
Copy link
Member

stevengj commented Dec 30, 2016

It seems much harder to pass a proper closure as a callback function in Julia 0.6 than in previous versions due to #17057. In particular, the method described in the manual and in this blog post no longer works: passing the Function via a "thunk" void* that is called from a cfunction fails because the Function sees an "old world age".

See JuliaPy/PyCall.jl#343 and JuliaMath/Cubature.jl#22 and the mailing list, for example, but this will affect any package wrapping a C library that expects callback functions.

In PyCall, @yuyichao suggested using eval, but this is clunky and seems likely to impose a large performance penalty. Is there a better solution?

@stevengj stevengj added the regression Regression in behavior compared to a previous version label Dec 30, 2016
@yuyichao yuyichao removed the regression Regression in behavior compared to a previous version label Dec 30, 2016
@yuyichao
Copy link
Contributor

This describes a expected behavior so this is not a regression but simply a breaking change. The eval here shouldn't add that much overhead although a lighter weight one will be good.

@stevengj stevengj added breaking This change will break code docs This change adds or pertains to documentation labels Dec 30, 2016
@yuyichao
Copy link
Contributor

The fix of this (adding doc or add a slightly cheaper way to call something in the latest world) won't be breaking.........

@stevengj
Copy link
Member Author

We need documentation of this, and to update the blog post. Can we have eval(function, args...) or something?

Why does a call to a Function object need to use the caller's world age?

@yuyichao
Copy link
Contributor

Inference cannot infer anything about a newer world so any change in world age has to be an optimization barrier. We also need to be consistent on what do we treat as optimization barrier and failure to do that is one part of #265. Since a function call can be optimized, it must never be an optimization barrier, i.e. the dispatch and the body of f() must see the same world as the caller.

@stevengj stevengj removed the breaking This change will break code label Dec 30, 2016
@stevengj
Copy link
Member Author

But a call to a Function object that is fetched from a pointer cannot be optimized, so it can be an optimization barrier, no?

@yuyichao
Copy link
Contributor

The semantics shouldn't be inference dependent unless we have a clear rule of what's inferrable.

@stevengj
Copy link
Member Author

stevengj commented Dec 30, 2016

Presumably unsafe_pointer_to_objref (or any ccall with a return type Any) should never result in an inferrable type?

@yuyichao
Copy link
Contributor

The result can be typeasserted. The underlying implementation also allow specifying the type.

@stevengj
Copy link
Member Author

stevengj commented Dec 30, 2016

Sure, but if it is not typeasserted, or is only typeasserted to an abstract type like Function, that still seems pretty clear-cut?

@yuyichao
Copy link
Contributor

No. I think it's a bad idea to treat it like that. There's nothing special of it and it'll be really bad if f() and Ref{Any}(f)[]() return different result.

@yuyichao
Copy link
Contributor

Adding a invokeinworld or invokelatest shouldn't be too hard. I can't do it in the next ~24hrs though.

@stevengj
Copy link
Member Author

stevengj commented Dec 30, 2016

+1 for invokelatest(f, args...).

Seems like it could be built by modifying jl_apply_generic to take a world age as an argument and then passing jl_get_world_counter()? No, that wouldn't work, because it wouldn't affect functions called by the called function. Seems like you need a try -- finally that temporarily resets the world age. Looks like jl_call already does this.

@stevengj
Copy link
Member Author

Looks like uv_getaddrinfocb in base/socket.jl may need this too?

@stevengj
Copy link
Member Author

Regarding your comment elsewhere, maybe cfunction should not capture the world by default?

@yuyichao
Copy link
Contributor

That will put a lot of overhead for almost all cfunctions.

stevengj added a commit to stevengj/julia that referenced this issue Dec 31, 2016
@stevengj
Copy link
Member Author

Yeah, I guess that would kill performance for calling any function from the cfunction.

stevengj added a commit to stevengj/julia that referenced this issue Jan 5, 2017
stevengj added a commit to stevengj/julia that referenced this issue Jan 7, 2017
@stevengj
Copy link
Member Author

@yuyichao, was this closed by a commit?

@yuyichao
Copy link
Contributor

#20167

stevengj added a commit to stevengj/julia that referenced this issue Apr 25, 2017
JeffBezanson pushed a commit that referenced this issue Apr 27, 2017
add invokelatest function to work around world-age problems (#19774) without using eval

use invokelatest in libuv getaddrinfo callback

update manual to mention invokelatest
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation
Projects
None yet
Development

No branches or pull requests

3 participants