[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os dialogs fail when called via dart:ffi on macOS (thread pinning Dart standalone) #38315

Open
mit-mit opened this issue Sep 11, 2019 · 7 comments
Labels
area-vm Use area-vm for VM related issues, including code coverage, FFI, and the AOT and JIT backends. library-ffi

Comments

@mit-mit
Copy link
Member
mit-mit commented Sep 11, 2019

Repro steps:

> dylib: osdialog.o osdialog_mac.o
> 	$(CC) $(CFLAGS) -dynamiclib -undefined suppress -flat_namespace $(LDFLAGS) osdialog.o osdialog_mac.o -o osdialog.dylib
  • Run make ARCH=mac dylib
  • Run the following .dart program:
import 'dart:ffi' as ffi;

// char *osdialog_file(osdialog_file_action action, const char *path,
// const char *filename, osdialog_filters *filters);
typedef OSDialogFileC = ffi.Pointer Function(
    ffi.Int32, ffi.Pointer, ffi.Pointer, ffi.Pointer);
typedef OSDialogFileDart = ffi.Pointer Function(
    int, ffi.Pointer, ffi.Pointer, ffi.Pointer);

main() {
  final dylib = ffi.DynamicLibrary.open('osdialog.dylib');
  final OSDialogFileDart osdialog = dylib
      .lookup<ffi.NativeFunction<OSDialogFileC>>('osdialog_file')
      .asFunction();

  osdialog(0, ffi.nullptr, ffi.nullptr, ffi.nullptr);
}

Result:

2019-09-11 10:33:32.334 dart[49968:894229] WARNING: NSWindow drag regions should only be invalidated on the Main Thread! This will throw an exception in the future. Called from (
	0   AppKit                              0x00007fff29deb607 -[NSWindow(NSWindow_Theme) _postWindowNeedsToResetDragMarginsUnlessPostingDisabled] + 378
	1   AppKit                              0x00007fff29de89f7 -[NSWindow _initContent:styleMask:backing:defer:contentView:] + 1479
	2   AppKit                              0x00007fff29ea7d95 -[NSPanel _initContent:styleMask:backing:defer:contentView:] + 50
	3   AppKit                              0x00007fff29de842a -[NSWindow initWithContentRect:styleMask:backing:defer:] + 45
	4   AppKit                              0x00007fff29ea7d4a -[NSPanel initWithContentRect:styleMask:backing:defer:] + 64
	5   AppKit                              0x00007fff2a4bf4f5 -[NSSavePanel initWithContentRect:styleMask:backing:defer:] + 592
	6   AppKit                              0x00007fff2a0b9dec +[NSSavePanel _crunchyRawUnbonedPanel] + 550
	7   osdialog.dylib                      0x00000001084567bc osdialog_file + 124
	8   ???                                 0x00000001087c41ee 0x0 + 4437328366
	9   ???                                 0x00000001094acd03 0x0 + 4450864387
)

...
@mit-mit mit-mit added area-vm Use area-vm for VM related issues, including code coverage, FFI, and the AOT and JIT backends. library-ffi labels Sep 11, 2019
@sjindel-google
Copy link
Contributor

The problem seems to be that the mutator isn't running on the system's "main" thread.

Since you're running from the standalone runtime, it's seems natural that the mutator for the main isolate should run on the main thread.

However, this sort of problem is more challenging to solve for embedders like Flutter, because the embedder can run any isolate on whatever thread it wants. I believe plugin code gets executed on the main thread of Flutter apps, and scheduling Dart code (or native code called by Dart) to run on the same thread would challenging.

/cc @chinmaygarde

@chinmaygarde
Copy link
Member

Right. In Flutter, all Dart code runs on either an engine or VM managed thread. This thread is never the platforms main thread. The platform channels mechanism works around this limitation by forwarding all platform messages to the main thread and then sending the responses from native code back to the originating thread running Dart code.

In this specific case, the limitation is the that the the AppKit method is only safe to be called from the main thread. I suspect this is the case for all UI toolkits (whether they warn on unsafe use or not) used by the linked project. Instead of calling osdialog_file directly, the project should call a method that dispatches the call to the main thread (using something like libdispatch).

@dcharkes dcharkes changed the title os dialogs fail when called via dart:ffi on macOS os dialogs fail when called via dart:ffi on macOS (thread pinning Dart standalone) Jan 5, 2021
@davewhit3
Copy link

@danrubel @chinmaygarde @mit-mit any updates on this issue?

@chinmaygarde
Copy link
Member

As I mentioned towards the end of my last comment, it is up to the native code to schedule the task on the appropriate thread. This is working as intended. In the case of osdialog_file, libdispatch may be used to schedule the task on the main thread.

@davewhit3
Copy link

A good idea!
Everything is clear now. Thank you very much!

@liamappelbe
Copy link
Contributor

We're working on solving this in flutter (flutter/flutter#136314), but for dart command line programs this isn't something we can solve in the VM. As far as macOS is concerned, the "main thread" doesn't exist in pure dart apps, because there is no thread running the OS event loop (there's no DispatchQueue). So even if we did provide something like PlatformIsolates or thread pinning in the Dart VM, it wouldn't help with this use case.

A 3rd party package could solve this problem by writing some native code that initialises all the required OS event loop infrastructure on some thread (which would then become the "main thread" by definition), and they could interact with that native code through FFI. Such a package could also use the Dart C API to spawn an isolate on that thread, and provide a way for users to run code on that isolate, if necessary. This is outside of the scope of what we can do from within the VM though.

@mraleph
Copy link
Member
mraleph commented Dec 13, 2023

This is outside of the scope of what we can do from within the VM though.

FWIW we fully control the embedder used by the dart binary so I don't see any reason why we can't actually start event loop when it is requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, FFI, and the AOT and JIT backends. library-ffi
Projects
None yet
Development

No branches or pull requests

6 participants