diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index f58d2b04b9..3606e27f88 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -855,7 +855,6 @@ namespace ObjCRuntime { #endif static Delegate CreateBlockProxy (MethodInfo method, IntPtr block) { - NSObject.DangerousRetain (block); return (Delegate) method.Invoke (null, new object [] { block } ); } diff --git a/tests/bindings-test/ApiDefinition.cs b/tests/bindings-test/ApiDefinition.cs index e92457191c..4c99638094 100644 --- a/tests/bindings-test/ApiDefinition.cs +++ b/tests/bindings-test/ApiDefinition.cs @@ -284,6 +284,13 @@ namespace Bindings.Test { [Export ("callOptionalCallback")] void CallOptionalCallback (); + + [Export ("testFreedBlocks")] + void TestFreedBlocks (); + + [Static] + [Export ("freedBlockCount")] + int FreedBlockCount { get; } } } diff --git a/tests/bindings-test/RegistrarBindingTest.cs b/tests/bindings-test/RegistrarBindingTest.cs index 495de89ac3..dc2441da23 100644 --- a/tests/bindings-test/RegistrarBindingTest.cs +++ b/tests/bindings-test/RegistrarBindingTest.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; #if __UNIFIED__ using Foundation; @@ -63,7 +64,7 @@ namespace Xamarin.BindingTests } } - class BlockCallbackTester : ObjCBlockTester + public class BlockCallbackTester : ObjCBlockTester { public override void ClassCallback (Action completionHandler) { diff --git a/tests/bindings-test/bindings-test-mac.csproj b/tests/bindings-test/bindings-test-mac.csproj index f950c3b6ef..4e89ea09d8 100644 --- a/tests/bindings-test/bindings-test-mac.csproj +++ b/tests/bindings-test/bindings-test-mac.csproj @@ -62,6 +62,7 @@ Registrar.cs + diff --git a/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs b/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs index 75c1e1f378..a8cb32f9ae 100644 --- a/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs +++ b/tests/monotouch-test/ObjCRuntime/RegistrarTest.cs @@ -2026,6 +2026,30 @@ namespace MonoTouchFixtures.ObjCRuntime { } } + [Test] + public void BlockCollection () + { + Exception ex = null; + int initialFreedCount = ObjCBlockTester.FreedBlockCount; + var thread = new Thread (() => { + try { + using (var obj = new Xamarin.BindingTests.RegistrarBindingTest.BlockCallbackTester ()) { + for (int i = 0; i < 10000; i++) + obj.TestFreedBlocks (); + } + } catch (Exception e) { + ex = e; + } + }); + thread.Start (); + thread.Join (); + GC.Collect (); + GC.WaitForPendingFinalizers (); + TestRuntime.RunAsync (DateTime.Now.AddSeconds (30), () => { }, () => ObjCBlockTester.FreedBlockCount > initialFreedCount); + Assert.IsNull (ex, "No exceptions"); + Assert.That (ObjCBlockTester.FreedBlockCount, Is.GreaterThan (initialFreedCount), "freed blocks"); + } + [Test] public void TestCtors () { diff --git a/tests/test-libraries/libtest.h b/tests/test-libraries/libtest.h index a9998bd2ba..9d86bb10aa 100644 --- a/tests/test-libraries/libtest.h +++ b/tests/test-libraries/libtest.h @@ -1,5 +1,6 @@ #import #include +#include #include "rename.h" @@ -149,6 +150,14 @@ typedef unsigned int (^RegistrarTestBlock) (unsigned int magic); -(void) callClassCallback; -(void) callRequiredCallback; -(void) callOptionalCallback; + +-(void) testFreedBlocks; ++(int) freedBlockCount; +@end + +@interface FreedNotifier : NSObject { +} +-(void) dealloc; @end #ifdef __cplusplus diff --git a/tests/test-libraries/libtest.m b/tests/test-libraries/libtest.m index ca6a7da5e0..5a8a4375a1 100644 --- a/tests/test-libraries/libtest.m +++ b/tests/test-libraries/libtest.m @@ -510,6 +510,8 @@ static UltimateMachine *shared; } @end +static volatile int freed_blocks = 0; + @implementation ObjCBlockTester -(void) classCallback: (void (^)(int32_t magic_number))completionHandler { @@ -549,6 +551,30 @@ static UltimateMachine *shared; assert (called); } +-(void) testFreedBlocks +{ + FreedNotifier* obj = [[FreedNotifier alloc] init]; + __block bool success = false; + [self classCallback: ^(int magic_number) + { + assert (magic_number == 42); + success = obj != NULL; // this captures the 'obj', and it's only freed when the block is freed. + }]; + assert (success); + [obj release]; +} ++(int) freedBlockCount +{ + return freed_blocks; +} +@end + +@implementation FreedNotifier +-(void) dealloc +{ + OSAtomicIncrement32 (&freed_blocks); + [super dealloc]; +} @end #include "libtest.decompile.m" diff --git a/tests/test-libraries/rename.h b/tests/test-libraries/rename.h index d11719d189..47f6f40490 100644 --- a/tests/test-libraries/rename.h +++ b/tests/test-libraries/rename.h @@ -4,6 +4,7 @@ #define useZLib object_useZLib #define ObjCRegistrarTest object_ObjCRegistrarTest #define ObjCBlockTester object_ObjCBlockTester + #define FreedNotifier object_FreedNotifier #define FakeType2 object_FakeType2 #define UltimateMachine object_UltimateMachine #define FrameworkTest object_FrameworkTest @@ -67,6 +68,7 @@ #define useZLib ar_useZLib #define ObjCRegistrarTest ar_ObjCRegistrarTest #define ObjCBlockTester ar_ObjCBlockTester + #define FreedNotifier ar_FreedNotifier #define FakeType2 ar_FakeType2 #define UltimateMachine ar_UltimateMachine #define FrameworkTest ar_FrameworkTest