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;

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

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

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

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

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

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

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

 76: /*
 77:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)

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

 86:   for (j = 0; j < n; j++) {
 87:     ptr1 = (char *)(buff + j);
 88:     for (i = 0; i < (PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64) - 1 - i];
 89:     for (i = 0; i < (PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
 90:   }
 91:   return 0;
 92: }

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

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

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

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

155: #if defined(PETSC_USE_COMPLEX)
156:   n *= 2;
157: #endif
158:   for (j = 0; j < n; j++) {
159:     ptr1 = (char *)(buff1 + j);
160:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
161:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
162:   }
163:   return 0;
164: }
165: /* --------------------------------------------------------- */
166: /*
167:   PetscByteSwapDouble - Swap bytes in a double
168: */
169: PetscErrorCode PetscByteSwapDouble(double *buff, PetscInt n)
170: {
171:   PetscInt i, j;
172:   double   tmp, *buff1 = (double *)buff;
173:   char    *ptr1, *ptr2 = (char *)&tmp;

175:   for (j = 0; j < n; j++) {
176:     ptr1 = (char *)(buff1 + j);
177:     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i];
178:     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr1[i] = ptr2[i];
179:   }
180:   return 0;
181: }

183: /*
184:   PetscByteSwapFloat - Swap bytes in a float
185: */
186: PetscErrorCode PetscByteSwapFloat(float *buff, PetscInt n)
187: {
188:   PetscInt i, j;
189:   float    tmp, *buff1 = (float *)buff;
190:   char    *ptr1, *ptr2 = (char *)&tmp;

192:   for (j = 0; j < n; j++) {
193:     ptr1 = (char *)(buff1 + j);
194:     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i];
195:     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr1[i] = ptr2[i];
196:   }
197:   return 0;
198: }

200: PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscInt count)
201: {
202:   if (pdtype == PETSC_INT) PetscByteSwapInt((PetscInt *)data, count);
203:   else if (pdtype == PETSC_ENUM) PetscByteSwapEnum((PetscEnum *)data, count);
204:   else if (pdtype == PETSC_BOOL) PetscByteSwapBool((PetscBool *)data, count);
205:   else if (pdtype == PETSC_SCALAR) PetscByteSwapScalar((PetscScalar *)data, count);
206:   else if (pdtype == PETSC_REAL) PetscByteSwapReal((PetscReal *)data, count);
207:   else if (pdtype == PETSC_COMPLEX) PetscByteSwapReal((PetscReal *)data, 2 * count);
208:   else if (pdtype == PETSC_INT64) PetscByteSwapInt64((PetscInt64 *)data, count);
209:   else if (pdtype == PETSC_DOUBLE) PetscByteSwapDouble((double *)data, count);
210:   else if (pdtype == PETSC_FLOAT) PetscByteSwapFloat((float *)data, count);
211:   else if (pdtype == PETSC_SHORT) PetscByteSwapShort((short *)data, count);
212:   else if (pdtype == PETSC_LONG) PetscByteSwapLong((long *)data, count);
213:   return 0;
214: }

216: /*@C
217:    PetscBinaryRead - Reads from a binary file.

219:    Not Collective

221:    Input Parameters:
222: +  fd - the file descriptor
223: .  num  - the maximum number of items to read
224: -  type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

226:    Output Parameters:
227: +  data - the buffer
228: -  count - the number of items read, optional

230:    Level: developer

232:    Notes:
233:    If count is not provided and the number of items read is less than
234:    the maximum number of items to read, then this routine errors.

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

243: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
244:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
245: @*/
246: PetscErrorCode PetscBinaryRead(int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
247: {
248:   size_t typesize, m = (size_t)num, n = 0, maxblock = 65536;
249:   char  *p = (char *)data;
250: #if defined(PETSC_USE_REAL___FLOAT128)
251:   PetscBool readdouble = PETSC_FALSE;
252:   double   *pdouble;
253: #endif
254:   void *ptmp  = data;
255:   char *fname = NULL;

257:   if (count) *count = 0;
259:   if (!num) return 0;

261:   if (type == PETSC_FUNCTION) {
262:     m     = 64;
263:     type  = PETSC_CHAR;
264:     fname = (char *)malloc(m * sizeof(char));
265:     p     = (char *)fname;
266:     ptmp  = (void *)fname;
268:   }
269:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);

271:   PetscDataTypeGetSize(type, &typesize);

273: #if defined(PETSC_USE_REAL___FLOAT128)
274:   PetscOptionsGetBool(NULL, NULL, "-binary_read_double", &readdouble, NULL);
275:   /* If using __float128 precision we still read in doubles from file */
276:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
277:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
278:     PetscMalloc1(cnt, &pdouble);
279:     p = (char *)pdouble;
280:     typesize /= 2;
281:   }
282: #endif

