2017-02-12 5 views
0

J'ai écrit le module Zsh. Là, j'ai une fonction intégrée mappée à la commande Zsh. Cette fonction fait double emploi avec son descripteur de fichier stdin:dup (fileno (stdin)) puis spawn de 32 threads -> erreurs d'E/S

/* Duplicate standard input */ 
oconf->stream = fdopen(dup(fileno(stdin)), "r"); 

Ensuite, un thread est généré qui obtient la structure oconf. Dans ce fil, je fais:

errno = 0; 

/* Read e.g. 5 characters, putting them after previous portion */ 
int count = fread(buf + index, 1, read_size, oconf->stream); 
/* Ensure that our whole data is a string - null terminated */ 
buf[ index + count ] = '\0'; 

if (errno) { 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno) > 
} 

Si je fraient 32 fils dans zsh:

for ((i=1; i<=32; i ++)); do 
    ls -R /Users/myuser/Documents | mybuiltin -A myhash_$i $i 
done 

Ensuite 2-3 fils ont l'erreur E/S rapporté de la fprintf() ci-dessus, par exemple:

erreur de lecture (descripteur: 7): entrée/sortie erreur

erreur de lecture (descripteur: 5): ioctl inappropriée pour le dispositif

erreur de lecture (descripteur: 14): ioctl pour le dispositif inapproprié

Debugger dit que ces discussions, après plusieurs (5-20) fread() répétitions, bloqués dans __read_nocancel() de noyau. Donc quelque chose de vraiment mauvais se passe avec le descripteur de fichier.

Sinon, cela fonctionne. Le tube transmet correctement les données de ls -R, il est lu par le builtin personnalisé. Alors, où est le danger? Comment se fait que dup() effectué dans le fil principal entraîne quelque chose d'illisible à fread()? Je pourrais avoir des doutes si je ferais dup() dans le fil secondaire. Mais je garde cela seulement en lieu sûr - fil principal, puis passer prêt FILE * flux au fil secondaire. Également essayé avec POSIX open(), read() et close(), le résultat est le même.

Répondre

0

Vous effectuez un test incorrect de errno. Vous devriez seulement vérifier errno si une fonction qui le définit a signalé une erreur. Aucune fonction dans la bibliothèque standard C ou POSIX ne définit errno à zéro. Et les fonctions peuvent définir errno à une valeur non nulle sans signaler une erreur. Par exemple, sur Solaris, c'était le cas (et c'est probablement toujours le cas) qu'après des opérations d'écriture, errno == ENOTTY si le flux de fichier n'était pas un terminal (par exemple redirigé vers un fichier ou un canal). Il n'y avait pas de problème. le périphérique de sortie n'étant pas un terminal, une opération de terminal uniquement a échoué, en définissant errno sur ENOTTY.

Vous avez actuellement:

/* Read e.g. 5 characters, putting them after previous portion */ 
int count = fread(buf + index, 1, read_size, oconf->stream); 
/* Ensure that our whole data is a string - null terminated */ 
buf[ index + count ] = '\0'; 

if (errno) { 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno)); 
} 

Vous devez utiliser quelque chose comme:

int count = fread(buf + index, 1, read_size, oconf->stream); 
if (count == 0) 
{ 
    /* EOF or error — this might be a time to use feof() or ferror() */ 
    fprintf(oconf->err, "Read error (descriptor: %d): %s\n", fileno(oconf->stream), strerror(errno)); 
    …flow control?… 
} 
else 
    buf[index + count] = '\0'; 

Vous avez probablement besoin d'autres flux de contrôle détails (retour ou cassez ou indicateur défini) dans l'EOF et le chemin d'erreur; il ne ressort pas clairement de votre fragment cité ce qui pourrait être approprié.