2011-03-11 2 views
0

Nous avons beaucoup de caches qui ont été construits sur une machine 32 bits que nous devons maintenant lire dans un environnement 64 bits. Nous obtenons une erreur de segmentation lorsque nous voulons ouvrir lire un fichier cache.Lire des caches 32 bits dans l'environnement 64bit

Il faudra des semaines pour reproduire les caches, donc je voudrais savoir comment peut encore traiter nos fichiers de cache 32 bits sur des machines 64 bits.

Voici le code que nous utilisons pour lire et écrire nos caches:

bool IntArray::fload(const char* fname, long offset, long _size){ 
    long size = _size * sizeof(long); 

    long fd = open(fname, O_RDONLY); 
    if (fd >0 ){ 
    struct stat file_status; 
    if (stat(fname, &file_status) == 0){ 
     if (offset < 0 || offset > file_status.st_size){ 
     std::__throw_out_of_range("offset out of range"); 
     return false; 
     } 
     if (size + offset > file_status.st_size){ 
     std::__throw_out_of_range("read size out of range"); 
     return false; 
     } 

     void *map = mmap(NULL, file_status.st_size, PROT_READ, MAP_SHARED, fd, offset); 
     if (map == MAP_FAILED) { 
     close(fd); 
     std::__throw_runtime_error("Error mmapping the file"); 
     return false; 
     } 

     this->resize(_size); 
     memcpy(this->values, map, size); 

     if (munmap(map, file_status.st_size) == -1) { 
     close(fd); 
     std::__throw_runtime_error("Error un-mmapping the file"); 
     return false; 
     /* Decide here whether to close(fd) and exit() or not. Depends... */ 
     } 

     close(fd); 
     return true; 
    } 
    } 
    return false; 
} 
bool IntArray::fsave(const char* fname){ 
    long fd = open(fname, O_WRONLY | O_CREAT, 0644); //O_TRUNC 
    if (fd >0 ){ 
    long size = this->_size * sizeof(long); 
    long r = write(fd,this->values,size); 
    close(fd); 

    if (r != size){ 
     std::__throw_runtime_error("Error writing the file"); 
    } 
    return true; 
    } 
    return false; 
} 
+1

Que contiennent ces caches? – DarkDust

+1

Il serait intéressant que vous fournissiez les types de données en cours de lecture et la plate-forme sur laquelle vous travaillez. Dans 64 plates-formes, 'long' est en 32 bits alors que dans d'autres, il est en 64 bits, ce qui pourrait expliquer le problème. En guise de note, vous ne devriez pas appeler les méthodes qui commencent par '__' directement, car elles sont réservées pour l'implémentation et peuvent être changées à tout moment. Si vous voulez lancer un 'std :: runtime_error', faites simplement:' throw std :: runtime_error ("my_error") ' –

Répondre

3

Depuis la ligne:

long size = this->_size * sizeof(long); 

Je suppose que values des points à un tableau de long. Sous la plupart des systèmes d'exploitation exceptés Widnows, long sont 32 bits en 32 bits et 64 bits en 64 bits.

Vous devriez lire votre fichier comme un vidage de valeurs de 32 bits, int32_t par exemple, puis le copier aussi longtemps. Et probablement version votre fichier afin que vous sachiez quelle logique à appliquer lors de la lecture. En fait, concevoir un format de fichier au lieu de simplement utiliser un vidage de mémoire permettra d'éviter ce genre de problèmes (endianness, padding, format FP, ... sont d'autres problèmes qui surviendront si vous essayez un peu plus large portabilité que juste le programme qui a écrit le remplissage de fichier en particulier pourrait changer avec les drapeaux de compilation et de compilation du compilateur).

+0

Ou changez juste le code pour utiliser explicitement' int32_t' pour 'values', et assurez-vous que le compilateur encapsule densement les 'int32_t' sans padding. Cela devrait fonctionner avec les anciens fichiers sur les machines 32 bits et 64 bits. Ensuite, la question de savoir comment utiliser un type 'int32_t' en C++ reste portable, comme AFAIR, c'est seulement C qui définit' stdint.h' dans un standard, et C++ doit encore le rattraper. – ndim

+0

Excepté si la raison de l'utilisation d'un 64 bits était une capacité plus élevée, ce qui implique que 'int32_t' ne peut pas maintenant contenir les valeurs. (Sous unix, '' est requis par POSIX, donc il est assez portable.) – AProgrammer

+0

Merci, nous utilisons votre réponse pour modifier int32_t pour le moment. – eddy147

1

Vous devez modifier la mise en page de mémoire de this->values (quel que soit le type qui peut être, vous n'êtes pas mentionner que des informations cruciales) sur le 64bit machines de sorte que la disposition de la mémoire devienne identique à la disposition de la mémoire utilisée par les machines 32 bits. Vous devrez peut-être utiliser des astuces du compilateur comme struct packing ou des choses similaires pour le faire, et si this->values arrive à contenir des classes, vous aurez beaucoup de mal avec les pointeurs internes de classe que le compilateur génère. Par ailleurs, est-ce que C++ a déjà des types entiers de taille explicite appropriés? #include <cstdint>?

0

Vous suis tombé faute d'utiliser long comme type de données 32bit ... qui est, au moins sur les systèmes des Nations Unies * X, pas le cas dans 64bit (modèle de données LP64, int étant 32bit mais long et pointeurs étant 64bit).

Sur Windows64 (IL32P64 modèle de données, int et long 32bit mais pointeurs 64 bits) votre code d'effectuer des calculs de taille en unités de sizeof(long) et directement faire memcpy() à partir du fichier mis en correspondance avec le tableau-isée objet serait en fait continuer à travailler ... Sur UN * X, cela signifie que lors de la migration vers 64 bits, pour garder votre code portable, il serait préférable de passer à un int32_t de taille explicite (à partir de <stdint.h>), pour vous assurer que la structure de votre structure de données reste de même lors de l'exécution des compilations cibles 32 bits et 64 bits.

Si vous insistez sur le maintien de la long, alors vous devez changer l'intériorisation/extériorisation du tableau de la simple memcpy()/write() à faire les choses différemment.Sans traitement des erreurs (vous avez déjà ci-dessus), il avait l'air comme ça pour la méthode ::fsave(), au lieu d'utiliser write() comme vous le faites:

long *array = this->values; 
int32_t *filebase = 
    mmap(NULL, file_status.st_size, PROT_WRITE, MAP_SHARED, fd, offset); 

for (int i = 0; i < this->_size; i++) { 
    if (array[i] > INT32_MAX || array[i] < INT32_MIN) 
     throw (std::bad_cast); // can't do ... 
    filebase[i] = static_cast<int32_t>(array[i]); 
} 

munmap(filebase, file_status.st_size); 

et pour la ::fload() que vous souhaitez effectuer les opérations suivantes au lieu de memcpy():

long *array = this->values; 
int32_t *filebase = 
    mmap(NULL, file_status.st_size, PROT_READ MAP_SHARED, fd, offset); 

for (int i = 0; i < this->_size; i++) 
    array[i] = filebase[i]; 

munmap(filebase, file_status.st_size); 

note: Comme on l'a déjà mentionné, cette approche échouera si vous avez quelque chose de plus complexe qu'un simple tableau, car abstraction faite des différences de taille de type de données il pourrait y avoir des restrictions différentes d'alignement et différents rembourrage règles aussi bien. Cela ne semble pas être le cas pour vous, par conséquent ne gardez en tête que si vous envisagez d'étendre ce mécanisme (n'utilisez pas une bibliothèque testée comme boost :: any ou Qt :: Variant qui peut externaliser/internalize).

Questions connexes