diff --git a/pkgs/ffigen/lib/src/code_generator.dart b/pkgs/ffigen/lib/src/code_generator.dart index caad4143f..0197d5c04 100644 --- a/pkgs/ffigen/lib/src/code_generator.dart +++ b/pkgs/ffigen/lib/src/code_generator.dart @@ -11,7 +11,6 @@ export 'code_generator/constant.dart'; export 'code_generator/enum_class.dart'; export 'code_generator/func.dart'; export 'code_generator/func_type.dart'; -export 'code_generator/future_type.dart'; export 'code_generator/global.dart'; export 'code_generator/handle.dart'; export 'code_generator/imports.dart'; diff --git a/pkgs/ffigen/lib/src/code_generator/future_type.dart b/pkgs/ffigen/lib/src/code_generator/future_type.dart deleted file mode 100644 index f5ef4da8d..000000000 --- a/pkgs/ffigen/lib/src/code_generator/future_type.dart +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import '../code_generator.dart'; -import '../visitor/ast.dart'; - -import 'writer.dart'; - -/// Represents a FutureOr. -class FutureOrType extends Type { - final Type child; - - FutureOrType(this.child); - - @override - String getCType(Writer w) => 'FutureOr<${child.getCType(w)}>'; - - @override - String getFfiDartType(Writer w) => 'FutureOr<${child.getFfiDartType(w)}>'; - - @override - String getDartType(Writer w) => 'FutureOr<${child.getDartType(w)}>'; - - @override - bool get sameFfiDartAndCType => child.sameFfiDartAndCType; - - @override - String toString() => 'FutureOr<$child>'; - - @override - String cacheKey() => 'FutureOr<${child.cacheKey()}>'; - - @override - void visitChildren(Visitor visitor) { - super.visitChildren(visitor); - visitor.visit(child); - } - - @override - bool isSupertypeOf(Type other) { - other = other.typealiasType; - if (other is FutureOrType) { - return child.isSupertypeOf(other.child); - } - return false; - } -} diff --git a/pkgs/ffigen/lib/src/code_generator/objc_block.dart b/pkgs/ffigen/lib/src/code_generator/objc_block.dart index b015a305b..494dff038 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_block.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_block.dart @@ -134,6 +134,8 @@ class ObjCBlock extends BindingType { w.topLevelUniqueNamer.makeUnique('_${name}_blockingTrampoline'); final blockingCallable = w.topLevelUniqueNamer.makeUnique('_${name}_blockingCallable'); + final blockingListenerCallable = + w.topLevelUniqueNamer.makeUnique('_${name}_blockingListenerCallable'); final callExtension = w.topLevelUniqueNamer.makeUnique('${name}_CallExtension'); @@ -180,14 +182,16 @@ $returnFfiDartType $listenerTrampoline( } ${func.trampNatCallType} $listenerCallable = ${func.trampNatCallType}.listener( $listenerTrampoline $exceptionalReturn)..keepIsolateAlive = false; -Future<$returnFfiDartType> $blockingTrampoline( - $blockCType block, ${blockingFunc.paramsFfiDartType}) async { - await ($getBlockClosure(block) as ${func.asyncFfiDartType})( - ${func.paramsNameOnly}); +$returnFfiDartType $blockingTrampoline( + $blockCType block, ${blockingFunc.paramsFfiDartType}) { + ($getBlockClosure(block) as ${func.ffiDartType})(${func.paramsNameOnly}); $signalWaiterFn(waiter); $releaseFn(block.cast()); } ${blockingFunc.trampNatCallType} $blockingCallable = + ${blockingFunc.trampNatCallType}.isolateLocal( + $blockingTrampoline $exceptionalReturn)..keepIsolateAlive = false; +${blockingFunc.trampNatCallType} $blockingListenerCallable = ${blockingFunc.trampNatCallType}.listener( $blockingTrampoline $exceptionalReturn)..keepIsolateAlive = false; '''); @@ -282,8 +286,12 @@ abstract final class $name { ${func.dartType} fn, {Duration timeout = const Duration(seconds: 1)}) { final raw = $newClosureBlock( $blockingCallable.nativeFunction.cast(), $listenerConvFn); - final wrapper = $wrapBlockingBlockFn($wrapBlockingFn, raw, timeout); + final rawListener = $newClosureBlock( + $blockingListenerCallable.nativeFunction.cast(), $listenerConvFn); + final wrapper = $wrapBlockingBlockFn( + $wrapBlockingFn, raw, rawListener, timeout); $releaseFn(raw.cast()); + $releaseFn(rawListener.cast()); return $blockType(wrapper, retain: false, release: true); } '''); @@ -334,7 +342,8 @@ ref.pointer.ref.invoke.cast<${func.trampNatFnCType}>() } final waiterParam = Parameter( name: 'waiter', type: PointerType(voidType), objCConsumed: false); - final blockingRetains = [waiterParam.name, ...retains]; + final blockingRetains = ['nil', ...retains]; + final blockingListenerRetains = [waiterParam.name, ...retains]; final argStr = argsReceived.join(', '); final blockingArgStr = [ @@ -364,13 +373,20 @@ $listenerName $listenerWrapper($listenerName block) NS_RETURNS_RETAINED { typedef ${returnType.getNativeType()} (^$blockingName)($blockingArgStr); __attribute__((visibility("default"))) __attribute__((used)) $listenerName $blockingWrapper( - $blockingName block, double timeoutSeconds, void* (*newWaiter)(), - void (*awaitWaiter)(void*, double)) NS_RETURNS_RETAINED { + $blockingName block, $blockingName listenerBlock, double timeoutSeconds, + void* (*newWaiter)(), void (*awaitWaiter)(void*, double)) + NS_RETURNS_RETAINED { + NSThread *targetThread = [NSThread currentThread]; return ^void($argStr) { - void* waiter = newWaiter(); - ${generateRetain('block')}; - block(${blockingRetains.join(', ')}); - awaitWaiter(waiter, timeoutSeconds); + if ([NSThread currentThread] == targetThread) { + ${generateRetain('block')}; + block(${blockingRetains.join(', ')}); + } else { + void* waiter = newWaiter(); + ${generateRetain('listenerBlock')}; + listenerBlock(${blockingListenerRetains.join(', ')}); + awaitWaiter(waiter, timeoutSeconds); + } }; } '''); @@ -456,7 +472,6 @@ class _FnHelper { late final String natFnPtrCType; late final String dartType; late final String ffiDartType; - late final String asyncFfiDartType; late final String trampCType; late final String trampFfiDartType; late final String trampNatCallType; @@ -473,10 +488,6 @@ class _FnHelper { dartType = fnType.getDartType(w, writeArgumentNames: false); ffiDartType = fnType.getFfiDartType(w, writeArgumentNames: false); - final asyncFnType = - FunctionType(returnType: FutureOrType(returnType), parameters: params); - asyncFfiDartType = asyncFnType.getFfiDartType(w, writeArgumentNames: false); - final trampFnType = FunctionType( returnType: returnType, parameters: [ diff --git a/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart b/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart index 03adb25d9..50b01f395 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart @@ -229,6 +229,10 @@ class ObjCBuiltInFunctions { type: PointerType(objCBlockType), objCConsumed: false), if (blocking) ...[ + Parameter( + name: 'listnerBlock', + type: PointerType(objCBlockType), + objCConsumed: false), Parameter( name: 'timeoutSeconds', type: doubleType, objCConsumed: false), Parameter( diff --git a/pkgs/ffigen/lib/src/code_generator/writer.dart b/pkgs/ffigen/lib/src/code_generator/writer.dart index 7325d99ac..8e2bb9bc0 100644 --- a/pkgs/ffigen/lib/src/code_generator/writer.dart +++ b/pkgs/ffigen/lib/src/code_generator/writer.dart @@ -420,6 +420,7 @@ class Writer { final s = StringBuffer(); s.write(''' #include +#import '''); for (final entryPoint in nativeEntryPoints) { diff --git a/pkgs/ffigen/test/native_objc_test/block_test.dart b/pkgs/ffigen/test/native_objc_test/block_test.dart index 450944b35..1d34f0672 100644 --- a/pkgs/ffigen/test/native_objc_test/block_test.dart +++ b/pkgs/ffigen/test/native_objc_test/block_test.dart @@ -115,19 +115,27 @@ void main() { expect(value, 123); });*/ - // test('Blocking block same thread', () { - // int value = 0; - // final block = VoidBlock.blocking(() async { - // await Future.delayed(Duration(milliseconds: 100)); - // value = 123; - // }); - // BlockTester.callOnSameThread_(block); - // expect(value, 123); - // }); + void waitSync(Duration d) { + final t = Stopwatch(); + t.start(); + while (t.elapsed < d) { + // Waiting... + } + } + + test('Blocking block same thread', () { + int value = 0; + final block = VoidBlock.blocking(() { + waitSync(Duration(milliseconds: 100)); + value = 123; + }); + BlockTester.callOnSameThread_(block); + expect(value, 123); + }); test('Blocking block new thread', () async { - final block = IntPtrBlock.blocking((Pointer result) async { - await Future.delayed(Duration(milliseconds: 100)); + final block = IntPtrBlock.blocking((Pointer result) { + waitSync(Duration(milliseconds: 100)); result.value = 123456; }, timeout: Duration(seconds: 60)); final resultCompleter = Completer(); @@ -140,8 +148,8 @@ void main() { test('Blocking block timeout', () async { int value = 0; - final block = VoidBlock.blocking(() async { - await Future.delayed(Duration(milliseconds: 300)); + final block = VoidBlock.blocking(() { + waitSync(Duration(milliseconds: 300)); value = 123456; }, timeout: Duration(milliseconds: 100)); BlockTester.callOnNewThread_(block).start(); diff --git a/pkgs/objective_c/lib/src/internal.dart b/pkgs/objective_c/lib/src/internal.dart index 618bbca8a..4f9c9ce74 100644 --- a/pkgs/objective_c/lib/src/internal.dart +++ b/pkgs/objective_c/lib/src/internal.dart @@ -425,13 +425,15 @@ Function getBlockClosure(_BlkPtr block) { typedef _NewWaiterFn = NativeFunction<_VoidPtr Function()>; typedef _AwaitWaiterFn = NativeFunction; typedef _NativeWrapperFn = _BlkPtr Function( - _BlkPtr, double, Pointer<_NewWaiterFn>, Pointer<_AwaitWaiterFn>); + _BlkPtr, _BlkPtr, double, Pointer<_NewWaiterFn>, Pointer<_AwaitWaiterFn>); /// Only for use by ffigen bindings. _BlkPtr wrapBlockingBlock( - _NativeWrapperFn nativeWrapper, _BlkPtr raw, Duration timeout) => + _NativeWrapperFn nativeWrapper, _BlkPtr raw, _BlkPtr rawListener, + Duration timeout) => nativeWrapper( raw, + rawListener, timeout.inMicroseconds / Duration.microsecondsPerSecond, Native.addressOf<_NewWaiterFn>(c.newWaiter), Native.addressOf<_AwaitWaiterFn>(c.awaitWaiter), diff --git a/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart b/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart index 4f5c4c3b0..81a3edcd0 100644 --- a/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart +++ b/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart @@ -39,6 +39,7 @@ set NSLocalizedDescriptionKey(NSString value) { @ffi.Native< ffi.Pointer Function( + ffi.Pointer, ffi.Pointer, ffi.Double, ffi.Pointer Function()>>, @@ -49,6 +50,7 @@ set NSLocalizedDescriptionKey(NSString value) { external ffi.Pointer _ObjectiveCBindings_wrapBlockingBlock_18d6mda( ffi.Pointer block, + ffi.Pointer listnerBlock, double timeoutSeconds, ffi.Pointer Function()>> newWaiter, ffi.Pointer< @@ -59,6 +61,7 @@ external ffi.Pointer @ffi.Native< ffi.Pointer Function( + ffi.Pointer, ffi.Pointer, ffi.Double, ffi.Pointer Function()>>, @@ -69,6 +72,7 @@ external ffi.Pointer external ffi.Pointer _ObjectiveCBindings_wrapBlockingBlock_1j2nt86( ffi.Pointer block, + ffi.Pointer listnerBlock, double timeoutSeconds, ffi.Pointer Function()>> newWaiter, ffi.Pointer< @@ -79,6 +83,7 @@ external ffi.Pointer @ffi.Native< ffi.Pointer Function( + ffi.Pointer, ffi.Pointer, ffi.Double, ffi.Pointer Function()>>, @@ -89,6 +94,7 @@ external ffi.Pointer external ffi.Pointer _ObjectiveCBindings_wrapBlockingBlock_ovsamd( ffi.Pointer block, + ffi.Pointer listnerBlock, double timeoutSeconds, ffi.Pointer Function()>> newWaiter, ffi.Pointer< @@ -99,6 +105,7 @@ external ffi.Pointer @ffi.Native< ffi.Pointer Function( + ffi.Pointer, ffi.Pointer, ffi.Double, ffi.Pointer Function()>>, @@ -109,6 +116,7 @@ external ffi.Pointer external ffi.Pointer _ObjectiveCBindings_wrapBlockingBlock_wjovn7( ffi.Pointer block, + ffi.Pointer listnerBlock, double timeoutSeconds, ffi.Pointer Function()>> newWaiter, ffi.Pointer< @@ -119,6 +127,7 @@ external ffi.Pointer @ffi.Native< ffi.Pointer Function( + ffi.Pointer, ffi.Pointer, ffi.Double, ffi.Pointer Function()>>, @@ -129,6 +138,7 @@ external ffi.Pointer external ffi.Pointer _ObjectiveCBindings_wrapBlockingBlock_wjvic9( ffi.Pointer block, + ffi.Pointer listnerBlock, double timeoutSeconds, ffi.Pointer Function()>> newWaiter, ffi.Pointer< @@ -9472,14 +9482,14 @@ ffi.NativeCallable< ffi.Pointer)>.listener( _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_listenerTrampoline) ..keepIsolateAlive = false; -Future +void _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingTrampoline( ffi.Pointer block, ffi.Pointer waiter, ffi.Pointer arg0, ffi.Pointer arg1, - ffi.Pointer arg2) async { - await (objc.getBlockClosure(block) as FutureOr Function( + ffi.Pointer arg2) { + (objc.getBlockClosure(block) as void Function( ffi.Pointer, ffi.Pointer, ffi.Pointer))(arg0, arg1, arg2); @@ -9495,6 +9505,23 @@ ffi.NativeCallable< ffi.Pointer, ffi.Pointer)> _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingCallable = + ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>.isolateLocal( + _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingTrampoline) + ..keepIsolateAlive = false; +ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)> + _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingListenerCallable = ffi.NativeCallable< ffi.Void Function( ffi.Pointer, @@ -9629,9 +9656,26 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO objc.ObjCObjectBase(arg1, retain: false, release: true), NSDictionary.castFromPointer(arg2, retain: false, release: true))); + final rawListener = objc.newClosureBlock( + _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingListenerCallable + .nativeFunction + .cast(), + (ffi.Pointer arg0, + ffi.Pointer arg1, + ffi.Pointer arg2) => + fn( + ObjCBlock_ffiVoid_objcObjCObject_NSError.castFromPointer(arg0, + retain: false, release: true), + objc.ObjCObjectBase(arg1, retain: false, release: true), + NSDictionary.castFromPointer(arg2, + retain: false, release: true))); final wrapper = objc.wrapBlockingBlock( - _ObjectiveCBindings_wrapBlockingBlock_1j2nt86, raw, timeout); + _ObjectiveCBindings_wrapBlockingBlock_1j2nt86, + raw, + rawListener, + timeout); objc.objectRelease(raw.cast()); + objc.objectRelease(rawListener.cast()); return objc.ObjCBlock< ffi.Void Function( objc.ObjCBlock< @@ -9706,12 +9750,11 @@ ffi.NativeCallable< ffi.Pointer)>.listener( _ObjCBlock_ffiVoid_ffiVoid_listenerTrampoline) ..keepIsolateAlive = false; -Future _ObjCBlock_ffiVoid_ffiVoid_blockingTrampoline( +void _ObjCBlock_ffiVoid_ffiVoid_blockingTrampoline( ffi.Pointer block, ffi.Pointer waiter, - ffi.Pointer arg0) async { - await (objc.getBlockClosure(block) as FutureOr Function( - ffi.Pointer))(arg0); + ffi.Pointer arg0) { + (objc.getBlockClosure(block) as void Function(ffi.Pointer))(arg0); objc.signalWaiter(waiter); objc.objectRelease(block.cast()); } @@ -9720,6 +9763,14 @@ ffi.NativeCallable< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)> _ObjCBlock_ffiVoid_ffiVoid_blockingCallable = ffi.NativeCallable< + ffi.Void Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)>.isolateLocal( + _ObjCBlock_ffiVoid_ffiVoid_blockingTrampoline) + ..keepIsolateAlive = false; +ffi.NativeCallable< + ffi.Void Function(ffi.Pointer, + ffi.Pointer, ffi.Pointer)> + _ObjCBlock_ffiVoid_ffiVoid_blockingListenerCallable = ffi.NativeCallable< ffi.Void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>.listener( _ObjCBlock_ffiVoid_ffiVoid_blockingTrampoline) @@ -9789,9 +9840,17 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_blockingCallable.nativeFunction.cast(), (ffi.Pointer arg0) => fn(arg0)); + final rawListener = objc.newClosureBlock( + _ObjCBlock_ffiVoid_ffiVoid_blockingListenerCallable.nativeFunction + .cast(), + (ffi.Pointer arg0) => fn(arg0)); final wrapper = objc.wrapBlockingBlock( - _ObjectiveCBindings_wrapBlockingBlock_ovsamd, raw, timeout); + _ObjectiveCBindings_wrapBlockingBlock_ovsamd, + raw, + rawListener, + timeout); objc.objectRelease(raw.cast()); + objc.objectRelease(rawListener.cast()); return objc.ObjCBlock)>(wrapper, retain: false, release: true); } @@ -9857,12 +9916,12 @@ ffi.NativeCallable< ffi.Pointer, ffi.Pointer)>.listener( _ObjCBlock_ffiVoid_ffiVoid_NSCoder_listenerTrampoline) ..keepIsolateAlive = false; -Future _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingTrampoline( +void _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingTrampoline( ffi.Pointer block, ffi.Pointer waiter, ffi.Pointer arg0, - ffi.Pointer arg1) async { - await (objc.getBlockClosure(block) as FutureOr Function( + ffi.Pointer arg1) { + (objc.getBlockClosure(block) as void Function( ffi.Pointer, ffi.Pointer))(arg0, arg1); objc.signalWaiter(waiter); objc.objectRelease(block.cast()); @@ -9875,6 +9934,21 @@ ffi.NativeCallable< ffi.Pointer, ffi.Pointer)> _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingCallable = ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>.isolateLocal( + _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingTrampoline) + ..keepIsolateAlive = false; +ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)> + _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingListenerCallable = ffi + .NativeCallable< ffi.Void Function( ffi.Pointer, ffi.Pointer, @@ -9960,9 +10034,19 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSCoder { .cast(), (ffi.Pointer arg0, ffi.Pointer arg1) => fn( arg0, NSCoder.castFromPointer(arg1, retain: false, release: true))); + final rawListener = objc.newClosureBlock( + _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingListenerCallable + .nativeFunction + .cast(), + (ffi.Pointer arg0, ffi.Pointer arg1) => fn( + arg0, NSCoder.castFromPointer(arg1, retain: false, release: true))); final wrapper = objc.wrapBlockingBlock( - _ObjectiveCBindings_wrapBlockingBlock_wjovn7, raw, timeout); + _ObjectiveCBindings_wrapBlockingBlock_wjovn7, + raw, + rawListener, + timeout); objc.objectRelease(raw.cast()); + objc.objectRelease(rawListener.cast()); return objc.ObjCBlock, NSCoder)>( wrapper, retain: false, @@ -10053,17 +10137,14 @@ ffi.NativeCallable< ffi.UnsignedLong)>.listener( _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_listenerTrampoline) ..keepIsolateAlive = false; -Future - _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingTrampoline( - ffi.Pointer block, - ffi.Pointer waiter, - ffi.Pointer arg0, - ffi.Pointer arg1, - int arg2) async { - await (objc.getBlockClosure(block) as FutureOr Function( - ffi.Pointer, - ffi.Pointer, - int))(arg0, arg1, arg2); +void _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingTrampoline( + ffi.Pointer block, + ffi.Pointer waiter, + ffi.Pointer arg0, + ffi.Pointer arg1, + int arg2) { + (objc.getBlockClosure(block) as void Function(ffi.Pointer, + ffi.Pointer, int))(arg0, arg1, arg2); objc.signalWaiter(waiter); objc.objectRelease(block.cast()); } @@ -10076,6 +10157,23 @@ ffi.NativeCallable< ffi.Pointer, ffi.UnsignedLong)> _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingCallable = + ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.UnsignedLong)>.isolateLocal( + _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingTrampoline) + ..keepIsolateAlive = false; +ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.UnsignedLong)> + _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingListenerCallable = ffi.NativeCallable< ffi.Void Function( ffi.Pointer, @@ -10177,9 +10275,23 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { arg0, NSStream.castFromPointer(arg1, retain: false, release: true), NSStreamEvent.fromValue(arg2))); + final rawListener = objc.newClosureBlock( + _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingListenerCallable + .nativeFunction + .cast(), + (ffi.Pointer arg0, ffi.Pointer arg1, + int arg2) => + fn( + arg0, + NSStream.castFromPointer(arg1, retain: false, release: true), + NSStreamEvent.fromValue(arg2))); final wrapper = objc.wrapBlockingBlock( - _ObjectiveCBindings_wrapBlockingBlock_18d6mda, raw, timeout); + _ObjectiveCBindings_wrapBlockingBlock_18d6mda, + raw, + rawListener, + timeout); objc.objectRelease(raw.cast()); + objc.objectRelease(rawListener.cast()); return objc.ObjCBlock< ffi.Void Function(ffi.Pointer, NSStream, ffi.UnsignedLong)>(wrapper, retain: false, release: true); @@ -10262,12 +10374,12 @@ ffi.NativeCallable< ffi.Pointer)>.listener( _ObjCBlock_ffiVoid_objcObjCObject_NSError_listenerTrampoline) ..keepIsolateAlive = false; -Future _ObjCBlock_ffiVoid_objcObjCObject_NSError_blockingTrampoline( +void _ObjCBlock_ffiVoid_objcObjCObject_NSError_blockingTrampoline( ffi.Pointer block, ffi.Pointer waiter, ffi.Pointer arg0, - ffi.Pointer arg1) async { - await (objc.getBlockClosure(block) as FutureOr Function( + ffi.Pointer arg1) { + (objc.getBlockClosure(block) as void Function( ffi.Pointer, ffi.Pointer))(arg0, arg1); objc.signalWaiter(waiter); objc.objectRelease(block.cast()); @@ -10280,6 +10392,21 @@ ffi.NativeCallable< ffi.Pointer, ffi.Pointer)> _ObjCBlock_ffiVoid_objcObjCObject_NSError_blockingCallable = ffi + .NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)>.isolateLocal( + _ObjCBlock_ffiVoid_objcObjCObject_NSError_blockingTrampoline) + ..keepIsolateAlive = false; +ffi.NativeCallable< + ffi.Void Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Pointer)> + _ObjCBlock_ffiVoid_objcObjCObject_NSError_blockingListenerCallable = ffi .NativeCallable< ffi.Void Function( ffi.Pointer, @@ -10381,9 +10508,24 @@ abstract final class ObjCBlock_ffiVoid_objcObjCObject_NSError { ? null : objc.ObjCObjectBase(arg0, retain: false, release: true), NSError.castFromPointer(arg1, retain: false, release: true))); + final rawListener = objc.newClosureBlock( + _ObjCBlock_ffiVoid_objcObjCObject_NSError_blockingListenerCallable + .nativeFunction + .cast(), + (ffi.Pointer arg0, + ffi.Pointer arg1) => + fn( + arg0.address == 0 + ? null + : objc.ObjCObjectBase(arg0, retain: false, release: true), + NSError.castFromPointer(arg1, retain: false, release: true))); final wrapper = objc.wrapBlockingBlock( - _ObjectiveCBindings_wrapBlockingBlock_wjvic9, raw, timeout); + _ObjectiveCBindings_wrapBlockingBlock_wjvic9, + raw, + rawListener, + timeout); objc.objectRelease(raw.cast()); + objc.objectRelease(rawListener.cast()); return objc.ObjCBlock< ffi.Void Function(ffi.Pointer?, NSError)>(wrapper, retain: false, release: true); diff --git a/pkgs/objective_c/src/objective_c.m b/pkgs/objective_c/src/objective_c.m index 63d44374f..41b35063b 100644 --- a/pkgs/objective_c/src/objective_c.m +++ b/pkgs/objective_c/src/objective_c.m @@ -59,20 +59,20 @@ -(void)wait: (double)timeoutSeconds { @end FFI_EXPORT void* DOBJC_newWaiter() { - DOBJCWaiter* wait = [[DOBJCWaiter alloc] init]; + DOBJCWaiter* w = [[DOBJCWaiter alloc] init]; // __bridge_retained increments the ref count, __bridge_transfer decrements // it, and __bridge doesn't change it. One of the __bridge_retained calls is // balanced by the __bridge_transfer in signalWaiter, and the other is // balanced by the one in awaitWaiter. In other words, this function returns // an object with a +2 ref count, and signal and await each decrement the // ref count. - return (__bridge_retained void*)(__bridge id)(__bridge_retained void*)(wait); + return (__bridge_retained void*)(__bridge id)(__bridge_retained void*)(w); } -FFI_EXPORT void DOBJC_signalWaiter(void* wait) { - [(__bridge_transfer DOBJCWaiter*)wait signal]; +FFI_EXPORT void DOBJC_signalWaiter(void* waiter) { + if (waiter) [(__bridge_transfer DOBJCWaiter*)waiter signal]; } -FFI_EXPORT void DOBJC_awaitWaiter(void* wait, double timeoutSeconds) { - [(__bridge_transfer DOBJCWaiter*)wait wait: timeoutSeconds]; +FFI_EXPORT void DOBJC_awaitWaiter(void* waiter, double timeoutSeconds) { + [(__bridge_transfer DOBJCWaiter*)waiter wait: timeoutSeconds]; } diff --git a/pkgs/objective_c/src/objective_c_bindings_generated.m b/pkgs/objective_c/src/objective_c_bindings_generated.m index 8285f4691..0366e9949 100644 --- a/pkgs/objective_c/src/objective_c_bindings_generated.m +++ b/pkgs/objective_c/src/objective_c_bindings_generated.m @@ -1,4 +1,5 @@ #include +#import #import "foundation.h" #import "input_stream_adapter.h" #import "proxy.h" @@ -24,13 +25,20 @@ _ListenerTrampoline _ObjectiveCBindings_wrapListenerBlock_1j2nt86(_ListenerTramp typedef void (^_BlockingTrampoline)(void * waiter, id arg0, id arg1, id arg2); __attribute__((visibility("default"))) __attribute__((used)) _ListenerTrampoline _ObjectiveCBindings_wrapBlockingBlock_1j2nt86( - _BlockingTrampoline block, double timeoutSeconds, void* (*newWaiter)(), - void (*awaitWaiter)(void*, double)) NS_RETURNS_RETAINED { + _BlockingTrampoline block, _BlockingTrampoline listenerBlock, double timeoutSeconds, + void* (*newWaiter)(), void (*awaitWaiter)(void*, double)) + NS_RETURNS_RETAINED { + NSThread *targetThread = [NSThread currentThread]; return ^void(id arg0, id arg1, id arg2) { - void* waiter = newWaiter(); - objc_retainBlock(block); - block(waiter, objc_retainBlock(arg0), objc_retain(arg1), objc_retain(arg2)); - awaitWaiter(waiter, timeoutSeconds); + if ([NSThread currentThread] == targetThread) { + objc_retainBlock(block); + block(nil, objc_retainBlock(arg0), objc_retain(arg1), objc_retain(arg2)); + } else { + void* waiter = newWaiter(); + objc_retainBlock(listenerBlock); + listenerBlock(waiter, objc_retainBlock(arg0), objc_retain(arg1), objc_retain(arg2)); + awaitWaiter(waiter, timeoutSeconds); + } }; } @@ -46,13 +54,20 @@ _ListenerTrampoline1 _ObjectiveCBindings_wrapListenerBlock_ovsamd(_ListenerTramp typedef void (^_BlockingTrampoline1)(void * waiter, void * arg0); __attribute__((visibility("default"))) __attribute__((used)) _ListenerTrampoline1 _ObjectiveCBindings_wrapBlockingBlock_ovsamd( - _BlockingTrampoline1 block, double timeoutSeconds, void* (*newWaiter)(), - void (*awaitWaiter)(void*, double)) NS_RETURNS_RETAINED { + _BlockingTrampoline1 block, _BlockingTrampoline1 listenerBlock, double timeoutSeconds, + void* (*newWaiter)(), void (*awaitWaiter)(void*, double)) + NS_RETURNS_RETAINED { + NSThread *targetThread = [NSThread currentThread]; return ^void(void * arg0) { - void* waiter = newWaiter(); - objc_retainBlock(block); - block(waiter, arg0); - awaitWaiter(waiter, timeoutSeconds); + if ([NSThread currentThread] == targetThread) { + objc_retainBlock(block); + block(nil, arg0); + } else { + void* waiter = newWaiter(); + objc_retainBlock(listenerBlock); + listenerBlock(waiter, arg0); + awaitWaiter(waiter, timeoutSeconds); + } }; } @@ -68,13 +83,20 @@ _ListenerTrampoline2 _ObjectiveCBindings_wrapListenerBlock_wjovn7(_ListenerTramp typedef void (^_BlockingTrampoline2)(void * waiter, void * arg0, id arg1); __attribute__((visibility("default"))) __attribute__((used)) _ListenerTrampoline2 _ObjectiveCBindings_wrapBlockingBlock_wjovn7( - _BlockingTrampoline2 block, double timeoutSeconds, void* (*newWaiter)(), - void (*awaitWaiter)(void*, double)) NS_RETURNS_RETAINED { + _BlockingTrampoline2 block, _BlockingTrampoline2 listenerBlock, double timeoutSeconds, + void* (*newWaiter)(), void (*awaitWaiter)(void*, double)) + NS_RETURNS_RETAINED { + NSThread *targetThread = [NSThread currentThread]; return ^void(void * arg0, id arg1) { - void* waiter = newWaiter(); - objc_retainBlock(block); - block(waiter, arg0, objc_retain(arg1)); - awaitWaiter(waiter, timeoutSeconds); + if ([NSThread currentThread] == targetThread) { + objc_retainBlock(block); + block(nil, arg0, objc_retain(arg1)); + } else { + void* waiter = newWaiter(); + objc_retainBlock(listenerBlock); + listenerBlock(waiter, arg0, objc_retain(arg1)); + awaitWaiter(waiter, timeoutSeconds); + } }; } @@ -90,13 +112,20 @@ _ListenerTrampoline3 _ObjectiveCBindings_wrapListenerBlock_18d6mda(_ListenerTram typedef void (^_BlockingTrampoline3)(void * waiter, void * arg0, id arg1, NSStreamEvent arg2); __attribute__((visibility("default"))) __attribute__((used)) _ListenerTrampoline3 _ObjectiveCBindings_wrapBlockingBlock_18d6mda( - _BlockingTrampoline3 block, double timeoutSeconds, void* (*newWaiter)(), - void (*awaitWaiter)(void*, double)) NS_RETURNS_RETAINED { + _BlockingTrampoline3 block, _BlockingTrampoline3 listenerBlock, double timeoutSeconds, + void* (*newWaiter)(), void (*awaitWaiter)(void*, double)) + NS_RETURNS_RETAINED { + NSThread *targetThread = [NSThread currentThread]; return ^void(void * arg0, id arg1, NSStreamEvent arg2) { - void* waiter = newWaiter(); - objc_retainBlock(block); - block(waiter, arg0, objc_retain(arg1), arg2); - awaitWaiter(waiter, timeoutSeconds); + if ([NSThread currentThread] == targetThread) { + objc_retainBlock(block); + block(nil, arg0, objc_retain(arg1), arg2); + } else { + void* waiter = newWaiter(); + objc_retainBlock(listenerBlock); + listenerBlock(waiter, arg0, objc_retain(arg1), arg2); + awaitWaiter(waiter, timeoutSeconds); + } }; } @@ -112,12 +141,19 @@ _ListenerTrampoline4 _ObjectiveCBindings_wrapListenerBlock_wjvic9(_ListenerTramp typedef void (^_BlockingTrampoline4)(void * waiter, id arg0, id arg1); __attribute__((visibility("default"))) __attribute__((used)) _ListenerTrampoline4 _ObjectiveCBindings_wrapBlockingBlock_wjvic9( - _BlockingTrampoline4 block, double timeoutSeconds, void* (*newWaiter)(), - void (*awaitWaiter)(void*, double)) NS_RETURNS_RETAINED { + _BlockingTrampoline4 block, _BlockingTrampoline4 listenerBlock, double timeoutSeconds, + void* (*newWaiter)(), void (*awaitWaiter)(void*, double)) + NS_RETURNS_RETAINED { + NSThread *targetThread = [NSThread currentThread]; return ^void(id arg0, id arg1) { - void* waiter = newWaiter(); - objc_retainBlock(block); - block(waiter, objc_retain(arg0), objc_retain(arg1)); - awaitWaiter(waiter, timeoutSeconds); + if ([NSThread currentThread] == targetThread) { + objc_retainBlock(block); + block(nil, objc_retain(arg0), objc_retain(arg1)); + } else { + void* waiter = newWaiter(); + objc_retainBlock(listenerBlock); + listenerBlock(waiter, objc_retain(arg0), objc_retain(arg1)); + awaitWaiter(waiter, timeoutSeconds); + } }; }