Actual source code: sysio.c

petsc-master 2020-08-10
Report Typos and Errors

  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


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

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

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

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

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

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

447:   while (m) {
448:     wsize = (m < maxblock) ? m : maxblock;
449:     err   = write(fd,pp,wsize);
450:     if (err < 0 && errno == EINTR) continue;
451:     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);
452:     m  -= wsize;
453:     pp += wsize;
454:   }

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

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

469: /*@C
470:    PetscBinaryOpen - Opens a PETSc binary file.

472:    Not Collective

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

478:    Output Parameter:
479: .  fd - the file

481:    Level: advanced


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

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

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

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

509:    Not Collective

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

514:    Level: advanced

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


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.


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

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

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

577:    Collective

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

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

589:    Level: developer

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

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

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


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

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

625:   MPI_Comm_rank(comm,&rank);
626:   if (!rank) {
627:     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
628:   }
629:   MPI_Bcast(ibuf,2,MPIU_INT,0,comm);
630:   (PetscErrorCode)ibuf[0];
631:   PetscDataTypeToMPIDataType(type,&mtype);
632:   MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);
633:   if (count) *count = ibuf[1];

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

646: /*@C
647:    PetscBinarySynchronizedWrite - writes to a binary file.

649:    Collective

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

658:    Level: developer

660:    Notes:
661:    Process 0 does a PetscBinaryWrite()

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

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

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


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

684:   MPI_Comm_rank(comm,&rank);
685:   if (!rank) {
686:     PetscBinaryWrite(fd,p,n,type);
687:   }
688:   return(0);
689: }

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


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

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

706:    Level: developer

708:    Notes:
709:    Integers are stored on the file as 32 long, regardless of whether
710:    they are stored in the machine as 32 or 64, this means the same
711:    binary file may be read on any machine. Hence you CANNOT use sizeof()
712:    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) {
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;


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

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

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

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


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

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

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

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


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

853: PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
854: {
855:   PetscDataType  pdtype;

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

865: #endif