Actual source code: sysio.c

  2: /* 
  3:    This file contains simple binary read/write routines.
  4:  */

 6:  #include petsc.h
 7:  #include petscsys.h

  9: #include <errno.h>
 10: #include <fcntl.h>
 11: #if defined(PETSC_HAVE_UNISTD_H)
 12: #include <unistd.h>
 13: #endif
 14: #if defined (PETSC_HAVE_IO_H)
 15: #include <io.h>
 16: #endif
 17:  #include petscbt.h


 20: #if !defined(PETSC_WORDS_BIGENDIAN)
 23: /*
 24:   PetscByteSwapInt - Swap bytes in an integer. NOT a PetscInt!

 26: */
 27: PetscErrorCode PetscByteSwapInt(int *buff,PetscInt n)
 28: {
 29:   PetscInt  i,j,tmp =0;
 30:   PetscInt  *tptr = &tmp;                /* Need to access tmp indirectly to get */
 31:   char      *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
 32: 
 34:   for (j=0; j<n; j++) {
 35:     ptr1 = (char*)(buff + j);
 36:     for (i=0; i<(int) sizeof(int); i++) {
 37:       ptr2[i] = ptr1[sizeof(int)-1-i];
 38:     }
 39:     buff[j] = *tptr;
 40:   }
 41:   return(0);
 42: }
 43: /* --------------------------------------------------------- */
 46: /*
 47:   PetscByteSwapShort - Swap bytes in a short
 48: */
 49: PetscErrorCode PetscByteSwapShort(short *buff,PetscInt n)
 50: {
 51:   PetscInt   i,j;
 52:   short      tmp;
 53:   short      *tptr = &tmp;           /* take care pf bug in DEC-ALPHA g++ */
 54:   char       *ptr1,*ptr2 = (char*)&tmp;

 57:   for (j=0; j<n; j++) {
 58:     ptr1 = (char*)(buff + j);
 59:     for (i=0; i<(int) sizeof(short); i++) {
 60:       ptr2[i] = ptr1[sizeof(int)-1-i];
 61:     }
 62:     buff[j] = *tptr;
 63:   }
 64:   return(0);
 65: }
 66: /* --------------------------------------------------------- */
 69: /*
 70:   PetscByteSwapScalar - Swap bytes in a double
 71:   Complex is dealt with as if array of double twice as long.
 72: */
 73: PetscErrorCode PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
 74: {
 75:   PetscInt  i,j;
 76:   PetscReal tmp,*buff1 = (PetscReal*)buff;
 77:   PetscReal *tptr = &tmp;          /* take care pf bug in DEC-ALPHA g++ */
 78:   char      *ptr1,*ptr2 = (char*)&tmp;

 81: #if defined(PETSC_USE_COMPLEX)
 82:   n *= 2;
 83: #endif
 84:   for (j=0; j<n; j++) {
 85:     ptr1 = (char*)(buff1 + j);
 86:     for (i=0; i<(int) sizeof(PetscReal); i++) {
 87:       ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
 88:     }
 89:     buff1[j] = *tptr;
 90:   }
 91:   return(0);
 92: }
 93: /* --------------------------------------------------------- */
 96: /*
 97:   PetscByteSwapDouble - Swap bytes in a double
 98: */
 99: PetscErrorCode PetscByteSwapDouble(double *buff,PetscInt n)
