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:   PetscFunctionBegin;
 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:   PetscFunctionReturn(PETSC_SUCCESS);
 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;

 52:   PetscFunctionBegin;
 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:   PetscFunctionReturn(PETSC_SUCCESS);
 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;

 70:   PetscFunctionBegin;
 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:   PetscFunctionReturn(PETSC_SUCCESS);
 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;

 89:   PetscFunctionBegin;
 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:   PetscFunctionReturn(PETSC_SUCCESS);
 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;

108:   PetscFunctionBegin;
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:   PetscFunctionReturn(PETSC_SUCCESS);
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;

125:   PetscFunctionBegin;
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:   PetscFunctionReturn(PETSC_SUCCESS);
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;

143:   PetscFunctionBegin;
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:   PetscFunctionReturn(PETSC_SUCCESS);
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;

162:   PetscFunctionBegin;
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:   PetscFunctionReturn(PETSC_SUCCESS);
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;

183:   PetscFunctionBegin;
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:   PetscFunctionReturn(PETSC_SUCCESS);
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;

201:   PetscFunctionBegin;
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:   PetscFunctionReturn(PETSC_SUCCESS);
208: }

210: PetscErrorCode PetscByteSwap(void *data, PetscDataType pdtype, PetscInt count)
211: {
212:   PetscFunctionBegin;
213:   if (pdtype == PETSC_INT) PetscCall(PetscByteSwapInt((PetscInt *)data, count));
214:   else if (pdtype == PETSC_ENUM) PetscCall(PetscByteSwapEnum((PetscEnum *)data, count));
215:   else if (pdtype == PETSC_BOOL) PetscCall(PetscByteSwapBool((PetscBool *)data, count));
216:   else if (pdtype == PETSC_SCALAR) PetscCall(PetscByteSwapScalar((PetscScalar *)data, count));
217:   else if (pdtype == PETSC_REAL) PetscCall(PetscByteSwapReal((PetscReal *)data, count));
218:   else if (pdtype == PETSC_COMPLEX) PetscCall(PetscByteSwapReal((PetscReal *)data, 2 * count));
219:   else if (pdtype == PETSC_INT64) PetscCall(PetscByteSwapInt64((PetscInt64 *)data, count));
220:   else if (pdtype == PETSC_DOUBLE) PetscCall(PetscByteSwapDouble((double *)data, count));
221:   else if (pdtype == PETSC_FLOAT) PetscCall(PetscByteSwapFloat((float *)data, count));
222:   else if (pdtype == PETSC_SHORT) PetscCall(PetscByteSwapShort((short *)data, count));
223:   else if (pdtype == PETSC_LONG) PetscCall(PetscByteSwapLong((long *)data, count));
224:   PetscFunctionReturn(PETSC_SUCCESS);
225: }

