Package abstrasy

Source Code of abstrasy.InterpreterSemaphore

package abstrasy;


import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.StdErrors;

import java.util.Vector;

/**
* Abstrasy Interpreter
*
* Copyright : Copyright (c) 2006-2012, Luc Bruninx.
*
* Concédée sous licence EUPL, version 1.1 uniquement (la «Licence»).
*
* Vous ne pouvez utiliser la présente oeuvre que conformément à la Licence.
* Vous pouvez obtenir une copie de la Licence à l’adresse suivante:
*
*   http://www.osor.eu/eupl
*
* Sauf obligation légale ou contractuelle écrite, le logiciel distribué sous
* la Licence est distribué "en l’état", SANS GARANTIES OU CONDITIONS QUELLES
* QU’ELLES SOIENT, expresses ou implicites.
*
* Consultez la Licence pour les autorisations et les restrictions
* linguistiques spécifiques relevant de la Licence.
*
*
* @author Luc Bruninx
* @version 1.0
*/

public class InterpreterSemaphore {

    public InterpreterSemaphore() {
    }

    /*
     * Délai d'attente passive (en ms).
     *
     * Ce délai permet de vérifier périodiquement l'état de l'interpréteur et les éventuelles
     * interaction de l'utilisateur.
     *
     */
    private final static int PASSIVE_WAITING_TIME = 50;

    /*
     * Drapeau mutex pour verrouillage exclusif global.
     * Un seul mutex peut fonctionner au même moement.
     */
    private static boolean mutex_lock = false;
    private static boolean signalBreak = false;
    private static boolean signalEnd = false;
    private Vector<Interpreter> threads = new Vector<Interpreter>();

    /**
     * Peut-on continuer l'exécution ou y a t-il un signal d'arrêt brutal ?
     *
     * @return
     */
    final private boolean canContinue() {
        return !(signalBreak || signalEnd);
    }

    /**
     * Object de synchronisation mutex global:
     * ---------------------------------------
     * Plutot que de verrouiller tout le InterpreterSemaphore, permet d'affiner la granularité du mutex.
     */
    private static Object mutex_object = new Object();

