Skip to content

Commit 263e712

Browse files
authored
Fixing multithreaded tests (#265)
This PR aims to fix multithreaded tests as noted in #179. To fix the issue, we needed to: - Capture all tasks in the shadow stack of other tasks; - Scan/conservatively process `scope`s and references in `__jmpbuf` in `task.eh`.
1 parent 017cfa8 commit 263e712

File tree

3 files changed

+77
-63
lines changed

3 files changed

+77
-63
lines changed

.github/scripts/ci-test-other.sh

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ declare -a max_moving_tests_to_skip=(
2323
"cmdlineargs"
2424
"Downloads"
2525
"read"
26-
"threads"
2726
"LibCURL"
28-
"rounding"
2927
"loading"
3028
"misc"
3129
)
@@ -63,8 +61,24 @@ if [[ $CHOOSE_TESTS_JL_CONTENT =~ $REGEX_PATTERN ]]; then
6361
continue
6462
fi
6563

64+
if [[ $test =~ "rounding" ]]; then
65+
# Run rounding test with single thread and Julia's
66+
# heap resizing (it OOMs with a fixed heap)
67+
echo "-> Run"
68+
ci_run_jl_test $test 1 $moving_feature
69+
continue
70+
fi
71+
72+
if [[ $test =~ "ranges" ]]; then
73+
# Run ranges test with single thread and Julia's
74+
# heap resizing (it OOMs with a fixed heap)
75+
echo "-> Run"
76+
ci_run_jl_test $test 1 $moving_feature
77+
continue
78+
fi
79+
6680
echo "-> Run"
67-
ci_run_jl_test $test 1 $moving_feature
81+
ci_run_jl_test $test 2 $moving_feature
6882
fi
6983
done
7084
else

mmtk/src/julia_types.rs

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -418,23 +418,26 @@ const _: () = {
418418
pub struct jl_thread_heap_common_t {
419419
pub weak_refs: small_arraylist_t,
420420
pub live_tasks: small_arraylist_t,
421+
pub all_tasks: small_arraylist_t,
421422
pub mallocarrays: small_arraylist_t,
422423
pub free_stacks: [small_arraylist_t; 16usize],
423424
}
424425
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
425426
const _: () = {
426427
["Size of jl_thread_heap_common_t"]
427-
[::std::mem::size_of::<jl_thread_heap_common_t>() - 1216usize];
428+
[::std::mem::size_of::<jl_thread_heap_common_t>() - 1280usize];
428429
["Alignment of jl_thread_heap_common_t"]
429430
[::std::mem::align_of::<jl_thread_heap_common_t>() - 8usize];
430431
["Offset of field: jl_thread_heap_common_t::weak_refs"]
431432
[::std::mem::offset_of!(jl_thread_heap_common_t, weak_refs) - 0usize];
432433
["Offset of field: jl_thread_heap_common_t::live_tasks"]
433434
[::std::mem::offset_of!(jl_thread_heap_common_t, live_tasks) - 64usize];
435+
["Offset of field: jl_thread_heap_common_t::all_tasks"]
436+
[::std::mem::offset_of!(jl_thread_heap_common_t, all_tasks) - 128usize];
434437
["Offset of field: jl_thread_heap_common_t::mallocarrays"]
435-
[::std::mem::offset_of!(jl_thread_heap_common_t, mallocarrays) - 128usize];
438+
[::std::mem::offset_of!(jl_thread_heap_common_t, mallocarrays) - 192usize];
436439
["Offset of field: jl_thread_heap_common_t::free_stacks"]
437-
[::std::mem::offset_of!(jl_thread_heap_common_t, free_stacks) - 192usize];
440+
[::std::mem::offset_of!(jl_thread_heap_common_t, free_stacks) - 256usize];
438441
};
439442
#[repr(C)]
440443
#[derive(Debug)]
@@ -480,13 +483,13 @@ pub struct jl_gc_tls_states_common_t {
480483
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
481484
const _: () = {
482485
["Size of jl_gc_tls_states_common_t"]
483-
[::std::mem::size_of::<jl_gc_tls_states_common_t>() - 1280usize];
486+
[::std::mem::size_of::<jl_gc_tls_states_common_t>() - 1344usize];
484487
["Alignment of jl_gc_tls_states_common_t"]
485488
[::std::mem::align_of::<jl_gc_tls_states_common_t>() - 8usize];
486489
["Offset of field: jl_gc_tls_states_common_t::heap"]
487490
[::std::mem::offset_of!(jl_gc_tls_states_common_t, heap) - 0usize];
488491
["Offset of field: jl_gc_tls_states_common_t::gc_num"]
489-
[::std::mem::offset_of!(jl_gc_tls_states_common_t, gc_num) - 1216usize];
492+
[::std::mem::offset_of!(jl_gc_tls_states_common_t, gc_num) - 1280usize];
490493
};
491494
#[repr(C)]
492495
#[derive(Debug, Copy, Clone)]
@@ -675,7 +678,7 @@ pub struct _jl_tls_states_t {
675678
}
676679
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
677680
const _: () = {
678-
["Size of _jl_tls_states_t"][::std::mem::size_of::<_jl_tls_states_t>() - 3616usize];
681+
["Size of _jl_tls_states_t"][::std::mem::size_of::<_jl_tls_states_t>() - 3680usize];
679682
["Alignment of _jl_tls_states_t"][::std::mem::align_of::<_jl_tls_states_t>() - 8usize];
680683
["Offset of field: _jl_tls_states_t::tid"]
681684
[::std::mem::offset_of!(_jl_tls_states_t, tid) - 0usize];
@@ -702,51 +705,51 @@ const _: () = {
702705
["Offset of field: _jl_tls_states_t::gc_tls_common"]
703706
[::std::mem::offset_of!(_jl_tls_states_t, gc_tls_common) - 1800usize];
704707
["Offset of field: _jl_tls_states_t::lazily_freed_mtarraylist_buffers"]
705-
[::std::mem::offset_of!(_jl_tls_states_t, lazily_freed_mtarraylist_buffers) - 3080usize];
708+
[::std::mem::offset_of!(_jl_tls_states_t, lazily_freed_mtarraylist_buffers) - 3144usize];
706709
["Offset of field: _jl_tls_states_t::defer_signal"]
707-
[::std::mem::offset_of!(_jl_tls_states_t, defer_signal) - 3144usize];
710+
[::std::mem::offset_of!(_jl_tls_states_t, defer_signal) - 3208usize];
708711
["Offset of field: _jl_tls_states_t::current_task"]
709-
[::std::mem::offset_of!(_jl_tls_states_t, current_task) - 3152usize];
712+
[::std::mem::offset_of!(_jl_tls_states_t, current_task) - 3216usize];
710713
["Offset of field: _jl_tls_states_t::next_task"]
711-
[::std::mem::offset_of!(_jl_tls_states_t, next_task) - 3160usize];
714+
[::std::mem::offset_of!(_jl_tls_states_t, next_task) - 3224usize];
712715
["Offset of field: _jl_tls_states_t::previous_task"]
713-
[::std::mem::offset_of!(_jl_tls_states_t, previous_task) - 3168usize];
716+
[::std::mem::offset_of!(_jl_tls_states_t, previous_task) - 3232usize];
714717
["Offset of field: _jl_tls_states_t::root_task"]
715-
[::std::mem::offset_of!(_jl_tls_states_t, root_task) - 3176usize];
718+
[::std::mem::offset_of!(_jl_tls_states_t, root_task) - 3240usize];
716719
["Offset of field: _jl_tls_states_t::timing_stack"]
717-
[::std::mem::offset_of!(_jl_tls_states_t, timing_stack) - 3184usize];
720+
[::std::mem::offset_of!(_jl_tls_states_t, timing_stack) - 3248usize];
718721
["Offset of field: _jl_tls_states_t::stackbase"]
719-
[::std::mem::offset_of!(_jl_tls_states_t, stackbase) - 3192usize];
722+
[::std::mem::offset_of!(_jl_tls_states_t, stackbase) - 3256usize];
720723
["Offset of field: _jl_tls_states_t::stacksize"]
721-
[::std::mem::offset_of!(_jl_tls_states_t, stacksize) - 3200usize];
724+
[::std::mem::offset_of!(_jl_tls_states_t, stacksize) - 3264usize];
722725
["Offset of field: _jl_tls_states_t::sig_exception"]
723-
[::std::mem::offset_of!(_jl_tls_states_t, sig_exception) - 3208usize];
726+
[::std::mem::offset_of!(_jl_tls_states_t, sig_exception) - 3272usize];
724727
["Offset of field: _jl_tls_states_t::bt_data"]
725-
[::std::mem::offset_of!(_jl_tls_states_t, bt_data) - 3216usize];
728+
[::std::mem::offset_of!(_jl_tls_states_t, bt_data) - 3280usize];
726729
["Offset of field: _jl_tls_states_t::bt_size"]
727-
[::std::mem::offset_of!(_jl_tls_states_t, bt_size) - 3224usize];
730+
[::std::mem::offset_of!(_jl_tls_states_t, bt_size) - 3288usize];
728731
["Offset of field: _jl_tls_states_t::profiling_bt_buffer"]
729-
[::std::mem::offset_of!(_jl_tls_states_t, profiling_bt_buffer) - 3232usize];
732+
[::std::mem::offset_of!(_jl_tls_states_t, profiling_bt_buffer) - 3296usize];
730733
["Offset of field: _jl_tls_states_t::signal_request"]
731-
[::std::mem::offset_of!(_jl_tls_states_t, signal_request) - 3240usize];
734+
[::std::mem::offset_of!(_jl_tls_states_t, signal_request) - 3304usize];
732735
["Offset of field: _jl_tls_states_t::io_wait"]
733-
[::std::mem::offset_of!(_jl_tls_states_t, io_wait) - 3244usize];
736+
[::std::mem::offset_of!(_jl_tls_states_t, io_wait) - 3308usize];
734737
["Offset of field: _jl_tls_states_t::signal_stack"]
735-
[::std::mem::offset_of!(_jl_tls_states_t, signal_stack) - 3248usize];
738+
[::std::mem::offset_of!(_jl_tls_states_t, signal_stack) - 3312usize];
736739
["Offset of field: _jl_tls_states_t::signal_stack_size"]
737-
[::std::mem::offset_of!(_jl_tls_states_t, signal_stack_size) - 3256usize];
740+
[::std::mem::offset_of!(_jl_tls_states_t, signal_stack_size) - 3320usize];
738741
["Offset of field: _jl_tls_states_t::system_id"]
739-
[::std::mem::offset_of!(_jl_tls_states_t, system_id) - 3264usize];
742+
[::std::mem::offset_of!(_jl_tls_states_t, system_id) - 3328usize];
740743
["Offset of field: _jl_tls_states_t::suspend_count"]
741-
[::std::mem::offset_of!(_jl_tls_states_t, suspend_count) - 3272usize];
744+
[::std::mem::offset_of!(_jl_tls_states_t, suspend_count) - 3336usize];
742745
["Offset of field: _jl_tls_states_t::finalizers"]
743-
[::std::mem::offset_of!(_jl_tls_states_t, finalizers) - 3280usize];
746+
[::std::mem::offset_of!(_jl_tls_states_t, finalizers) - 3344usize];
744747
["Offset of field: _jl_tls_states_t::previous_exception"]
745-
[::std::mem::offset_of!(_jl_tls_states_t, previous_exception) - 3536usize];
748+
[::std::mem::offset_of!(_jl_tls_states_t, previous_exception) - 3600usize];
746749
["Offset of field: _jl_tls_states_t::locks"]
747-
[::std::mem::offset_of!(_jl_tls_states_t, locks) - 3544usize];
750+
[::std::mem::offset_of!(_jl_tls_states_t, locks) - 3608usize];
748751
["Offset of field: _jl_tls_states_t::engine_nqueued"]
749-
[::std::mem::offset_of!(_jl_tls_states_t, engine_nqueued) - 3608usize];
752+
[::std::mem::offset_of!(_jl_tls_states_t, engine_nqueued) - 3672usize];
750753
};
751754
pub type jl_function_t = jl_value_t;
752755
pub type jl_timing_block_t = _jl_timing_block_t;
@@ -3520,10 +3523,3 @@ const _: () = {
35203523
["Align of template specialization: pinned_ref_open0_jl_value_t_close0"]
35213524
[::std::mem::align_of::<pinned_ref<jl_value_t>>() - 8usize];
35223525
};
3523-
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
3524-
const _: () = {
3525-
["Size of template specialization: pinned_ref_open0_jl_value_t_close0"]
3526-
[::std::mem::size_of::<pinned_ref<jl_value_t>>() - 8usize];
3527-
["Align of template specialization: pinned_ref_open0_jl_value_t_close0"]
3528-
[::std::mem::align_of::<pinned_ref<jl_value_t>>() - 8usize];
3529-
};

mmtk/src/scanning.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ impl Scanning<JuliaVM> for VMScanning {
6262
crate::conservative::mmtk_conservative_scan_ptls_registers(ptls);
6363

6464
// Scan thread local from ptls: See gc_queue_thread_local in gc.c
65-
let mut root_scan_task = |task: *const _jl_task_t, task_is_root: bool| {
65+
66+
// scan task object to conservatively pin references from shadow,
67+
// gc_preserve and regular stack and registers
68+
let mut scan_root_task = |task: *const _jl_task_t| {
6669
if !task.is_null() {
6770
// Scan gc preserve and shadow stacks
6871
unsafe {
@@ -92,40 +95,41 @@ impl Scanning<JuliaVM> for VMScanning {
9295
crate::conservative::mmtk_conservative_scan_task_registers(task);
9396
}
9497
// }
98+
};
99+
};
95100

96-
if task_is_root {
97-
// captures wrong root nodes before creating the work
98-
debug_assert!(
99-
Address::from_ptr(task).as_usize() % 16 == 0
100-
|| Address::from_ptr(task).as_usize() % 8 == 0,
101-
"root node {:?} is not aligned to 8 or 16",
102-
Address::from_ptr(task)
103-
);
101+
// adding task object as root
102+
let mut add_task_as_root = |task: *const _jl_task_t| {
103+
if !task.is_null() {
104+
// captures wrong root nodes before creating the work
105+
debug_assert!(
106+
Address::from_ptr(task).as_usize() % 16 == 0
107+
|| Address::from_ptr(task).as_usize() % 8 == 0,
108+
"root node {:?} is not aligned to 8 or 16",
109+
Address::from_ptr(task)
110+
);
104111

105-
// unsafe: We checked `!task.is_null()` before.
106-
let objref = unsafe {
107-
ObjectReference::from_raw_address_unchecked(Address::from_ptr(task))
108-
};
109-
node_buffer.push(objref);
110-
}
112+
let objref =
113+
unsafe { ObjectReference::from_raw_address_unchecked(Address::from_ptr(task)) };
114+
node_buffer.push(objref);
111115
}
112116
};
113-
root_scan_task(ptls.root_task, true);
114117

115-
// need to iterate over live tasks as well to process their shadow stacks
116-
// we should not set the task themselves as roots as we will know which ones are still alive after GC
118+
add_task_as_root(ptls.root_task);
119+
add_task_as_root(ptls.current_task as *mut _jl_task_t);
120+
add_task_as_root(ptls.next_task);
121+
add_task_as_root(ptls.previous_task);
122+
123+
// need to iterate over all tasks as well to process their shadow stacks and scan their stacks
117124
let mut i = 0;
118-
while i < ptls.gc_tls_common.heap.live_tasks.len {
119-
let mut task_address = Address::from_ptr(ptls.gc_tls_common.heap.live_tasks.items);
125+
while i < ptls.gc_tls_common.heap.all_tasks.len {
126+
let mut task_address = Address::from_ptr(ptls.gc_tls_common.heap.all_tasks.items);
120127
task_address = task_address.shift::<Address>(i as isize);
121128
let task = unsafe { task_address.load::<*const jl_task_t>() };
122-
root_scan_task(task, false);
129+
scan_root_task(task);
123130
i += 1;
124131
}
125132

126-
root_scan_task(ptls.current_task as *mut _jl_task_t, true);
127-
root_scan_task(ptls.next_task, true);
128-
root_scan_task(ptls.previous_task, true);
129133
if !ptls.previous_exception.is_null() {
130134
node_buffer.push(unsafe {
131135
// unsafe: We have just checked `ptls.previous_exception` is not null.

0 commit comments

Comments
 (0)