Jinoh Kang (@iamahuman) commented about dlls/ntdll/heap.c:
+ group = group_allocate( heap, flags, block_size, category ); + else + group = CONTAINING_RECORD( entry, struct group, entry ); + + return group; +} + +/* release a thread owned and fully freed group to the category shared group, or free its memory */ +static NTSTATUS heap_release_category_group( struct heap *heap, ULONG flags, struct category *category, + struct group *group ) +{ + DWORD affinity = NtCurrentTeb()->HeapVirtualAffinity % ARRAY_SIZE(category->affinity_group); + NTSTATUS status = STATUS_SUCCESS; + + /* we cannot use InterlockedExchangePointer here because to the contrary to our current group, + * the current affinity_group might be only partially free. This explanation is not exactly right, since there is a way to use `InterlockedExchangePointer` here without a problem: we can simply move the old group into the `category->groups` list, just like `find_free_block_lfh`. A more useful comment would explain _why_ we choose not to replace the affinity group in some cases.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/1628#note_22839