    /**
     * Verrouillage mutex...
     *
     * Utilisé par l'opérateur mutex pour introduire une section critique (mutual exclude).
     *
     * @throws Exception
     */
    final public void lockMutex() throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();
        synchronized (mutex_object) {
            while (mutex_lock && threads.size() > 1 && canContinue() && (!myself.isThreadRaising())) { // && thisThread!=byThread) {
                mutex_object.wait(PASSIVE_WAITING_TIME); // avec passive_waiting_time, on peut tester l'état de l'interpréteur (sinon, on le bloque).
            }
            mutex_lock = true;
        }
        myself.actor_LOCKMUTEX();
    }

    /**
     * Déverrouillage mutex...
     *
     * Utilisé par l'opérateur mutex pour libérer une section critique.
     */
    final public void unlockMutex() {
        Interpreter.mySelf().actor_UNLOCKMUTEX();
        synchronized (mutex_object) {
            mutex_lock = false;
            mutex_object.notify();
        }
    }

    /**
     * Verrouillage (lock node{...})...
     *
     * Utilisé par l'opérateur lock pour introduire une section critique.
     *
     * @throws Exception
     */
    final public void lockNode(Node node) throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();
        Exception exc = null;
        synchronized (node) {
            myself.threadlock_R_add(node);
            try {
                while (node.tryLock(myself) && threads.size() > 1 && canContinue() && (!myself.isThreadRaising())) { // && thisThread!=byThread) {
                    myself.thowsDeadlock(node.getlock_by());
                    node.wait(PASSIVE_WAITING_TIME); // avec passive_waiting_time, on peut tester l'état de l'interpréteur (sinon, on le bloque).
                }
            }
            catch (Exception e) {
                // en cas de problème, récupérer l'exception...
                exc = e;
            }
            myself.threadlock_R_remove(node);
        }
        if (exc != null) {
            // si exception, alors répercuter celle-ci...
            throw exc;
        }
    }

    /**
     * Déverrouillage (lock node{...})...
     *
     * Utilisé par l'opérateur lock pour libérer une section critique.
     */
    final public void unlockNode(Node node) throws Exception {
        Interpreter interpreter=Interpreter.mySelf();
        synchronized (node) {
            node.unlock(interpreter);
            node.notify();
        }
    }

    /**
     * Réveille l'acteur thread...
     *
     * Depuis REV6251(31/01/2011): Ne fragmente plus le verrouillage du semaphore.
     * resume n'est pas bloquant. Il peut donc être utilisé dans une section critique.
     *
     * @param thread
     * @throws Exception
     */
    public void resume(Interpreter thread) throws Exception {
        //thread.actor_RESUME(); // appliqué lors du réveil par l'acteur de destination...
        thread.actor_SIGNAL();
        Object obj = thread.thread_getSuspendLock();
        synchronized (obj) {
            obj.notify();
        }
    }

    /**
     * L'acteur en cours suspend son activité et attend qu'on le réveille
     *
     * Depuis REV6251(31/01/2011): Ne fragmente plus le verrouillage du semaphore.
     * suspend est un opérateur bloquant. Il ne peut pas être utilisé dans une section
     * atomique (section critique).
     *
     * @throws Exception
     */
    public void suspendAndWaitResume() throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();

        Object obj = myself.thread_getSuspendLock();

        while (!myself.actor_CONSUMESIGNAL() && !myself.isThreadRaising() && canContinue()) {
            synchronized (obj) {
                myself.actor_SUSPEND();
                //myself.yield(); //(optimisation 30/01/2011)
                if (!myself.actor_HASSIGNALS()) { // dans le cas où un signal serait arrivé dans l'interval
                    obj.wait(PASSIVE_WAITING_TIME);
                }
            }
        }
        myself.actor_RESUME();

    }

    /**
     * L'acteur en cours suspend son activité et attend qu'on le réveille comme suspendAndWaitResume().
     * Toutefois, ici, un délai d'attente maximum est déterminé.  Si ce délai est dépassé, retourne true.
     *
     * On notera aussi que cette méthode est sûr. Si le signal n'est pas capturé avant le dépassement
     * de temps, le signal reste dans la file d'attente. Il pourra être récupéré lors d'un prochain
     * suspend.
     *
     * @throws Exception
     */
    public boolean suspendAndWaitResume(long millis) throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();

        Object obj = myself.thread_getSuspendLock();

        long base = System.currentTimeMillis();
        long now = 0;
        long delay;

        while (((delay = millis - now) > 0) && !myself.actor_CONSUMESIGNAL() && !myself.isThreadRaising() && canContinue()) {
            synchronized (obj) {
                myself.actor_SUSPEND();
                //myself.yield(); //(optimisation 30/01/2011)
                if (!myself.actor_HASSIGNALS()) { // dans le cas où un signal serait arrivé dans l'interval
                    obj.wait(Math.min(delay, PASSIVE_WAITING_TIME));
                }
            }
            now = System.currentTimeMillis() - base;
        }

        myself.actor_RESUME();

        return (delay <= 0); // retourne true en cas de dépassement...
    }

    /**
     * Réception d'un message
     *
     * Depuis REV6251(31/01/2011): Ne fragmente plus le verrouillage du semaphore.
     * receive est un opérateur bloquant. Il ne peut donc pas être utilisé dans une section critique.
     *
     * @return
     * @throws Exception
     */
    public Node receive_MSG() throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();

        Node msg = null;
        Object obj = myself.thread_getSuspendLock();

        while ((msg = myself.actor_GETMSG()) == null && (!myself.isThreadRaising()) && canContinue()) {
            synchronized (obj) {
                myself.actor_SUSPEND();
                // myself.yield(); //(optimisation 30/01/2011)
                if (!myself.actor_HASMSG()) { // dans le cas où un message serait arrivé dans l'interval...
                    obj.wait(PASSIVE_WAITING_TIME);
                }
            }
        }

        // si un message valide, alors on se réveille...
        myself.actor_RESUME();

        return msg;
    }

    /**
     * Réception d'un message avec délai d'expiration de l'attente.
     *
     * Notez que cette méthode est transactionnelle. Si le délai est écoulé et qu'un message arrive juste à ce moment
     * là, celui-ci reste dans la file d'attente et pourra être récupéré ultérieurement par le prochain receive.
     *
     * @return
     * @throws Exception
     */
    public Node receive_MSG(long millis) throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();

        Node msg = null;
        Object obj = myself.thread_getSuspendLock();

        long base = System.currentTimeMillis();
        long now = 0;
        long delay;

        while (((delay = millis - now) > 0) && (msg = myself.actor_GETMSG()) == null && (!myself.isThreadRaising()) && canContinue()) {
            /*
             * On notera que le message éventuel est extrait uniquement si le délai n'est pas dépassé!!!
             *
             * Si le délai est dépassé (donc delay<=0), la partie (msg=myself.actor_GETMSG()) n'est pas évaluée (caractéristique d'évaluation
             * paresseuse de Java).
             *
             */
            synchronized (obj) {
                myself.actor_SUSPEND();
                // myself.yield(); //(optimisation 30/01/2011)
                if (!myself.actor_HASMSG()) { // dans le cas où un message serait arrivé dans l'interval...
                    obj.wait(Math.min(delay, PASSIVE_WAITING_TIME));
                }
            }
            now = System.currentTimeMillis() - base;
        }
        /*
         * S'il n'y a pas de message et que le délai est dépassé, alors signaler un dépassement de temps...
         */
        if (msg == null && delay <= 0) {
            myself.setTimeOutRaising(true);
            /*
             * Ceci répercutera une exception...
             *
             * Attention, cette manière de procéder est différente de celle de suspendAndWaitResume(long millis) parce qu'ici
             * nous devons renvoyer le message. Si on renvoie null, normalement, nous devons nous trouver en situation
             * de time-out!!! Sinon, il s'agit d'une erreur interne.
             */
        }
        // si un message valide, alors on se réveille...
        myself.actor_RESUME();

        return msg;
    }

    /**
     * Envoyer un le message 'msg' à l'acteur 'thread'.
     *
     * Depuis REV6251(31/01/2011): Ne fragmente plus le verrouillage du semaphore.
     * send n'est pas bloquant. Il peut donc être utilisé dans une section critique.
     *
     * @param thread
     * @param msg
     * @throws Exception
     */
    public void send_MSG(Interpreter thread, Node msg) throws Exception {
        thread.actor_PUTMSG(msg);
        // thread.actor_RESUME(); // appliqué par l'acteur de destination à son réveille...
        Object obj = thread.thread_getSuspendLock();
        synchronized (obj) {
            obj.notify();
        }
    }

    /**
     * Suspendre son activité pendant 'millis' ms.
     *
     * Depuis REV6251(31/01/2011): Ne fragmente plus le verrouillage du semaphore.
     * sleep est un opérateur bloquant. Il ne peut pas être utilisé dans une section critique.
     *
     * @param millis
     * @throws Exception
     */
    public void sleep(long millis) throws Exception {
        Interpreter myself = (Interpreter) Thread.currentThread();
        long base = System.currentTimeMillis();
        long now = 0;
        long delay;

        Object obj = myself.thread_getSuspendLock();
        while (((delay = millis - now) > 0) && (!myself.isThreadRaising()) && canContinue()) {
            synchronized (obj) {
                myself.actor_SUSPEND();
                // myself.yield(); //(optimisation 30/01/2011)
                obj.wait(Math.min(delay, PASSIVE_WAITING_TIME));
            }
            now = System.currentTimeMillis() - base;
        }
        // on repart...
        myself.actor_RESUME();
    }

    /**
     * Tuer l'acteur 'thread'...
     *
     * @param thread
     * @throws Exception
     */
    public synchronized void kill(Interpreter thread) throws Exception {
        if (thread != null) {
            /*
             * Le processus doit exister...
             */
            thread.actor_STOP();
            thread.actor_SIGNAL();
            Interpreter myself = (Interpreter) Thread.currentThread();
            long base = System.currentTimeMillis();
            long now = 0;
            long millis = 100;
            int i = 30;
            if (thread == myself) {
                throw new InterpreterException(StdErrors.extend(StdErrors.Thread_error, "a thread can not kill himself"));
            }
            Object obj = myself.thread_getSuspendLock();
            while (((millis - now) > 0) && (!myself.isThreadRaising()) && canContinue() && isThreadsExists(thread)) {
                synchronized (obj) {
                    notifyAll();
                    wait(1);
                }
                now = System.currentTimeMillis() - base;
            }
            /*
             * lorsque le processus s'est arrêté, il doit normalement s'avoir désenregistré lui-même...
             */
        }

    }

    public synchronized void reset() { // du sémaphore...
        endAllCoroutines();
        signalBreak = false;
        signalEnd = false;
        mutex_lock = false;
    }


    public synchronized void setSignalBreak(boolean signalBreak) {
        InterpreterSemaphore.signalBreak = signalBreak;
    }

    boolean isSignalBreak() {
        return signalBreak;
    }

    public synchronized void setSignalEnd(boolean signalEnd) {
        InterpreterSemaphore.signalEnd = signalEnd;
    }

    boolean isSignalEnd() {
        return signalEnd;
    }

    public void registerThread(Interpreter corout) {
        synchronized (threads) {
            boolean fnd = false;
            for (int i = 0; i < threads.size(); ) {
                if (fnd = (corout == threads.elementAt(i++))) {
                    i = threads.size();
                }
            }
            if (!fnd) {
                // pas de doublon...
                threads.addElement(corout);
            }
        }
    }

    public void unregisterThread(Interpreter corout) {
        Interpreter myself = Interpreter.mySelf();
        synchronized (threads) {
            /*
             * Si je suis mutex, je libère celui-ci...
             */
            if (myself.actor_ISMUTEX()) {
                this.unlockMutex();
            }
            /*
             * je m'enlève de la liste des acteurs moi-même...
             */
            threads.remove(corout);
        }
        // myself.yield(); //(optimisation 30/01/2011)
    }

    private Interpreter getRegistered() {
        synchronized (threads) {
            Interpreter myself = Interpreter.mySelf();
            Interpreter inter = null;
            for (int i = 0; i < threads.size(); i++) {
                inter = threads.elementAt(i);
                if (inter == myself) {
                    // ne pas trouver le thread superviseur...
                    inter = null;
                }
                else {
                    i = threads.size();
                }
            }
            return inter;
        }
    }

    public synchronized String getUniqueThreadName() {
        String res = null;
        while (res == null) {
            res = "actor/" + java.util.UUID.randomUUID().toString();
            if (isThreadsExists(res)) {
                res = null;
            }
        }
        return res;
    }

    public Node getACTORS() throws Exception {
        synchronized (threads) {
            Node res = Node.createCList();
            Interpreter inter = null;
            for (int i = 0; i < threads.size(); i++) {
                inter = threads.elementAt(i);
                if (inter.isInterThread()) {
                    // n'inclure que les threads fils... pas le thread superviseur
                    res.addElement(new Node(inter.getName()));
                }
            }
            return res;
        }
    }

    public synchronized Vector<String> getThreadsNames() {
        Vector<String> res = new Vector<String>();
        Interpreter inter = null;
        for (int i = 0; i < threads.size(); i++) {
            inter = threads.elementAt(i);
            if (inter.isInterThread()) {
                // n'inclure que les threads fils... pas le thread superviseur
                res.addElement(inter.getName());
            }
        }
        return res;
    }

    public synchronized Interpreter getThread(String name) {
        Interpreter res = null;
        Interpreter inter = null;
        for (int i = 0; i < threads.size(); i++) {
            inter = threads.elementAt(i);
            /**
             * ATTENTION TROUVE TOUS LES THREADS... MEME LE THREAD SUPERVISEUR !!!
             */
            if (inter.getName().equals(name)) {
                res = inter;
                i = threads.size();
            }
        }
        return res;
    }

    public synchronized boolean isThreadsExists(String name) {
        Interpreter inter = null;
        boolean res = false;
        for (int i = 0; i < threads.size(); i++) {
            inter = threads.elementAt(i);
            if (inter.isInterThread()) {
                // n'inclure que les threads fils...
                if (res = (inter.getName().equals(name))) {
                    i = threads.size();
                }
            }
        }
        //if(!res){
        //  System.out.println("Thread not exists " +name);
        //}
        return res;
    }

    public synchronized boolean isThreadsExists(Interpreter thread) {
        Interpreter inter = null;
        boolean res = false;
        for (int i = 0; i < threads.size(); i++) {
            inter = threads.elementAt(i);
            if (inter.isInterThread()) {
                // n'inclure que les threads fils...
                if (res = (inter == thread)) {
                    i = threads.size();
                }
            }
        }
        return res;
    }

    public static long interThreadUID = 0;

    public boolean hasOtherRegistered() {
        // synchronized (threads) {
        return threads.size() > 1;
        // }
    }

    public boolean hasRegistered() {
        // synchronized (threads) {
        return threads.size() > 0;
        // }
    }

    public void endAllCoroutines() {
        // interdit à partir d'une coroutine...
        Interpreter myself = Interpreter.mySelf();
        if (!myself.isInterThread()) {
            setSignalEnd(true);
            Interpreter corout = null;
            while ((corout = getRegistered()) != null) {
                Interpreter.Log("Asking thread interruption [" + corout.getName() + " : " + corout.getId() + "] by " + myself.getName() + "<" + myself.getId() +
                        ">...");
                corout.actor_STOP();
                corout.interrupt();
                try {
                    Thread.sleep(100);
                }
                catch (Exception ex) {
                    if (Interpreter.isDebugMode()) {
                        ex.printStackTrace();
                    }
                }
                if (corout.isInterrupted()) {
                    Interpreter.Log(" ->  thread [" + corout.getName() + " : " + corout.getId() + "] Interrupted.");
                    unregisterThread(corout);
                }
                if (!corout.isAlive()) {
                    unregisterThread(corout);
                    Interpreter.Log(" ->  thread [" + corout.getName() + " : " + corout.getId() + "] Died.");
                }

            }
        }
        else {
            Interpreter.Log("Asking thread interruption from InterThread !!!...");
        }
    }

}
TOP

Related Classes of abstrasy.InterpreterSemaphore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.