Skip to content

Commit b7d170a

Browse files
committed
Refactor ThreadStatus:
- Add `ThreadStatus::Running` - Replace `ThreadStatus::Unresumable` with `ThreadStatus::Finished` Change `Error::CoroutineInactive` to `Error::CoroutineUnresumable`
1 parent 5acf9d7 commit b7d170a

File tree

4 files changed

+43
-45
lines changed

4 files changed

+43
-45
lines changed

src/error.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,17 @@ pub enum Error {
9898
/// A string containing more detailed error information.
9999
message: Option<StdString>,
100100
},
101-
/// [`Thread::resume`] was called on an inactive coroutine.
101+
/// [`Thread::resume`] was called on an unresumable coroutine.
102102
///
103-
/// A coroutine is inactive if its main function has returned or if an error has occurred inside
104-
/// the coroutine. Already running coroutines are also marked as inactive (unresumable).
103+
/// A coroutine is unresumable if its main function has returned or if an error has occurred inside
104+
/// the coroutine. Already running coroutines are also marked as unresumable.
105105
///
106106
/// [`Thread::status`] can be used to check if the coroutine can be resumed without causing this
107107
/// error.
108108
///
109109
/// [`Thread::resume`]: crate::Thread::resume
110110
/// [`Thread::status`]: crate::Thread::status
111-
CoroutineInactive,
111+
CoroutineUnresumable,
112112
/// An [`AnyUserData`] is not the expected type in a borrow.
113113
///
114114
/// This error can only happen when manually using [`AnyUserData`], or when implementing
@@ -259,7 +259,7 @@ impl fmt::Display for Error {
259259
Some(ref message) => write!(fmt, " ({message})"),
260260
}
261261
}
262-
Error::CoroutineInactive => write!(fmt, "cannot resume inactive coroutine"),
262+
Error::CoroutineUnresumable => write!(fmt, "coroutine is non-resumable"),
263263
Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"),
264264
Error::UserDataDestructed => write!(fmt, "userdata has been destructed"),
265265
Error::UserDataBorrowError => write!(fmt, "error borrowing userdata"),

src/thread.rs

