Git Product home page Git Product logo

Comments (24)

clayrisser avatar clayrisser commented on June 20, 2024 1

Btw, just thought I'd mention this. When it comes to overhead, we're mostly concerned about rendering overhead. The ffi overhead pales in comparison to rendering overhead.

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

I'm not sure if this is related to it or not, but I noticed the ffi documentation makes an extra reference to the callback pointer on exit.

var ffi = require('ffi');

// Interface into the native lib
var libname = ffi.Library('./libname', {
  'setCallback': ['void', ['pointer']]
});

// Callback from the native lib back into js
var callback = ffi.Callback('void', ['int', 'string'], function(id, name) {
  console.log("id: ", id);
  console.log("name: ", name);
});

console.log("registering the callback");
libname.setCallback(callback);
console.log('done');

// Make an extra reference to the callback pointer to avoid GC
process.on('exit', function() {
  callback
});

from gtk-node.

Place1 avatar Place1 commented on June 20, 2024

Yeah the segfault isn't from FFI. I fixed that issue by doing this.onActivate = ffi.Callback(...)
Because they 'app' is still referenced it will work.

The seg fault happens anywhere from 3 to 10 seconds after the application window first opening. I think the problem is to do with app.init.async(). From the docs, this will schedule the C function on a uv thread (just a normal pthread on linux). My reading on the GTK event loop suggests that this is could be problematic because GTK is not thread safe and so must run all on the same thread. I'd imagine there are various concurrency issues arising from this. The GTK callback for 'activate' would be invoked from the GTK thread (the uv thread from app.init.async()) I believe, which could mess up Node, perhaps ffi manages this though and schedules the callback on the eventloop correctly (might have to read up on this). Similarly any ffi calls such as 'button.attach(window)would violate GTK's thread safety because those GTK api functions would be called from a different thread that whereapp.init.async()scheduled theg_application_run()`.

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

Could you submit a pull request for your fix?

from gtk-node.

Place1 avatar Place1 commented on June 20, 2024

I haven't found a fix yet. The work I did on my branch seg faults because i'm still using app.init.async(). And if I don't use async, then promises don't resolve (the ffi callbacks run but calling resolve() in them does nothing :(`, even with the event loop code (probably buggy or not the right solution).

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

"I fixed that issue by doing this.onActivate = ffi.Callback(...)"

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

So, we have to somehow interact with GTK in a thread safe way, which ffi doesn't seem to allow?

from gtk-node.

Place1 avatar Place1 commented on June 20, 2024

I'm not sure to be honest. Maybe we could experiment by making sure in attach() C functions (as an example) we make sure to actually run the GTK api calls on the GTK main loop. I'm not super familiar with GTK but I assume there's a way to make that happen. If that solves some of the crashes then maybe that'll be a good solution? That basically would leave us with 1 main thread for Node's UV loop and another thread for GTK's main loop. And then GTK is providing the currency tools for Node calling GTK.

Node function ---- calls ---> ffi binding --- calls ---> C code --- schedules with GTK main loop ---> GTK api call.

That's adding another overhead though, on top of FFI calls, so it might not be a good solution?

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

I just added an extra ref to callbacks on exit, like the ffi docs said to do. I doubt this has anything to do with this issue, but thought I'd give it a try. I've not gotten any segmentation faults yet. How can I reproduce your error?

from gtk-node.

Place1 avatar Place1 commented on June 20, 2024

I'm not sure tbh. the seg fault was not from the ffi callback, it was unrelated. I'm speculating it's because of running the g_application_run on another thread but i'm not sure.

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

This is one of the reasons why this is a much better alternative to electron. Electron does not do native rendering, but this does.

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

https://blogs.gnome.org/ebassi/documentation/lazy-loading/

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

https://developer.gnome.org/gdk3/stable/gdk3-Threads.html

from gtk-node.

nuxlli avatar nuxlli commented on June 20, 2024

Replacing the node's main loop is not trivial and can lead to several problems. I even had commenting on http://libyue.com in issue #3. There are no own cases of a more complex solution: https://github.com/yue/yode

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

We're not replacing node's main loop. We're dealing with the gtk thread.

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

Ok, I figured out how to multithread gtk. It works so long as you leave the rendering on the same thread.

Look in the multi-threading branch.

https://github.com/jamrizzi/node-gtk3/tree/multi-threading

However, I'm having a race condition problem with the multi-threading right now. I need to figure out how to wait for the render thread to finish before returning the ffi thread. You'll see that it's not rendering the button. I'm pretty sure the following is happening.

GTK Main Thread -> App and Window created                                                     -> App Rendered   -> Button added to GTK
FFI Button Thread                        -> Create button called from JS ->  Function returned

d543dca

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

Basically, the app gets rendered before the button is created. Somehow I need the attach function to wait until the button has been attached, rather than returning it immediately after I call gdk_threads_add_idle().

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

The following prints 21, but it needs to print 12;

// button/index.c

 gboolean attach_main(gpointer p_package) {                                                                                                                        
   AttachPackage package = *(AttachPackage*)p_package;                                                                                                             
   g_signal_connect(package.button, "clicked", G_CALLBACK(on_click), NULL);                                                                                        
   GtkWidget *button_box;                                                                                                                                          
   button_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);                                                                                                    
   gtk_container_add(GTK_CONTAINER(package.container), button_box);                                                                                                
   gtk_container_add(GTK_CONTAINER(button_box), package.button);                                                                                                   
+  printf("1");                                                                                                                                                    
   return G_SOURCE_REMOVE;                                                                                                                                         
 }                                                                                                                                                                 
 void attach(GtkWidget *button, GtkWidget *container) {                                                                                                            
   AttachPackage *p_package = g_malloc(sizeof(AttachPackage));                                                                                                     
   p_package->button = button;                                                                                                                                     
   p_package->container = container;                                                                                                                               
   p_package->test = "wow";                                                                                                                                        
   gdk_threads_add_idle(attach_main, p_package);                                                                                                                   
+  printf("2");                                                                                                                                                    
 }

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

Well, it seems that the solution is to explicitly show the button widget since it gets attached after the main window is rendered.

7093ce8

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

Multithreading should be working now. @Place1 let me know if it fixed the segfault issue you were having.

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

@Place1 can you confirm if the segfault was fixed for you?

from gtk-node.

Place1 avatar Place1 commented on June 20, 2024

Yep all good now!

from gtk-node.

clayrisser avatar clayrisser commented on June 20, 2024

Yeeees

from gtk-node.

Place1 avatar Place1 commented on June 20, 2024

@jamrizzi can the mutithreading approach lead to developer unfriendly race conditions?

Take this example (not real code)

const layout = new Layout()
const button = new Button()
layout.put(button, 0, 0)
console.log('the button is at: ', button.x, button.y)
layout.move(button, 20, 20)
console.log('the button is at: ', button.x, button.y)

If the layout.put() and layout.move() methods aren't actually doing anything but instead enqueing work on the GTK main loop that will do the work, then there is the potential for the button.x and button.y to not be updated when javascript calls them. A solution for this, would be to make everything that needs to touch GTK go through the gtk main loop in the same way (to ensure concurrency of operations), but would this lead to any significant overheads?

from gtk-node.

Related Issues (7)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.