Jinoh Kang (@iamahuman) commented about dlls/ntdll/heap.c:
+ struct group *group; + + /* acquire a group, the thread will own it and no other thread can clear free bits. + * some other thread might still set the free bits if they are freeing blocks. + */ + if (!(group = heap_acquire_bin_group( heap, flags, block_size, bin ))) return NULL; + group->affinity = affinity; + + block = group_find_free_block( group, block_size ); + + /* serialize with heap_free_block_lfh: atomically set GROUP_FLAG_FREE when the free bits are all 0. */ + if (ReadNoFence( &group->free_bits ) || InterlockedCompareExchange( &group->free_bits, GROUP_FLAG_FREE, 0 )) + { + /* if GROUP_FLAG_FREE isn't set, thread is responsible for putting it back into group list. */ + if ((group = InterlockedExchangePointer( (void *)bin_get_affinity_group( bin, affinity ), group ))) + RtlInterlockedPushEntrySList( &bin->groups, (SLIST_ENTRY *)&group->entry ); \[redundant-cast-v10\]
RtlInterlockedPushEntrySList( &bin->groups, &group->entry );
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/1628#note_23836