284:   m *= typesize;

286:   while (m) {
287:     size_t len = (m < maxblock) ? m : maxblock;
288:     int    ret = (int)read(fd, p, len);
289:     if (ret < 0 && errno == EINTR) continue;
290:     if (!ret && len > 0) break; /* Proxy for EOF */
292:     m -= (size_t)ret;
293:     p += ret;
294:     n += (size_t)ret;
295:   }

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

301: #if defined(PETSC_USE_REAL___FLOAT128)
302:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
303:     PetscInt   i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
304:     PetscReal *preal = (PetscReal *)data;
305:     if (!PetscBinaryBigEndian()) PetscByteSwapDouble(pdouble, cnt);
306:     for (i = 0; i < cnt; i++) preal[i] = pdouble[i];
307:     PetscFree(pdouble);
308:     return 0;
309:   }
310: #endif

312:   if (!PetscBinaryBigEndian()) PetscByteSwap(ptmp, type, num);

314:   if (type == PETSC_FUNCTION) {
315: #if defined(PETSC_SERIALIZE_FUNCTIONS)
316:     PetscDLSym(NULL, fname, (void **)data);
317: #else
318:     *(void **)data = NULL;
319: #endif
320:     free(fname);
321:   }
322:   return 0;
323: }

325: /*@C
326:    PetscBinaryWrite - Writes to a binary file.

328:    Not Collective

330:    Input Parameters:
331: +  fd     - the file
332: .  p      - the buffer
333: .  n      - the number of items to write
334: -  type   - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

336:    Level: advanced

338:    Notes:
339:    `PetscBinaryWrite()` uses byte swapping to work on all machines; the files
340:    are written using big-endian ordering to the file. On little-endian machines the numbers
341:    are converted to the big-endian format when they are written to disk.
342:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
343:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
344:    is used.

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

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

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

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

358: .seealso: `PetscBinaryRead()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscViewerBinaryGetDescriptor()`, `PetscBinarySynchronizedWrite()`,
359:           `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
360: @*/
361: PetscErrorCode PetscBinaryWrite(int fd, const void *p, PetscInt n, PetscDataType type)
362: {
363:   const char *pp = (char *)p;
364:   int         err, wsize;
365:   size_t      m = (size_t)n, maxblock = 65536;
366:   const void *ptmp  = p;
367:   char       *fname = NULL;
368: #if defined(PETSC_USE_REAL___FLOAT128)
369:   PetscBool  writedouble = PETSC_FALSE;
370:   double    *ppp;
371:   PetscReal *pv;
372:   PetscInt   i;
373: #endif
374:   PetscDataType wtype = type;

377:   if (!n) return 0;

379:   if (type == PETSC_FUNCTION) {
380: #if defined(PETSC_SERIALIZE_FUNCTIONS)
381:     const char *fnametmp;
382: #endif
383:     m     = 64;
384:     fname = (char *)malloc(m * sizeof(char));
386: #if defined(PETSC_SERIALIZE_FUNCTIONS)
388:     PetscFPTFind(*(void **)p, &fnametmp);
389:     PetscStrncpy(fname, fnametmp, m);
390: #else
391:     PetscStrncpy(fname, "", m);
392: #endif
393:     wtype = PETSC_CHAR;
394:     pp    = (char *)fname;
395:     ptmp  = (void *)fname;
396:   }

398: #if defined(PETSC_USE_REAL___FLOAT128)
399:   PetscOptionsGetBool(NULL, NULL, "-binary_write_double", &writedouble, NULL);
400:   /* If using __float128 precision we still write in doubles to file */
401:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
402:     wtype = PETSC_DOUBLE;
403:     PetscMalloc1(n, &ppp);
404:     pv = (PetscReal *)pp;
405:     for (i = 0; i < n; i++) ppp[i] = (double)pv[i];
406:     pp   = (char *)ppp;
407:     ptmp = (char *)ppp;
408:   }
409: #endif