227: /*@C
228:    PetscBinaryRead - Reads from a binary file.

230:    Not Collective

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

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

241:    Level: developer

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

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

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

268:   PetscFunctionBegin;
269:   if (count) *count = 0;
270:   PetscCheck(num >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to read a negative amount of data %" PetscInt_FMT, num);
271:   if (!num) PetscFunctionReturn(PETSC_SUCCESS);

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

283:   PetscCall(PetscDataTypeGetSize(type, &typesize));

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

296:   m *= typesize;

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

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

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

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

326:   if (type == PETSC_FUNCTION) {
327: #if defined(PETSC_SERIALIZE_FUNCTIONS)
328:     PetscCall(PetscDLSym(NULL, fname, (void **)data));
329: #else
330:     *(void **)data = NULL;
331: #endif
332:     free(fname);
333:   }
334:   PetscFunctionReturn(PETSC_SUCCESS);
335: }

337: /*@C
338:    PetscBinaryWrite - Writes to a binary file.

340:    Not Collective

342:    Input Parameters:
343: +  fd     - the file
344: .  p      - the buffer
345: .  n      - the number of items to write
346: -  type   - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

348:    Level: advanced

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

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

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

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

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

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

388:   PetscFunctionBegin;
389:   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to write a negative amount of data %" PetscInt_FMT, n);
390:   if (!n) PetscFunctionReturn(PETSC_SUCCESS);

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

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

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

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

443:   while (m) {
444:     wsize = (m < maxblock) ? m : maxblock;
445:     err   = write(fd, pp, wsize);
446:     if (err < 0 && errno == EINTR) continue;
447:     PetscCheck(err == wsize, PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE, "Error writing to file total size %d err %d wsize %d", (int)n, (int)err, (int)wsize);
448:     m -= wsize;
449:     pp += wsize;
450:   }

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

454:   if (type == PETSC_FUNCTION) free(fname);
455: #if defined(PETSC_USE_REAL___FLOAT128)
456:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) PetscCall(PetscFree(ppp));
457: #endif
458:   PetscFunctionReturn(PETSC_SUCCESS);
459: }

461: /*@C
462:    PetscBinaryOpen - Opens a PETSc binary file.

464:    Not Collective

466:    Input Parameters:
467: +  name - filename
468: -  mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND``

470:    Output Parameter:
471: .  fd - the file

473:    Level: advanced

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

480: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscFileMode`, `PetscViewerFileSetMode()`, `PetscViewerBinaryGetDescriptor()`,
481:           `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`, `PetscBinarySynchronizedSeek()`
482: @*/
483: PetscErrorCode PetscBinaryOpen(const char name[], PetscFileMode mode, int *fd)
484: {
485:   PetscFunctionBegin;
486:   switch (mode) {
487:   case FILE_MODE_READ:
488:     *fd = open(name, O_BINARY | O_RDONLY, 0);
489:     break;
490:   case FILE_MODE_WRITE:
491:     *fd = open(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
492:     break;
493:   case FILE_MODE_APPEND:
494:     *fd = open(name, O_BINARY | O_WRONLY | O_APPEND, 0);
495:     break;
496:   default:
497:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[mode]);
498:   }
499:   PetscCheck(*fd != -1, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open file %s for %s", name, PetscFileModes[mode]);
500:   PetscFunctionReturn(PETSC_SUCCESS);
501: }

503: /*@
504:    PetscBinaryClose - Closes a PETSc binary file.

506:    Not Collective

508:    Output Parameter:
509: .  fd - the file

511:    Level: advanced

513: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
514:           `PetscBinarySynchronizedSeek()`
515: @*/
516: PetscErrorCode PetscBinaryClose(int fd)
517: {
518:   PetscFunctionBegin;
519:   PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor");
520:   PetscFunctionReturn(PETSC_SUCCESS);
521: }

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

526:    Not Collective

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

536:    Output Parameter:
537: .   offset - new offset in file

539:    Level: developer

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

547: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
548:           `PetscBinarySynchronizedSeek()`
549: @*/
550: PetscErrorCode PetscBinarySeek(int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
551: {
552:   int iwhence = 0;

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

569: /*@C
570:    PetscBinarySynchronizedRead - Reads from a binary file.

572:    Collective

574:    Input Parameters:
575: +  comm - the MPI communicator
576: .  fd - the file descriptor
577: .  num  - the maximum number of items to read
578: -  type - the type of items to read (`PETSC_INT`, `PETSC_REAL`, `PETSC_SCALAR`, etc.)

580:    Output Parameters:
581: +  data - the buffer
582: -  count - the number of items read, optional

584:    Level: developer

586:    Notes:
587:    Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`

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

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

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

608:   PetscFunctionBegin;
609:   if (type == PETSC_FUNCTION) {
610:     num   = 64;
611:     type  = PETSC_CHAR;
612:     fname = (char *)malloc(num * sizeof(char));
613:     fptr  = data;
614:     data  = (void *)fname;
615:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
616:   }

618:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
619:   PetscCallMPI(MPI_Comm_size(comm, &size));
620:   if (rank == 0) ibuf[0] = PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
621:   PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
622:   PetscCall((PetscErrorCode)ibuf[0]);

624:   /* 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 */
625:   if (size > 1) {
626:     PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
627:     PetscCallMPI(MPI_Bcast(data, count ? ibuf[1] : num, mtype, 0, comm));
628:   }
629:   if (count) *count = ibuf[1];

631:   if (type == PETSC_FUNCTION) {
632: #if defined(PETSC_SERIALIZE_FUNCTIONS)
633:     PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
634: #else
635:     *(void **)fptr = NULL;
636: #endif
637:     free(fname);
638:   }
639:   PetscFunctionReturn(PETSC_SUCCESS);
640: }

642: /*@C
643:    PetscBinarySynchronizedWrite - writes to a binary file.

645:    Collective

647:    Input Parameters:
648: +  comm - the MPI communicator
649: .  fd - the file
650: .  n  - the number of items to write
651: .  p - the buffer
652: -  type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

654:    Level: developer

656:    Notes:
657:    Process 0 does a `PetscBinaryWrite()`

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

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

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

670: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
671:           `PetscBinarySynchronizedSeek()`
672: @*/
673: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
674: {
675:   PetscMPIInt rank;

677:   PetscFunctionBegin;
678:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
679:   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
680:   PetscFunctionReturn(PETSC_SUCCESS);
681: }

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

686:    Input Parameters:
687: +  fd - the file
688: .  whence - if `PETSC_BINARY_SEEK_SET` then size is an absolute location in the file
689:             if `PETSC_BINARY_SEEK_CUR` then size is offset from current location
690:             if `PETSC_BINARY_SEEK_END` then size is offset from end of file
691: -  off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
692:             etc. in your calculation rather than `sizeof()` to compute byte lengths.

694:    Output Parameter:
695: .   offset - new offset in file

697:    Level: developer

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

705: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
706:           `PetscBinarySynchronizedSeek()`
707: @*/
708: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm, int fd, off_t off, PetscBinarySeekType whence, off_t *offset)
709: {
710:   PetscMPIInt rank;

712:   PetscFunctionBegin;
713:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
714:   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
715:   PetscFunctionReturn(PETSC_SUCCESS);
716: }

718: #if defined(PETSC_HAVE_MPIIO)

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

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

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

729: */
730: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype, MPI_Aint *file_extent, void *extra_state)
731: {
732:   MPI_Aint    ub;
733:   PetscMPIInt ierr;

735:   ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
736:   return ierr;
737: }

