IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linux Discussion :

[Linux] [Kernel] [Driver] [workqueue]


Sujet :

Linux

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 35
    Points : 17
    Points
    17
    Par défaut [Linux] [Kernel] [Driver] [workqueue]
    Bonjour,
    les macros pour la déclaration des workqueue ont récemment changée. Auparavant, on avait des macros du type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    DECLARE_WORK(name, void (*function)(void *), void *data);
    INIT_WORK(struct work_struct *work, void (*function)(void *), void *data);
    PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data);
    pour déclarer et préparer une tâche en l'associant à une fonction, function, et indiquer les paramètres d'entrée, data, de cette fonction. Depuis le noyau 2.6.20 (je crois), les macros ont été revues :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    DECLARE_WORK(name, void (*function)(void *));
    INIT_WORK(struct work_struct *work, void (*function)(void *));
    PREPARE_WORK(struct work_struct *work, void (*function)(void *));
    Quelqu'un sait-il comment l'on doit faire pour indiquer les paramètres à passer à la fonction ?

    Merci d'avance,
    Cédric

  2. #2
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Effectivement et à l'habitude des développeurs kernel linux, je n'ai pas réussi à avoir plus d'explication.
    On avait en 2.6.19.7:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /*
      * initialize a work-struct's func and data pointers:
      */
     #define PREPARE_WORK(_work, _func, _data)                       \
             do {                                                    \
                     (_work)->func = _func;                          \
                     (_work)->data = _data;                          \
             } while (0)
      /*
       * initialize all of a work-struct:
       */
    #define INIT_WORK(_work, _func, _data)                          \
             do {                                                    \
                     INIT_LIST_HEAD(&(_work)->entry);                \
                     (_work)->pending = 0;                           \
                     PREPARE_WORK((_work), (_func), (_data));        \
                     init_timer(&(_work)->timer);                    \
             } while (0)
    puis en 2.6.20:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #define PREPARE_WORK(_work, _func)                              \
            do {                                                    \
                    (_work)->func = (_func);                        \
            } while (0)
     
    /*
     * initialize all of a work item in one go
     *
     * NOTE! No point in using "atomic_long_set()": useing a direct
     * assignment of the work data initializer allows the compiler
     * to generate better code.
     */
    #define INIT_WORK(_work, _func)                                 \
            do {                                                    \
                    (_work)->data = (atomic_long_t) WORK_DATA_INIT(0);      \
                    INIT_LIST_HEAD(&(_work)->entry);                \
                    PREPARE_WORK((_work), (_func));                 \
            } while (0)
    Je ne suis pas certain que tu puisses encore passer un argument...

  3. #3
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    Bonjour,

    Je n'ai de connaissance particulière sur le kernel mais en comparant les deux versions, on remarque que les données sont initialisées durant la macro INIT_WORK
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (_work)->data = (atomic_long_t) WORK_DATA_INIT(0);
    Mais je ne sais où la macor WORK_DATA_INIT est définie.

  4. #4
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par jowo Voir le message
    Bonjour,

    Je n'ai de connaissance particulière sur le kernel mais en comparant les deux versions, on remarque que les données sont initialisées durant la macro INIT_WORK
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (_work)->data = (atomic_long_t) WORK_DATA_INIT(0);
    Mais je ne sais où la macor WORK_DATA_INIT est définie.
    J'avais déjà regardé mais à priori ça ne t'avancera à rien:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define WORK_DATA_INIT(autorelease) \
            ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define WORK_STRUCT_NOAUTOREL 1         /* F if work item automatically released on exec */
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define ATOMIC_LONG_INIT(i)     ATOMIC_INIT(i)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define ATOMIC_INIT(i)  { (i) }

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 35
    Points : 17
    Points
    17
    Par défaut
    Merci de votre intérêt pour ce problème. C'est tout de même étrange que ces modifs soient si peu documentées.
    j'ai vu que certaines personnes arrivaient à se débrouiller en utilisant la macro container_of pour passer les données à la fonction. Ca me parait être de la bidouille.

    Je vais finir par utiliser les Tasklets, elle ont encore une macro a trois arguments permettant de passer des données. Mais pour combien de temps ? ...

  6. #6
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par Cédric-29 Voir le message
    Merci de votre intérêt pour ce problème. C'est tout de même étrange que ces modifs soient si peu documentées.
    j'ai vu que certaines personnes arrivaient à se débrouiller en utilisant la macro container_of pour passer les données à la fonction. Ca me parait être de la bidouille.

    Je vais finir par utiliser les Tasklets, elle ont encore une macro a trois arguments permettant de passer des données. Mais pour combien de temps ? ...
    C'est un vrai problème je te l'accorde, voici un problème auquel j'ai été confronté avec sys_futex():
    since FUTEX_FD was scheduled for removal in June 2007 lets remove it.
    Google Code search found no users for it and NGPT was abandoned in 2003
    according to IBM. futex.h is left untouched to make sure the id does
    not get reassigned. Since queue_me() has no users left it is commented
    out to avoid a warning, i didnt remove it completely since it is part
    of the internal api (matching unqueue_me())
    Le monde du libre et en particuliers les développeurs kernel ont un gros travail à faire sur eux même.
    Bon courage.

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 35
    Points : 17
    Points
    17
    Par défaut
    Finalement j'ai utilisé la macro container_of pour passer les données. Vous trouverez ci-dessous l'exemple que j'ai récupéré sur le web, je n'ai gardé que les bouts de code utiles :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    struct bbr_private {
    	struct dm_dev			*dev;
    	struct bbr_table		*bbr_table;
    	struct bbr_runtime_remap	*remap_root;
    	spinlock_t			remap_root_lock;
    
    	struct work_struct		remap_work;
    	struct bio_list			remap_ios;
    	spinlock_t			remap_ios_lock;
    
    	u64				offset;
    	u64				lba_table1;
    	u64				lba_table2;
    	u64				nr_sects_bbr_table;
    	u64				start_replacement_sect;
    	u64				nr_replacement_blks;
    	u32				blksize_in_sects;
    	atomic_t			in_use_replacement_blks;
    };
    
    
    static void bbr_remap_handler(struct work_struct *work);
    
    static struct bbr_private *bbr_alloc_private(void)
    {
    	struct bbr_private *bbr_id;
    
    	bbr_id = kzalloc(sizeof(*bbr_id), GFP_KERNEL);
    	if (bbr_id == NULL)
    		return NULL;
    
    	INIT_WORK(&bbr_id->remap_work, bbr_remap_handler);
    	spin_lock_init(&bbr_id->remap_root_lock);
    	spin_lock_init(&bbr_id->remap_ios_lock);
    	bbr_id->in_use_replacement_blks = (atomic_t) ATOMIC_INIT(0);
    
    	return bbr_id;
    }
    
    
    /**
     * bbr_remap_handler
     *
     * This is the handler for the bbr work-queue.
     *
     * I/O requests should only be sent to this handler if we know that:
     * a) the request contains at least one remapped sector.
     *   or
     * b) the request caused an error on the normal I/O path.
     *
     * This function uses synchronous I/O, so sending a request to this
     * thread that doesn't need special processing will cause severe
     * performance degredation.
     **/
    
    static void bbr_remap_handler(struct work_struct *work)
    {
    	struct bbr_private *bbr_id =
    		container_of(work, struct bbr_private, remap_work);
    	struct bio *bio;
    	unsigned long flags;
    
    	spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
    	bio = bio_list_get(&bbr_id->remap_ios);
    	spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
    
    	bbr_io_process_requests(bbr_id, bio);
    }
    
    static int bbr_endio(struct dm_target *ti, struct bio *bio,
    		     int error, union map_info *map_context)
    {
    	struct bbr_private *bbr_id = ti->private;
    	struct dm_bio_details *bbr_io = map_context->ptr;
    
    	if (error && bbr_io) {
    		unsigned long flags;
    		char b[32];
    
    		dm_bio_restore(bbr_io, bio);
    		map_context->ptr = NULL;
    
    		DMERR("device %s: I/O failure on sector %lu. "
    		      "Scheduling for retry.",
    		      format_dev_t(b, bbr_id->dev->bdev->bd_dev),
    		      (unsigned long)bio->bi_sector);
    
    		spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
    		bio_list_add(&bbr_id->remap_ios, bio);
    		spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
    
    		queue_work(dm_bbr_wq, &bbr_id->remap_work);
    
    		error = 1;
    	}
    
    	if (bbr_io)
    		mempool_free(bbr_io, bbr_io_pool);
    
    	return error;
    }

Discussions similaires

  1. Linux kernel developpement avec un driver [tutoriel].
    Par Luke spywoker dans le forum Contribuez
    Réponses: 8
    Dernier message: 05/05/2014, 13h48
  2. sous-section Linux Kernel dans la section développement Linux
    Par kromartien dans le forum Evolutions du club
    Réponses: 1
    Dernier message: 13/04/2007, 10h36
  3. Trouver les sources de linux pour drivers wifi
    Par jff_caen32 dans le forum SUSE
    Réponses: 1
    Dernier message: 18/03/2007, 22h41
  4. Linux->kernel->sources : Documentation
    Par doccpu dans le forum Administration système
    Réponses: 3
    Dernier message: 04/09/2006, 12h03
  5. Linux Kernel Developpement
    Par Invité(e) dans le forum Linux
    Réponses: 3
    Dernier message: 13/06/2006, 15h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo