Maison  >  Article  >  Tutoriel système  >  Explication détaillée du développement du minuteur du noyau Linux et du pilote de travail différé

Explication détaillée du développement du minuteur du noyau Linux et du pilote de travail différé

WBOY
WBOYavant
2024-02-13 11:57:24724parcourir

Les minuteries du noyau Linux et les tâches de retard sont deux mécanismes couramment utilisés pour implémenter des tâches planifiées et des tâches d'exécution retardées. Ils permettent au pilote d'exécuter des fonctions spécifiques au moment approprié pour s'adapter aux besoins et aux caractéristiques du périphérique matériel. Mais comment utiliser correctement les timers du noyau Linux pour gérer les retards ? Cet article présentera les connaissances et les compétences de base du développement de pilotes de minuterie et de retard du noyau Linux sous les aspects théoriques et pratiques, ainsi que certains problèmes et solutions courants.

Explication détaillée du développement du minuteur du noyau Linux et du pilote de travail différé

Minuterie du noyau

La minuterie du logiciel repose en fin de compte sur l'horloge matérielle. En termes simples, le noyau détectera si chaque minuterie enregistrée dans le noyau a expiré après l'expiration de l'horloge, il rappellera la fonction d'enregistrement correspondante et la sauvegardera. . Effectué comme moitié inférieure d’interruption. En fait, le gestionnaire d'interruption d'horloge déclenche l'interruption logicielle TIMER_SOFTIRQ et exécute toutes les minuteries qui ont expiré sur le processeur actuel.
Les pilotes de périphériques qui souhaitent obtenir des informations temporelles et nécessitent des services de synchronisation peuvent utiliser des minuteries du noyau.

jiffies

Pour parler du timer du noyau, il faut d'abord parler d'un concept important de temps dans le noyau : variable jiffies, comme base de l'horloge du noyau, les jiffies augmenteront de 1 à chaque temps fixe, ce qui s'appelle ajouter un battement . , cet intervalle fixe est implémenté par des interruptions de minuterie. Le nombre d'interruptions de minuterie générées par seconde est déterminé par la macro HZ définie dans De cette façon, une période de temps peut être obtenue via des jiffies, tels que jiffies/. HZ. Nombre de secondes depuis le démarrage du système. Les deux secondes suivantes sont (jiffies/HZ+2). Le noyau utilise des jiffies pour le chronométrage. Les secondes sont converties en jiffies :secondes*HZ, donc l'unité est jiffy et l'heure actuelle est utilisée comme base pour chronométrer 2 secondes. : (jiffies/HZ +2)*HZ=jiffies+2*HZSi vous souhaitez obtenir l'heure actuelle, vous pouvez utiliser **do_gettimeofday()** Cette fonction remplit une structure struct timeval avec une résolution proche de. subtil.

//kernel/time/timekeeping.c
 473 /**
 474  * do_gettimeofday - Returns the time of day in a timeval
 475  * @tv:         pointer to the timeval to be set
 476  *
 477  * NOTE: Users should be converted to using getnstimeofday()
 478  */
 479 void do_gettimeofday(struct timeval *tv)   

Afin de laisser au matériel suffisamment de temps pour effectuer certaines tâches, le pilote doit souvent retarder l'exécution d'un code spécifique pendant un certain temps en fonction de la durée du délai, de deux types, délai long et délai court. , sont utilisés dans le concept de développement du noyau. La définition d'un long délai est : temps de retard > plusieurs jiffies Pour obtenir un long délai, vous pouvez utiliser la méthode d'interrogation des jiffies :

.
time_before(jiffies, new_jiffies);
time_after(new_jiffiesmjiffies);

**La définition du délai court est la suivante : l'événement de retard est proche ou inférieur à un jiffy. Pour obtenir un délai court, vous pouvez appeler

.
udelay();
mdelay();

Les deux fonctions sont des fonctions d'attente occupées, qui consomment beaucoup de temps CPU. La première utilise des boucles logicielles pour retarder un nombre spécifié de microsecondes, et la seconde utilise l'imbrication de la première pour obtenir des retards de l'ordre de la milliseconde.

Minuterie

Le pilote peut enregistrer un minuteur de noyau pour spécifier une fonction à exécuter à un certain moment dans le futur. Le minuteur commence à compter lorsqu'il est enregistré dans le noyau, et la fonction enregistrée sera exécutée une fois le temps spécifié atteint. Autrement dit, la valeur du délai d'attente est une valeur en jiffies. Lorsque la valeur en jiffies est supérieure à timer->expires, la fonction timer-> sera exécutée. L'API est la suivante

//定一个定时器
struct timer_list my_timer;

//初始化定时器
void init_timer(struct timer_list *timer);
mytimer.function = my_function;
mytimer.expires = jiffies +HZ;

//增加定时器
void add_timer(struct timer_list *timer);

//删除定时器
int del_tiemr(struct timer_list *timer);

Instances

static struct timer_list tm;
struct timeval oldtv;

void callback(unsigned long arg)
{
    struct timeval tv;
    char *strp = (char*)arg;
    do_gettimeofday(&tv);
    printk("%s: %ld, %ld\n", __func__,
        tv.tv_sec - oldtv.tv_sec,
        tv.tv_usec- oldtv.tv_usec);
    oldtv = tv;
    tm.expires = jiffies+1*HZ;
    add_timer(&tm);
}

static int __init demo_init(void)
{
    init_timer(&tm);
    do_gettimeofday(&oldtv);
    tm.function= callback;
    tm.data    = (unsigned long)"hello world";
    tm.expires = jiffies+1*HZ;
    add_timer(&tm);
    return 0;
}

Travaux retardés

En plus d'utiliser le minuteur du noyau pour effectuer le travail de retard planifié, le noyau Linux fournit également un ensemble de "raccourcis" encapsulés - delayed_work, qui est similaire au minuteur du noyau. Son essence est également implémentée à l'aide de files d'attente de travail et de minuteurs,

//include/linux/workqueue.h
100 struct work_struct {           
101         atomic_long_t data;
102         struct list_head entry;
103         work_func_t func;
104 #ifdef CONFIG_LOCKDEP
105         struct lockdep_map lockdep_map;
106 #endif
107 };
113 struct delayed_work {              
114         struct work_struct work;
115         struct timer_list timer;
116 
117         /* target workqueue and CPU ->timer uses to queue ->work */
118         struct workqueue_struct *wq;
119         int cpu;
120 };

«

struct work_struct
–103–>需要延迟执行的函数, typedef void (work_func_t)(struct work_struct work);

至此,我们可以使用一个delayed_work对象以及相应的调度API实现对指定任务的延时执行

//注册一个延迟执行
591 static inline bool schedule_delayed_work(struct delayed_work *dwork,unsigned long delay)
//注销一个延迟执行
2975 bool cancel_delayed_work(struct delayed_work *dwork)    

和内核定时器一样,延迟执行只会在超时的时候执行一次,如果要实现循环延迟,只需要在注册的函数中再次注册一个延迟执行函数。

schedule_delayed_work(&work,msecs_to_jiffies(poll_interval));

本文从理论和实践两方面,详细介绍了Linux内核定时器与延迟工作驱动开发的基本知识和技巧。我们首先了解了Linux内核定时器与延迟工作的概念、原理、特点和API函数,然后学习了如何使用Linux内核定时器与延迟工作来实现按键事件的检测和处理。最后,我们介绍了一些在Linux内核定时器与延迟工作驱动开发过程中可能遇到的问题,以及相应的解决方法。

通过本文,我们希望能够帮助你掌握Linux内核定时器与延迟工作驱动开发的基本方法和技巧,为你在嵌入式Linux领域的进一步学习和工作打下坚实的基础。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer