@@ -21,8 +21,12 @@ use crate::thread::Thread;
21
21
use crate :: traits:: { FromLua , FromLuaMulti , IntoLua , IntoLuaMulti } ;
22
22
use crate :: types:: {
23
23
AppDataRef , AppDataRefMut , ArcReentrantMutexGuard , Integer , LuaType , MaybeSend , Number , ReentrantMutex ,
24
- ReentrantMutexGuard , RegistryKey , VmState , XRc , XWeak ,
24
+ ReentrantMutexGuard , RegistryKey , VmState , XRc , XWeak
25
25
} ;
26
+
27
+ #[ cfg( any( feature = "luau" , doc) ) ]
28
+ #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
29
+ use crate :: types:: ThreadEventInfo ;
26
30
use crate :: userdata:: { AnyUserData , UserData , UserDataProxy , UserDataRegistry , UserDataStorage } ;
27
31
use crate :: util:: {
28
32
assert_stack, check_stack, protect_lua_closure, push_string, push_table, rawset_field, StackGuard ,
@@ -671,6 +675,71 @@ impl Lua {
671
675
}
672
676
}
673
677
678
+ /// Sets a callback that will be called by Luau whenever a thread is created/destroyed.
679
+ ///
680
+ /// Often used for keeping track of threads.
681
+ #[ cfg( any( feature = "luau" , doc) ) ]
682
+ #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
683
+ pub fn set_thread_event_callback < F > ( & self , callback : F )
684
+ where
685
+ F : Fn ( & Lua , ThreadEventInfo ) -> Result < ( ) > + MaybeSend + ' static ,
686
+ {
687
+ use std:: rc:: Rc ;
688
+
689
+ unsafe extern "C-unwind" fn userthread_proc ( parent : * mut ffi:: lua_State , state : * mut ffi:: lua_State ) {
690
+ callback_error_ext ( state, ptr:: null_mut ( ) , move |extra, _| {
691
+ let raw_lua: & RawLua = ( * extra) . raw_lua ( ) ;
692
+ let _guard = StateGuard :: new ( raw_lua, state) ;
693
+
694
+ let userthread_cb = ( * extra) . userthread_callback . clone ( ) ;
695
+ let userthread_cb = mlua_expect ! ( userthread_cb, "no userthread callback set in userthread_proc" ) ;
696
+ if parent. is_null ( ) {
697
+ raw_lua. push ( Value :: Nil ) . unwrap ( ) ;
698
+ } else {
699
+ raw_lua. push_ref_thread ( parent) . unwrap ( ) ;
700
+ }
701
+ if parent. is_null ( ) {
702
+ let event_info = ThreadEventInfo :: Destroyed ( state. cast_const ( ) . cast ( ) ) ;
703
+ let main_state = raw_lua. main_state ( ) ;
704
+ if main_state == state {
705
+ return Ok ( ( ) ) ; // Don't process Destroyed event on main thread.
706
+ }
707
+ let main_extra = ExtraData :: get ( main_state) ;
708
+ let main_raw_lua: & RawLua = ( * main_extra) . raw_lua ( ) ;
709
+ let _guard = StateGuard :: new ( main_raw_lua, state) ;
710
+ userthread_cb ( ( * main_extra) . lua ( ) , event_info)
711
+ } else {
712
+ raw_lua. push_ref_thread ( parent) . unwrap ( ) ;
713
+ let event_info = match raw_lua. pop_value ( ) {
714
+ Value :: Thread ( thr) => ThreadEventInfo :: Created ( thr) ,
715
+ _ => unimplemented ! ( )
716
+ } ;
717
+ userthread_cb ( ( * extra) . lua ( ) , event_info)
718
+ }
719
+ } ) ;
720
+ }
721
+
722
+ // Set interrupt callback
723
+ let lua = self . lock ( ) ;
724
+ unsafe {
725
+ ( * lua. extra . get ( ) ) . userthread_callback = Some ( Rc :: new ( callback) ) ;
726
+ ( * ffi:: lua_callbacks ( lua. main_state ( ) ) ) . userthread = Some ( userthread_proc) ;
727
+ }
728
+ }
729
+
730
+ /// Removes any thread event function previously set by `set_thread_event_callback`.
731
+ ///
732
+ /// This function has no effect if a callback was not previously set.
733
+ #[ cfg( any( feature = "luau" , doc) ) ]
734
+ #[ cfg_attr( docsrs, doc( cfg( feature = "luau" ) ) ) ]
735
+ pub fn remove_thread_event_callback ( & self ) {
736
+ let lua = self . lock ( ) ;
737
+ unsafe {
738
+ ( * lua. extra . get ( ) ) . userthread_callback = None ;
739
+ ( * ffi:: lua_callbacks ( lua. main_state ( ) ) ) . userthread = None ;
740
+ }
741
+ }
742
+
674
743
/// Sets the warning function to be used by Lua to emit warnings.
675
744
///
676
745
/// Requires `feature = "lua54"`
0 commit comments