godot-rust / godot-rust/gdext

Nested Exported Resource requires `experimental-threads` feature

Open
#610 4 comments 0 reactions 0 assignees View on GitHub
bug c: engine c: threads
Dominant language
Rust
Stars
5.2k
Forks
312
Avg merge
12h 59m
Merged PRs (30d)
9

Description

The issue was originally posted in the discord thread and some initial testing was executed. Below I will share the original question and initiali findings. Issue is similiar to #597 as it invokes the same multithreading problem with `Resource` handling of Godot, but contrary to the former, there is no custom `ResourceFormatLoader` there, only custom `Resource` (so it is saved as `.tres` and `.res` formats) - for this reason, I believe it is worthy to have this as a separate Issue here.

## Example and initial data:

```rust
struct Test {}

#[gdextension]
unsafe impl ExtensionLibrary for Test {}

#[derive(GodotClass)]
#[class(base=Node)]
struct TestNode {
#[export]
nested_resources: Gd,
}

#[godot_api]
impl INode for TestNode {
fn init(_base: Base) -> Self {
Self {
nested_resources: Gd::from_init_fn(ParentResource::init),
}
}
}

#[derive(GodotClass)]
#[class(base=Resource)]
struct ParentResource {
base: Base,
#[export]
sub_resource: Gd,
}

#[godot_api]
impl IResource for ParentResource {
fn init(base: Base) -> Self {
Self {
base,
sub_resource: Gd::from_init_fn(SubResource::init),
}
}
}

#[derive(GodotClass)]
#[class(base=Resource)]
struct SubResource {
#[export]
value: i32,
base: Base,
}

#[godot_api]
impl IResource for SubResource {
fn init(base: Base) -> Self {
Self { value: 50, base }
}
}
```

Above code panicked with stack trace:

```
' panicked at ~/.cargo/git/checkouts/gdext-76630c89719e160c/b4a91a6/godot-core/src/lib.rs:160:43:
no panic info available
stack backtrace:
0: rust_begin_unwind
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
1: core::panicking::panic_fmt
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
2: core::panicking::panic_display
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:196:5
3: core::panicking::panic_str
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:171:5
4: core::option::expect_failed
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/option.rs:1980:5
5: core::option::Option::expect
at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/option.rs:894:21
6: godot_core::private::handle_panic
at ~/.cargo/git/checkouts/gdext-76630c89719e160c/b4a91a6/godot-core/src/lib.rs:160:28
7: ::__register_exports::function
at ./rust/src/lib.rs:24:10
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
fatal runtime error: failed to initiate panic, error 5
```

With error message introduced in #581
```
assertion `left == right` failed: attempted to access binding from different thread than main thread; this is UB - use the "experimental-threads" feature.
left: ThreadId(1)
right: ThreadId(2)
```

Removing the `#[export]` annotation from `ParentResource::sub_resource` field stop the error from happening, but also removes the possibility of assigning `SubResource` in the Godot Editor AND saving the `ParentResource` with `SubResource` data, either as Bundled or External Resource.

## Initial hypothesis and findings

My initial hypothesis was that the user code was in some way callled by Godot Editor, similiar to mentioned `ResourceFormatLoader` issue. To check it, the simple thread printing function was added to `init` function of all structs:

```rust
pub(crate) fn print_thread(class: &str, method: &str) {
let thread_id = Os::singleton().get_thread_caller_id();

godot_print!("Thread: {thread_id}: {class}::{method}");
}

#[godot_api]
impl IResource for SubResource {
fn init(base: Base) -> Self {
print_thread("SubResource", "init");
Self { value: 50, base }
}
}
```

The thread number that were always printed was `1` though, contrary to mentioned issue, so it seems that the secondary thread was used within no user defined code (at least not explicitly).

Additionally, the same *nested export* situation was tested with `Node`-inheriting classes instead of `Resource`. Panic wasn't happening, so it should be specific to Resources.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.