Actual source code: sysio.c


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

  6: #include <petscsys.h>
  7: #include <petscbt.h>
  8: #include <errno.h>
  9: #include <fcntl.h>
 10: #if defined(PETSC_HAVE_UNISTD_H)
 11: #include <unistd.h>
 12: #endif
 13: #if defined(PETSC_HAVE_IO_H)
 14: #include <io.h>
 15: #endif
 16: #if !defined(PETSC_HAVE_O_BINARY)
 17: #define O_BINARY 0
 18: #endif

 20: const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL};

 22: /* --------------------------------------------------------- */
 23: /*
 24:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

 26: */
 27: PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
 28: {
 29:   PetscInt  i,j;
 30:   PetscEnum tmp = ENUM_DUMMY;
 31:   char      *ptr1,*ptr2 = (char*)&tmp;

 34:   for (j=0; j<n; j++) {
 35:     ptr1 = (char*)(buff + j);
 36:     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum)-1-i];
 37:     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
 38:   }
 39:   return(0);
 40: }

 42: /*
 43:   PetscByteSwapBool - Swap bytes in a  PETSc Bool

 45: */
 46: PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
 47: {
 48:   PetscInt  i,j;
 49:   PetscBool tmp = PETSC_FALSE;
 50:   char      *ptr1,*ptr2 = (char*)&tmp;

 53:   for (j=0; j<n; j++) {
 54:     ptr1 = (char*)(buff + j);
 55:     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
 56:     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
 57:   }
 58:   return(0);
 59: }

 61: /*
 62:   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)

 64: */
 65: PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
 66: {
 67:   PetscInt i,j,tmp = 0;
 68:   char     *ptr1,*ptr2 = (char*)&tmp;

 71:   for (j=0; j<n; j++) {
 72:     ptr1 = (char*)(buff + j);
 73:     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
 74:     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
 75:   }
 76:   return(0);
 77: }

 79: /*
 80:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)

 82: */
 83: PetscErrorCode  PetscByteSwapInt64(PetscInt64 *buff,PetscInt n)
 84: {
 85:   PetscInt   i,j;
 86:   PetscInt64 tmp = 0;
 87:   char       *ptr1,*ptr2 = (char*)&tmp;

 90:   for (j=0; j<n; j++) {
 91:     ptr1 = (char*)(buff + j);
 92:     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64)-1-i];
 93:     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
 94:   }
 95:   return(0);
 96: }

 98: /* --------------------------------------------------------- */
 99: /*
100:   PetscByteSwapShort - Swap bytes in a short
101: */
102: PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
103: {
104:   PetscInt i,j;
105:   short    tmp;
106:   char     *ptr1,*ptr2 = (char*)&tmp;

109:   for (j=0; j<n; j++) {
110:     ptr1 = (char*)(buff + j);
111:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
112:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
113:   }
114:   return(0);
115: }
116: /*
117:   PetscByteSwapLong - Swap bytes in a long
118: */
119: PetscErrorCode  PetscByteSwapLong(long *buff,PetscInt n)
120: {
121:   PetscInt i,j;
122:   long     tmp;
123:   char     *ptr1,*ptr2 = (char*)&tmp;

126:   for (j=0; j<n; j++) {
127:     ptr1 = (char*)(buff + j);
128:     for (i=0; i<(PetscInt) sizeof(long); i++) ptr2[i] = ptr1[sizeof(long)-1-i];
129:     for (i=0; i<(PetscInt) sizeof(long); i++) ptr1[i] = ptr2[i];
130:   }
131:   return(0);
132: }
133: /* --------------------------------------------------------- */
134: /*
135:   PetscByteSwapReal - Swap bytes in a PetscReal
136: */
137: PetscErrorCode  PetscByteSwapReal(PetscReal *buff,PetscInt n)
138: {
139:   PetscInt  i,j;
140:   PetscReal tmp,*buff1 = (PetscReal*)buff;
141:   char      *ptr1,*ptr2 = (char*)&tmp;

144:   for (j=0; j<n; j++) {
145:     ptr1 = (char*)(buff1 + j);
146:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
147:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
148:   }
149:   return(0);
150: }
151: /* --------------------------------------------------------- */
152: /*
153:   PetscByteSwapScalar - Swap bytes in a PetscScalar
154:   The complex case is dealt with with an array of PetscReal, twice as long.
155: */
156: PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
157: {
158:   PetscInt  i,j;
159:   PetscReal tmp,*buff1 = (PetscReal*)buff;
160:   char      *ptr1,*ptr2 = (char*)&tmp;

163: #if defined(PETSC_USE_COMPLEX)
164:   n *= 2;
165: #endif
166:   for (j=0; j<n; j++) {
167:     ptr1 = (char*)(buff1 + j);
168:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
169:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
170:   }
171:   return(0);
172: }
173: /* --------------------------------------------------------- */
174: /*
175:   PetscByteSwapDouble - Swap bytes in a double
176: */
177: PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
178: {
179:   PetscInt i,j;
180:   double   tmp,*buff1 = (double*)buff;
181:   char     *ptr1,*ptr2 = (char*)&tmp;

184:   for (j=0; j<n; j++) {
185:     ptr1 = (char*)(buff1 + j);
186:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
187:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
188:   }
189:   return(0);
190: }

