@@ -21,7 +21,7 @@ use crate::thread::Thread;
2121use crate :: traits:: { FromLua , FromLuaMulti , IntoLua , IntoLuaMulti } ;
2222use crate :: types:: {
2323 AppDataRef , AppDataRefMut , ArcReentrantMutexGuard , Integer , LuaType , MaybeSend , Number , ReentrantMutex ,
24- ReentrantMutexGuard , RegistryKey , VmState , XRc , XWeak ,
24+ ReentrantMutexGuard , RegistryKey , VmState , XRc , XWeak , ThreadEventInfo
2525} ;
2626use crate :: userdata:: { AnyUserData , UserData , UserDataProxy , UserDataRegistry , UserDataStorage } ;
2727use crate :: util:: {
@@ -671,6 +671,55 @@ impl Lua {
671671 }
672672 }
673673
674+ /// Sets a callback that will be called by Luau whenever a thread is created/destroyed.
675+ ///
676+ /// Often used for keeping track of threads.
677+ #[ cfg( any( feature = "luau" , doc) ) ]
678+ #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
679+ pub fn set_thread_event_callback < F > ( & self , callback : F )
680+ where
681+ F : Fn ( & Lua , ThreadEventInfo ) -> Result < ( ) > + MaybeSend + ' static ,
682+ {
683+ use std:: rc:: Rc ;
684+
685+ unsafe extern "C-unwind" fn userthread_proc ( parent : * mut ffi:: lua_State , state : * mut ffi:: lua_State ) {
686+ let extra = ExtraData :: get ( state) ;
687+ let _guard = StateGuard :: new ( ( * extra) . raw_lua ( ) , state) ;
688+ let raw_lua: & RawLua = ( * extra) . raw_lua ( ) ;
689+ raw_lua. push_ref_thread ( parent) . unwrap ( ) ;
690+ callback_error_ext ( state, ptr:: null_mut ( ) , move |extra, _| {
691+ let userthread_cb = ( * extra) . userthread_callback . clone ( ) ;
692+ let userthread_cb = mlua_expect ! ( userthread_cb, "no userthread callback set in userthread_proc" ) ;
693+ let event_info = match ( * extra) . raw_lua ( ) . pop_value ( ) {
694+ Value :: Thread ( thr) => ThreadEventInfo :: Created ( thr) ,
695+ Value :: Nil => ThreadEventInfo :: Destroying ,
696+ _ => unreachable ! ( )
697+ } ;
698+ userthread_cb ( ( * extra) . lua ( ) , event_info)
699+ } ) ;
700+ }
701+
702+ // Set interrupt callback
703+ let lua = self . lock ( ) ;
704+ unsafe {
705+ ( * lua. extra . get ( ) ) . userthread_callback = Some ( Rc :: new ( callback) ) ;
706+ ( * ffi:: lua_callbacks ( lua. main_state ( ) ) ) . userthread = Some ( userthread_proc) ;
707+ }
708+ }
709+
710+ /// Removes any thread event function previously set by `set_thread_event_callback`.
711+ ///
712+ /// This function has no effect if a callback was not previously set.
713+ #[ cfg( any( feature = "luau" , doc) ) ]
714+ #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
715+ pub fn remove_thread_event_callback ( & self ) {
716+ let lua = self . lock ( ) ;
717+ unsafe {
718+ ( * lua. extra . get ( ) ) . userthread_callback = None ;
719+ ( * ffi:: lua_callbacks ( lua. main_state ( ) ) ) . userthread = None ;
720+ }
721+ }
722+
674723 /// Sets the warning function to be used by Lua to emit warnings.
675724 ///
676725 /// Requires `feature = "lua54"`
0 commit comments