mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-11 08:08:08 +00:00
batch relocations to reduce contention on global reference list
This commit is contained in:
+144
-152
@@ -1813,7 +1813,7 @@ lnk_link_inputs(TP_Context *tp,
|
|||||||
is_addr_import = hash_map_search_stringf_raw(&imports_hm, "__imp_%S", member_ref->link_symbol->name);
|
is_addr_import = hash_map_search_stringf_raw(&imports_hm, "__imp_%S", member_ref->link_symbol->name);
|
||||||
}
|
}
|
||||||
if (is_thunk_import != 0 || is_addr_import != 0) {
|
if (is_thunk_import != 0 || is_addr_import != 0) {
|
||||||
lnk_invalid_path("duplicate import member queue detected");
|
lnk_log(LNK_Log_Debug, "duplicate import %S member queue detected", member_ref->link_symbol->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2379,62 +2379,53 @@ lnk_link_image(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
lnk_reloc_refs_list_push_node(LNK_RelocRefsList *list, LNK_RelocRefsNode *node)
|
lnk_reloc_ref_batch_list_push_node(LNK_RelocRefsBatchList *list, LNK_RelocRefsBatch *node)
|
||||||
{
|
{
|
||||||
LNK_RelocRefsPointer old_head = list->head;
|
LNK_RelocRefsBatchPointer old_head = list->head;
|
||||||
node->next = old_head.node;
|
node->next = old_head.node;
|
||||||
list->head = (LNK_RelocRefsPointer){ .node = node, .tag = old_head.tag + 1 };
|
list->head = (LNK_RelocRefsBatchPointer){ .node = node, .tag = old_head.tag + 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LNK_RelocRefsNode *
|
internal void
|
||||||
lnk_reloc_refs_list_pop_node(LNK_RelocRefsList *list)
|
lnk_reloc_ref_batch_list_push(Arena *arena, LNK_RelocRefsBatchList *list, LNK_RelocRefs v)
|
||||||
{
|
{
|
||||||
LNK_RelocRefsPointer old_head = list->head;
|
LNK_RelocRefsBatch *batch = list->head.node;
|
||||||
|
if (list->head.node == 0 || list->head.node->count >= ArrayCount(list->head.node->v)) {
|
||||||
|
batch = push_array(arena, LNK_RelocRefsBatch, 1);
|
||||||
|
lnk_reloc_ref_batch_list_push_node(list, batch);
|
||||||
|
}
|
||||||
|
batch->v[batch->count++] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LNK_RelocRefsBatch *
|
||||||
|
lnk_reloc_ref_batch_list_pop(LNK_RelocRefsBatchList *list)
|
||||||
|
{
|
||||||
|
LNK_RelocRefsBatchPointer old_head = list->head;
|
||||||
if (old_head.node) {
|
if (old_head.node) {
|
||||||
list->head = (LNK_RelocRefsPointer){ .node = old_head.node->next, .tag = old_head.tag + 1};
|
list->head = (LNK_RelocRefsBatchPointer){ .node = old_head.node->next, .tag = old_head.tag + 1};
|
||||||
}
|
}
|
||||||
return old_head.node;
|
return old_head.node;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LNK_RelocRefsNode *
|
internal LNK_RelocRefsBatch *
|
||||||
lnk_reloc_refs_list_push(Arena *arena, LNK_RelocRefsList *list, LNK_RelocRefs *v)
|
lnk_reloc_ref_batch_list_pop_atomic(LNK_RelocRefsBatchList *list)
|
||||||
{
|
{
|
||||||
LNK_RelocRefsNode *node = push_array(arena, LNK_RelocRefsNode, 1);
|
LNK_RelocRefsBatchPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) };
|
||||||
node->v = v;
|
|
||||||
lnk_reloc_refs_list_push_node(list, node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal LNK_RelocRefsNode *
|
|
||||||
lnk_reloc_refs_list_pop_node_atomic(LNK_RelocRefsList *list)
|
|
||||||
{
|
|
||||||
LNK_RelocRefsPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) };
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (old_head.node == 0) { break; }
|
if (old_head.node == 0) { break; }
|
||||||
LNK_RelocRefsPointer new_head = { .node = old_head.node->next, .tag = old_head.tag + 1 };
|
LNK_RelocRefsBatchPointer new_head = { .node = old_head.node->next, .tag = old_head.tag + 1 };
|
||||||
if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; }
|
if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; }
|
||||||
}
|
}
|
||||||
return old_head.node;
|
return old_head.node;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
lnk_reloc_refs_list_push_node_atomic(LNK_RelocRefsList *list, LNK_RelocRefsNode *node)
|
lnk_reloc_ref_batch_list_concat_in_place_atomic(LNK_RelocRefsBatchList *list, LNK_RelocRefsBatch *first, LNK_RelocRefsBatch *last)
|
||||||
{
|
{
|
||||||
LNK_RelocRefsPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) };
|
LNK_RelocRefsBatchPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) };
|
||||||
for (;;) {
|
|
||||||
node->next = old_head.node;
|
|
||||||
LNK_RelocRefsPointer new_head = { .node = node, .tag = old_head.tag + 1 };
|
|
||||||
if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
lnk_reloc_refs_list_concat_in_place(LNK_RelocRefsList *list, LNK_RelocRefsNode *first, LNK_RelocRefsNode *last)
|
|
||||||
{
|
|
||||||
LNK_RelocRefsPointer old_head = { .node = ins_atomic_ptr_eval(&list->head.node), .tag = ins_atomic_u64_eval(&list->head.tag) };
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
last->next = old_head.node;
|
last->next = old_head.node;
|
||||||
LNK_RelocRefsPointer new_head = { .node = first, .tag = old_head.tag + 1 };
|
LNK_RelocRefsBatchPointer new_head = { .node = first, .tag = old_head.tag + 1 };
|
||||||
if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; }
|
if (ins_atomic_u128_eval_cond_assign(&list->head, &new_head, &old_head)) { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2452,13 +2443,12 @@ THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task)
|
|||||||
LNK_Config *config = task->config;
|
LNK_Config *config = task->config;
|
||||||
LNK_ObjList objs = task->objs;
|
LNK_ObjList objs = task->objs;
|
||||||
|
|
||||||
U8 **is_live = 0;
|
U8 **is_live = 0;
|
||||||
U64 *active_thread_count = 0;
|
U64 *active_thread_count = 0;
|
||||||
LNK_RelocRefsList *ref_queue = 0;
|
LNK_RelocRefsBatchList *global_batch_list = 0;
|
||||||
LNK_RelocRefsList free_list = {0};
|
|
||||||
if (task_id == 0) {
|
if (task_id == 0) {
|
||||||
active_thread_count = push_array(scratch.arena, U64, 1);
|
active_thread_count = push_array(scratch.arena, U64, 1);
|
||||||
ref_queue = push_array(scratch.arena, LNK_RelocRefsList, 1);
|
global_batch_list = push_array(scratch.arena, LNK_RelocRefsBatchList, 1);
|
||||||
|
|
||||||
// alloc live flags for each section
|
// alloc live flags for each section
|
||||||
is_live = push_array_no_zero(scratch.arena, U8 *, objs.count);
|
is_live = push_array_no_zero(scratch.arena, U8 *, objs.count);
|
||||||
@@ -2490,13 +2480,13 @@ THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task)
|
|||||||
LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name);
|
LNK_Symbol *root = lnk_symbol_table_search(symtab, root_n->v.name);
|
||||||
LNK_ObjSymbolRef root_ref = lnk_ref_from_symbol(root);
|
LNK_ObjSymbolRef root_ref = lnk_ref_from_symbol(root);
|
||||||
|
|
||||||
LNK_RelocRefs *r = push_array(scratch.arena, LNK_RelocRefs, 1);
|
LNK_RelocRefs r = {0};
|
||||||
r->obj = root_ref.obj;
|
r.obj = root_ref.obj;
|
||||||
r->relocs.count = 1;
|
r.relocs.count = 1;
|
||||||
r->relocs.v = push_array(scratch.arena, COFF_Reloc, 1);
|
r.relocs.v = push_array(scratch.arena, COFF_Reloc, 1);
|
||||||
r->relocs.v[0].isymbol = root_ref.symbol_idx;
|
r.relocs.v[0].isymbol = root_ref.symbol_idx;
|
||||||
|
|
||||||
lnk_reloc_refs_list_push(scratch.arena, ref_queue, r);
|
lnk_reloc_ref_batch_list_push(scratch.arena, global_batch_list, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
// push task for every non-COMDAT section
|
// push task for every non-COMDAT section
|
||||||
@@ -2513,159 +2503,161 @@ THREAD_POOL_TASK_FUNC(lnk_walk_relocs_and_mark_ref_sections_task)
|
|||||||
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||||
|
|
||||||
// divide relocs and push task for each reloc block
|
// divide relocs and push task for each reloc block
|
||||||
COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number);
|
COFF_RelocArray relocs = lnk_coff_reloc_info_from_section_number(obj, section_number);
|
||||||
U64 new_task_count = CeilIntegerDiv(relocs.count, LNK_RELOCS_PER_TASK);
|
U64 relocs_per_batch = 1000;
|
||||||
LNK_RelocRefs *new_tasks = push_array(scratch.arena, LNK_RelocRefs, new_task_count);
|
U64 new_task_count = CeilIntegerDiv(relocs.count, relocs_per_batch);
|
||||||
for EachIndex(new_task_idx, new_task_count) {
|
for EachIndex(new_task_idx, new_task_count) {
|
||||||
LNK_RelocRefs *r = new_tasks + new_task_idx;
|
LNK_RelocRefs r = {0};
|
||||||
r->obj = obj;
|
r.obj = obj;
|
||||||
r->relocs.count = Min(LNK_RELOCS_PER_TASK, relocs.count - (new_task_idx * LNK_RELOCS_PER_TASK));
|
r.relocs.count = Min(relocs_per_batch, relocs.count - (new_task_idx * relocs_per_batch));
|
||||||
r->relocs.v = relocs.v + (new_task_idx * LNK_RELOCS_PER_TASK);
|
r.relocs.v = relocs.v + (new_task_idx * relocs_per_batch);
|
||||||
|
lnk_reloc_ref_batch_list_push(scratch.arena, global_batch_list, r);
|
||||||
lnk_reloc_refs_list_push(scratch.arena, ref_queue, r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tp_broadcast(&is_live);
|
tp_broadcast(&is_live);
|
||||||
tp_broadcast(&ref_queue);
|
tp_broadcast(&global_batch_list);
|
||||||
tp_broadcast(&active_thread_count);
|
tp_broadcast(&active_thread_count);
|
||||||
|
|
||||||
|
LNK_RelocRefsBatchList free_list = {0};
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// update active thread count
|
// update active thread count
|
||||||
ins_atomic_u32_inc_eval(active_thread_count);
|
ins_atomic_u32_inc_eval(active_thread_count);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// pop head node
|
// pop batch
|
||||||
LNK_RelocRefsNode *node = lnk_reloc_refs_list_pop_node_atomic(ref_queue);
|
LNK_RelocRefsBatch *batch = lnk_reloc_ref_batch_list_pop_atomic(global_batch_list);
|
||||||
if (!node) { break; }
|
if (!batch) { break; }
|
||||||
|
|
||||||
LNK_RelocRefs *reloc_refs = node->v;
|
// walk batch relocations
|
||||||
LNK_RelocRefsNode *first_node = 0, *last_node = 0;
|
LNK_RelocRefsBatch *first_batch = 0, *last_batch = 0;
|
||||||
|
for EachIndex(i, batch->count) {
|
||||||
|
for EachIndex(reloc_idx, batch->v[i].relocs.count) {
|
||||||
|
COFF_Reloc *reloc = &batch->v[i].relocs.v[reloc_idx];
|
||||||
|
|
||||||
for EachIndex(reloc_idx, reloc_refs->relocs.count) {
|
// reloc -> symbol
|
||||||
COFF_Reloc *reloc = &reloc_refs->relocs.v[reloc_idx];
|
LNK_ObjSymbolRef ref_symbol = (LNK_ObjSymbolRef){ .obj = batch->v[i].obj, .symbol_idx = reloc->isymbol };
|
||||||
|
{
|
||||||
|
Temp temp = temp_begin(scratch2.arena);
|
||||||
|
HashMap seen_hm = {0};
|
||||||
|
B32 keep_walking = 1;
|
||||||
|
do {
|
||||||
|
// detect cyclic chains
|
||||||
|
U64 symbol_key = ((U64)ref_symbol.obj->input_idx << 32ull) | (U64)ref_symbol.symbol_idx;
|
||||||
|
if (hash_map_search_u64_u64(&seen_hm, symbol_key) == 0) {
|
||||||
|
hash_map_push_u64_u64(temp.arena, &seen_hm, symbol_key, 1);
|
||||||
|
} else {
|
||||||
|
COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(batch->v[i].obj, reloc->isymbol);
|
||||||
|
lnk_error_obj(LNK_Warning_CyclicSymbol, batch->v[i].obj, "symbol %S forms a cyclic chain (/OPT:REF)", reloc_parsed.name);
|
||||||
|
MemoryZeroStruct(&ref_symbol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// reloc -> symbol
|
// unpack symbol
|
||||||
LNK_ObjSymbolRef ref_symbol = (LNK_ObjSymbolRef){ .obj = reloc_refs->obj, .symbol_idx = reloc->isymbol };
|
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
||||||
{
|
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
||||||
Temp temp = temp_begin(scratch2.arena);
|
|
||||||
HashMap seen_hm = {0};
|
|
||||||
B32 keep_walking = 1;
|
|
||||||
do {
|
|
||||||
// detect cyclic chains
|
|
||||||
U64 symbol_key = ((U64)ref_symbol.obj->input_idx << 32ull) | (U64)ref_symbol.symbol_idx;
|
|
||||||
if (hash_map_search_u64_u64(&seen_hm, symbol_key) == 0) {
|
|
||||||
hash_map_push_u64_u64(temp.arena, &seen_hm, symbol_key, 1);
|
|
||||||
} else {
|
|
||||||
COFF_ParsedSymbol reloc_parsed = lnk_parsed_symbol_from_coff_symbol_idx(reloc_refs->obj, reloc->isymbol);
|
|
||||||
lnk_error_obj(LNK_Warning_CyclicSymbol, reloc_refs->obj, "symbol %S forms a cyclic chain (/OPT:REF)", reloc_parsed.name);
|
|
||||||
MemoryZeroStruct(&ref_symbol);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// unpack symbol
|
// resolve symbol
|
||||||
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
LNK_ObjSymbolRef next_ref = {0};
|
||||||
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
if (lnk_resolve_symbol(symtab, ref_symbol, &next_ref)) {
|
||||||
|
keep_walking = (ref_interp == COFF_SymbolValueInterp_Weak || ref_interp == COFF_SymbolValueInterp_Undefined);
|
||||||
|
ref_symbol = next_ref;
|
||||||
|
} else {
|
||||||
|
keep_walking = 0;
|
||||||
|
}
|
||||||
|
} while (keep_walking);
|
||||||
|
temp_end(temp);
|
||||||
|
}
|
||||||
|
|
||||||
// resolve symbol
|
// skip unresolved symbol
|
||||||
LNK_ObjSymbolRef next_ref = {0};
|
if (ref_symbol.obj == 0) { continue; }
|
||||||
if (lnk_resolve_symbol(symtab, ref_symbol, &next_ref)) {
|
|
||||||
keep_walking = (ref_interp == COFF_SymbolValueInterp_Weak || ref_interp == COFF_SymbolValueInterp_Undefined);
|
|
||||||
ref_symbol = next_ref;
|
|
||||||
} else {
|
|
||||||
keep_walking = 0;
|
|
||||||
}
|
|
||||||
} while (keep_walking);
|
|
||||||
temp_end(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip unresolved symbol
|
// unpack resolved symbol
|
||||||
if (ref_symbol.obj == 0) { continue; }
|
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
||||||
|
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
||||||
|
|
||||||
// unpack resolved symbol
|
if (ref_interp == COFF_SymbolValueInterp_Regular) {
|
||||||
COFF_ParsedSymbol ref_parsed = lnk_parsed_symbol_from_coff_symbol_idx(ref_symbol.obj, ref_symbol.symbol_idx);
|
Temp temp = temp_begin(scratch2.arena);
|
||||||
COFF_SymbolValueInterpType ref_interp = coff_interp_from_parsed_symbol(ref_parsed);
|
|
||||||
|
|
||||||
if (ref_interp == COFF_SymbolValueInterp_Regular) {
|
HashMap visited_sections_hm = {0};
|
||||||
Temp temp = temp_begin(scratch2.arena);
|
U32Node *stack = push_array(temp.arena, U32Node, 1);
|
||||||
|
stack->data = ref_parsed.section_number;
|
||||||
|
do {
|
||||||
|
U32 section_number = stack->data;
|
||||||
|
SLLStackPop(stack);
|
||||||
|
|
||||||
HashMap visited_sections_hm = {0};
|
// is section number valid?
|
||||||
U32Node *stack = push_array(temp.arena, U32Node, 1);
|
if (section_number == 0 || section_number > ref_symbol.obj->header.section_count_no_null) { continue; }
|
||||||
stack->data = ref_parsed.section_number;
|
|
||||||
do {
|
|
||||||
U32 section_number = stack->data;
|
|
||||||
SLLStackPop(stack);
|
|
||||||
|
|
||||||
// is section number valid?
|
// detect cyclic associative sections
|
||||||
if (section_number == 0 || section_number > ref_symbol.obj->header.section_count_no_null) { continue; }
|
if (hash_map_search_u64_u64(&visited_sections_hm, section_number)) { continue; }
|
||||||
|
hash_map_push_u64_u64(temp.arena, &visited_sections_hm, section_number, 1);
|
||||||
|
|
||||||
// detect cyclic associative sections
|
// push associated section
|
||||||
if (hash_map_search_u64_u64(&visited_sections_hm, section_number)) { continue; }
|
for EachNode(associated_n, U32Node, ref_symbol.obj->associated_sections[section_number]) {
|
||||||
hash_map_push_u64_u64(temp.arena, &visited_sections_hm, section_number, 1);
|
if (hash_map_search_u64_u64(&visited_sections_hm, associated_n->data)) { continue; }
|
||||||
|
U32Node *stack_n = push_array(temp.arena, U32Node, 1);
|
||||||
|
stack_n->data = associated_n->data;
|
||||||
|
SLLStackPush(stack, stack_n);
|
||||||
|
}
|
||||||
|
|
||||||
// push associated section
|
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_symbol.obj, section_number);
|
||||||
for EachNode(associated_n, U32Node, ref_symbol.obj->associated_sections[section_number]) {
|
|
||||||
if (hash_map_search_u64_u64(&visited_sections_hm, associated_n->data)) { continue; }
|
|
||||||
U32Node *stack_n = push_array(temp.arena, U32Node, 1);
|
|
||||||
stack_n->data = associated_n->data;
|
|
||||||
SLLStackPush(stack, stack_n);
|
|
||||||
}
|
|
||||||
|
|
||||||
COFF_SectionHeader *section_header = lnk_coff_section_header_from_section_number(ref_symbol.obj, section_number);
|
// is section eligible for walking?
|
||||||
|
if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; }
|
||||||
|
if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; }
|
||||||
|
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
||||||
|
|
||||||
// is section eligible for walking?
|
// on first section visit, set live flag and enqueue section
|
||||||
if (section_header->flags & COFF_SectionFlag_LnkRemove) { continue; }
|
U8 was_visited = ins_atomic_u8_eval_assign(&is_live[ref_symbol.obj->input_idx][section_number], 1);
|
||||||
if (section_header->flags & COFF_SectionFlag_LnkInfo) { continue; }
|
if (was_visited) { continue; }
|
||||||
if (section_header->flags & LNK_SECTION_FLAG_DEBUG) { continue; }
|
|
||||||
|
|
||||||
// on first section visit set live flag and queue new section to walk
|
LNK_RelocRefs refs = {0};
|
||||||
U8 was_visited = ins_atomic_u8_eval_assign(&is_live[ref_symbol.obj->input_idx][section_number], 1);
|
refs.obj = ref_symbol.obj;
|
||||||
if (was_visited) { continue; }
|
refs.relocs = lnk_coff_reloc_info_from_section_number(ref_symbol.obj, section_number);
|
||||||
|
|
||||||
LNK_RelocRefsNode *node;
|
// get a batch node
|
||||||
if (free_list.head.node) {
|
LNK_RelocRefsBatch *batch = last_batch;
|
||||||
node = lnk_reloc_refs_list_pop_node(&free_list);
|
if (last_batch == 0 || last_batch->count >= ArrayCount(last_batch->v)) {
|
||||||
} else {
|
if (free_list.head.node) {
|
||||||
node = push_array(scratch.arena, LNK_RelocRefsNode, 1);
|
batch = lnk_reloc_ref_batch_list_pop(&free_list);
|
||||||
node->v = push_array(scratch.arena, LNK_RelocRefs, 1);
|
MemoryZeroStruct(batch);
|
||||||
}
|
} else {
|
||||||
|
batch = push_array(scratch.arena, LNK_RelocRefsBatch, 1);
|
||||||
|
}
|
||||||
|
SLLQueuePush(first_batch, last_batch, batch);
|
||||||
|
}
|
||||||
|
|
||||||
node->v->obj = ref_symbol.obj;
|
batch->v[batch->count++] = refs;
|
||||||
node->v->relocs = lnk_coff_reloc_info_from_section_number(ref_symbol.obj, section_number);
|
|
||||||
|
|
||||||
if (first_node == 0) {
|
} while (stack);
|
||||||
first_node = node, last_node = node;
|
|
||||||
} else {
|
|
||||||
node->next = first_node;
|
|
||||||
first_node = node;
|
|
||||||
}
|
|
||||||
} while (stack);
|
|
||||||
|
|
||||||
temp_end(temp);
|
temp_end(temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// free walk node
|
|
||||||
lnk_reloc_refs_list_push_node(&free_list, node);
|
|
||||||
|
|
||||||
// queue new walks
|
// queue new walks
|
||||||
if (first_node && last_node) {
|
if (first_batch && last_batch) {
|
||||||
lnk_reloc_refs_list_concat_in_place(ref_queue, first_node, last_node);
|
lnk_reloc_ref_batch_list_concat_in_place_atomic(global_batch_list, first_batch, last_batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// put batch on the free list
|
||||||
|
lnk_reloc_ref_batch_list_push_node(&free_list, batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// are all threads done walking?
|
// are all threads done walking?
|
||||||
{
|
{
|
||||||
U32 c = ins_atomic_u32_dec_eval(active_thread_count);
|
U32 c = ins_atomic_u32_dec_eval(active_thread_count);
|
||||||
if (c == 0 && ins_atomic_ptr_eval(&ref_queue->head.node) == 0) {
|
if (c == 0 && ins_atomic_ptr_eval(&global_batch_list->head.node) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// comprehensive solution to the waiting problem
|
// comprehensive solution to the waiting problem
|
||||||
for (; ins_atomic_ptr_eval(&ref_queue->head.node) == 0; ) {
|
for (; ins_atomic_ptr_eval(&global_batch_list->head.node) == 0; ) {
|
||||||
// was signaled to exit?
|
// was signaled to exit?
|
||||||
if (ins_atomic_u32_eval(active_thread_count) == 0) { goto exit; }
|
if (ins_atomic_u32_eval(active_thread_count) == 0) { goto exit; }
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-13
@@ -140,9 +140,7 @@ typedef struct LNK_CommonBlockContrib
|
|||||||
} u;
|
} u;
|
||||||
} LNK_CommonBlockContrib;
|
} LNK_CommonBlockContrib;
|
||||||
|
|
||||||
// --- Ref ---------------------------------------------------------------------
|
// --- Reloc Ref ---------------------------------------------------------------
|
||||||
|
|
||||||
#define LNK_RELOCS_PER_TASK 0x1000
|
|
||||||
|
|
||||||
typedef struct LNK_RelocRefs
|
typedef struct LNK_RelocRefs
|
||||||
{
|
{
|
||||||
@@ -150,25 +148,27 @@ typedef struct LNK_RelocRefs
|
|||||||
COFF_RelocArray relocs;
|
COFF_RelocArray relocs;
|
||||||
} LNK_RelocRefs;
|
} LNK_RelocRefs;
|
||||||
|
|
||||||
typedef struct LNK_RelocRefsNode
|
typedef struct LNK_RelocRefsBatch LNK_RelocRefsBatch;
|
||||||
|
struct LNK_RelocRefsBatch
|
||||||
{
|
{
|
||||||
LNK_RelocRefs *v;
|
LNK_RelocRefsBatch *next;
|
||||||
struct LNK_RelocRefsNode *next;
|
U64 count;
|
||||||
} LNK_RelocRefsNode;
|
LNK_RelocRefs v[64];
|
||||||
|
};
|
||||||
|
|
||||||
typedef union LNK_RelocRefsPointer
|
typedef union
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
LNK_RelocRefsNode *node;
|
LNK_RelocRefsBatch *node;
|
||||||
U64 tag;
|
U64 tag;
|
||||||
};
|
};
|
||||||
U64 v[2];
|
U64 v[2];
|
||||||
} LNK_RelocRefsPointer;
|
} LNK_RelocRefsBatchPointer;
|
||||||
|
|
||||||
typedef struct AlignType(16) LNK_RelocRefsList
|
typedef struct AlignType(16)
|
||||||
{
|
{
|
||||||
LNK_RelocRefsPointer head;
|
LNK_RelocRefsBatchPointer head;
|
||||||
} LNK_RelocRefsList;
|
} LNK_RelocRefsBatchList;
|
||||||
|
|
||||||
// --- Base Reloc --------------------------------------------------------------
|
// --- Base Reloc --------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user