192: /*
193:   PetscByteSwapFloat - Swap bytes in a float
194: */
195: PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
196: {
197:   PetscInt i,j;
198:   float    tmp,*buff1 = (float*)buff;
199:   char     *ptr1,*ptr2 = (char*)&tmp;

202:   for (j=0; j<n; j++) {
203:     ptr1 = (char*)(buff1 + j);
204:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
205:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
206:   }
207:   return(0);
208: }

210: PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
211: {

215:   if      (pdtype == PETSC_INT)    {PetscByteSwapInt((PetscInt*)data,count);}
216:   else if (pdtype == PETSC_ENUM)   {PetscByteSwapEnum((PetscEnum*)data,count);}
217:   else if (pdtype == PETSC_BOOL)   {PetscByteSwapBool((PetscBool*)data,count);}
218:   else if (pdtype == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)data,count);}
219:   else if (pdtype == PETSC_REAL)   {PetscByteSwapReal((PetscReal*)data,count);}
220:   else if (pdtype == PETSC_COMPLEX){PetscByteSwapReal((PetscReal*)data,2*count);}
221:   else if (pdtype == PETSC_INT64)  {PetscByteSwapInt64((PetscInt64*)data,count);}
222:   else if (pdtype == PETSC_DOUBLE) {PetscByteSwapDouble((double*)data,count);}
223:   else if (pdtype == PETSC_FLOAT)  {PetscByteSwapFloat((float*)data,count);}
224:   else if (pdtype == PETSC_SHORT)  {PetscByteSwapShort((short*)data,count);}
225:   else if (pdtype == PETSC_LONG)   {PetscByteSwapLong((long*)data,count);}
226:   return(0);
227: }

229: /*@C
230:    PetscBinaryRead - Reads from a binary file.

232:    Not Collective

234:    Input Parameters:
235: +  fd - the file descriptor
236: .  num  - the maximum number of items to read
237: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

239:    Output Parameters:
240: +  data - the buffer
241: -  count - the number of items read, optional

243:    Level: developer

245:    Notes:
246:    If count is not provided and the number of items read is less than
247:    the maximum number of items to read, then this routine errors.

249:    PetscBinaryRead() uses byte swapping to work on all machines; the files
250:    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
251:    are converted to the little-endian format when they are read in from the file.
252:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
253:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
254:    is used.

256: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
257:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
258: @*/
259: PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
260: {
261:   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
262:   char              *p = (char*)data;
263: #if defined(PETSC_USE_REAL___FLOAT128)
264:   PetscBool         readdouble = PETSC_FALSE;
265:   double            *pdouble;
266: #endif
267:   void              *ptmp = data;
268:   char              *fname = NULL;
269:   PetscErrorCode    ierr;

272:   if (count) *count = 0;
273:   if (num < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %D",num);
274:   if (!num) return(0);

276:   if (type == PETSC_FUNCTION) {
277:     m     = 64;
278:     type  = PETSC_CHAR;
279:     fname = (char*)malloc(m*sizeof(char));
280:     p     = (char*)fname;
281:     ptmp  = (void*)fname;
282:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
283:   }
284:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);

286:   PetscDataTypeGetSize(type,&typesize);

288: #if defined(PETSC_USE_REAL___FLOAT128)
289:   PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);
290:   /* If using __float128 precision we still read in doubles from file */
291:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
292:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
293:     PetscMalloc1(cnt,&pdouble);
294:     p = (char*)pdouble;
295:     typesize /= 2;
296:   }
297: #endif

299:   m *= typesize;

