2009-12-28 4 views
4

J'ai cherché avec diligence (à la fois dans le réseau S [O | F | U] et ailleurs) et je crois que c'est une question rare. Je travaille avec une carte de développement Atmel AT91SAM9263-EK (noyau ARM926EJ-S, jeu d'instructions ARMv5) sous Debian Linux 2.6.28-4. J'écris en utilisant (je crois) le tty driver pour parler à un RS-485 serial controller. Je dois m'assurer que les écritures et les lectures sont atomiques. Plusieurs lignes de code source (listées sous la fin de ce post par rapport au répertoire d'installation de la source du noyau) impliquent ou implicitement cela.Comment vérifier les écritures atomiques?

Est-il possible de vérifier que l'écriture/la lecture vers/depuis cet appareil est réellement une opération atomique? Ou, le périphérique/dev/ttyXX est-il considéré comme une FIFO et l'argument se termine-t-il? Il ne semble pas suffisant de simplement croire que le code applique cette revendication - aussi récemment que février de cette année, freebsd était demonstrated to lack atomic writes for small lines. Oui, je me rends compte que freebsd n'est pas exactement la même chose que Linux, mais ce que je veux dire, c'est que ça ne fait pas de mal d'en être bien sûr. Tout ce que je peux penser est de continuer à envoyer des données et de chercher une permutation - j'espérais quelque chose d'un peu plus scientifique et, idéalement, déterministe. Malheureusement, je ne me souviens précisément de rien de mes cours de programmation simultanée à l'époque universitaire. J'apprécierais profondément une gifle ou une poussée dans la bonne direction. Merci d'avance si vous choisissez de répondre.

Cordialement,

Jayce


drivers/char/tty_io.c: 1087

void tty_write_message(struct tty_struct *tty, char *msg) 
{ 
    lock_kernel(); 
    if (tty) { 
     mutex_lock(&tty->atomic_write_lock); 
     if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) 
      tty->ops->write(tty, msg, strlen(msg)); 
     tty_write_unlock(tty); 
    } 
    unlock_kernel(); 
    return; 
} 


arc/bras/include/asm/bitops.h: 37

static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p) 
{ 
    unsigned long flags; 
    unsigned long mask = 1UL << (bit & 31); 

    p += bit >> 5; 

    raw_local_irq_save(flags); 
    *p |= mask; 
    raw_local_irq_restore(flags); 
} 


pilotes/série/serial_core.c: 2376

static int 
uart_write(struct tty_struct *tty, const unsigned char *buf, int count) 
{ 
    struct uart_state *state = tty->driver_data; 
    struct uart_port *port; 
    struct circ_buf *circ; 
    unsigned long flags; 
    int c, ret = 0; 

    /* 
    * This means you called this function _after_ the port was 
    * closed. No cookie for you. 
    */ 
    if (!state || !state->info) { 
     WARN_ON(1); 
     return -EL3HLT; 
    } 

    port = state->port; 
    circ = &state->info->xmit; 

    if (!circ->buf) 
     return 0; 

    spin_lock_irqsave(&port->lock, flags); 
    while (1) { 
     c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); 
     if (count < c) 
      c = count; 
     if (c <= 0) 
      break; 
     memcpy(circ->buf + circ->head, buf, c); 
     circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); 
     buf += c; 
     count -= c; 
     ret += c; 
    } 
    spin_unlock_irqrestore(&port->lock, flags); 

    uart_start(tty); 
    return ret; 
} 

En outre, à partir de la documentation écriture de l'homme (3):

Une tentative d'écrire à un tuyau ou FIFO a plusieurs caractéristiques principales:

  • Atomique/non-atomique: A écrire est atomique si la quantité totale écrite en une opération n'est pas entrelacée avec les données d'un autre processus. Ceci est utile lorsque plusieurs auteurs envoient des données à un seul lecteur. Les applications doivent connaître la taille de la requête d'écriture qui doit être exécutée de manière atomique. Ce maximum est appelé {PIPE_BUF}. Ce volume de IEEE Std 1003.1-2001 ne dit pas si les demandes d'écriture pour plus de {PIPE_BUF} octets sont atomiques, mais nécessite que les écritures de {PIPE_BUF} ou moins d'octets doivent être atomiques.
