Gtk event loop

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Gtk event loop

MrGwen
Hi,

Right now the gtk event look works like this :

call gtk_main

[ handleEvents. true ] whileTrue: [ Processor yield ]

first problem the gtk_main function blocks the smalltalk processes.
second problem if we enter in the event handling loop this is an active
waiting it burns your CPU :P.

As we can see the Gtk event loop doesn't feet at all with Smalltalk.
since in the first case Smalltalk processes are not handled. In the
second case the Smalltalk processes are handled but with an high cpu
usage.

So here is my proposal for a new Gtk event handling :

  first we create a c thread with the gtk_main function, when there is
an event the c function : invoke_smalltalk_closure will be called signal
a Smalltalk semaphore and lock a C muted.

  in Smalltalk inside an infinite loop we wait for an event with a
Semaphore, when there is an event we get the signal get the event and
handle it :
  - if it works well the result is sent to a C Function and signal the C
Mutex
  - if there is an exception launch a debugger and launch a new gtk_main
inner loop

  Some events can occurs if we are not inside the gtk_main loop so we
handle it like this : in the c function : invoke_smalltalk_closure we
check if the thread is the main thread if yes we call Gtk innerEvent
function.

  Right now that works well (for example I can launch iLiad without any
problem) I should fix the gtk_dialog_run because this function launch an
inner loop outside the same thread that the main gtk_loop; the two loops
are locked :D.

  If you have a better idea, cleaner approach any comments, remarks are
welcome !

Cheers,
Gwenael
 



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

Paolo Bonzini-2
>  Right now that works well (for example I can launch iLiad without any
> problem) I should fix the gtk_dialog_run because this function launch an
> inner loop outside the same thread that the main gtk_loop; the two loops
> are locked :D.

I think it should not be hard to rewrite gtk_dialog_run in Smalltalk, see

http://www.google.com/codesearch/p?hl=en#ErvFMsc8kPE/pub/GNOME/sources/gtk+/2.6/gtk+-2.6.9.tar.gz|z8d-VbwUHqs/gtk+-2.6.9/gtk/gtkdialog.c

around line 900.

>  If you have a better idea, cleaner approach any comments, remarks are
> welcome !

Can you post a patch? I know it is in your github repo, but still...

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

MrGwen
On Thursday 11 February 2010 11:39:38 am Paolo Bonzini wrote:

> >  Right now that works well (for example I can launch iLiad without any
> > problem) I should fix the gtk_dialog_run because this function launch an
> > inner loop outside the same thread that the main gtk_loop; the two loops
> > are locked :D.
>
> I think it should not be hard to rewrite gtk_dialog_run in Smalltalk, see
>
> http://www.google.com/codesearch/p?hl=en#ErvFMsc8kPE/pub/GNOME/sources/gtk+
> /2.6/gtk+-2.6.9.tar.gz|z8d-VbwUHqs/gtk+-2.6.9/gtk/gtkdialog.c
>
> around line 900.
>

Normally a simple
run [
  self showAll
]
 
That should be enough ^^

> >  If you have a better idea, cleaner approach any comments, remarks are
> > welcome !
>
> Can you post a patch? I know it is in your github repo, but still...
>

I'll clean up the code and send it this week end ;)

> Paolo

Gwen


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

Paolo Bonzini-2
On 02/12/2010 10:59 AM, Gwenael Casaccio wrote:

> On Thursday 11 February 2010 11:39:38 am Paolo Bonzini wrote:
>>>   Right now that works well (for example I can launch iLiad without any
>>> problem) I should fix the gtk_dialog_run because this function launch an
>>> inner loop outside the same thread that the main gtk_loop; the two loops
>>> are locked :D.
>>
>> I think it should not be hard to rewrite gtk_dialog_run in Smalltalk, see
>>
>> http://www.google.com/codesearch/p?hl=en#ErvFMsc8kPE/pub/GNOME/sources/gtk+
>> /2.6/gtk+-2.6.9.tar.gz|z8d-VbwUHqs/gtk+-2.6.9/gtk/gtkdialog.c
>>
>> around line 900.
>>
>
> Normally a simple
> run [
>    self showAll
> ]
>
> That should be enough ^^

When it is, the caller should have said "showAll".  "Run" is blocking.

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

MrGwen
On Friday 12 February 2010 11:55:36 am Paolo Bonzini wrote:

> On 02/12/2010 10:59 AM, Gwenael Casaccio wrote:
> > On Thursday 11 February 2010 11:39:38 am Paolo Bonzini wrote:
> >>>   Right now that works well (for example I can launch iLiad without any
> >>>
> >>> problem) I should fix the gtk_dialog_run because this function launch
> >>> an inner loop outside the same thread that the main gtk_loop; the two
> >>> loops are locked :D.
> >>
> >> I think it should not be hard to rewrite gtk_dialog_run in Smalltalk,
> >> see
> >>
> >> http://www.google.com/codesearch/p?hl=en#ErvFMsc8kPE/pub/GNOME/sources/g
> >> tk+ /2.6/gtk+-2.6.9.tar.gz|z8d-VbwUHqs/gtk+-2.6.9/gtk/gtkdialog.c
> >>
> >> around line 900.
> >
> > Normally a simple
> > run [
> >
> >    self showAll
> >
> > ]
> >
> > That should be enough ^^
>
> When it is, the caller should have said "showAll".  "Run" is blocking.
>
> Paolo
Hi,

you'll find as an attached file the first release of the new gtk event loop.

Gwen

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk

gtk-event-loop.patch (15K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

MrGwen
On Tuesday 16 February 2010 01:44:01 pm Gwenael Casaccio wrote:

> On Friday 12 February 2010 11:55:36 am Paolo Bonzini wrote:
> > On 02/12/2010 10:59 AM, Gwenael Casaccio wrote:
> > > On Thursday 11 February 2010 11:39:38 am Paolo Bonzini wrote:
> > >>>   Right now that works well (for example I can launch iLiad without
> > >>>   any
> > >>>
> > >>> problem) I should fix the gtk_dialog_run because this function launch
> > >>> an inner loop outside the same thread that the main gtk_loop; the two
> > >>> loops are locked :D.
> > >>
> > >> I think it should not be hard to rewrite gtk_dialog_run in Smalltalk,
> > >> see
> > >>
> > >> http://www.google.com/codesearch/p?hl=en#ErvFMsc8kPE/pub/GNOME/sources
> > >> /g tk+ /2.6/gtk+-2.6.9.tar.gz|z8d-VbwUHqs/gtk+-2.6.9/gtk/gtkdialog.c
> > >>
> > >> around line 900.
> > >
> > > Normally a simple
> > > run [
> > >
> > >    self showAll
> > >
> > > ]
> > >
> > > That should be enough ^^
> >
> > When it is, the caller should have said "showAll".  "Run" is blocking.
> >
> > Paolo
>
> Hi,
>
> you'll find as an attached file the first release of the new gtk event
> loop.
>
> Gwen

we should extend the binding generator to generate  thread safe gtk functions
(with gdk_threads_enter the gtk_function gdk_threads_leave)

Gwen


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

Paolo Bonzini-2
On 02/16/2010 03:32 PM, Gwenael Casaccio wrote:
> we should extend the binding generator to generate  thread safe gtk functions
> (with gdk_threads_enter the gtk_function gdk_threads_leave)

Please expand?

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

Paolo Bonzini-2
In reply to this post by MrGwen
Despite the apparent harshness of the review, it's really good stuff.
Thanks!

Go through the comments in the order I mention (see asterisked numbers;
each number refers to the text before) and commit the solution to each
part (which may not be exactly what I write of course!) separately so
it's easy to understand when things wrong.

So let's start... first: where is the ChangeLog? :-)

> +    handleInnerEvent [
> +
> + | event |
> +        event := GTK.Gtk events.
> +        event ifNotNil: [ | args |
> +            args := Array new: event n_params value.
> +            1 to: args size do: [ :i | args at: i put: (event data value at: i - 1) ].
> +            [ ^ (event receiver value perform: event selector value withArguments: args) ] on: Exception do: [ :exception |
> + Behavior debuggerClass open ] ]
> +    ]

Why the handler?  It shouldn't be necessary as the inner event runs in
its own Smalltalk process. *10*

> +    insideLoop [
> +
> + | event |
> +        eventSem wait.
> +        event := GTK.Gtk events.
> +        event ifNotNil: [ | args |
> +            args := Array new: event n_params value.
> +            1 to: args size do: [ :i | args at: i put: (event data value at: i - 1) ].
> +            [ GTK.Gtk result: (event receiver value perform: event selector value withArguments: args) mutex: event mutex value ] on: Exception do: [ :exception |
> + event status value: 0.
> + Behavior debuggerClass open.
> + GTK.Gtk result: nil mutex: event mutex value ] ]

What about something like this instead, trapping Exception is almost
always wrong (you trap Notification and Warning as well):

[ [ result := event receiver value perform: event selector value
withArguments: args ]
    on: System.UnhandledException do: [ :ex |
        event status value: 0.
        ex pass ] ]
            ensure: [ GTK.Gtk result: result mutex: event mutex value ]

*11*

> - sem := Semaphore new.
> - GTK.Gtk main: sem.

> + eventSem:= Semaphore new.
> + GTK.Gtk eventSemaphore: eventSem.
> +      GTK.Gtk mainLoop.
> + [ self insideLoop.

What about instead keeping more of the old code: *3*

    sem := Semaphore new.
    GTK.Gtk mainLoop: sem.
    [ self insideLoop: sem

?

(BTW I'd rename insideLoop to #processEvents or something like that). *2*

> +          true ] whileTrue: [ "DOES NOT WORK ::::::  Processor yield" ]

Is it needed at all, since we yield when waiting on sem? *1*  Just do

     [ self insideLoop ] repeat

(or the similar thing with sem if you accept my suggestion above).

> diff --git a/packages/gtk/MoreFuncs.st b/packages/gtk/MoreFuncs.st
> index a07ae29..d16210d 100644
> --- a/packages/gtk/MoreFuncs.st
> +++ b/packages/gtk/MoreFuncs.st
> @@ -12,9 +12,9 @@ Gtk class extend [
>  
>       ]
>
> -    main: aSemaphore [
> +    mainLoop [
>   <category: 'C call-outs'>
> - <asyncCCall: 'gstGtkMain' args: #(#smalltalk )>
> + <asyncCCall: 'gstGtkMain' args: #()>

Doesn't need to be asynchronous anymore.  In fact, I'd like to deprecate
#asyncCCall:, I'm not even sure I understand their implications.

Just make it return void. *4*

> +static OOP result = NULL;

This is never read?!?

Also, maybe you want to move it to SmalltalkClosureStruct. *5*

> +typedef struct SmalltalkClosureStruct {
> +  OOP receiver;
> +  OOP selector;
> +  OOP *data;
> +  OOP widget;
> +  int n_params;
> +  GMutex *mutex;
> +  int status
> +} SmalltalkClosureStruct;
> +
> +static SmalltalkClosureStruct *event;

Does not need to be static. *6*

> -static void my_gtk_main (OOP semaphore);
> +static void my_gtk_main ();

As above, consider keeping the parameter. *3*

> +  event = malloc (sizeof (*event));

Nowhere freed. *7*

> +  event->receiver = stc->receiver;
> +  event->selector = stc->selector;

registerOOP on these and args.  Even better, construct a DirectedMessage
object so that #insideLoop and #handleInnerEvent can just do "event
message value send".  Right now they have duplicated code! *7*

> +  if (g_thread_self () != main_thread) {

g_thread_equal. *8*

> +    event->mutex = g_mutex_new ();
> +    g_mutex_lock (event->mutex);
> +
> +    _gst_vm_proxy->syncSignal (event_sem, true);
> +    _gst_vm_proxy->wakeUp ();
> +
> +    g_mutex_lock (event->mutex);

Locking twice is surely wrong? *9*

> +    // Smalltalk event handling raises an exception launch an inner
> +    // event loop
> +    //
> +    if (event->status == 0)
> +      gtk_main ();

Longer longer longer explanation needed? (And no // comments). Actually,
let's postpone this to after the next iteration.

> +void
> +set_event_semaphore (OOP semaphore)
> +{
> +  event_sem = semaphore;
> +  _gst_vm_proxy->registerOOP (semaphore);
> +}

Unnecessary if you pass the semaphore to my_gtk_main. *3*

> +void
> +set_result (OOP anObject, GMutex *mutex)
> +{
> +  result = anObject;
> +  g_mutex_unlock (mutex);
> +}

Pass back the entire events struct so that you can also call
unregisterOOP, free the args, and free the struct itself.  If you make
it like this:

void
set_event_result (SmalltalkClosureStruct *event, OOP anObject)
{
   event->result = anObject;
   g_mutex_unlock (event->mutex);
}

you can even declare it as an instance-side method in
SmalltalkClosureStruct.  Much nicer that way! *5*

> - self
> + "self
>      connectSignal: 'paste-clipboard' to: self selector: #paste userData: nil;
>               connectSignal: 'cut-clipboard' to: self selector: #cut userData: nil.
>
> @@ -24,7 +24,7 @@ GTK.GtkTextView subclass: GtkTextWidget [
>               connectSignal: 'begin-user-action' to: self selector: #'beginUserAction' userData: nil;
>               connectSignal: 'end-user-action' to: self selector: #'endUserAction' userData: nil;
>               connectSignal: 'insert-text' to: self selector: #'insert:at:text:size:' userData: nil;
> -            connectSignal: 'delete-range' to: self selector: #'delete:from:to:' userData: nil
> +            connectSignal: 'delete-range' to: self selector: #'delete:from:to:' userData: nil"

What's the problem?  Things like this should not be there for the new
event loop to go in.


> @@ -218,10 +221,7 @@ THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.';
>   <category: 'file events'>
>
>   (GTK.GtkFileChooserDialog save: 'Save image as...' parent: window)
> -    runNonBlockingAndDo: [ :dlg :res |
> - imageName := dlg getFilename.
> - dlg destroy.
> - res = GTK.Gtk gtkResponseAccept ifTrue: [ self saveImage: [ ObjectMemory snapshot: imageName ] ] ]
> +    run

Same here of course.

> -<start>VisualGST.VisualGST open.
> -    GTK.Gtk main</start>
> +<start>
> +        | a |
> + VisualGST.VisualGST open.
> + [ GTK.Gtk main ] fork.
> + a := Semaphore new.
> + a wait.
> + 'byebye' printNl.
> +</start>

This is just debugging code I guess?

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

Paolo Bonzini-2
In reply to this post by Paolo Bonzini-2
On 02/16/2010 05:00 PM, Paolo Bonzini wrote:
> On 02/16/2010 03:32 PM, Gwenael Casaccio wrote:
>> we should extend the binding generator to generate thread safe gtk
>> functions
>> (with gdk_threads_enter the gtk_function gdk_threads_leave)
>
> Please expand?

Uhm, from discussion on IRC I see what you're saying.

While nice, this approach is probably a kind of dead end.  You'd have a
huge nightmare stemming from executing C callbacks in a thread and
Smalltalk callbacks in another.

Instead, we should keep the best of the two approaches we have.

 From your code we get the fact that polling runs in another thread.
 From what exists we get the fact that only one thread runs GTK+ stuff.

Based on GLib's code, this is approximately the code that should run in
the other thread:

gpointer
loop (gpointer data)
{
     static GPollFD *fds;
     static int allocated_nfds;
     GMainLoop *loop = data;
     GMainContext *context = g_main_loop_get_context (loop);

     if (!fds) {
         fds = g_new (GPollFD, 20);
         allocated_nfds = 20;
     }

     while (g_main_loop_is_running (loop)) {
         int nfds, maxprio, timeout;
         if (!g_main_context_acquire (context)) {
             if (!g_main_context_pending (context))
                 continue;
         } else {
             g_main_context_prepare (context, &maxprio);
             while ((nfds = g_main_context_query (context, maxprio,
                                &timeout, fds, allocated_nfds)) >
                      allocated_nfds) {
                 g_free (fds);
                 fds = g_new (GPollFD, nfds);
                 allocated_nfds = nfds;
             }

             // release the context so that the other thread can dispatch
             g_main_context_release (context);
             g_poll (timeout, fds, nfds);

             // If the other thread is now dispatching, calling
             // g_main_context_pending will wait until it releases the
             // context and then poll again---but without dispatching,
             // so we still have to signal the semaphore!
             if (!g_main_context_acquire (context)) {
                 if (!g_main_context_pending (context))
                     continue;
             } else {
                 g_main_context_check (context, maxprio, fds, nfds);
                 g_main_context_release (context);
             }
         }

         // signal smalltalk semaphore and wake up other thread
         sched_yield ();
     }
}

static GMainLoop *loop;
static GThread *thread;

void
gstGtkMain ()
{
     loop = g_main_loop_new (NULL, TRUE);
     thread = // create thread
}

void
gstGtkMainQuit ()
{
     g_main_loop_quit (loop);
     g_thread_join (thread);
}

and the Smalltalk process will just call repeatedly (with an async C
callout, contradicting what I said in the previous email):

void
gstGtkMainDispatch ()
{
     while (!g_main_context_acquire (context)) {
         g_main_context_pending (context);
     }
     g_main_context_dispatch (g_main_loop_get_context (loop));
     g_main_context_release (context);
}

after waiting on a Semaphore.

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Gtk event loop

Paolo Bonzini-2
In reply to this post by MrGwen
On 02/16/2010 01:44 PM, Gwenael Casaccio wrote:
> Hi,
>
> you'll find as an attached file the first release of the new gtk event loop.

And you'll find attached the second release of the new GTK event loop. :-)

The handling of dialogs is needed with this one too, but it should not
be hard (especially with the #runOnAnswer: temporary trick).

I only tested it with example_tictactoe.st but it seems to work!

Paolo

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk

gst-eventloop-second-try.patch (12K) Download Attachment