301:   while (m) {
302:     size_t len = (m < maxblock) ? m : maxblock;
303:     int    ret = (int)read(fd,p,len);
304:     if (ret < 0 && errno == EINTR) continue;
305:     if (!ret && len > 0) break; /* Proxy for EOF */
306:     if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
307:     m -= ret;
308:     p += ret;
309:     n += ret;
310:   }
311:   if (m && !count) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");

313:   num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */
314:   if (count) *count = num;      /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */

316: #if defined(PETSC_USE_REAL___FLOAT128)
317:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
318:     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
319:     PetscReal *preal = (PetscReal*)data;
320:     if (!PetscBinaryBigEndian()) {PetscByteSwapDouble(pdouble,cnt);}
321:     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
322:     PetscFree(pdouble);
323:     return(0);
324:   }
325: #endif

327:   if (!PetscBinaryBigEndian()) {PetscByteSwap(ptmp,type,num);}

329:   if (type == PETSC_FUNCTION) {
330: #if defined(PETSC_SERIALIZE_FUNCTIONS)
331:     PetscDLSym(NULL,fname,(void**)data);
332: #else
333:     *(void**)data = NULL;
334: #endif
335:     free(fname);
336:   }
337:   return(0);
338: }

340: /*@C
341:    PetscBinaryWrite - Writes to a binary file.

343:    Not Collective

345:    Input Parameters:
346: +  fd     - the file
347: .  p      - the buffer
348: .  n      - the number of items to write
349: -  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

351:    Level: advanced

353:    Notes:
354:    PetscBinaryWrite() uses byte swapping to work on all machines; the files
355:    are written using big-endian ordering to the file. On little-endian machines the numbers
356:    are converted to the big-endian format when they are written to disk.
357:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
358:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
359:    is used.

361:    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option

363:    The Buffer p should be read-write buffer, and not static data.
364:    This way, byte-swapping is done in-place, and then the buffer is
365:    written to the file.

367:    This routine restores the original contents of the buffer, after
368:    it is written to the file. This is done by byte-swapping in-place
369:    the second time.

371:    Because byte-swapping may be done on the values in data it cannot be declared const

373: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
374:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
375: @*/
376: PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
377: {
378:   const char     *pp = (char*)p;
379:   int            err,wsize;
380:   size_t         m = (size_t)n,maxblock=65536;
382:   const void     *ptmp = p;
383:   char           *fname = NULL;
384: #if defined(PETSC_USE_REAL___FLOAT128)
385:   PetscBool      writedouble = PETSC_FALSE;
386:   double         *ppp;
387:   PetscReal      *pv;
388:   PetscInt       i;
389: #endif
390:   PetscDataType  wtype = type;

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

396:   if (type == PETSC_FUNCTION) {
397: #if defined(PETSC_SERIALIZE_FUNCTIONS)
398:     const char *fnametmp;
399: #endif
400:     m     = 64;
401:     fname = (char*)malloc(m*sizeof(char));
402:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
403: #if defined(PETSC_SERIALIZE_FUNCTIONS)
404:     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
405:     PetscFPTFind(*(void**)p,&fnametmp);
406:     PetscStrncpy(fname,fnametmp,m);
407: #else
408:     PetscStrncpy(fname,"",m);
409: #endif
410:     wtype = PETSC_CHAR;
411:     pp    = (char*)fname;
412:     ptmp  = (void*)fname;
413:   }

415: #if defined(PETSC_USE_REAL___FLOAT128)
416:   PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);
417:   /* If using __float128 precision we still write in doubles to file */
418:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
419:     wtype = PETSC_DOUBLE;
420:     PetscMalloc1(n,&ppp);
421:     pv = (PetscReal*)pp;
422:     for (i=0; i<n; i++) {
423:       ppp[i] = (double) pv[i];
424:     }
425:     pp   = (char*)ppp;
426:     ptmp = (char*)ppp;
427:   }
428: #endif

430:   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
431:   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
432: #if defined(PETSC_HAVE_COMPLEX)
433:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
434: #endif
435:   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
436:   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
437:   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
438:   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
439:   else if (wtype == PETSC_LONG)    m *= sizeof(long);
440:   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
441:   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
442:   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
443:   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
444:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
445:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

447:   if (!PetscBinaryBigEndian()) {PetscByteSwap((void*)ptmp,wtype,n);}

449:   while (m) {
450:     wsize = (m < maxblock) ? m : maxblock;
451:     err   = write(fd,pp,wsize);
452:     if (err < 0 && errno == EINTR) continue;
453:     if (err != wsize) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file total size %d err %d wsize %d",(int)n,(int)err,(int)wsize);
454:     m  -= wsize;
455:     pp += wsize;
456:   }

