Hi,

this might be of common interest for ECL users, so please see attached
file if you want to know more.

Cheers,

Paul

EQL (ECL + Qt) in Slime -- how does it work?

  • Start swank using the EQL executable, running the swank server in an ECL thread, and using the main thread for the Qt main event loop.

  • Wrap every internal EQL function in a macro, which will call the function either directly (if called from GUI/main thread), or, if called from another ECL thread, will wrap the function call in a closure.

  • This closure will be passed to a queued, blocking Qt function running in the GUI thread, which will in turn call the closure.

The crucial part is passing a Lisp closure from an ECL thread to Qt and calling it from C++ in the GUI/main thread.

This is trivial in ECL/Qt, since both ECL and Qt use/wrap native C threads, and Qt offers a nice utility with Q_INVOKABLE.

First let's wrap the actual Lisp function, e.g. (foo x y) in a closure, so we only need to pass one ECL closure pointer to C++.

No need to pass Lisp arguments to C++, they are in the closure; no return value needed from C++, Lisp return values will be assigned in the closure:


  ;; in some ECL thread
  (let (values)
    (run-in-gui-thread

      ;; in ECL main/GUI thread
      (lambda ()
        (setf values (multiple-value-list (foo x y)))))

    ;; back in some ECL thread
    (values-list values))

Here the implementation of the ECL function run-in-gui-thread (embedded in Qt):


  cl_object run_in_gui_thread(cl_object closure) // define ECL function
  {
      QMetaObject::invokeMethod(
          caller,                       // any object from GUI thread
          "runInGuiThread",             // see Q_INVOKABLE
          Qt::BlockingQueuedConnection, // blocking for return values
          Q_ARG(void*, closure));       // 'closure' is just a pointer

      return Cnil;
  }

Now the Lisp closure will run in the GUI/main thread, and the implementation of the Qt function runInGuiThread is as simple as:


  Q_INVOKABLE void runInGuiThread(void* closure) // note Q_INVOKABLE
  {
      cl_funcall(1, (cl_object)closure); // ECL function call
  }

After introducing a macro qrun*, and wrapping all EQL functions int it (see "slime/thread-safe.lisp"), we are done!

(Please note that the above code is a stripped down version, see sources for the actual implementation.)


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
_______________________________________________
Ecls-list mailing list
Ecls-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ecls-list

Reply via email to