[runtime] Add support for keeping the same block alive multiple times. Fixes #18161. (#18277)

We can be asked to keep the same block+delegate pair alive multiple
times, so add support for keeping track how many times a block must be freed once
the corresponding delegate is collected by the GC.

Fixes https://github.com/xamarin/xamarin-macios/issues/18161.
This commit is contained in:
Rolf Bjarne Kvinge 2023-05-17 14:14:03 +02:00 коммит произвёл GitHub
Родитель aec2af30ce
Коммит 70de850be6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 24 добавлений и 3 удалений

Просмотреть файл

@ -564,10 +564,27 @@ namespace ObjCRuntime {
}
// This class will free the specified block when it's collected by the GC.
internal class BlockCollector : TrampolineBlockBase {
internal class BlockCollector {
IntPtr block;
int count;
public BlockCollector (IntPtr block)
: base (block, owns: true)
{
this.block = block;
count = 1;
}
public void Add (IntPtr block)
{
if (block != this.block)
throw new InvalidOperationException (string.Format ("Can't release the block 0x{0} because this BlockCollector instance is already tracking 0x{1}.", block.ToString ("x"), this.block.ToString ("x")));
Interlocked.Increment (ref count);
}
~BlockCollector ()
{
for (var i = 0; i < count; i++)
Runtime.ReleaseBlockOnMainThread (block);
count = 0;
}
}
#endif

Просмотреть файл

@ -2055,7 +2055,11 @@ namespace ObjCRuntime {
if (block == IntPtr.Zero)
return @delegate;
block_lifetime_table.Add (@delegate, new BlockCollector (block));
if (block_lifetime_table.TryGetValue (@delegate, out var existingCollector)) {
existingCollector.Add (block);
} else {
block_lifetime_table.Add (@delegate, new BlockCollector (block));
}
return @delegate;
}