458:   if (!PetscBinaryBigEndian()) {PetscByteSwap((void*)ptmp,wtype,n);}

460:   if (type == PETSC_FUNCTION) {
461:     free(fname);
462:   }
463: #if defined(PETSC_USE_REAL___FLOAT128)
464:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
465:     PetscFree(ppp);
466:   }
467: #endif
468:   return(0);
469: }

471: /*@C
472:    PetscBinaryOpen - Opens a PETSc binary file.

474:    Not Collective

476:    Input Parameters:
477: +  name - filename
478: -  mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND

480:    Output Parameter:
481: .  fd - the file

483:    Level: advanced

485:    Notes:
486:     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
487:    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
488:    PetscBinaryRead() and PetscBinaryWrite() on any machine.

490: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
491:           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()

493: @*/
494: PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
495: {
497:   switch (mode) {
498:   case FILE_MODE_READ:   *fd = open(name,O_BINARY|O_RDONLY,0); break;
499:   case FILE_MODE_WRITE:  *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
500:   case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
501:   default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
502:   }
503:   if (*fd == -1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file %s for %s: %s",name,PetscFileModes[mode]);
504:   return(0);
505: }

507: /*@
508:    PetscBinaryClose - Closes a PETSc binary file.

510:    Not Collective

512:    Output Parameter:
513: .  fd - the file

515:    Level: advanced

517: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
518:           PetscBinarySynchronizedSeek()
519: @*/
520: PetscErrorCode  PetscBinaryClose(int fd)
521: {
523:   if (close(fd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"close() failed on file descriptor");
524:   return(0);
525: }

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

530:    Not Collective

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

540:    Output Parameter:
541: .   offset - new offset in file

543:    Level: developer

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

551: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
552:           PetscBinarySynchronizedSeek()
553: @*/
554: PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
555: {
556:   int iwhence = 0;

559:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
560:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
561:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
562:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
563: #if defined(PETSC_HAVE_LSEEK)
564:   *offset = lseek(fd,off,iwhence);
565: #elif defined(PETSC_HAVE__LSEEK)
566:   *offset = _lseek(fd,(long)off,iwhence);
567: #else
568:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
569: #endif
570:   return(0);
571: }

573: /*@C
574:    PetscBinarySynchronizedRead - Reads from a binary file.

576:    Collective

578:    Input Parameters:
579: +  comm - the MPI communicator
580: .  fd - the file descriptor
581: .  num  - the maximum number of items to read
582: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

584:    Output Parameters:
585: +  data - the buffer
586: -  count - the number of items read, optional

588:    Level: developer

590:    Notes:
591:    Does a PetscBinaryRead() followed by an MPI_Bcast()

593:    If count is not provided and the number of items read is less than
594:    the maximum number of items to read, then this routine errors.

596:    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
597:    Integers are stored on the file as 32 long, regardless of whether
598:    they are stored in the machine as 32 or 64, this means the same
599:    binary file may be read on any machine.

601: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
602:           PetscBinarySynchronizedSeek()
603: @*/
604: PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
605: {
607:   PetscMPIInt    rank,size;
608:   MPI_Datatype   mtype;
609:   PetscInt       ibuf[2] = {0, 0};
610:   char           *fname = NULL;
611:   void           *fptr = NULL;

614:   if (type == PETSC_FUNCTION) {
615:     num   = 64;
616:     type  = PETSC_CHAR;
617:     fname = (char*)malloc(num*sizeof(char));
618:     fptr  = data;
619:     data  = (void*)fname;
620:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
621:   }

623:   MPI_Comm_rank(comm,&rank);
624:   MPI_Comm_size(comm,&size);
625:   if (rank == 0) {
626:     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
627:   }
628:   MPI_Bcast(ibuf,2,MPIU_INT,0,comm);
629:   (PetscErrorCode)ibuf[0];

631:   /* skip MPI call on potentially huge amounts of data when running with one process; this allows the amount of data to basically unlimited in that case */
632:   if (size > 1) {
633:     PetscDataTypeToMPIDataType(type,&mtype);
634:     MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);
635:   }
636:   if (count) *count = ibuf[1];

638:   if (type == PETSC_FUNCTION) {
639: #if defined(PETSC_SERIALIZE_FUNCTIONS)
640:     PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);
641: #else
642:     *(void**)fptr = NULL;
643: #endif
644:     free(fname);
645:   }
646:   return(0);
647: }