+0

Vous pouvez avoir une meilleure réponse si vous mettez la "Question" en haut (un résumé des sortes). –

+0

J'ai fait ce changement, merci pour le conseil. -Jayce – user239719

+0

On dirait que ce que vous voulez vraiment est un test de stress de torture pour les conducteurs de vérifier l'exactitude. Cela semble être vraiment utile partout. – Omnifarious

Répondre

3

Je pense que, sur le plan technique, les appareils ne sont pas FIFOs, il est donc pas du tout clair que les garanties que vous citez sont censés appliquer.

Êtes-vous préoccupé par partiel écrit et lit dans un processus, ou lisez-vous et/ou écrivez-vous le même périphérique de différents processus? En supposant que ce dernier, vous feriez mieux de mettre en œuvre un processus de proxy de quelque sorte.Le proxy possède exclusivement le périphérique et effectue toutes les lectures et écritures, évitant ainsi entièrement le problème d'atomicité multi-processus. En bref, je conseille de ne pas essayer de vérifier que "lire/écrire à partir de cet appareil est en fait une opération atomique". Ce sera difficile à faire en toute confiance, et vous laisser avec une application qui est sujette à des échecs subtils si une version ultérieure de Linux (ou de tout autre O/S) ne parvient pas à implémenter l'atomicité comme vous le souhaitez.

+0

+1. Essayer de déduire des garanties API en lisant le code source ou en exécutant des tests de stress par rapport à la version actuelle sonne comme une erreur. –

+0

@Dale, Merci pour votre réponse. En réponse à votre question, il n'y a qu'un seul processus de lecture/écriture, mais je dois m'assurer que la lecture/écriture se fasse sans interruption. C'est-à-dire, interrompt, préemption, tout ce qui peut interférer est arrêté pendant la durée de l'opération d'écriture ou de lecture. Je crois que le montant du transfert est trivialement petit, 16 bits ou quelques facteurs de 2 à proximité. Je me méfie de mettre en place mon propre processus d'arbitrage des transactions parce que j'ajouterai quelque chose qui a probablement des bogues à quelque chose qui pourrait avoir des bogues. Merci encore pour votre aide. – user239719

+0

@Jason Merci pour votre réponse. Que suggérez-vous dans ce cas? – user239719

2

Je pense que PIPE_BUF est la bonne chose. Maintenant, écrit de moins de PIPE_BUF octets ne peut pas être atomique, mais si ce n'est pas le cas, c'est un bogue du système d'exploitation. Je suppose que vous pourriez demander ici si un système d'exploitation a connu des bogues. Mais vraiment, si ça a un bug comme ça, ça devrait juste être réparé immédiatement.

Si vous voulez écrire plus de PIPE_BUF atomiquement, je pense que vous n'avez pas de chance. Je ne pense pas qu'il y ait un moyen, en dehors de la coordination et de la coopération, de faire en sorte que les écritures de plus grande taille soient atomiques.

Une solution à ce problème consiste à placer votre propre processus devant l'appareil et à vous assurer que tout le monde qui souhaite écrire sur l'appareil contacte le processus et lui envoie les données à la place. Ensuite, vous pouvez faire ce qui est logique pour votre application en termes de garanties d'atomicité.

+0

@Omnifarious, merci pour votre réponse. J'ai vérifié la définition de PIPE_BUF, il me semble que je suis bien en dessous du seuil avec mes structures de données. Je suis d'accord avec vous sur le fait que je pose des questions sur les bogues connus. Je me demande aussi plus en raison de la nature de l'appareil que j'utilise. Il m'est plus facile de faire confiance à l'exhaustivité du code pour une distribution de bureau qui peut être utilisée par des millions de personnes sur un matériel non standard avec un petit noyau personnalisé utilisé par seulement quelques personnes. Merci encore pour votre aide, je l'apprécie. – user239719

+0

Notez que 'PIPE_BUF' varie considérablement entre les systèmes Unix. Voir ici pour un aperçu des valeurs observées: http://ar.to/notes/posix#pipe-buf –

Questions connexes