{"id":18258700,"url":"https://github.com/maaarcocr/lucchetto","last_synced_at":"2025-04-04T19:31:55.540Z","repository":{"id":199085855,"uuid":"702117284","full_name":"Maaarcocr/lucchetto","owner":"Maaarcocr","description":"easily call a rust function without holding the GVL lock","archived":false,"fork":false,"pushed_at":"2023-10-10T16:28:12.000Z","size":14,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-02T17:15:56.586Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Maaarcocr.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-10-08T14:46:46.000Z","updated_at":"2025-02-11T14:17:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"3c7864ce-cc60-4939-8ec7-10f3afb8a8b1","html_url":"https://github.com/Maaarcocr/lucchetto","commit_stats":null,"previous_names":["maaarcocr/lucchetto"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Maaarcocr%2Flucchetto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Maaarcocr%2Flucchetto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Maaarcocr%2Flucchetto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Maaarcocr%2Flucchetto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Maaarcocr","download_url":"https://codeload.github.com/Maaarcocr/lucchetto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247237680,"owners_count":20906329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T10:33:59.719Z","updated_at":"2025-04-04T19:31:50.532Z","avatar_url":"https://github.com/Maaarcocr.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lucchetto\n\neasily call a rust function without holding the GVL lock\n\nlucchetto = lock in italian\n\n## How to install\n\nadd this to your `Cargo.toml`:\n\n```toml\n[dependencies]\nlucchetto = \"0.2.0\"\n```\n\nor\n\n```bash\ncargo add lucchetto\n```\n\n## Why?\n\nlet's say that you have written a rust function that is called from ruby, using\n[magnus](https://github.com/matsadler/magnus) and [rb-sys](https://github.com/oxidize-rb/rb-sys).\n\nas an example let's take this simple function (from our simple example):\n\n```rust\nuse magnus::{define_global_function, function};\n\nfn slow_func(input: String) -\u003e String {\n    std::thread::sleep(std::time::Duration::from_secs(2));\n    input.len().to_string()\n}\n\n#[magnus::init]\nfn init() {\n    define_global_function(\"slow_func\", function!(slow_func, 1));\n}\n\n```\n\nThis allows you to write a ruby script like this:\n\n```ruby\nrequire_relative \"./lib/simple\"\n\nt = Thread.new do\n  puts slow_func(\"hello\")\nend\n\n1..10.times do\n  sleep 0.1\n  puts \"main thread\"\nend\n\nt.join\n```\n\nbut you'll notice that because your rust function takes a long time, all ruby threads will be blocked until the rust function returns. This would be the output of the above script:\n\n```\nmain thread\n5\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\n```\n\nthis shows that the main thread is blocked until the rust function returns (which is running a different thread). This is because the GVL lock is held by the rust thread, and no other ruby thread can run.\n\n## Can we fix this?\n\nyes! we can use a simple attribute macro from lucchetto to tell the ruby VM that we are not going to use the GVL lock, and that it can run other ruby threads while we are running our rust function.\n\n```rust\nuse lucchetto::without_gvl;\nuse magnus::{define_global_function, function};\n\n#[without_gvl]\nfn slow_func(input: String) -\u003e String {\n    std::thread::sleep(std::time::Duration::from_secs(2));\n    input.len().to_string()\n}\n\n#[magnus::init]\nfn init() {\n    define_global_function(\"slow_func\", function!(slow_func, 1));\n}\n```\n\nIf we run the same ruby script as before, we'll see that the main thread is not blocked anymore:\n\n```\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\nmain thread\n5\n```\n\nas you can see, the main thread is not blocked anymore, and the rust function is still running in the background.\n\n## Safety concerns\n\nIn order to not allow the possibility of running a function that would be not safe, as it would have access\nto ruby objects, a trait called `GvlSafe` has been introduced. Functions can only take and return types that\nimplement this trait if they want to use the `#[without_gvl]` attribute macro.\n\nIt's an empty trait, so it's easy to implement on your own types if you think they are safe to use. Example:\n\n```rust\nuse lucchetto::GvlSafe;\n\nstruct MyStruct;\n\nimpl GvlSafe for MyStruct {}\n```\n\nYou can think of `GvlSafe` as `Send` and `Sync` for the GVL lock.\n\n## Is this good code?\n\nHonestly? I don't know. It may contain memory bugs (I've had to do lots of pointer-y things to make this work), and it may be unsafe. I have not spent a lot of time on this, so I'm not sure if this is the best way to do this. But does it seem to work? Yes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaaarcocr%2Flucchetto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaaarcocr%2Flucchetto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaaarcocr%2Flucchetto/lists"}