739: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
740: {
741:   PetscDataType pdtype;
742:   PetscMPIInt   ierr;
743:   size_t        dsize;

745:   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
746:   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));

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

751:   PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
752:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
753:   return ierr;
754: }

756: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype, PetscMPIInt count, void *filebuf, MPI_Offset position, void *extra_state)
757: {
758:   PetscDataType pdtype;
759:   PetscMPIInt   ierr;
760:   size_t        dsize;

762:   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
763:   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));

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

768:   PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
769:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
770:   return ierr;
771: }
772:   #endif

774: PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
775: {
776:   PetscDataType pdtype;

778:   PetscFunctionBegin;
779:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
780:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
781:   PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
782:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
783:   PetscFunctionReturn(PETSC_SUCCESS);
784: }

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

790:   PetscFunctionBegin;
791:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
792:   PetscCallMPI(MPI_File_read_all(fd, data, cnt, dtype, status));
793:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
794:   PetscFunctionReturn(PETSC_SUCCESS);
795: }

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

801:   PetscFunctionBegin;
802:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
803:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
804:   PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
805:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
806:   PetscFunctionReturn(PETSC_SUCCESS);
807: }

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

813:   PetscFunctionBegin;
814:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
815:   PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
816:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
817:   PetscFunctionReturn(PETSC_SUCCESS);
818: }

820: PetscErrorCode MPIU_File_write_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
821: {
822:   PetscDataType pdtype;

824:   PetscFunctionBegin;
825:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
826:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
827:   PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
828:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
829:   PetscFunctionReturn(PETSC_SUCCESS);
830: }

832: PetscErrorCode MPIU_File_read_at_all(MPI_File fd, MPI_Offset off, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
833: {
834:   PetscDataType pdtype;

836:   PetscFunctionBegin;
837:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
838:   PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
839:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
840:   PetscFunctionReturn(PETSC_SUCCESS);
841: }

843: #endif