/*=====================================================================*/
/*    serrano/prgm/project/bigloo/fthread/src/Java/BglThread.java      */
/*    -------------------------------------------------------------    */
/*    Author      :  Manuel Serrano                                    */
/*    Creation    :  Wed Jan 30 10:40:23 2002                          */
/*    Last change :  Fri Nov 14 17:25:13 2003 (serrano)                */
/*    Copyright   :  2002-03 Manuel Serrano                            */
/*    -------------------------------------------------------------    */
/*    Bigloo Class for threads. Nothing fancy here.                    */
/*=====================================================================*/

/*---------------------------------------------------------------------*/
/*    The package                                                      */
/*---------------------------------------------------------------------*/
package bigloo.fairthread;
import java.lang.*;
import bigloo.*;

/*---------------------------------------------------------------------*/
/*    BglThread                                                        */
/*---------------------------------------------------------------------*/
public class BglThread extends Thread {
   // global cpu token
   private static Object token;

   // Bigloo connection
   private Object bgl_obj;
   private Object ident;
   private procedure bgl_thunk;
   private static bgldynamic current_dynamic_env;
   public bgldynamic env;
   
   // parent thread (i.e. the Java thread that has entered this Bgl thread)
   private Thread parent;

   // public constructor
   public BglThread() {
      super();
      env = new bgldynamic( bgldynamic.current_dynamic_env );
   }
   
   // public constructor
   public BglThread( procedure thunk ) {
      super();
      env = new bgldynamic( bgldynamic.current_dynamic_env );
      bgl_thunk = thunk;
   }

   // public constructor
   public BglThread( procedure thunk, symbol name ) {
      super( new String( name.string ) );
      ident = name;
      env = new bgldynamic( bgldynamic.current_dynamic_env );
      bgl_thunk = thunk;
   }

   // This method is invoked by Bigloo when the Bigloo object
   // representing the thread has been allocated.
   public void setup( Object o ) {
      bgl_obj = o;
   }

   // This method is used for compatibility with the Posix implementation
   // Don't remove it
   public Object idSet( Object o ) {
      ident = o;
      return o;
   }

   // Return back the pointer to the Bigloo object
   public Object getBglObj() {
      return bgl_obj;
   }

   // The thread entry-point
   public void run() {
      try {
	 fairWait();
	 bgl_thunk.funcall0();
      } catch( Throwable e ) {
	 e.printStackTrace();
	 try {
	    foreign.internalerror( e );
	 } catch( Throwable _ ) {
	    System.exit( 1 );
	 }
      }
   }

   // wait for a notification
   public void fairWait() {
      synchronized( this ) {
	 try {
	    while( token != this ) {
	       wait();
	    }
	 } catch( InterruptedException e ) { 
	    System.err.println( "interrupted wait exception: " + e ); 
	 }
      }
   }

   // switch to another thread
   public void fairSwitch( BglThread next ) {
      synchronized( next ) {
	 token = next;
	 bgldynamic.current_dynamic_env = next.env;
	 next.notify();
      }
   }

   // enter the scheduler
   public void enter_scheduler() {
      parent = currentThread();

      current_dynamic_env = bgldynamic.current_dynamic_env;
      bgldynamic.current_dynamic_env = this.env;
      
      /* switch into the scheduler thread */
      fairSwitch( this );

      /* wait for the token to be back */
      synchronized( parent ) {
	 try {
	    while( token != parent ) {
	       parent.wait();
	    }
	 } catch( InterruptedException e ) {
	    System.err.println( "interrupted wait exception: " + e ); 
	 }
      }
   }

   // leave the scheduler
   public void leave_scheduler() {
      token = null;
      bgldynamic.current_dynamic_env = current_dynamic_env;

      synchronized( parent ) {
	 token = parent;
	 parent.notify();
      }
      
      synchronized( this ) {
	 while( token != this ) {
	    try {
	       wait();
	    } catch( InterruptedException e ) {
	       System.err.println( "interrupted wait exception: " + e ); 
	    }
	 }
      }
   }
}
