L’ordonnancement développé jusque ici est un ordonnancement avec partage volontaire du processeur. Un contexte passe la main par un appel explicite à yield(). Nous allons maintenant développer un ordonnancement préemptif avec partage involontaire du processeur : l’ordonnanceur va être capable d’interrompre le contexte en cours d’exécution et de changer de contexte. Cet ordonnancement est basé sur la génération d’interruptions. Une interruption déclenche l’exécution d’une fonction associée à l’interruption (un gestionnaire d’interruptions ou handler). Le matériel sur lequel nous travaillons fournit l’interface suivante :
typedef void (irq_handler_func_t)(void); #define TIMER_IRQ 2 void setup_irq(unsigned int irq, irq_handler_func_t handler); void start_hw(); void irq_disable(); void irq_enable();
La primitive setup_irq() associe la fonction handler à l’interruption irq. Seule l’interruption TIMER_IRQ est définie ; elle est remontée périodiquement du matériel.
La primitive start_hw() permet d’initialiser le matériel ; elle doit être invoquée pour démarrer la génération des interruptions.
Les deux primitives irq_disable() et irq_enable() permettent de délimiter des zones de code devant être exécutées de manière non interruptible.
La nouvelle interface que va fournir notre ordonnanceur est la suivante :
int create_ctx(int stack_size, func_t f, void *args); void start_sched();
La fonction start_sched() va installer les gestionnaires d’interruptions et initialiser le matériel.
Notre ordonnanceur est maintenant préemptif, il reste à isoler les sections critiques de code ne pouvant être interrompues par un gestionnaire d’interruptions.
Simulateur de matériel
La bibliothèque hw qui vous est fournie dans
/home/enseign/ASE/src/hw.tgzimplémente l’interface décrite section 5 à l’aide signaux et timers posix. Vous pouvez en étudier le code ou l’utiliser sans vous en soucier...
![]()
![]()
![]()