Entraides et échanges autour de la technologie Scol - Informations and exchanges on the Scol technology
Vous pouvez changer la langue de l'interface une fois inscrit - You can change the language once registered
You are not logged in.
Pages: 1
Salut,
Par exemple :
typeof win = ObjWin;;
fun main ()=
_showconsole;
set win = _CRwindow _channel nil 0 0 500 300 WN_NORMAL "o";
_DSwindow win;
_fooS if win == nil then "NILLL" else "OKKKK";
_MVwindow win 50 50;
0;;
Quelque soit le type d'objet, l'objet ne vaut pas NIL après sa destruction.
Dans cet exemple (mais on peut le reproduire avec n'importe quel objet Scol), "OKKKK" est affiché et la fonction _MVwindow normalement exécutée même si sans effet ici.
En effet, dans son code source (win.c line 1415), le test :
s = MMget(m, 0);
if (s == NIL)
{
MMechostr (1, "MoveWindow : Window object is NIL\n");
return 0;
}
n'est pas validé (logique puisque l'objet, pourtant détruit, ne vaut pas nil). Ce genre de test, partout présent dans toutes les APIs, est valable uniquement si l'objet n'est pas encore créé ce qui limite sa pertinence, non ?
C'est une question ancienne mais jamais résolue. Avez-vous des idées ?
pour que l'objet soit à NIL après destruction sans devoir explicitement écrire dans le code
set win = nil;
qui est un non-sens.
Note : _MVwindow est un exemple. C'est la même chose pour n'importe quelle fonction de n'importe quel objet de n'importe quel API.
Offline
Yop !
C'est tout a fait normal.
la variable scol contient la référence de l'objet, la fonction _DS... détruit l'objet mais les références ne peuvent êtres remises a NIL.
c'est le même problème que pour tout autre langage.
c'est pourquoi en C/C++ il faut initialiser les variables (en scol elles sont initialisées a nil automatiquement) et les remettre a null (0) et dans notre cas a nil.
s = MMget(m, 0); renvoi la référence de la variable scol stockée dans la pile, le contenu de s n'est pas l'objet lui meme mais encore une fois la référence de l'objet (pointer de l'objet dans la pile scol) qui elle est toujours vraie.
le test s == NIL est important car en effet une fonction peut être appelée avec un mauvais paramètre ou à la suite d'une autre fonction ayant échouée.
en C/C++ ce n'est pas parceque l'on détruit un objet que l'adresse mémoire du pc n'éxiste plus, en scol c'est la même chose mais avec les positions de la pile.
une dernière explication un peu plus imagée :
Dans une bibliothèque, tu demande la fiche d'un livre qui est stocké sur une étagère.
la fiche référence le livre, mais la position dans l'étagère est vide puisque le livre a déja été emprunté.
la fiche et l'emplacement dans l'étagère existent toujours même si le livre n'existe plus.
pour éviter ce genre d'erreur il faut détruire la fiche ou la ranger dans le tiroir "emprunté".
Offline
Oui, ça ok
Justement, cette position dans la pile devrait pouvoir être écrasée en valant un NIL, comme à l'initialisation (sorte de reset) puisque pas de mémoire allouée. Effectivement, dans le cas d'un langage de base niveau style C, la problématique est autre.
MMget / MMpull devrait renvoyer nil si l'objet / le handle system a été détruit et pas se contenter de renvoyer l'adresse mémoire dans tous les cas. (je résume à gros traits)
le test s == NIL est important car en effet une fonction peut être appelée avec un mauvais paramètre ou à la suite d'une autre fonction ayant échouée.
Le problème est bien là ! La fonction ne devrait pas être exécutée avec un objet détruit comme elle ne l'est pas à la suite d'une autre fonction ayant échouée.
Une solution est de tester aussi le handle système.
Offline
Oui en effet mais encore une fois le handle system n'est qu'une adresse mémoire qui peut avoir été écrasée par une autre valeur et donc ne plus valoir 0.
le moyen serait de rechercher dans toute la pile les références au pointeur de l'objet pour les remettre a nil, et dans certains cas la pile peut être énorme... donc le temps d'éxécution très long.
on pourrais aussi stocker une liste de références a chaque let et set var .... (houla)
Offline
Tout à fait, le handle system peut être occupé par autre chose ...
Le pb avec cette destruction d'objets, c'est qu'aucune fonction ne renverra jamais nil et que tu peux continuer à utiliser 1000 fonctions derrière la destruction, tu ne sauras pas que l'objet a été détruit.
Je pensais plutôt à une modification de la structure d'un objet en ajoutant une associé à un flag supplémentaire (cf OFFOBJHAND, OFFOBJTYP ...). Genre OFFOBJALIVE Seter à 1 à la création (fonction OBJcreate de scolobj.c), à 0 à la destruction (OBJdestroy) et tester lors d'un MMget / MMpull. Comme est tester le type d'un objet, par exemple (MMfetch(m,p,OFFOBJTYP))
Il me semble que c'est moins contraignant.
Offline
le problème c'est que ce n'est pas vrai que pour les objets mais pour tout type de variable
et une adresse scol peut aussi etre réattribuées après un GC (enfin je pense).
Offline
Si on recherche la référence physique allouée d'un objet dans la pile, on obtient 0 pour un objet détruit :
MMfetch (m, MTOP (mobj), OFFOBJMAG)
où mobj est l'objet Scol passé en paramètre de la fonction.
Avec une macro
#define TESTNILOBJ(o) !((MMfetch (m, MTOP (mobj), OFFOBJMAG)) || (mobj == NIL))
on a :
int funScolApi (mmachine m)
{
int mobj;
mobj = MMpull (m);
if (TESTNILOBJ (mobj))
{
/* code lorsque l'objet vaut nil */
return 0;
}
...
}
et l'objet détruit est logiquement vu par le test.
Voyez-vous des objections potentielles ?
Offline
hmm ça me semble une bonne idée, reste a voir comment ça se comporte après des GC ^^
tu peux forcer des GC avec la fonction scol _freememory (ou un truc du genre)
Offline
_freememory / _trimmemory
Théoriquement, un GC ne devrait pas avoir de conséquences car il s'agit de l'objet magma qui est retournée, non celui de l'objet système.
Si un autre objet venait à être alloué, la référence dans la pile devrait être différente.
En pratique ....
Je vais faire quelques tests
Offline
Rien trouvé de négatif mais faudrait des tests plus en profondeur.
Reste l'éventuelle réallocation mais je suis plutôt sceptique sur une telle réallocation en pratique puisque ce nouvel objet ne sera pas à la même position que l'ancien dans la pile.
Cette technique présente deux avantages :
1- on a deux tests complémentaires au lieu d'un. Même s'il s'avère incomplet, ce sera toujours mieux que le test existant.
2- l'usage d'une macro permet de faire évoluer facilement ce test sans avoir à le réécrire dans chaque fonction.
Accessoirement, elle est valable aussi bien pour la version Linux que pour la version Windows.
En conséquence, j'implémente ce test dans mes APIs. Ça va être un peu rébarbatif mais c'est un investissement intéressant pour l'avenir du code
Pour les anciennes APIs, euh ... à voir !
Pour les autres APIs, issues d'I-maginer, c'est à Arkeon et Nodrev de faire leur choix
Offline
Oui, nous ne développons de la même manière (ni avec le même langage ! ), le C est suffisamment différent du C++.
Cependant, vous feriez bien de tester aussi le cas présenté ici, voir comment réagissent vos fonctions.
Attention, lorsque tu as recodé SerialIO le mois dernier (j'y pense parce qu'on en a parlé récemment), tu as utilisé le test "classique". Dans le SO3Engine, c'est la même chose mais en lui adjoignant quasiment "mon" test dans un second temps :
int n = MMget(m, 0);
if (n==NIL)
{
MMset(m, 0, NIL);
return 0;
}
SNode* node = (SNode*) MMfetch(m, MTOP(n), 0);
if (node==NULL)
{
MMset(m, 0, NIL);
return 0;
}
Connaissant mal le C++, le cast ne perturbe t-il pas le resultat dans le cas d'une destruction antérieure de l'objet ?
par rapport à un
if (MMfetch(m, MTOP(n), 0) == 0)
{
...
}
SNode* node = (SNode*) MMfetch(m, MTOP(n), 0);
/* suite du code sans test */
Offline
Pages: 1