649: /*@C
650:    PetscBinarySynchronizedWrite - writes to a binary file.

652:    Collective

654:    Input Parameters:
655: +  comm - the MPI communicator
656: .  fd - the file
657: .  n  - the number of items to write
658: .  p - the buffer
659: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

661:    Level: developer

663:    Notes:
664:    Process 0 does a PetscBinaryWrite()

666:    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
667:    Integers are stored on the file as 32 long, regardless of whether
668:    they are stored in the machine as 32 or 64, this means the same
669:    binary file may be read on any machine.

671:    Notes:
672:     because byte-swapping may be done on the values in data it cannot be declared const

674:    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
675:    while PetscSynchronizedFPrintf() has all processes print their strings in order.

677: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
678:           PetscBinarySynchronizedSeek()
679: @*/
680: PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
681: {
683:   PetscMPIInt    rank;

686:   MPI_Comm_rank(comm,&rank);
687:   if (rank == 0) {
688:     PetscBinaryWrite(fd,p,n,type);
689:   }
690:   return(0);
691: }

693: /*@C
694:    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.

696:    Input Parameters:
697: +  fd - the file
698: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
699:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
700:             if PETSC_BINARY_SEEK_END then size is offset from end of file
701: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
702:             etc. in your calculation rather than sizeof() to compute byte lengths.

704:    Output Parameter:
705: .   offset - new offset in file

707:    Level: developer

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

715: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
716:           PetscBinarySynchronizedSeek()
717: @*/
718: PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
719: {
721:   PetscMPIInt    rank;

724:   MPI_Comm_rank(comm,&rank);
725:   if (rank == 0) {
726:     PetscBinarySeek(fd,off,whence,offset);
727:   }
728:   return(0);
729: }

731: #if defined(PETSC_HAVE_MPIIO)

733: #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
734: /*
735:       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
736:     These are set into MPI in PetscInitialize() via MPI_Register_datarep()

738:     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)

740:     The next three routines are not used because MPICH does not support their use

742: */
743: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
744: {
745:   MPI_Aint    ub;
746:   PetscMPIInt ierr;

748:   MPI_Type_get_extent(datatype,&ub,file_extent);
749:   return ierr;
750: }

752: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
753: {
754:   PetscDataType pdtype;
755:   PetscMPIInt   ierr;
756:   size_t        dsize;

758:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
759:   PetscDataTypeGetSize(pdtype,&dsize);

761:   /* offset is given in units of MPI_Datatype */
762:   userbuf = ((char*)userbuf) + dsize*position;

764:   PetscMemcpy(userbuf,filebuf,count*dsize);
765:   if (!PetscBinaryBigEndian()) {PetscByteSwap(userbuf,pdtype,count);}
766:   return ierr;
767: }

769: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
770: {
771:   PetscDataType pdtype;
772:   PetscMPIInt   ierr;
773:   size_t        dsize;

775:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
776:   PetscDataTypeGetSize(pdtype,&dsize);

778:   /* offset is given in units of MPI_Datatype */
779:   userbuf = ((char*)userbuf) + dsize*position;

781:   PetscMemcpy(filebuf,userbuf,count*dsize);
782:   if (!PetscBinaryBigEndian()) {PetscByteSwap(filebuf,pdtype,count);}
783:   return ierr;
784: }
785: #endif

787: PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
788: {
789:   PetscDataType  pdtype;

793:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
794:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
795:   MPI_File_write_all(fd,data,cnt,dtype,status);
796:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
797:   return(0);
798: }

800: PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
801: {
802:   PetscDataType  pdtype;

806:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
807:   MPI_File_read_all(fd,data,cnt,dtype,status);
808:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
809:   return(0);
810: }

812: PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
813: {
814:   PetscDataType  pdtype;

818:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
819:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
820:   MPI_File_write_at(fd,off,data,cnt,dtype,status);
821:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
822:   return(0);
823: }

825: PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
826: {
827:   PetscDataType  pdtype;

831:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
832:   MPI_File_read_at(fd,off,data,cnt,dtype,status);
833:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
834:   return(0);
835: }

837: PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
838: {
839:   PetscDataType  pdtype;

843:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
844:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
845:   MPI_File_write_at_all(fd,off,data,cnt,dtype,status);
846:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
847:   return(0);
848: }

850: PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
851: {
852:   PetscDataType  pdtype;

856:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
857:   MPI_File_read_at_all(fd,off,data,cnt,dtype,status);
858:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
859:   return(0);
860: }

862: #endif