411:   if (wtype == PETSC_INT) m *= sizeof(PetscInt);
412:   else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar);
413: #if defined(PETSC_HAVE_COMPLEX)
414:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
415: #endif
416:   else if (wtype == PETSC_REAL) m *= sizeof(PetscReal);
417:   else if (wtype == PETSC_DOUBLE) m *= sizeof(double);
418:   else if (wtype == PETSC_FLOAT) m *= sizeof(float);
419:   else if (wtype == PETSC_SHORT) m *= sizeof(short);
420:   else if (wtype == PETSC_LONG) m *= sizeof(long);
421:   else if (wtype == PETSC_CHAR) m *= sizeof(char);
422:   else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum);
423:   else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool);
424:   else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64);
425:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m) * sizeof(char);
426:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown type");

428:   if (!PetscBinaryBigEndian()) PetscByteSwap((void *)ptmp, wtype, n);

430:   while (m) {
431:     wsize = (m < maxblock) ? m : maxblock;
432:     err   = write(fd, pp, wsize);
433:     if (err < 0 && errno == EINTR) continue;
435:     m -= wsize;
436:     pp += wsize;
437:   }

439:   if (!PetscBinaryBigEndian()) PetscByteSwap((void *)ptmp, wtype, n);

441:   if (type == PETSC_FUNCTION) free(fname);
442: #if defined(PETSC_USE_REAL___FLOAT128)
443:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscFree(ppp);
444: #endif
445:   return 0;
446: }

448: /*@C
449:    PetscBinaryOpen - Opens a PETSc binary file.

451:    Not Collective

453:    Input Parameters:
454: +  name - filename
455: -  mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND``

457:    Output Parameter:
458: .  fd - the file

460:    Level: advanced

462:    Note:
463:     Files access with PetscBinaryRead()` and `PetscBinaryWrite()` are ALWAYS written in
464:    big-endian format. This means the file can be accessed using `PetscBinaryOpen()` and
465:    `PetscBinaryRead()` and `PetscBinaryWrite()` on any machine.

467: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscFileMode`, `PetscViewerFileSetMode()`, `PetscViewerBinaryGetDescriptor()`,
468:           `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
469: @*/
470: PetscErrorCode PetscBinaryOpen(const char name[], PetscFileMode mode, int *fd)
471: {
472:   switch (mode) {
473:   case FILE_MODE_READ:
474:     *fd = open(name, O_BINARY | O_RDONLY, 0);
475:     break;
476:   case FILE_MODE_WRITE:
477:     *fd = open(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
478:     break;
479:   case FILE_MODE_APPEND:
480:     *fd = open(name, O_BINARY | O_WRONLY | O_APPEND, 0);
481:     break;
482:   default:
483:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[mode]);
484:   }
486:   return 0;
487: }

489: /*@
490:    PetscBinaryClose - Closes a PETSc binary file.

492:    Not Collective

494:    Output Parameter:
495: .  fd - the file

497:    Level: advanced

499: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
500:           `PetscBinarySynchronizedSeek()`
501: @*/
502: PetscErrorCode PetscBinaryClose(int fd)
503: {
505:   return 0;
506: }

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

511:    Not Collective

