Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
ensures that the native libraries are always loaded before trying to access them
[simgrid.git] / org / simgrid / msg / Process.java
index d5e10d6..edde2bf 100644 (file)
@@ -1,20 +1,16 @@
 /*
- * $Id$
- *
- * Copyright 2006,2007 Martin Quinson, Malek Cherier           
+ * Copyright 2006-2012 The SimGrid team
  * All right reserved. 
  *
  * This program is free software; you can redistribute 
  * it and/or modify it under the terms of the license 
- *(GNU LGPL) which comes with this package. 
+ * (GNU LGPL) which comes with this package.
  */
 
 package org.simgrid.msg;
  
 import java.util.Arrays;
-import java.util.Hashtable;
 import java.util.Vector;
-import java.util.concurrent.Semaphore;
 
 /**
  * A process may be defined as a code, with some private data, executing 
@@ -47,32 +43,39 @@ import java.util.concurrent.Semaphore;
  * 
  */
 
-public abstract class Process extends Thread {
+public abstract class Process implements Runnable {
        /**
         * This attribute represents a bind between a java process object and
         * a native process. Even if this attribute is public you must never
         * access to it. It is set automatically during the build of the object.
         */
-       public long bind;
-
+       private long bind;
+       /**
+        * Indicates if the process is started
+        */
+       boolean started;
        /**
         * Even if this attribute is public you must never access to it.
         * It is used to compute the id of an MSG process.
         */
        public static long nextProcessId = 0;
-
+       
        /**
         * Even if this attribute is public you must never access to it.
         * It is compute automatically during the creation of the object. 
         * The native functions use this identifier to synchronize the process.
         */
        public long id;
-
-    /**
-     *
-     */
-    public Hashtable<String,String> properties;
-
+       
+       /**
+        * Start time of the process
+        */
+       public double startTime = 0;
+       /**
+        * Kill time of the process
+        */
+       public double killTime = -1;
+       
        /**
         * The name of the process.                                                     
         */
@@ -89,38 +92,19 @@ public abstract class Process extends Thread {
         * The host of the process
         */
        protected Host host = null;
-    /**
-     *
-     * @return
-     */
-    public String msgName() {
-               return this.name;
-       }
+
        /** The arguments of the method function of the process. */     
        public Vector<String> args;
 
-       /* process synchronization tools */
-    /**
-     *
-     */
-    /**
-     *
-     */
-    protected Semaphore schedBegin, schedEnd;
-    private boolean nativeStop = false;
-
+       
        /**
         * Default constructor (used in ApplicationHandler to initialize it)
         */
        protected Process() {
-               super();
                this.id = nextProcessId++;
                this.name = null;
                this.bind = 0;
                this.args = new Vector<String>();
-               this.properties = null;
-               schedBegin = new Semaphore(0);
-               schedEnd = new Semaphore(0);
        }
 
 
@@ -172,12 +156,10 @@ public abstract class Process extends Thread {
         * @param host                  The host of the process to create.
         * @param name                  The name of the process.
         * @param args                  The arguments of main method of the process.
-        *
-        */
+        */     
        public Process(Host host, String name, String[]args) {
-               /* This is the constructor called by all others */
                this();
-               
+               this.host = host;
                if (name == null)
                        throw new NullPointerException("Process name cannot be NULL");
                this.name = name;
@@ -185,16 +167,37 @@ public abstract class Process extends Thread {
                this.args = new Vector<String>();
                if (null != args)
                        this.args.addAll(Arrays.asList(args));
+       }       
+       /**
+        * Constructs a new process from a host and his name, the arguments of here method function are
+        * specified by the parameter args.
+        *
+        * @param host                  The host of the process to create.
+        * @param name                  The name of the process.
+        * @param args                  The arguments of main method of the process.
+        * @param startTime             Start time of the process
+        * @param killTime              Kill time of the process
+        *
+        */
+       public Process(Host host, String name, String[]args, double startTime, double killTime) {
+               this();
+               this.host = host;
+               if (name == null)
+                       throw new NullPointerException("Process name cannot be NULL");
+               this.name = name;
 
-               try {
-                       MsgNative.processCreate(this, host.getName());
-               } catch (HostNotFoundException e) {
-                       throw new RuntimeException("The impossible happend (yet again): the host that I have were not found",e);
-               }
-               
+               this.args = new Vector<String>();
+               if (null != args)
+                       this.args.addAll(Arrays.asList(args));
+                               
+               this.startTime = startTime;
+               this.killTime = killTime;               
        }
-
-
+       /**
+        * The natively implemented method to create an MSG process.
+        * @param host    A valid (binded) host where create the process.
+        */
+       protected native void create(String hostName) throws HostNotFoundException;
        /**
         * This method kills all running process of the simulation.
         *
@@ -205,79 +208,58 @@ public abstract class Process extends Thread {
         * @return                              The function returns the PID of the next created process.
         *                      
         */ 
-       public static int killAll(int resetPID) {
-               return MsgNative.processKillAll(resetPID);
-       }
-
-       /**
-        * This method sets a flag to indicate that this thread must be killed. End user must use static method kill
-        *
-        * @return                              
-        *                      
-        */ 
-       public void nativeStop()
-       {
-       nativeStop = true;
-       }
-       /**
-        * getter for the flag that indicates that this thread must be killed
-        *
-        * @return                              
-        *                      
-        */ 
-       public boolean getNativeStop()
-       {
-               return nativeStop;
-       }
+       public static native int killAll(int resetPID);
 
        /**
         * This method kill a process.
-        * @param process  the process to be killed.
         *
         */
-       public void kill() {
-                nativeStop();
-                Msg.info("Process " + msgName() + " will be killed.");                         
-                                
-       }
-
+       public native void kill();
        /**
         * Suspends the process by suspending the task on which it was
         * waiting for the completion.
-        *
         */
+       public native void suspend();
+       /**
+        * Suspends the process by suspending the task on which it was
+        * waiting for the completion.
+        * DEPRECATED: use suspend instead.
+        */
+       @Deprecated
        public void pause() {
-               MsgNative.processSuspend(this);
+               suspend();
        }
+       /**
+        * Sets the "auto-restart" flag of the process.
+        */
+       public native void setAutoRestart(boolean autoRestart);
+       /**
+        * Restarts the process from the beginning
+        */
+       public native void restart();
        /**
         * Resumes a suspended process by resuming the task on which it was
         * waiting for the completion.
-        *
-        *
-        */ 
-       public void restart()  {
-               MsgNative.processResume(this);
-       }
+        */
+       public native void resume();    
        /**
         * Tests if a process is suspended.
         *
         * @return                              The method returns true if the process is suspended.
         *                                              Otherwise the method returns false.
         */ 
-       public boolean isSuspended() {
-               return MsgNative.processIsSuspended(this);
+       public native boolean isSuspended();
+       /**
+        * Returns the name of the process
+        */
+       public String msgName() {
+               return this.name;
        }
        /**
-        * Returns the host of a process.
-        *
+        * Returns the host of the process.
         * @return                              The host instance of the process.
-        *
-        *
         */ 
        public Host getHost() {
-               if (this.host == null) {
-                       this.host = MsgNative.processGetHost(this);
-               }
                return this.host;
        }
        /**
@@ -289,9 +271,7 @@ public abstract class Process extends Thread {
         *
         * @exception                   NativeException on error in the native SimGrid code
         */ 
-       public static Process fromPID(int PID) throws NativeException {
-               return MsgNative.processFromPID(PID);
-       }
+       public static native Process fromPID(int PID) throws NativeException;
        /**
         * This method returns the PID of the process.
         *
@@ -299,9 +279,6 @@ public abstract class Process extends Thread {
         *
         */ 
        public int getPID()  {
-               if (pid == -1) {
-                       pid = MsgNative.processGetPID(this);
-               }
                return pid;
        }
        /**
@@ -311,20 +288,26 @@ public abstract class Process extends Thread {
         *
         */ 
        public int getPPID()  {
-               if (ppid == -1) {
-                       ppid = MsgNative.processGetPPID(this);
-               }
                return ppid;
        }
+       /**
+        * @brief Returns the value of a given process property. 
+        */
+       public native String getProperty(String name);
+       
+       /**
+        * Set the kill time of the process
+        * @param killTime the time when the process is killed
+        */
+       public native void setKillTime(double killTime);
+       
        /**
         * This static method returns the currently running process.
         *
         * @return                              The current process.
         *
         */ 
-       public static Process currentProcess()  {
-               return MsgNative.processSelf();
-       }
+       public static native Process currentProcess();
        /**
         * Migrates a process to another host.
         *
@@ -332,21 +315,31 @@ public abstract class Process extends Thread {
         * @param host                  The host where to migrate the process.
         *
         */
-       public static void migrate(Process process, Host host)  {
-               MsgNative.processMigrate(process, host);
-               process.host = null;
+       public native void migrate(Host host);  
+       /**
+        * Makes the current process sleep until millis millisecondes have elapsed.
+        * You should note that unlike "waitFor" which takes seconds, this method takes milliseconds.
+        * FIXME: Not optimal, maybe we should have two native functions.
+        * @param millis the length of time to sleep in milliseconds.
+        */
+       public static void sleep(long millis) throws HostFailureException  {
+               sleep(millis,0);
        }
+       /**
+        * Makes the current process sleep until millis milliseconds and nanos nanoseconds 
+        * have elapsed.
+        * You should note that unlike "waitFor" which takes seconds, this method takes milliseconds and nanoseconds.
+        * Overloads Thread.sleep.
+        * @param millis the length of time to sleep in milliseconds.
+        * @param nanos additionnal nanoseconds to sleep.
+        */
+       public native static void sleep(long millis, int nanos) throws HostFailureException;
        /**
         * Makes the current process sleep until time seconds have elapsed.
-        *
         * @param seconds               The time the current process must sleep.
-        *
-        * @exception                   HostFailureException on error in the native SimGrid code
         */ 
-       public static void waitFor(double seconds) throws HostFailureException {
-               MsgNative.processWaitFor(seconds);
-       } 
-    /**
+       public native void waitFor(double seconds) throws HostFailureException;    
+       /**
      *
      */
     public void showArgs() {
@@ -357,29 +350,25 @@ public abstract class Process extends Thread {
                                        "] args[" + i + "]=" + (String) (this.args.get(i)));
        }
     /**
-     * Let the simulated process sleep for the given amount of millisecond in the simulated world.
-     * 
-     *  You don't want to use sleep instead, because it would freeze your simulation 
-     *  run without any impact on the simulated world.
-     * @param millis
+     * This method actually creates and run the process.
+     * It is a noop if the process is already launched.
+     * @throws HostNotFoundException
      */
-    public native void simulatedSleep(double seconds);
-
+    public final void start() throws HostNotFoundException {
+       if (!started) {
+               started = true;
+               create(host.getName());
+       }
+    }
+    
        /**
         * This method runs the process. Il calls the method function that you must overwrite.
         */
        public void run() {
 
-               String[]args = null;      /* do not fill it before the signal or this.args will be empty */
-
+               String[] args = null;      /* do not fill it before the signal or this.args will be empty */
                //waitSignal(); /* wait for other people to fill the process in */
 
-
-               try {
-                       schedBegin.acquire();
-               } catch(InterruptedException e) {
-               }
-
                try {
                        args = new String[this.args.size()];
                        if (this.args.size() > 0) {
@@ -387,37 +376,15 @@ public abstract class Process extends Thread {
                        }
 
                        this.main(args);
-                       MsgNative.processExit(this);
-                       schedEnd.release();
                } catch(MsgException e) {
                        e.printStackTrace();
                        Msg.info("Unexpected behavior. Stopping now");
                        System.exit(1);
                }
-                catch(ProcessKilled pk) {
-                       if (nativeStop) {
-                               try {
-                                       MsgNative.processExit(this);
-                               } catch (ProcessKilled pk2) {
-                                       /* Ignore that other exception that *will* occur all the time. 
-                                        * This is because the C mechanic gives the control to the now-killed process 
-                                        * so that it does some garbage collecting on its own. When it does so here, 
-                                        * the Java thread checks when starting if it's supposed to be killed (to inform 
-                                        * the C world). To avoid the infinite loop or anything similar, we ignore that 
-                                        * exception now. This should be ok since we ignore only a very specific exception 
-                                        * class and not a generic (such as any RuntimeException).
-                                        */
-                                       System.err.println(currentThread().getName()+": I ignore that other exception");                                        
-                               }
-                       Msg.info(" Process " + ((Process) Thread.currentThread()).msgName() + " has been killed.");                                             
-                       schedEnd.release();                     
-                       }
-                       else {
-                       pk.printStackTrace();
-                       Msg.info("Unexpected behavior. Stopping now");
-                       System.exit(1);
-                       }
-               }       
+                catch(ProcessKilledError pk) {
+                        
+                }      
+               exit();
        }
 
        /**
@@ -428,157 +395,20 @@ public abstract class Process extends Thread {
      */
        public abstract void main(String[]args) throws MsgException;
 
-
-    /** @brief Gives the control from the given user thread back to the maestro 
-     * 
-     * schedule() and unschedule() are the basis of interactions between the user threads 
-     * (executing the user code), and the maestro thread (executing the platform models to decide 
-     * which user thread should get executed when. Once it decided which user thread should be run 
-     * (because the blocking action it were blocked onto are terminated in the simulated world), the 
-     * maestro passes the control to this uthread by calling uthread.schedule() in the maestro thread 
-     * (check its code for the simple semaphore-based synchronization schema). 
-     * 
-     * The uthread executes (while the maestro is blocked), until it starts another blocking 
-     * action, such as a communication or so. In that case, uthread.unschedule() gets called from 
-     * the user thread.    
-     *
-     * As other complications, these methods are called directly by the C through a JNI upcall in 
-     * response to the JNI downcalls done by the Java code. For example, you have this (simplified) 
-     * execution path: 
-     *   - a process calls the Task.send() method in java
-     *   - this calls Java_org_simgrid_msg_MsgNative_taskSend() in C through JNI
-     *   - this ends up calling jprocess_unschedule(), still in C
-     *   - this calls the java method "org/simgrid/msg/Process/unschedule()V" through JNI
-     *   - that is to say, the unschedule() method that you are reading the documentation of.
-     *   
-     * To understand all this, you must keep in mind that there is no difference between the C thread 
-     * describing a process, and the Java thread doing the same. Most of the time, they are system 
-     * threads from the kernel anyway. In the other case (such as when using green java threads when 
-     * the OS does not provide any thread feature), I'm unsure of what happens: it's a very long time 
-     * that I didn't see any such OS. 
-     * 
-     * The synchronization itself is implemented using simple semaphores in Java, as you can see by
-     * checking the code of these functions (and run() above). That's super simple, and thus welcome
-     * given the global complexity of the synchronization architecture: getting C and Java cooperate
-     * with regard to thread handling in a portable manner is very uneasy. A simple and straightforward 
-     * implementation of each synchronization point is precious. 
-     *  
-     * But this kinda limits the system scalability. It may reveal difficult to simulate dozens of 
-     * thousands of processes this way, both for memory limitations and for hard limits pushed by the 
-     * system on the amount of threads and semaphores (we have 2 semaphores per user process).
-     * 
-     * At time of writing, the best source of information on how to simulate large systems within the 
-     * Java bindings of simgrid is here: http://tomp2p.net/dev/simgrid/
-     * 
-     */
-    public void unschedule() {
-       /* this function is called from the user thread only */
-               try {     
-                       
-                       /* unlock the maestro before going to sleep */
-                       schedEnd.release();
-                       /* Here, the user thread is locked, waiting for the semaphore, and maestro executes instead */
-                       schedBegin.acquire();
-                       /* now that the semaphore is acquired, it means that maestro gave us the control back */
-                       
-                       /* the user thread is starting again after giving the control to maestro. 
-                        * Let's check if we were asked to die in between */
-                       if ( (Thread.currentThread() instanceof Process) &&((Process) Thread.currentThread()).getNativeStop()) {                                
-                               throw new ProcessKilled();
-                       }
-                       
-               } catch (InterruptedException e) {
-                       /* ignore this exception because this is how we get killed on process.kill or end of simulation.
-                        * I don't like hiding exceptions this way, but fail to see any other solution 
-                        */
-               }
-               
-       }
-
-    /** @brief Gives the control from the maestro back to the given user thread 
-     * 
-     * Must be called from the maestro thread -- see unschedule() for details.
-     *
-     */
-    public void schedule() {
-               try {
-                       /* unlock the user thread before going to sleep */
-                       schedBegin.release();
-                       /* Here, maestro is locked, waiting for the schedEnd semaphore to get signaled by used thread, that executes instead */
-                       schedEnd.acquire();
-                       /* Maestro now has the control back and the user thread went to sleep gently */
-                       
-               } catch(InterruptedException e) {
-                       throw new RuntimeException("The impossible did happend once again: I got interrupted in schedEnd.acquire()",e);
-               }
-       }
-
-       /** Send the given task in the mailbox associated with the specified alias  (waiting at most given time) 
-     * @param mailbox
-     * @param task 
-     * @param timeout
-     * @throws TimeoutException
-        * @throws HostFailureException 
-        * @throws TransferFailureException */
-       public void taskSend(String mailbox, Task task, double timeout) throws TransferFailureException, HostFailureException, TimeoutException {
-               MsgNative.taskSend(mailbox, task, timeout);
-       }
-
-       /** Send the given task in the mailbox associated with the specified alias
-     * @param mailbox
-     * @param task
-     * @throws TimeoutException
-        * @throws HostFailureException 
-        * @throws TransferFailureException */
-       public void taskSend(String mailbox, Task task) throws  TransferFailureException, HostFailureException, TimeoutException {
-               MsgNative.taskSend(mailbox, task, -1);
-       }
-
-    /** Receive a task on mailbox associated with the specified mailbox
-     * @param mailbox
-     * @return
-     * @throws TransferFailureException
-     * @throws HostFailureException
-     * @throws TimeoutException
-     */
-       public Task taskReceive(String mailbox) throws TransferFailureException, HostFailureException, TimeoutException {
-               return MsgNative.taskReceive(mailbox, -1.0, null);
-       }
-
-    /** Receive a task on mailbox associated with the specified alias (waiting at most given time)
-     * @param mailbox
-     * @param timeout
-     * @return
-     * @throws TransferFailureException
-     * @throws HostFailureException
-     * @throws TimeoutException
-     */
-       public Task taskReceive(String mailbox, double timeout) throws  TransferFailureException, HostFailureException, TimeoutException {
-               return MsgNative.taskReceive(mailbox, timeout, null);
-       }
-
-    /** Receive a task on mailbox associated with the specified alias from given sender
-     * @param mailbox
-     * @param host
-     * @param timeout
-     * @return
-     * @throws TransferFailureException
-     * @throws HostFailureException
-     * @throws TimeoutException
-     */
-       public Task taskReceive(String mailbox, double timeout, Host host) throws  TransferFailureException, HostFailureException, TimeoutException {
-               return MsgNative.taskReceive(mailbox, timeout, host);
+       public native void exit();    
+       /**
+        * Class initializer, to initialize various JNI stuff
+        */
+       public static native void nativeInit();
+       static {
+               Msg.nativeInit();
+               nativeInit();
        }
+       /**
+        * This static method returns the current amount of processes running
+        *
+        * @return                      The count of the running processes
+        */ 
+       public native static int getCount();
 
-    /** Receive a task on mailbox associated with the specified alias from given sender
-     * @param mailbox
-     * @param host
-     * @return
-     * @throws TransferFailureException
-     * @throws HostFailureException
-     * @throws TimeoutException
-     */
-       public Task taskReceive(String mailbox, Host host) throws  TransferFailureException, HostFailureException, TimeoutException {
-               return MsgNative.taskReceive(mailbox, -1.0, host);
-       }
 }