100: {
101:   PetscInt i,j;
102:   double   tmp,*buff1 = (double*)buff;
103:   double   *tptr = &tmp;          /* take care pf bug in DEC-ALPHA g++ */
104:   char     *ptr1,*ptr2 = (char*)&tmp;

107:   for (j=0; j<n; j++) {
108:     ptr1 = (char*)(buff1 + j);
109:     for (i=0; i<(int) sizeof(double); i++) {
110:       ptr2[i] = ptr1[sizeof(double)-1-i];
111:     }
112:     buff1[j] = *tptr;
113:   }
114:   return(0);
115: }
116: #endif
117: /* --------------------------------------------------------- */
120: /*@C
121:    PetscBinaryRead - Reads from a binary file.

123:    Not Collective

125:    Input Parameters:
126: +  fd - the file
127: .  n  - the number of items to read 
128: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

130:    Output Parameters:
131: .  p - the buffer



135:    Level: developer

137:    Notes: 
138:    PetscBinaryRead() uses byte swapping to work on all machines.
139:    Integers are stored on the file as 32 long, regardless of whether
140:    they are stored in the machine as 32 or 64, this means the same
141:    binary file may be read on any machine.

143:    Concepts: files^reading binary
144:    Concepts: binary files^reading

146: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose()
147: @*/
148: PetscErrorCode PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
149: {
150: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT) || !defined(PETSC_WORDS_BIGENDIAN)
151:   PetscErrorCode    ierr;
152: #endif
153:   int               maxblock = 65536,wsize,err,m = (int) n;
154:   char              *pp = (char*)p;
155: #if (PETSC_SIZEOF_INT == 8) || !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_64BIT_INT)
156:   void              *ptmp = p;
157: #endif

160:   if (!n) return(0);


163:   if (type == PETSC_INT){
164: #if (PETSC_SIZEOF_INT == 8)
165:     /* read them in as shorts, later stretch into ints */
166:     m   *= sizeof(short);
167:     PetscMalloc(m,&pp);
168:     ptmp = (void*)pp;
169: #elif defined(PETSC_USE_64BIT_INT)
170:     /* read them in as int, later stretch into PetscInts */
171:     m   *= sizeof(int);
172:     PetscMalloc(m,&pp);
173:     ptmp = (void*)pp;
174: #else
175:     m *= sizeof(int);
176: #endif
177:   }
178:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
179:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
180:   else if (type == PETSC_SHORT)   m *= sizeof(short);
181:   else if (type == PETSC_CHAR)    m *= sizeof(char);
182:   else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
183:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
184: 
185:   while (m) {
186:     wsize = (m < maxblock) ? m : maxblock;
187:     err = read(fd,pp,wsize);
188:     if (err < 0 && errno == EINTR) continue;
189:     if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
190:     if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
191:     m  -= err;
192:     pp += err;
193:   }
194: #if !defined(PETSC_WORDS_BIGENDIAN)
195:   if      (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
196:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
197:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
198:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
199: #endif

201: #if (PETSC_SIZEOF_INT == 8)
202:   if (type == PETSC_INT){
203:     int   *p_int = (int*)p,i;
204:     short *p_short = (short *)ptmp;
205:     for (i=0; i<n; i++) {
206:       p_int[i] = (int)p_short[i];
207:     }
208:     PetscFree(ptmp);
209:   }
210: #elif defined(PETSC_USE_64BIT_INT)
211:   if (type == PETSC_INT){
212:     PetscInt   *p_int = (PetscInt*)p,i;
213:     int       *p_short = (int *)ptmp;
214:     for (i=0; i<n; i++) {
215:       p_int[i] = (PetscInt)p_short[i];
216:     }
217:     PetscFree(ptmp);
218:   }
219: #endif

221:   return(0);
222: }
223: /* --------------------------------------------------------- */
226: /*@C
227:    PetscBinaryWrite - Writes to a binary file.

229:    Not Collective

231:    Input Parameters:
232: +  fd     - the file
233: .  p      - the buffer
234: .  n      - the number of items to write
235: .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
236: -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.

238:    Level: advanced

240:    Notes: 
241:    PetscBinaryWrite() uses byte swapping to work on all machines.
242:    Integers are stored on the file as 32 long, regardless of whether
243:    they are stored in the machine as 32 or 64, this means the same
244:    binary file may be read on any machine.

246:    The Buffer p should be read-write buffer, and not static data.
247:    This way, byte-swapping is done in-place, and then the buffer is
248:    written to the file.
249:    
250:    This routine restores the original contents of the buffer, after 
251:    it is written to the file. This is done by byte-swapping in-place 
252:    the second time. If the flag istemp is set to 1, the second
253:    byte-swapping operation is not done, thus saving some computation,
254:    but the buffer corrupted is corrupted.

256:    Concepts: files^writing binary
257:    Concepts: binary files^writing

259: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose()
260: @*/
261: PetscErrorCode PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
262: {
263:   char           *pp = (char*)p;
264:   int            err,maxblock,wsize,m = (int)n;
265: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8) ||  defined(PETSC_USE_64BIT_INT)
267:   void           *ptmp = p;
268: #endif

