Chapitre 2. API du noyau

Table des matières
Un module de base
Fonction d'ajustage, chromosomes, restriction d'évènement
Matrices, domaines
Conflits de ressources, slist, restriction de ressource
Extensions d'emploi du temps
Evènements dépendants
Divers

Un module de base

Commençons avec le simple module "Bonjour vous !" :

#include "module.h"

int module_init(moduleoption *opt)
{
        debug("Bonjour vous !");
        debug("Poids: %d", option_int(opt, "weight"));

        return(0);
}

Comme vous pouvez le voir, ce module ne contient que la fonction module_init().
Cette fonction est appelée juste après que le noyau a chargé le module et est la seule qui doit être définie pour tous les modules d'ajustage écrits pour la branche 0.2.x de Tablix (le prototype de cette fonction est défini dans le fichier modsup.h, voir init_f).
Aucune autre fonction ne sera appelée, à moins que vous en fassiez l'appel dans module_init().

Note: module_init() est équivalent à la fonction init_mod() de la branche 0.1.x .

Le paramètre opt de la fonction module_init() est une structure comprenant toutes les options du module qui ont été spécifiées dans le fichier de configuration (en utilisant les balises <option>).
Vous pouvez récupérer les valeurs de ces options de la structure moduleoption en utilisant les deux fonctions suivantes :

char *option_str(moduleoption *opt, char *name)

Cette fonction retourne la chaîne de caractère correspondant à la valeur de l'option nommée name ou retourne NULL si l'option n'est pas spécifiée dans le fichier de configuration XML. Vous devrez ensuite libérer l'espace mémoire utilisé par la chaîne de caractères retournée en utilisant la fonction free().

int option_int(moduleoption *opt, char *name)

Cette fonction est équivalente à option_str().
Elle convertit le contenu de l'option en un entier. Si ce n'est pas possible, ou si l'option n'a pas été trouvée, elle retourne INT_MIN.

Deux options sont toujours définies :
le poids, option weight, qui est toujours un entier (celui donné dans le fichier XML).
Le caractère obligatoire, option mandatory, qui est toujours l'entier 0 ou l'entier 1, en fonction du choix "yes" ou "no" dans le fichier de configuration.

Attention

Le pointeur vers la liste chaînée des options du module est uniquement passé à la fonction module_init().
Immédiatement après le retour de cette fonction, la mémoire utilisée par la liste est libérée. Cela signifie que ce pointeur n'est utisable que le contexte de la fonction module_init().

Ce module simple montre également l'utilisation des fonctions de rapport d'erreurs qui sont définies dans le fichier error.h. Les fonctions error(), info() et debug() peuvent être utilisées pour rapporter des avertissements et des erreurs variés à l'utilisateur. Elles sont utilisées à peu de chose près comme la fonction printf de la librairie standard.

Vous pouvez aussi constater que la fonction module_init() retourne la valeur 0 .
Cela signifie qu'il n'y a pas d'erreur. Lorsque c'est le cas, cette fonction doit retournée une valeur négative. Cela vaut pour toutes les fonctions de module que nous verrons plus tard. C'est en fait le cas pour la plupart des fonctions de Tablix qui retourne un entier.

Vous devez éviter d'utiliser la fonction fatal() dans les modules, car l'appel de cette fonctionne arrête immédiatement le noyau.
Utilisez error() pour rapporter des erreurs et utilisez ensuite la valeur de retour appropriée pour signaler qu'une erreur fatal est arrivée dans l'exécution du module. Le noyau terminera alors plus proprement.

Compiler votre module

Il y a deux moyens de compiler votre module. Dans la plupart des cas, vous utiliserez la première méthode. La deuxième, décrite ici, requiert les outils "autotools" récents pour votre système et est recommandée uniquement si vous voulez que le module soit compilé exactement de la même manière que tous les modules officiels de la distribution.

La méthode simple

Créer un sous-répertoire dans l'arbre des sources de Tablix, par exemple local/. Nommez le fichier le fichier contenant les sources du module hello.c et sauvegardez le dans le sous-répertoire que vous venez de créer.
Créez maintenant un fichier nommé Makefile, dans le même répertoire, avec le contenu suivant (vous devez utiliser la tabulation pour indenter -mettre en retrait- les lignes !):

CFLAGS = -Wall -O2
INCLUDES = -I../src -I..

MODULES = hello.so

all: $(MODULES)

