diff --git a/include/thespian/c/instance.h b/include/thespian/c/instance.h index 09d3bd8..1b0fab3 100644 --- a/include/thespian/c/instance.h +++ b/include/thespian/c/instance.h @@ -28,6 +28,9 @@ thespian_handle thespian_self(); int thespian_spawn_link(thespian_behaviour, thespian_behaviour_state, const char *name, thespian_env, thespian_handle *); +int thespian_spawn(thespian_behaviour, thespian_behaviour_state, + const char *name, thespian_env, thespian_handle *); + #ifdef __cplusplus } #endif diff --git a/src/c/instance.cpp b/src/c/instance.cpp index 7b25aec..b30c377 100644 --- a/src/c/instance.cpp +++ b/src/c/instance.cpp @@ -96,4 +96,30 @@ auto thespian_spawn_link(thespian_behaviour b, thespian_behaviour_state s, new thespian::handle{ret.value()}); return 0; } + +auto thespian_spawn(thespian_behaviour b, thespian_behaviour_state s, + const char *name, thespian_env env, thespian_handle *handle) + -> int { + const thespian::env_t empty_env_{}; + thespian::env_t env_ = + env ? *reinterpret_cast(env) : empty_env_; // NOLINT + + auto ret = spawn( + [b, s]() -> thespian::result { + auto *ret = b(s); + if (ret) { + auto err = cbor::buffer(); + const uint8_t *data = ret->base; // NOLINT + std::copy(data, data + ret->len, back_inserter(err)); // NOLINT + return thespian::to_error(err); + } + return thespian::ok(); + }, + string_view(name), std::move(env_)); + if (!ret) + return -1; + *handle = reinterpret_cast( // NOLINT + new thespian::handle{ret.value()}); + return 0; +} } diff --git a/src/thespian.zig b/src/thespian.zig index d05e261..588878e 100644 --- a/src/thespian.zig +++ b/src/thespian.zig @@ -584,6 +584,28 @@ pub fn spawn_link( return spawn_link_env(a, data, f, name, env.get()); } +/// Spawn a new actor WITHOUT creating a link to the calling actor. +/// The new actor runs independently; its exit does not propagate to the +/// caller. Think twice before you use this form of spawn. It's rarely want +/// you want to do. +pub fn spawn( + a: std.mem.Allocator, + data: anytype, + f: Behaviour(@TypeOf(data)).FunT, + name: [:0]const u8, +) error{ OutOfMemory, ThespianSpawnFailed }!pid { + const Tclosure = Behaviour(@TypeOf(data)); + var handle_: c.thespian_handle = null; + try neg_to_error(c.thespian_spawn( + Tclosure.run, + try Tclosure.create(a, f, data), + name, + env.get().env, + &handle_, + ), error.ThespianSpawnFailed); + return wrap_pid(handle_); +} + pub fn spawn_link_env( a: std.mem.Allocator, data: anytype,