@@ -613,8 +613,6 @@ class taskgroup {
613
613
}
614
614
}
615
615
616
- fn taskgroup_key ( +_group : @taskgroup ) { } // For TLS
617
-
618
616
fn enlist_in_taskgroup ( group_arc : taskgroup_arc ,
619
617
me : * rust_task ) -> option < uint > {
620
618
do group_arc. with |_c, state| {
@@ -682,9 +680,16 @@ fn kill_taskgroup(group_arc: taskgroup_arc, me: *rust_task, index: uint,
682
680
} ;
683
681
}
684
682
683
+ // FIXME (#2912): Work around core-vs-coretest function duplication. Can't use
684
+ // a proper closure because the #[test]s won't understand. Have to fake it.
685
+ unsafe fn taskgroup_key ( ) -> local_data_key < taskgroup > {
686
+ // Use a "code pointer" value that will never be a real code pointer.
687
+ unsafe :: transmute ( ( -2 as uint , 0 u) )
688
+ }
689
+
685
690
fn share_parent_taskgroup ( ) -> ( taskgroup_arc , bool ) {
686
691
let me = rustrt:: rust_get_task ( ) ;
687
- alt unsafe { local_get ( me, taskgroup_key) } {
692
+ alt unsafe { local_get ( me, taskgroup_key ( ) ) } {
688
693
some ( group) {
689
694
// Clone the shared state for the child; propagate main-ness.
690
695
( group. tasks . clone ( ) , group. is_main )
@@ -693,7 +698,7 @@ fn share_parent_taskgroup() -> (taskgroup_arc, bool) {
693
698
// Main task, doing first spawn ever.
694
699
let tasks = arc:: exclusive ( some ( dvec:: from_elem ( some ( me) ) ) ) ;
695
700
let group = @taskgroup ( tasks. clone ( ) , me, 0 , true ) ;
696
- unsafe { local_set ( me, taskgroup_key, group) ; }
701
+ unsafe { local_set ( me, taskgroup_key ( ) , group) ; }
697
702
// Tell child task it's also in the main group.
698
703
( tasks, true )
699
704
}
@@ -764,12 +769,13 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
764
769
some ( my_index) {
765
770
let group =
766
771
@taskgroup ( child_tg, child_task, my_index, is_main) ;
767
- unsafe { local_set ( child_task, taskgroup_key, group) ; }
772
+ unsafe { local_set ( child_task, taskgroup_key ( ) , group) ; }
768
773
// Run the child's body.
769
774
f ( ) ;
770
775
// TLS cleanup code will exit the taskgroup.
771
776
}
772
- none { }
777
+ none {
778
+ }
773
779
}
774
780
}
775
781
}
@@ -820,34 +826,30 @@ fn spawn_raw(opts: task_opts, +f: fn~()) {
820
826
****************************************************************************/
821
827
822
828
/**
823
- * Indexes a task-local data slot. The function itself is used to
824
- * automatically finalise stored values; also, its code pointer is used for
829
+ * Indexes a task-local data slot. The function's code pointer is used for
825
830
* comparison. Recommended use is to write an empty function for each desired
826
- * task-local data slot (and use class destructors, instead of code inside the
827
- * finaliser , if specific teardown is needed). DO NOT use multiple
831
+ * task-local data slot (and use class destructors, not code inside the
832
+ * function , if specific teardown is needed). DO NOT use multiple
828
833
* instantiations of a single polymorphic function to index data of different
829
834
* types; arbitrary type coercion is possible this way. The interface is safe
830
835
* as long as all key functions are monomorphic.
831
836
*/
832
837
type local_data_key < T > = fn @( +@T ) ;
833
838
839
+ iface local_data { }
840
+ impl < T > of local_data for @T { }
841
+
834
842
// We use dvec because it's the best data structure in core. If TLS is used
835
843
// heavily in future, this could be made more efficient with a proper map.
836
- type task_local_element = ( * libc:: c_void , * libc:: c_void , fn @ ( + * libc :: c_void ) ) ;
844
+ type task_local_element = ( * libc:: c_void , * libc:: c_void , local_data ) ;
837
845
// Has to be a pointer at outermost layer; the foreign call returns void *.
838
846
type task_local_map = @dvec:: dvec < option < task_local_element > > ;
839
847
840
848
extern fn cleanup_task_local_map ( map_ptr : * libc:: c_void ) unsafe {
841
849
assert !map_ptr. is_null ( ) ;
842
850
// Get and keep the single reference that was created at the beginning.
843
- let map: task_local_map = unsafe :: reinterpret_cast ( map_ptr) ;
844
- for ( * map) . each |entry| {
845
- alt entry {
846
- // Finaliser drops data. We drop the finaliser implicitly here.
847
- some( ( _key, data, finalise_fn) ) { finalise_fn( data) ; }
848
- none { }
849
- }
850
- }
851
+ let _map: task_local_map = unsafe :: reinterpret_cast ( map_ptr) ;
852
+ // All local_data will be destroyed along with the map.
851
853
}
852
854
853
855
// Gets the map from the runtime. Lazily initialises if not done so already.
@@ -881,15 +883,15 @@ unsafe fn key_to_key_value<T>(key: local_data_key<T>) -> *libc::c_void {
881
883
882
884
// If returning some(..), returns with @T with the map's reference. Careful!
883
885
unsafe fn local_data_lookup < T > ( map : task_local_map , key : local_data_key < T > )
884
- -> option < ( uint , * libc:: c_void , fn @ ( + * libc :: c_void ) ) > {
886
+ -> option < ( uint , * libc:: c_void ) > {
885
887
let key_value = key_to_key_value ( key) ;
886
888
let map_pos = ( * map) . position ( |entry|
887
889
alt entry { some( ( k, _, _) ) { k == key_value } none { false } }
888
890
) ;
889
891
do map_pos. map |index| {
890
892
// .get() is guaranteed because of "none { false }" above.
891
- let ( _, data_ptr, finaliser ) = ( * map) [ index] . get ( ) ;
892
- ( index, data_ptr, finaliser )
893
+ let ( _, data_ptr, _ ) = ( * map) [ index] . get ( ) ;
894
+ ( index, data_ptr)
893
895
}
894
896
}
895
897
@@ -898,15 +900,15 @@ unsafe fn local_get_helper<T>(task: *rust_task, key: local_data_key<T>,
898
900
let map = get_task_local_map ( task) ;
899
901
// Interpret our findings from the map
900
902
do local_data_lookup ( map, key) . map |result| {
901
- // A reference count magically appears on 'data' out of thin air.
902
- // 'data' has the reference we originally stored it with. We either
903
- // need to erase it from the map or artificially bump the count.
904
- let ( index, data_ptr, _) = result;
903
+ // A reference count magically appears on 'data' out of thin air. It
904
+ // was referenced in the local_data box, though, not here, so before
905
+ // overwriting the local_data_box we need to give an extra reference.
906
+ // We must also give an extra reference when not removing.
907
+ let ( index, data_ptr) = result;
905
908
let data: @T = unsafe :: transmute ( data_ptr) ;
909
+ unsafe :: bump_box_refcount ( data) ;
906
910
if do_pop {
907
911
( * map) . set_elt ( index, none) ;
908
- } else {
909
- unsafe :: bump_box_refcount ( data) ;
910
912
}
911
913
data
912
914
}
@@ -926,20 +928,20 @@ unsafe fn local_set<T>(task: *rust_task, key: local_data_key<T>, +data: @T) {
926
928
let map = get_task_local_map ( task) ;
927
929
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
928
930
let keyval = key_to_key_value ( key) ;
929
- let data_ptr = unsafe :: transmute ( data) ;
930
- // Finaliser is called at task exit to de-reference up remaining entries.
931
- let finaliser: fn @( +* libc:: c_void ) = unsafe :: reinterpret_cast ( key) ;
931
+ // We keep the data in two forms: one as an unsafe pointer, so we can get
932
+ // it back by casting; another in an existential box, so the reference we
933
+ // own on it can be dropped when the box is destroyed. The unsafe pointer
934
+ // does not have a reference associated with it, so it may become invalid
935
+ // when the box is destroyed.
936
+ let data_ptr = unsafe :: reinterpret_cast ( data) ;
937
+ let data_box = data as local_data ;
932
938
// Construct new entry to store in the map.
933
- let new_entry = some ( ( keyval, data_ptr, finaliser ) ) ;
939
+ let new_entry = some ( ( keyval, data_ptr, data_box ) ) ;
934
940
// Find a place to put it.
935
941
alt local_data_lookup ( map, key) {
936
- some ( ( index, old_data_ptr, old_finaliser) ) {
937
- // Key already had a value set, old_data_ptr, whose reference we
938
- // need to drop. After that, overwriting its slot will be safe.
939
- // (The heap-allocated finaliser will be freed in the overwrite.)
940
- // FIXME(#2734): just transmuting old_data_ptr to @T doesn't work,
941
- // similarly to the sample there (but more our/unsafety's fault?).
942
- old_finaliser ( old_data_ptr) ;
942
+ some ( ( index, _old_data_ptr) ) {
943
+ // Key already had a value set, _old_data_ptr, whose reference
944
+ // will get dropped when the local_data box is overwritten.
943
945
( * map) . set_elt ( index, new_entry) ;
944
946
}
945
947
none {
0 commit comments