Nous allons commencer par télécharger le code source d'un noyau sur le site www.kernel.org. Toutes les
versions y sont disponibles. Prenons un exemple : supposons que nous voulons compiler la version 2.6.x (x=17
dans ce TP) du noyau Linux. Nous devons télécharger le code source depuis cette adresse :
http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.tar.bz2
Vous pouvez aussi utiliser directement la commande wget
wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.17.tar.bz2
Une fois le code source de la version du noyau requise téléchargé, il faut le décompresser avec bunzip et le
désarchiver avec untar
tar xvjf linux-2.6.17.tar.bz2
L'option x désigne l'extraction de l’archive, « v » signifie en mode « verbeux », « j » spécifie que nous
employons la commande bunzip avant de désarchiver et « f » indique le nom du fichier en entrée.
Le fichier sera désarchivé dans le répertoire linux-2.6.x.
fork()
, vfork()
et clone()
se fait de la manière suivante
system_call()
et enregistre les registres de la pile noyau (dans les 2 cadres mémoire préservées en RAM pour chaque processus,
voir le cours, structure thread_info)
sys_fork
/sys_clone
ou sys_vfork
ret_from_sys_cal()
do_fork()
dans kernel/fork.c (celle-ci est indépendante de l'architecture).
schedule()
est le coeur de l'ordonnancement, cette dernière est appelée à plusieurs
endroits du code du noyau. On peut y voir 3 phases différentes :
rq
est la runqueue du processeur actuel.
prefetch
se trouve dans include/asm-i386/processor.h, et
sert à signifier au processeur de précharger une partie du processus que l'on va activer
clear_tsk_need_resched()
se trouve dans include/linux/sched.h
rcu_qsctr_inc()
se trouve dans include/linux/rcupdate.h
, (vous pouvez ignorer celle-ci)
update_cpu_clock()
, sched_info_switch()
, prepare_task_switch()
et
context_switch()
se trouvent dans le même fichier
man
, identifier les librairies à inclure)
/proc/self
.
Les informations à rechercher sont dans les 2 fichiers : /proc/self/sched
et /proc/self/status
.
/proc/self
: When a process accesses this magic symbolic link, it resolves to the process's own /proc/[pid] directory.
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <string.h>
#include <sys/resource.h>
int main(int argc , char * argv[])
{
//Lecture PID du processus courant
pid_t pid = getpid();
printf("PID:\t%d\n",pid);
}
$: sudo ./myprog
)
int timer_create( clockid_t clockid,
struct sigevent *evp,
timer_t *timerid);
union sigval {
int sival_int;
void *sival_ptr;
};
struct sigevent {
int sigev_notify; /* Méthode de notification */
int sigev_signo; /* Signal d’expiration de la minuterie */
union sigval sigev_value; /* Valeur accompagnant le signal ou étant fournie à la fonction du thread */
void (*sigev_notify_function) (union sigval); /* Fonction utilisée pour la notification d’un thread (SIGEV_THREAD) */
void *sigev_notify_attributes /* Paramètres pour la notification d’un thread (SIGEV_THREAD) */
pid_t sigev_notify_thread_id; /* Identifiant du thread auquel est envoyé un signal (SIGEV_THREAD_ID) */
};
Une fois le timer crée, on peut le configurer en indiquant 2 éléments :
1) le délai avant le premier déclenchement et
2) la période de déclenchement. Cela se fait avec la fonction timer_settime():
int timer_settime( timer_t timerid, int flags,
const struct itimerspec *new_value,
struct itimerspec * old_value);
Le premier argument de la fonction est l'identifiant du timer obtenu avec la fonction timer_create(). Le second
argument est un paramètre qui spécifie si la structure itimerspec contient une durée (par rapport à l'instant
actuel de l'appel) ou une valeur absolue.
struct itimerspec {
struct timespec it_interval; /* Intervalle pour les minuteries périodiques */
struct timespec it_value; /* Expiration initiale */
};
struct timespec {
time_t tv_sec; /* Secondes */
long tv_nsec; /* Nanosecondes */
};
signal.h, time.h, sched.h
int nb_mesures = 0;
int nb_total_mesures = 0;
//Function called when a signal is received
void handler_signal(){
//Do something here (printf, clock_gettime()...)
nb_mesures++;
}
int main(int argc, char *argv[])
{
timer_t timerid;
long int periode = 200; //period = 200 ms
struct sigevent event; //structure for notification
struct itimerspec spec; //interval for a timer with nanosecond precision, to be used with timer_settime(...)
//Configuration of the signal related to the timer
signal(SIGRTMIN, handler_signal);
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGRTMIN;
//Configure the timer
spec.it_interval.tv_sec = periode / 1000;
spec.it_interval.tv_nsec = 0;
spec.it_value = spec.it_interval;
//Create a timer with timer_create()
//Programme the timer with timer_settime()
//Main loop
while (nb_mesures < nb_total_mesures)
{
//The pause function suspends program execution until a signal arrives
//whose action is either to execute a handler function, or to terminate the process
pause();
}
}