+29-31
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ use {
3030
/// Status of a Lua thread (coroutine).
3131
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
3232
pub enum ThreadStatus {
33-
/// The thread was just created, or is suspended because it has called `coroutine.yield`.
33+
/// The thread was just created or is suspended (yielded).
3434
///
3535
/// If a thread is in this state, it can be resumed by calling [`Thread::resume`].
36-
///
37-
/// [`Thread::resume`]: crate::Thread::resume
3836
Resumable,
39-
/// Either the thread has finished executing, or the thread is currently running.
40-
Unresumable,
37+
/// The thread is currently running.
38+
Running,
39+
/// The thread has finished executing.
40+
Finished,
4141
/// The thread has raised a Lua error during execution.
4242
Error,
4343
}
@@ -108,7 +108,7 @@ impl Thread {
108108
///
109109
/// // The coroutine has now returned, so `resume` will fail
110110
/// match thread.resume::<_, u32>(()) {
111-
/// Err(Error::CoroutineInactive) => {},
111+
/// Err(Error::CoroutineUnresumable) => {},
112112
/// unexpected => panic!("unexpected result {:?}", unexpected),
113113
/// }
114114
/// # Ok(())
@@ -120,9 +120,8 @@ impl Thread {
120120
R: FromLuaMulti,
121121
{
122122
let lua = self.0.lua.lock();
123-
124-
if unsafe { self.status_unprotected() } != ThreadStatus::Resumable {
125-
return Err(Error::CoroutineInactive);
123+
if self.status_inner(&lua) != ThreadStatus::Resumable {
124+
return Err(Error::CoroutineUnresumable);
126125
}
127126

128127
let state = lua.state();
@@ -170,25 +169,23 @@ impl Thread {
170169

171170
/// Gets the status of the thread.
172171
pub fn status(&self) -> ThreadStatus {
173-
let _guard = self.0.lua.lock();
174-
unsafe { self.status_unprotected() }
172+
self.status_inner(&self.0.lua.lock())
175173
}
176174

177-
/// Gets the status of the thread without locking the Lua state.
178-
pub(crate) unsafe fn status_unprotected(&self) -> ThreadStatus {
175+
/// Gets the status of the thread (internal implementation).
176+
pub(crate) fn status_inner(&self, lua: &RawLua) -> ThreadStatus {
179177
let thread_state = self.state();
180-
// FIXME: skip double lock
181-
if thread_state == self.0.lua.lock().state() {
182-
// The coroutine is currently running
183-
return ThreadStatus::Unresumable;
178+
if thread_state == lua.state() {
179+
// The thread is currently running
180+
return ThreadStatus::Running;
184181
}
185-
let status = ffi::lua_status(thread_state);
182+
let status = unsafe { ffi::lua_status(thread_state) };
186183
if status != ffi::LUA_OK && status != ffi::LUA_YIELD {
187184
ThreadStatus::Error
188-
} else if status == ffi::LUA_YIELD || ffi::lua_gettop(thread_state) > 0 {
185+
} else if status == ffi::LUA_YIELD || unsafe { ffi::lua_gettop(thread_state) > 0 } {
189186
ThreadStatus::Resumable
190187
} else {
191-
ThreadStatus::Unresumable
188+
ThreadStatus::Finished
192189
}
193190
}
194191

@@ -226,10 +223,11 @@ impl Thread {
226223
#[cfg_attr(docsrs, doc(cfg(any(feature = "lua54", feature = "luau"))))]
227224
pub fn reset(&self, func: crate::function::Function) -> Result<()> {
228225
let lua = self.0.lua.lock();
229-
let thread_state = self.state();
230-
if thread_state == lua.state() {
226+
if self.status_inner(&lua) == ThreadStatus::Running {
231227
return Err(Error::runtime("cannot reset a running thread"));
232228
}
229+
230+
let thread_state = self.state();
233231
unsafe {
234232
#[cfg(all(feature = "lua54", not(feature = "vendored")))]
235233
let status = ffi::lua_resetthread(thread_state);
@@ -398,7 +396,7 @@ impl<R> Drop for AsyncThread<R> {
398396
// For Lua 5.4 this also closes all pending to-be-closed variables
399397
if !lua.recycle_thread(&mut self.thread) {
400398
#[cfg(feature = "lua54")]
401-
if self.thread.status_unprotected() == ThreadStatus::Error {
399+
if self.thread.status_inner(&lua) == ThreadStatus::Error {
402400
#[cfg(not(feature = "vendored"))]
403401
ffi::lua_resetthread(self.thread.state());
404402
#[cfg(feature = "vendored")]
@@ -416,13 +414,13 @@ impl<R: FromLuaMulti> Stream for AsyncThread<R> {
416414

417415
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
418416
let lua = self.thread.0.lua.lock();
417+
if self.thread.status_inner(&lua) != ThreadStatus::Resumable {
418+
return Poll::Ready(None);
419+
}
420+
419421
let state = lua.state();
420422
let thread_state = self.thread.state();
421423
unsafe {
422-
if self.thread.status_unprotected() != ThreadStatus::Resumable {
423-
return Poll::Ready(None);
424-
}
425-
426424
let _sg = StackGuard::new(state);
427425
let _thread_sg = StackGuard::with_top(thread_state, 0);
428426
let _wg = WakerGuard::new(&lua, cx.waker());
@@ -454,13 +452,13 @@ impl<R: FromLuaMulti> Future for AsyncThread<R> {
454452

455453
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
456454
let lua = self.thread.0.lua.lock();
455+
if self.thread.status_inner(&lua) != ThreadStatus::Resumable {
456+
return Poll::Ready(Err(Error::CoroutineUnresumable));
457+
}
458+
457459
let state = lua.state();
458460
let thread_state = self.thread.state();
459461
unsafe {
460-
if self.thread.status_unprotected() != ThreadStatus::Resumable {
461-
return Poll::Ready(Err(Error::CoroutineInactive));
462-
}
463-
464462
let _sg = StackGuard::new(state);
465463
let _thread_sg = StackGuard::with_top(thread_state, 0);
466464
let _wg = WakerGuard::new(&lua, cx.waker());

tests/luau.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn test_interrupts() -> Result<()> {
362362
let result: i32 = co.resume(())?;
363363
assert_eq!(result, 6);
364364
assert_eq!(yield_count.load(Ordering::Relaxed), 7);
365-
assert_eq!(co.status(), ThreadStatus::Unresumable);
365+
assert_eq!(co.status(), ThreadStatus::Finished);
366366

367367
//
368368
// Test errors in interrupts

tests/thread.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn test_thread() -> Result<()> {
3131
assert_eq!(thread.resume::<_, i64>(3)?, 6);
3232
assert_eq!(thread.status(), ThreadStatus::Resumable);
3333
assert_eq!(thread.resume::<_, i64>(4)?, 10);
34-
assert_eq!(thread.status(), ThreadStatus::Unresumable);
34+
assert_eq!(thread.status(), ThreadStatus::Finished);
3535

3636
let accumulate = lua.create_thread(
3737
lua.load(
@@ -85,17 +85,17 @@ fn test_thread() -> Result<()> {
8585
assert_eq!(thread.resume::<_, u32>(43)?, 987);
8686

8787
match thread.resume::<_, u32>(()) {
88-
Err(Error::CoroutineInactive) => {}
88+
Err(Error::CoroutineUnresumable) => {}
8989
Err(_) => panic!("resuming dead coroutine error is not CoroutineInactive kind"),
9090
_ => panic!("resuming dead coroutine did not return error"),
9191
}
9292

9393
// Already running thread must be unresumable
9494
let thread = lua.create_thread(lua.create_function(|lua, ()| {
95-
assert_eq!(lua.current_thread().status(), ThreadStatus::Unresumable);
95+
assert_eq!(lua.current_thread().status(), ThreadStatus::Running);
9696
let result = lua.current_thread().resume::<_, ()>(());
9797
assert!(
98-
matches!(result, Err(Error::CoroutineInactive)),
98+
matches!(result, Err(Error::CoroutineUnresumable)),
9999
"unexpected result: {result:?}",
100100
);
101101
Ok(())
@@ -128,7 +128,7 @@ fn test_thread_reset() -> Result<()> {
128128
assert_eq!(thread.status(), ThreadStatus::Resumable);
129129
assert_eq!(Arc::strong_count(&arc), 2);
130130
thread.resume::<_, ()>(())?;
131-
assert_eq!(thread.status(), ThreadStatus::Unresumable);
131+
assert_eq!(thread.status(), ThreadStatus::Finished);
132132
thread.reset(func.clone())?;
133133
lua.gc_collect()?;
134134
assert_eq!(Arc::strong_count(&arc), 1);
@@ -147,11 +147,11 @@ fn test_thread_reset() -> Result<()> {
147147
// It's became possible to force reset thread by popping error object
148148
assert!(matches!(
149149
thread.status(),
150-
ThreadStatus::Unresumable | ThreadStatus::Error
150+
ThreadStatus::Finished | ThreadStatus::Error
151151
));
152152
// Would pass in 5.4.4
153-
// assert!(thread.reset(func.clone()).is_ok());
154-
// assert_eq!(thread.status(), ThreadStatus::Resumable);
153+
assert!(thread.reset(func.clone()).is_ok());
154+
assert_eq!(thread.status(), ThreadStatus::Resumable);
155155
}
156156
#[cfg(any(feature = "lua54", feature = "luau"))]
157157
{

0 commit comments

Comments
 (0)