271:   if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
272:   if (!n) return(0);

274:   maxblock = 65536;


277:   if (type == PETSC_INT){
278: #if (PETSC_SIZEOF_INT == 8)
279:     int   *p_int = (int*)p,i;
280:     short *p_short;
281:     m       *= sizeof(short);
282:     PetscMalloc(m,&pp);
283:     ptmp    = (void*)pp;
284:     p_short = (short*)pp;

286:     for (i=0; i<n; i++) {
287:       p_short[i] = (short) p_int[i];
288:     }
289: #elif defined(PETSC_USE_64BIT_INT)
290:     PetscInt   *p_int = (PetscInt*)p,i;
291:     int        *p_short;
292:     m       *= sizeof(int);
293:     PetscMalloc(m,&pp);
294:     ptmp    = (void*)pp;
295:     p_short = (int*)pp;

297:     for (i=0; i<n; i++) {
298:       p_short[i] = (int) p_int[i];
299:     }
300: #else
301:     m *= sizeof(int);
302: #endif
303:   }
304:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
305:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
306:   else if (type == PETSC_SHORT)   m *= sizeof(short);
307:   else if (type == PETSC_CHAR)    m *= sizeof(char);
308:   else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
309:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

311: #if !defined(PETSC_WORDS_BIGENDIAN)
312:   if      (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
313:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
314:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
315:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
316: #endif

318:   while (m) {
319:     wsize = (m < maxblock) ? m : maxblock;
320:     err = write(fd,pp,wsize);
321:     if (err < 0 && errno == EINTR) continue;
322:     if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
323:     m -= wsize;
324:     pp += wsize;
325:   }

327: #if !defined(PETSC_WORDS_BIGENDIAN) && !(PETSC_SIZEOF_INT == 8) && !defined(PETSC_USE_64BIT_INT)
328:   if (!istemp) {
329:     if      (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
330:     else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
331:     else if (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
332:   }
333: #endif

335: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
336:   if (type == PETSC_INT){
337:     PetscFree(ptmp);
338:   }
339: #endif
340:   return(0);
341: }

345: /*@C
346:    PetscBinaryOpen - Opens a PETSc binary file.

348:    Not Collective

350:    Input Parameters:
351: +  name - filename
352: -  type - type of binary file, on of PETSC_FILE_RDONLY, PETSC_FILE_WRONLY, PETSC_FILE_CREATE

354:    Output Parameter:
355: .  fd - the file

357:    Level: advanced

359:   Concepts: files^opening binary
360:   Concepts: binary files^opening

362: .seealso: PetscBinaryRead(), PetscBinaryWrite()
363: @*/
364: PetscErrorCode PetscBinaryOpen(const char name[],int type,int *fd)
365: {
367: #if defined(PETSC_HAVE_O_BINARY) 
368:   if (type == PETSC_FILE_CREATE) {
369:     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
370:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
371:     }
372:   } else if (type == PETSC_FILE_RDONLY) {
373:     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
374:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
375:     }
376:   } else if (type == PETSC_FILE_WRONLY) {
377:     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
378:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
379:     }
380: #else
381:   if (type == PETSC_FILE_CREATE) {
382:     if ((*fd = creat(name,0666)) == -1) {
383:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
384:     }
385:   } else if (type == PETSC_FILE_RDONLY) {
386:     if ((*fd = open(name,O_RDONLY,0)) == -1) {
387:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
388:     }
389:   }
390:   else if (type == PETSC_FILE_WRONLY) {
391:     if ((*fd = open(name,O_WRONLY,0)) == -1) {
392:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
393:     }
394: #endif
395:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file type");
396:   return(0);
397: }

401: /*@C
402:    PetscBinaryClose - Closes a PETSc binary file.

404:    Not Collective

406:    Output Parameter:
407: .  fd - the file

409:    Level: advanced

411: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
412: @*/
413: PetscErrorCode PetscBinaryClose(int fd)
414: {
416:   close(fd);
417:   return(0);
418: }


423: /*@C
424:    PetscBinarySeek - Moves the file pointer on a PETSc binary file.

426:    Not Collective

428:    Input Parameters:
429: +  fd - the file
430: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
431:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
432:             if PETSC_BINARY_SEEK_END then size is offset from end of file
433: -  size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
434:             etc. in your calculation rather than sizeof() to compute byte lengths.

436:    Output Parameter:
437: .   offset - new offset in file

439:    Level: developer

441:    Notes: 
442:    Integers are stored on the file as 32 long, regardless of whether
443:    they are stored in the machine as 32 or 64, this means the same
444:    binary file may be read on any machine. Hence you CANNOT use sizeof()
445:    to determine the offset or location.

447:    Concepts: files^binary seeking
448:    Concepts: binary files^seeking

450: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
451: @*/
452: PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
453: {
454:   int iwhence=0;

457:   if (whence == PETSC_BINARY_SEEK_SET) {
458:     iwhence = SEEK_SET;
459:   } else if (whence == PETSC_BINARY_SEEK_CUR) {
460:     iwhence = SEEK_CUR;
461:   } else if (whence == PETSC_BINARY_SEEK_END) {
462:     iwhence = SEEK_END;
463:   } else {
464:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
465:   }
466: #if defined(PETSC_HAVE_LSEEK)
467:   *offset = lseek(fd,off,iwhence);
468: #elif defined(PETSC_HAVE__LSEEK)
469:   *offset = _lseek(fd,(long)off,iwhence);
470: #else
471:   SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
472: #endif

474:   return(0);
475: }

479: /*@C
480:    PetscSynchronizedBinaryRead - Reads from a binary file.

482:    Collective on MPI_Comm

484:    Input Parameters:
485: +  comm - the MPI communicator 
486: .  fd - the file
487: .  n  - the number of items to read 
488: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

490:    Output Parameters:
491: .  p - the buffer

493:    Options Database Key:
494: .   -binary_longints - indicates the file was generated on a Cray vector 
495:          machine (not the T3E/D) and the ints are stored as 64 bit 
496:          quantities, otherwise they are stored as 32 bit

498:    Level: developer

500:    Notes: 
501:    Does a PetscBinaryRead() followed by an MPI_Bcast()

503:    PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
504:    Integers are stored on the file as 32 long, regardless of whether
505:    they are stored in the machine as 32 or 64, this means the same
506:    binary file may be read on any machine.

508:    Concepts: files^synchronized reading of binary files
509:    Concepts: binary files^reading, synchronized

511: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
512: @*/
513: PetscErrorCode PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
514: {
516:   PetscMPIInt    rank;
517:   MPI_Datatype   mtype;

520:   MPI_Comm_rank(comm,&rank);
521:   if (!rank) {
522:     PetscBinaryRead(fd,p,n,type);
523:   }
524:   PetscDataTypeToMPIDataType(type,&mtype);
525:   MPI_Bcast(p,n,mtype,0,comm);
526:   return(0);
527: }

531: /*@C
532:    PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.


535:    Input Parameters:
536: +  fd - the file
537: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
538:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
539:             if PETSC_BINARY_SEEK_END then size is offset from end of file
540: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
541:             etc. in your calculation rather than sizeof() to compute byte lengths.

543:    Output Parameter:
544: .   offset - new offset in file

546:    Level: developer

548:    Notes: 
549:    Integers are stored on the file as 32 long, regardless of whether
550:    they are stored in the machine as 32 or 64, this means the same
551:    binary file may be read on any machine. Hence you CANNOT use sizeof()
552:    to determine the offset or location.

554:    Concepts: binary files^seeking
555:    Concepts: files^seeking in binary 

557: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
558: @*/
559: PetscErrorCode PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
560: {
562:   PetscMPIInt    rank;

565:   MPI_Comm_rank(comm,&rank);
566:   if (!rank) {
567:     PetscBinarySeek(fd,off,whence,offset);
568:   }
569:   return(0);
570: }