Re: [cp-patches] RFC: Change GtkToolkit threading

2006-08-03 Thread Thomas Fitzsimmons

Hi,

Sven de Marothy wrote:

This should fix PR #16203, and also make for a general improvement.

In short: The main GTK loop is not started statically in GtkToolkit,
but rather on creating the first window peer. (as it should be).

In long:
On destroying the last window peer, we call gtk to end the main
loop and the thread exits. If a new window is opened, we create
a new thread object and restart the main gtk loop.

I also moved all the stuff related to this (except native methods) 
out from GtkToolkit and into a new GtkMainThread class. This should

help reduce the clutter in the already ugly GtkToolkit class.

It seems to work just fine for me, but being a rather central thing
I'd like some feedback and testing before committing it.
(Obviously not intended for the 0.92 release)


Thanks for tackling this.  On Sun's implementation, according to this document:

http://java.sun.com/j2se/1.5.0/docs/api/java/awt/doc-files/AWTThreadIssues.html

the three exit conditions are:

* There are no displayable AWT or Swing components.
* There are no native events in the native event queue.
* There are no AWT events in java EventQueues.

The first two conditions are satisfied by quitting the GTK main thread (no 
native events) when there are no windows left (no displayable AWT or Swing 
components).  I'm wondering if we need a check for the third condition before 
quitting the GTK main loop.


Tom



Re: [cp-patches] RFC: Change GtkToolkit threading

2006-08-03 Thread Sven de Marothy
On Thu, 2006-08-03 at 13:10 -0400, Thomas Fitzsimmons wrote:

> the three exit conditions are:
> 
>  * There are no displayable AWT or Swing components.
>  * There are no native events in the native event queue.
>  * There are no AWT events in java EventQueues.
> 
> The first two conditions are satisfied by quitting the GTK main thread (no 
> native events) when there are no windows left (no displayable AWT or Swing 
> components).  I'm wondering if we need a check for the third condition before 
> quitting the GTK main loop.

Right, 1) is what I just implemented. As for 2), calling gtk_main_quit()
doesn't quit immediately but rather "Makes the innermost invocation of
the main loop return when it regains control." as the GTK docs say. 
So I'm 95% sure that's to be interpreted as the native queue being empty
at that point.

Condition 3) Is also fulfilled. The EventDispatchThread shuts itself
down as it should, and I'm certain we don't need to check with the GTK
thread. The way I read it, the first two points relate only to the main
GTK thread, and the third point only to the EventDispatchThread. 

So basically when 1) and 2) are satisfied we can shut down the GTK
thread (since the peers are disposed of at that point, the EventQueue
can't call into them and cause new native events). There's no apparent 
reason why we'd need or want to shut them all down at the same time.

Once the GTK thread is shut down the EventQueue empties itself and then
shuts down. It seems to work just fine. I'm attaching a little testcase
that creates and destroys some windows and prints the number of active
threads. As expected we have two; the main GTK thread and the
EventDispatchThread.

Interestingly, the testcase shows that the 1.4 JDK revs up 6 (!)
threads by then. (But 'only' 4 on the 1.5 JDK). I dunno what it's
doing with all those extra threads. Running a botnet? :)

/Sven
import java.awt.*;

public class ThreadTest
{
  public static void main(String[] args)
  {
System.out.println("Thread initially active:"+Thread.activeCount());
Frame f = new Frame();
f.setSize(100,100);
f.setVisible(true);
System.out.println("Active after opening window:"+Thread.activeCount());
long t = System.currentTimeMillis();
System.out.println("Delaying 5s");
while( (System.currentTimeMillis() - t) < 5000 )
  Thread.yield();
System.out.println("Active now:"+Thread.activeCount());
System.out.println("Disposing peers.");
f.dispose();
f = null;
t = System.currentTimeMillis();
System.out.println("Active now::"+Thread.activeCount());
System.out.println("Waiting 5 s");
while( (System.currentTimeMillis() - t) < 5000 )
  Thread.yield();
f = new Frame();
f.setSize(100,100);
System.out.println("Recreating peers.");
f.setVisible(true);
System.out.println("# of active threads now:"+Thread.activeCount());
System.out.println("End.");
  }
}