package abstrasy.pcfx;
import abstrasy.Interpreter;
import abstrasy.Node;
import abstrasy.StaticHeap;
import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.StdErrors;
/**
* 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 PCFx_sync extends PCFx {
public PCFx_sync() {
}
/**
* Trier les nodes en fonction de leur UID respectif.
*
* Il s'agit d'un simple tri à bulles. Ceci doit être suffisant étant donné
* le faible nombre d'éléments à trier. L'algorithme est donc purement
* itératif et non récursif. Un tri rapide serait certainement plus
* avantageux s'il y avait un grand nombre d'éléments. Mais ce n'est pas
* le cas.
*
* @param n
*/
private static final void sortNodes_(Node[] n){
for(int i=0;i<n.length-1;i++){
for(int j=i+1;j<n.length;j++){
if(n[i].getUID()>n[j].getUID()){
Node s=n[i];
n[i]=n[j];
n[j]=s;
}
}
}
}
/**
* eval
*
* @param startAt Node
* @return Node
* @throws Exception
* @todo Implémenter cette méthode abstrasy.PCFx
*/
public Node eval(Node startAt) throws Exception {
/*
* (syn var var ... {...}) : Déclare une section synchronisée (spin-lock) dans laquelle les variables
* déclarées nécessitent un verrouillage actif.
*
* On notera que la stratégie de verrouillage dépend du UID des nodes des variables à verrouiller:
* -----------------------------------------------------------------------------------------------
* En effet, il apparait clairement que les principales causes de problèmes en programmation
* concurrente apparaissent avec les verrouillages multiples. Par exemple, immaginons que le
* processus T1 verrouille la variable X et que le processus T2 verrouille Y, si T1 essaye de
* verrouiller Y et T2, X sans libérer les variables précécdemment bloquées, les deux processus
* seront inévitablement bloqué en livelock.
*
* Aussi, l'ordre de verrouillage des variables est important. S'il est toujours le même, on évite
* notamment la situation de livelock ci-dessus.
*
*
*/
startAt.isGoodArgsLength(false, 2);
/*
* on calcul les limites des variables arguments
*/
int maxdx=startAt.size()-1;
int mindx=1;
/*
* on extrait la section lazy
*/
Node xnode = startAt.getSubNode(maxdx--, Node.TYPE_LAZY);
/*
* on récupère les variables arguments...
*/
Node[] vnodes = new Node[maxdx-mindx+1];
for(int i=mindx;i<=maxdx;i++) {
vnodes[i-mindx] = startAt.getSubNode_unsafeAccess(i, Node.VTYPE_VALUABLE); //Node.VTYPE_BY_VALUE);
/**
* Attention, Le verrouillage n'est pas automatiquement propagé aux instances internes.
* ===================================================================================
*
* Lorsque l'on combine la programmation concurrente et la programmatioon objet, il convient
* d'utiliser un système de verrous suffisant pour garantir la fiabilité et la cohérence de la
* protection.
*
*/
}
/*
* S'il y en a + que 1, on les trie selon un ordre toujours identique...
*/
if(vnodes.length>1){
sortNodes_(vnodes);
}
Node res = null;
Interpreter myself = Interpreter.mySelf();
StaticHeap global = myself.getGLOBAL();
Exception reportExcep = null;
/*
* Si les nodes sont déjà verrrouillés par moi-même, on ignore le verrouillage...
*/
for(int i=0;i<vnodes.length;i++){
vnodes[i].acquirelock(myself);
if(!vnodes[i].isLockedBy(myself)){ throw new InterpreterException(StdErrors.Critical_section_locking_fail); }
}
/*
* Nouveau contexte...
*/
global.push();
// Entrée dans la section verrouillée réussie...
myself.actor_LOCKSECTION();
try {
res = xnode.exec(true);
}
catch (Exception e) {
reportExcep = e;
}
//Sortie de la section verrouillée...
myself.actor_UNLOCKSECTION();
/*
* restaurer le contexte
*/
global.pull();
/*
* Si les nodes étaient déjà verrouillés par moi-même avant, je ne déverrouille
* pas ici...
*
* S'il y a une exception et/ou que j'avais verrouillé ici, je déverrouille
* maintenant... Equivalent de fin
*
* Remarque:
* --------
* Si on déverrouille dans le même ordre qu'on à verrouillé, on obtient
* une libération dans un ordre permettant le re-verrouillage dans
* l'ordre chronologique des déverrouillage:
*
* T1: x <----------------->
* y <----------------->
*
* T2 x <---------------->
* y <---------------->
*
* Verrouillages et déverrouillage peuvent ainsi se chevaucher.
*
*/
for(int i=0;i<vnodes.length;i++){
vnodes[i].unlock(myself);
}
/*
* reporter l'exception s'il y en a une...
*/
if (reportExcep != null) {
throw reportExcep;
}
return res;
}
}