%.so: %.o
        gcc -shared -Wl,-soname,$@ -o $@ $< -lc
%.o: %.c
        gcc $(CFLAGS) $(INCLUDES) -c -o $@ $<

clean:
        -rm *.o *.so

install:
        cp $(MODULES) /usr/local/lib/tablix2

Plus tard, lorsque vous ajouterez d'autres modules personnalisés, vous pourrez ajouter leurs noms à la ligne MODULES =, après hello.so. Assurez-vous de remplacer l'extension .c par .so.

Les modules sont généralement installés dans /usr/local/lib/tablix2, mais cela peut être différent sur votre système, si l'option --prefix a été utilisée pour la configuration de Tablix, ou que les paquets utilisés pour l'installation utilisent un autre chemin.
Vous pouvez connaitre l'endroit où sont enregistrés les modules en exécutant la commande :

$ tablix -v

Modifiez le chemin dans la règle d'installation du Makefile si nécessaire.

Vous pouvez maintenant compiler et installer le module en exécutant les commandes suivantes :

$ make
$ make install

La méthode en utilisant autotools

Note: Cette méthode requiert une version récente d'Autoconf, d'Automake et des logiciels associés. C'est la méthode utilisée pour compiler les modules officiels de la distribution.

Si vous obtenez des erreurs bizarres pendant l'exécution d'autoconf ou d'automake, cela provient dans 99% des cas d'une mauvaise version des autotools. Les avertissements à propos des "underquoted definitions" sont normales et peuvent être ignorées (elles n'ont rien à voir avec Tablix).

Mettez le fichier des sources de votre module dans le sous-répertoire modules . Vous devez ensuite éditer le fichier Makefile.am . Tout d'abord, ajouter les deux lignes suivantes en fin de fichier

hello_la_SOURCES = hello.c
hello_la_LDFLAGS = -module -avoid-version

Ajoutez ensuite hello.la à la fin de la ligne commençant par pkglib_LTLIBRARIES.

Vous devez maintenant exécuter autoconf et automake depuis le répertoire du plus haut niveau et relancer le script ./configure pour rafraîchir les Makefiles existants. Vous pouvez aussi lancer make -f Makefile.cvs si vous utilisez la version CVS.

Vous pouvez maintenant compiler et installer votre modules en lançant les commandes suivantes :

$ make
$ make install

Tester votre module

Tout d'abord, nous avons besoin d'un fichier de configuration qui utilise notre nouveau module. Parce que ce module simplissime ne fait rien du tout, nous pouvons utiliser un fichier XML aussi simple que possible.
Nous avons simplement besoin de définir une ressource et un évènement pour satisfaire le noyau.

<?xml version="1.0" encoding="iso-8859-1"?>
<ttm version="0.2.0">
        <modules>
                <module name="hello.so" weight="10" mandatory="yes"/>
        </modules>

        <resources>
                <variable>
                        <resourcetype type="dummy-type">
                                <resource name="dummy-resource"/>
                        </resourcetype>
                </variable>
        </resources>

        <events>
                <event name="dummy-event" repeats="1"/>
        </events>
</ttm>

Enregistrez cette configuration dans un fichier nommé hello.xml et lancez Tablix.
Comme nous utilisons la fonction debug() dans le module, nous devons lancer Tablix avec l'option -d5 pour voir le message "Bonjour vous !" .

Quelques écrans de messages défileront dans la console pendant l'exécution de Tablix. Puisque le module ne définit aucune valeur d'ajustage, tous les emplois du temps sont affectés d'une valeur d'ajustage nulle et Tablix ne réalisera que quelques centaines de générations avant de déclarer qu'il a trouvé une solution.
Quelque part au début du fichier de sortie, vous trouverez le message "Bonjour vous !".

$ tablix2 -d5 hello.xml
TABLIX version 0.2.1, PGA general timetable solver
Copyright (C) 2002-2005 Tomaz Solc

[tablix] PGA using 4 nodes on 1 host
[tablix] maximum 1 node will do local search
[tablix] multicasting XML data
[tablix] Initializing nodes
...
[xxxxx] xmlsup: variable dummy-type: 1 resources
[xxxxx] xmlsup: Loading module /home/avian/software/lib/tablix2/hello.so
[xxxxx] xmlsup: Bonjour vous !
[xxxxx] xmlsup: Weight: 10
[xxxxx] kernel: I have 1 tuples
...