513:    Input Parameters:
514: +  fd - the file
515: .  off - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
516:             etc. in your calculation rather than sizeof() to compute byte lengths.
517: -  whence - if `PETSC_BINARY_SEEK_SET` then off is an absolute location in the file
518:             if `PETSC_BINARY_SEEK_CUR` then off is an offset from the current location
519:             if `PETSC_BINARY_SEEK_END` then off is an offset from the end of file

521:    Output Parameter:
522: .   offset - new offset in file

524:    Level: developer

526:    Note:
527:    Integers are stored on the file as 32 long, regardless of whether
528:    they are stored in the machine as 32 or 64, this means the same
529:    binary file may be read on any machine. Hence you CANNOT use `sizeof()`
530:    to determine the offset or location.

532: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
533:           `PetscBinarySynchronizedSeek()`
534: @*/
535: PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
536: {
537:   int iwhence = 0;

539:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
540:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
541:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
542:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
543: #if defined(PETSC_HAVE_LSEEK)
544:   *offset = lseek(fd, off, iwhence);
545: #elif defined(PETSC_HAVE__LSEEK)
546:   *offset = _lseek(fd, (long)off, iwhence);
547: #else
548:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
549: #endif
550:   return 0;
551: }

553: /*@C
554:    PetscBinarySynchronizedRead - Reads from a binary file.

556:    Collective

558:    Input Parameters:
559: +  comm - the MPI communicator
560: .  fd - the file descriptor
561: .  num  - the maximum number of items to read
562: -  type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

564:    Output Parameters:
565: +  data - the buffer
566: -  count - the number of items read, optional

568:    Level: developer

570:    Notes:
571:    Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`

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

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

581: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedWrite()`,
582:           `PetscBinarySynchronizedSeek()`
583: @*/
584: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm, int fd, void *data, PetscInt num, PetscInt *count, PetscDataType type)
585: {
586:   PetscMPIInt  rank, size;
587:   MPI_Datatype mtype;
588:   PetscInt     ibuf[2] = {0, 0};
589:   char        *fname   = NULL;
590:   void        *fptr    = NULL;

592:   if (type == PETSC_FUNCTION) {
593:     num   = 64;
594:     type  = PETSC_CHAR;
595:     fname = (char *)malloc(num * sizeof(char));
596:     fptr  = data;
597:     data  = (void *)fname;
599:   }

601:   MPI_Comm_rank(comm, &rank);
602:   MPI_Comm_size(comm, &size);
603:   if (rank == 0) ibuf[0] = PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
604:   MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm);
605:   (PetscErrorCode)ibuf[0];

607:   /* 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 */
608:   if (size > 1) {
609:     PetscDataTypeToMPIDataType(type, &mtype);
610:     MPI_Bcast(data, count ? ibuf[1] : num, mtype, 0, comm);
611:   }
612:   if (count) *count = ibuf[1];

614:   if (type == PETSC_FUNCTION) {
615: #if defined(PETSC_SERIALIZE_FUNCTIONS)
616:     PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr);
617: #else
618:     *(void **)fptr = NULL;
619: #endif
620:     free(fname);
621:   }
622:   return 0;
623: }

625: /*@C
626:    PetscBinarySynchronizedWrite - writes to a binary file.

628:    Collective

630:    Input Parameters:
631: +  comm - the MPI communicator
632: .  fd - the file
633: .  n  - the number of items to write
634: .  p - the buffer
635: -  type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

637:    Level: developer

639:    Notes:
640:    Process 0 does a `PetscBinaryWrite()`

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

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

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

653: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
654:           `PetscBinarySynchronizedSeek()`
655: @*/
656: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
657: {
658:   PetscMPIInt rank;

660:   MPI_Comm_rank(comm, &rank);
661:   if (rank == 0) PetscBinaryWrite(fd, p, n, type);
662:   return 0;
663: }

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

