Lisp HUG Maillist Archive

Using CAPI from dynamic library

Hi,

Is it possible to use the CAPI from a delivered dynamic library?

I’m on macOS, and while the following code produces a valid dynamic library, calling it (using the rundll program in examples/delivery/dynamic-library) makes the program crash:

2019-08-31 00:57:46.975 rundll[82750:1587011] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.’

So how do I make the code run in the main thread? Is it even possible?

Erik


(fli:define-foreign-callable (capitest :result-type :int)
    ((argc :int)
     (argv (:pointer (:pointer :char))))
  (declare (ignore argc argv))

  (capi:contain (make-instance 'capi:title-pane :text "Hurrah!"))
  0)

(deliver nil
         (current-pathname "lib-test" nil)
         0
         :interface :capi
         :dll-exports '("capitest”))



_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Using CAPI from dynamic library

Yes, should be absolutely possible. 

My recommendation (because this change is necessary anyway — never “do” anything in the callback thread — is that you should make the following change. I think it will fix your problem. 

Use the callback thread to switch threads (either create a new one or leave a message for an existing one). Use the other thread to invoke CAPI. 

- nick

> On 31 Aug 2019, at 00:06, Erik Ronström <erik.ronstrom@doremir.com> wrote:
> 
> Hi,
> 
> Is it possible to use the CAPI from a delivered dynamic library?
> 
> I’m on macOS, and while the following code produces a valid dynamic library, calling it (using the rundll program in examples/delivery/dynamic-library) makes the program crash:
> 
> 2019-08-31 00:57:46.975 rundll[82750:1587011] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.’
> 
> So how do I make the code run in the main thread? Is it even possible?
> 
> Erik
> 
> 
> (fli:define-foreign-callable (capitest :result-type :int)
>    ((argc :int)
>     (argv (:pointer (:pointer :char))))
>  (declare (ignore argc argv))
> 
>  (capi:contain (make-instance 'capi:title-pane :text "Hurrah!"))
>  0)
> 
> (deliver nil
>         (current-pathname "lib-test" nil)
>         0
>         :interface :capi
>         :dll-exports '("capitest”))
> 
> 
> 
> _______________________________________________
> Lisp Hug - the mailing list for LispWorks users
> lisp-hug@lispworks.com
> http://www.lispworks.com/support/lisp-hug.html

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Using CAPI from dynamic library

see also:

4.1  The correct thread for CAPI operations


http://www.lispworks.com/documentation/lw71/CAPI-U/html/capi-u-27.htm




Am 31.08.2019 um 08:50 schrieb Erik Ronström <erik.ronstrom@doremir.com>:

Thanks for your answer!

But I’m not sure I understand how you mean – should I switch thread on the calling side or in the library itself? Do you have an example?

Erik



31 aug. 2019 kl. 06:04 skrev Nick Levine <nick@nicklevine.org>:

Yes, should be absolutely possible.

My recommendation (because this change is necessary anyway — never “do” anything in the callback thread — is that you should make the following change. I think it will fix your problem.

Use the callback thread to switch threads (either create a new one or leave a message for an existing one). Use the other thread to invoke CAPI.

- nick

On 31 Aug 2019, at 00:06, Erik Ronström <erik.ronstrom@doremir.com> wrote:

Hi,

Is it possible to use the CAPI from a delivered dynamic library?

I’m on macOS, and while the following code produces a valid dynamic library, calling it (using the rundll program in examples/delivery/dynamic-library) makes the program crash:

2019-08-31 00:57:46.975 rundll[82750:1587011] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.’

So how do I make the code run in the main thread? Is it even possible?

Erik


(fli:define-foreign-callable (capitest :result-type :int)
 ((argc :int)
  (argv (:pointer (:pointer :char))))
(declare (ignore argc argv))

(capi:contain (make-instance 'capi:title-pane :text "Hurrah!"))
0)

(deliver nil
      (current-pathname "lib-test" nil)
      0
      :interface :capi
      :dll-exports '("capitest”))



_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Using CAPI from dynamic library

I would think that UI/Cocoa code needs to run in the main process.

In Lisp it would be the value of mp:*main-process*

Not sure how you do it in a dynamic library.



> Am 31.08.2019 um 12:05 schrieb Erik Ronström <erik.ronstrom@doremir.com>:
> 
>> see also:
>> 
>> 4.1  The correct thread for CAPI operations
> 
> Yes, but that assumes I already have some displayed interface, so that I can call capi:execute-with-interface on it. I failed even trying to display an interface in the first place.
> 
> Erik
> 


_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Using CAPI from dynamic library

I think it is a LispWorks issue when using a library. I have tried to use CAPI in a 4th Dimension plugin. 4D provides a plugin entry point to call a function in the main process (EX_RUN_IN_MAIN_PROCESS - https://github.com/4d/4D-Plugin-SDK/blob/master/4D%20Plugin%20API/EntryPoints.h). Anything with a simple CAPI interface causes 4D to crash and the backtrace has similarities to the error you posted. Something with the NSUndoManager.

If I just use Cocoa to create an alert, that works without crashing.


Thread 22 Crashed:
0   libsystem_kernel.dylib        	0x00007fff667642c6 __pthread_kill + 10
1   libsystem_pthread.dylib       	0x00007fff6681fbf1 pthread_kill + 284
2   libsystem_c.dylib             	0x00007fff666ce6a6 abort + 127
3   libc++abi.dylib               	0x00007fff638aa641 abort_message + 231
4   libc++abi.dylib               	0x00007fff638aa7df default_terminate_handler() + 267
5   libobjc.A.dylib               	0x00007fff64e5dee3 _objc_terminate() + 97
6   libc++abi.dylib               	0x00007fff638b619e std::__terminate(void (*)()) + 8
7   libc++abi.dylib               	0x00007fff638b5f86 __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception*) + 27
8   libc++abi.dylib               	0x00007fff638a8f99 __cxa_throw + 113
9   libobjc.A.dylib               	0x00007fff64e5bb51 objc_exception_throw + 362
10  com.apple.CoreFoundation      	0x00007fff3a7a5016 +[NSException raise:format:arguments:] + 98
11  com.apple.Foundation          	0x00007fff3ca44bd5 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 194
12  com.apple.Foundation          	0x00007fff3c977c4a +[NSUndoManager(NSPrivate) _endTopLevelGroupings] + 473
13  com.apple.AppKit              	0x00007fff37cc3681 -[NSApplication run] + 916
14  ???                           	0x0000004000050712 0 + 274878236434


(fli:define-foreign-callable capi-test-call ()
  ;(uui:ui-alert "test 123"))
  (capi:display (make-instance 'capi:interface :title "Test")))


(defun-4d-plugin ("CAPI_TEST") ()
  (let ((func (fli:make-pointer :symbol-name 'capi-test-call)))
    (run-in-main-process func)))



John DeSoi, Ph.D.


> On Aug 31, 2019, at 1:31 PM, Erik Ronström <erik.ronstrom@doremir.com> wrote:
> 
> As the pointers addresses are identical, it looks like the callback _is_ run in the main thread after all?! Or how should I otherwise interpret this result? And in that case, why does capi:contain still result in an error saying I’m not in the main thread?


_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Updated at: 2020-12-10 08:29 UTC