forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 3
Moving GC Extensions to Julia's FFI #95
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| # This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
|
||
| export increment_pin_count!, decrement_pin_count!, | ||
| increment_tpin_count!, decrement_tpin_count!, | ||
| get_pin_count, get_tpin_count | ||
|
|
||
| """ | ||
| increment_pin_count!(obj) | ||
|
|
||
| Increment the pin count of `obj` to preserve it beyond a lexical scope. | ||
|
|
||
| This ensures that `obj` is not moved or collected by the garbage collector. | ||
| It is crucial for safely passing references to foreign code. | ||
|
|
||
| Each call increments the pin count by one. The object remains pinned and | ||
| alive until the count is decremented to zero via `decrement_pin_count!`. | ||
|
|
||
| # Examples | ||
|
|
||
| ```julia | ||
| x = SomeObject() | ||
| increment_pin_count!(x) # x is now pinned (count = 1) | ||
|
|
||
| increment_pin_count!(x) # pin count is now 2 | ||
| """ | ||
| function increment_pin_count!(obj) | ||
| ccall(:jl_increment_pin_count, Cvoid, (Any,), obj) | ||
| end | ||
|
|
||
| """ | ||
| decrement_pin_count!(obj) | ||
|
|
||
| Decrement the pin count of `obj`. | ||
|
|
||
| When the count drops to zero, the object is no longer pinned and may be | ||
| moved (or collected by the garbage collector, if no other references | ||
| exist). | ||
|
|
||
| This is necessary to release objects that were previously preserved for | ||
| foreign code. | ||
|
|
||
| # Examples | ||
|
|
||
| ```julia | ||
| x = SomeObject() | ||
| increment_pin_count!(x) # x is now pinned (count = 1) | ||
|
|
||
| increment_pin_count!(x) # pin count is now 2 | ||
|
|
||
| decrement_pin_count!(x) # reduces pin count to 1 | ||
|
|
||
| decrement_pin_count!(x) # count is 0; x may now be collected | ||
| """ | ||
| function decrement_pin_count!(obj) | ||
| ccall(:jl_decrement_pin_count, Cvoid, (Any,), obj) | ||
| end | ||
|
|
||
| """ | ||
| increment_tpin_count!(obj) | ||
|
|
||
| Increment the transitive pin count of `obj` to preserve it beyond a | ||
| lexical scope. | ||
|
|
||
| This ensures that `obj` and any other objects reachable from it are not | ||
| moved or collected by the garbage collector. This is crucial for safely | ||
| passing references to foreign code. | ||
|
|
||
| Each call increments the transitive pin count by one. The object remains | ||
| transitively pinned and alive until the count is decremented to zero via | ||
| `decrement_tpin_count!`. | ||
|
|
||
| # Examples | ||
|
|
||
| ```julia | ||
| x = SomeObject() | ||
| increment_tpin_count!(x) # x is now transitively pinned (count = 1) | ||
|
|
||
| increment_tpin_count!(x) # transitive pin count is now 2 | ||
| """ | ||
| function increment_tpin_count!(obj) | ||
| ccall(:jl_increment_tpin_count, Cvoid, (Any,), obj) | ||
| end | ||
|
|
||
| """ | ||
| decrement_tpin_count!(obj) | ||
|
|
||
| Decrement the transitive pin count of `obj`. | ||
|
|
||
| When the count drops to zero, `obj` and any objects reachable from it are | ||
| no longer pinned and may be moved (if no other pins exist) or collected by | ||
| the garbage collector (if no other references exist). | ||
|
|
||
| This is necessary to release object graphs that were previously preserved | ||
| for foreign code. | ||
|
|
||
| # Examples | ||
|
|
||
| ```julia | ||
| x = SomeObject() | ||
| increment_tpin_count!(x) # pins x and reachable objects (count = 1) | ||
|
|
||
| decrement_tpin_count!(x) # reduces transitive pin count to 0 | ||
| # objects may now be collected | ||
| """ | ||
| function decrement_tpin_count!(obj) | ||
| ccall(:jl_decrement_tpin_count, Cvoid, (Any,), obj) | ||
| end | ||
|
|
||
| """ | ||
| get_pin_count(obj) | ||
|
|
||
| Return the current pin count of `obj`. | ||
|
|
||
| This indicates how many times `obj` has been explicitly pinned via | ||
| `increment_pin_count!`. A nonzero count means the object is currently | ||
| pinned and will not be moved or collected by the garbage collector (GC). | ||
|
|
||
| # Examples | ||
|
|
||
| ```julia | ||
| x = SomeObject() | ||
| increment_pin_count!(x) | ||
| get_pin_count(x) # returns 1 | ||
|
|
||
| increment_pin_count!(x) | ||
| get_pin_count(x) # returns 2 | ||
|
|
||
| decrement_pin_count!(x) | ||
| get_pin_count(x) # returns 1 | ||
| """ | ||
| function get_pin_count(obj) | ||
| c = ccall(:jl_get_pin_count, Csize_t, (Any,), obj) | ||
| return Int64(c) | ||
| end | ||
|
|
||
| """ | ||
| get_tpin_count(obj) | ||
|
|
||
| Return the current transitive pin count of `obj`. | ||
|
|
||
| This indicates how many times `obj` has been explicitly transitively pinned | ||
| via `increment_tpin_count!`. A nonzero count means `obj` and all objects | ||
| reachable from it are currently pinned and will not be moved or collected | ||
| by the garbage collector (GC). | ||
|
|
||
| # Examples | ||
|
|
||
| ```julia | ||
| x = SomeObject() | ||
| increment_tpin_count!(x) | ||
| get_tpin_count(x) # returns 1 | ||
|
|
||
| increment_tpin_count!(x) | ||
| get_tpin_count(x) # returns 2 | ||
|
|
||
| decrement_tpin_count!(x) | ||
| get_tpin_count(x) # returns 1 | ||
| """ | ||
| function get_tpin_count(obj) | ||
| c = ccall(:jl_get_tpin_count, Csize_t, (Any,), obj) | ||
| return Int64(c) | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| // This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
|
||
| #include <map> | ||
| #include <mutex> | ||
|
|
||
| #include "julia.h" | ||
|
|
||
| // Let's just use global maps in this first implementation | ||
| // They could cause contention in multi-threaded code, so we might need to optimize them later | ||
|
|
||
| // Pinning | ||
| std::map<void *, size_t> pin_count_map; | ||
| std::mutex pin_count_map_lock; | ||
| // Transitive Pinning | ||
| std::map<void *, size_t> tpin_count_map; | ||
| std::mutex tpin_count_map_lock; | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| // Pinning | ||
| JL_DLLEXPORT void jl_increment_pin_count(void *obj) { | ||
| pin_count_map_lock.lock(); | ||
| if (pin_count_map.find(obj) == pin_count_map.end()) { | ||
| pin_count_map[obj] = 0; | ||
| } | ||
| pin_count_map[obj]++; | ||
| pin_count_map_lock.unlock(); | ||
| } | ||
| JL_DLLEXPORT void jl_decrement_pin_count(void *obj) { | ||
| pin_count_map_lock.lock(); | ||
| auto it = pin_count_map.find(obj); | ||
| if (it != pin_count_map.end()) { | ||
| if (it->second == 1) { | ||
| pin_count_map.erase(it); | ||
| } else { | ||
| it->second--; | ||
| } | ||
| } | ||
| pin_count_map_lock.unlock(); | ||
| } | ||
|
|
||
| // Transitive Pinning | ||
| JL_DLLEXPORT void jl_increment_tpin_count(void *obj) { | ||
| tpin_count_map_lock.lock(); | ||
| if (tpin_count_map.find(obj) == tpin_count_map.end()) { | ||
| tpin_count_map[obj] = 0; | ||
| } | ||
| tpin_count_map[obj]++; | ||
| tpin_count_map_lock.unlock(); | ||
| } | ||
| JL_DLLEXPORT void jl_decrement_tpin_count(void *obj) { | ||
| tpin_count_map_lock.lock(); | ||
| auto it = tpin_count_map.find(obj); | ||
| if (it != tpin_count_map.end()) { | ||
| if (it->second == 1) { | ||
| tpin_count_map.erase(it); | ||
| } else { | ||
| it->second--; | ||
| } | ||
| } | ||
| tpin_count_map_lock.unlock(); | ||
| } | ||
|
|
||
| // Retrieve Pinning and Transitive Pinning counts for a given object | ||
| JL_DLLEXPORT size_t jl_get_pin_count(void *obj) { | ||
| pin_count_map_lock.lock(); | ||
| auto it = pin_count_map.find(obj); | ||
| size_t count = (it != pin_count_map.end()) ? it->second : 0; | ||
| pin_count_map_lock.unlock(); | ||
| return count; | ||
| } | ||
| JL_DLLEXPORT size_t jl_get_tpin_count(void *obj) { | ||
| tpin_count_map_lock.lock(); | ||
| auto it = tpin_count_map.find(obj); | ||
| size_t count = (it != tpin_count_map.end()) ? it->second : 0; | ||
| tpin_count_map_lock.unlock(); | ||
| return count; | ||
| } | ||
|
|
||
| // Returns all pinned and transitively pinned objects | ||
| // Argument should have been initialized by the caller | ||
| // TODO: add a few assertions to check this? | ||
| JL_DLLEXPORT void jl_dump_all_pinned_objects(arraylist_t *objects) { | ||
| pin_count_map_lock.lock(); | ||
| for (const auto &pair : pin_count_map) { | ||
| arraylist_push(objects, pair.first); | ||
| } | ||
| pin_count_map_lock.unlock(); | ||
| } | ||
| JL_DLLEXPORT void jl_dump_all_tpinned_objects(arraylist_t *objects) { | ||
| tpin_count_map_lock.lock(); | ||
| for (const auto &pair : tpin_count_map) { | ||
| arraylist_push(objects, pair.first); | ||
| } | ||
| tpin_count_map_lock.unlock(); | ||
| } | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 think this should throw if you try to dec something that's not pinned.
Otherwise it will be easy to accidentally
increment_pinbutdecrement_tpinThere 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'd probs change the c function to return the new count or -1 if not foudn)