668:    Input Parameters:
669: +  fd - the file
670: .  whence - if `PETSC_BINARY_SEEK_SET` then size is an absolute location in the file
671:             if `PETSC_BINARY_SEEK_CUR` then size is offset from current location
672:             if `PETSC_BINARY_SEEK_END` then size is offset from end of file
673: -  off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
674:             etc. in your calculation rather than `sizeof()` to compute byte lengths.

676:    Output Parameter:
677: .   offset - new offset in file

679:    Level: developer

681:    Note:
682:    Integers are stored on the file as 32 long, regardless of whether
683:    they are stored in the machine as 32 or 64, this means the same
684:    binary file may be read on any machine. Hence you CANNOT use `sizeof()`
685:    to determine the offset or location.

687: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
688:           `PetscBinarySynchronizedSeek()`
689: @*/
690: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
691: {
692:   PetscMPIInt rank;

694:   MPI_Comm_rank(comm, &rank);
695:   if (rank == 0) PetscBinarySeek(fd, off, whence, offset);
696:   return 0;
697: }

699: #if defined(PETSC_HAVE_MPIIO)

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

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

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

710: */
711: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state)
712: {
713:   MPI_Aint    ub;
714:   PetscMPIInt ierr;

716:   MPI_Type_get_extent(datatype, &ub, file_extent);
717:   return ierr;
718: }

720: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
721: {
722:   PetscDataType pdtype;
723:   PetscMPIInt   ierr;
724:   size_t        dsize;

726:   PetscMPIDataTypeToPetscDataType(datatype, &pdtype);
727:   PetscDataTypeGetSize(pdtype, &dsize);

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

732:   PetscMemcpy(userbuf, filebuf, count * dsize);
733:   if (!PetscBinaryBigEndian()) PetscByteSwap(userbuf, pdtype, count);
734:   return ierr;
735: }

737: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
738: {
739:   PetscDataType pdtype;
740:   PetscMPIInt   ierr;
741:   size_t        dsize;

743:   PetscMPIDataTypeToPetscDataType(datatype, &pdtype);
744:   PetscDataTypeGetSize(pdtype, &dsize);

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

749:   PetscMemcpy(filebuf, userbuf, count * dsize);
750:   if (!PetscBinaryBigEndian()) PetscByteSwap(filebuf, pdtype, count);
751:   return ierr;
752: }
753:   #endif

755: PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
756: {
757:   PetscDataType pdtype;

759:   PetscMPIDataTypeToPetscDataType(dtype, &pdtype);
760:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
761:   MPI_File_write_all(fd, data, cnt, dtype, status);
762:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
763:   return 0;
764: }

766: PetscErrorCode MPIU_File_read_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
767: {
768:   PetscDataType pdtype;

770:   PetscMPIDataTypeToPetscDataType(dtype, &pdtype);
771:   MPI_File_read_all(fd, data, cnt, dtype, status);
772:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
773:   return 0;
774: }

776: PetscErrorCode MPIU_File_write_at(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
777: {
778:   PetscDataType pdtype;

780:   PetscMPIDataTypeToPetscDataType(dtype, &pdtype);
781:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
782:   MPI_File_write_at(fd, off, data, cnt, dtype, status);
783:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
784:   return 0;
785: }

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

791:   PetscMPIDataTypeToPetscDataType(dtype, &pdtype);
792:   MPI_File_read_at(fd, off, data, cnt, dtype, status);
793:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
794:   return 0;
795: }

797: PetscErrorCode MPIU_File_write_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
798: {
799:   PetscDataType pdtype;

801:   PetscMPIDataTypeToPetscDataType(dtype, &pdtype);
802:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
803:   MPI_File_write_at_all(fd, off, data, cnt, dtype, status);
804:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
805:   return 0;
806: }

808: PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
809: {
810:   PetscDataType pdtype;

812:   PetscMPIDataTypeToPetscDataType(dtype, &pdtype);
813:   MPI_File_read_at_all(fd, off, data, cnt, dtype, status);
814:   if (!PetscBinaryBigEndian()) PetscByteSwap(data, pdtype, cnt);
815:   return 0;
816: }

818: #endif