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:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

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

 32:   PetscFunctionBegin;
 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:   PetscFunctionReturn(PETSC_SUCCESS);
 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:   PetscFunctionBegin;
 52:   for (j = 0; j < n; j++) {
 53:     ptr1 = (char *)(buff + j);
 54:     for (i = 0; i < (PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool) - 1 - i];
 55:     for (i = 0; i < (PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
 56:   }
 57:   PetscFunctionReturn(PETSC_SUCCESS);
 58: }

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

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

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

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

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

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

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

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

123:   PetscFunctionBegin;
124:   for (j = 0; j < n; j++) {
125:     ptr1 = (char *)(buff + j);
126:     for (i = 0; i < (PetscInt)sizeof(long); i++) ptr2[i] = ptr1[sizeof(long) - 1 - i];
127:     for (i = 0; i < (PetscInt)sizeof(long); i++) ptr1[i] = ptr2[i];
128:   }
129:   PetscFunctionReturn(PETSC_SUCCESS);
130: }

132: /*
133:   PetscByteSwapReal - Swap bytes in a PetscReal
134: */
135: PetscErrorCode PetscByteSwapReal(PetscReal *buff, PetscInt n)
136: {
137:   PetscInt  i, j;
138:   PetscReal tmp, *buff1 = (PetscReal *)buff;
139:   char     *ptr1, *ptr2 = (char *)&tmp;

141:   PetscFunctionBegin;
142:   for (j = 0; j < n; j++) {
143:     ptr1 = (char *)(buff1 + j);
144:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
145:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
146:   }
147:   PetscFunctionReturn(PETSC_SUCCESS);
148: }

150: /*
151:   PetscByteSwapScalar - Swap bytes in a PetscScalar
152:   The complex case is dealt with with an array of PetscReal, twice as long.
153: */
154: PetscErrorCode PetscByteSwapScalar(PetscScalar *buff, PetscInt n)
155: {
156:   PetscInt  i, j;
157:   PetscReal tmp, *buff1 = (PetscReal *)buff;
158:   char     *ptr1, *ptr2 = (char *)&tmp;

160:   PetscFunctionBegin;
161: #if defined(PETSC_USE_COMPLEX)
162:   n *= 2;
163: #endif
164:   for (j = 0; j < n; j++) {
165:     ptr1 = (char *)(buff1 + j);
166:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal) - 1 - i];
167:     for (i = 0; i < (PetscInt)sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
168:   }
169:   PetscFunctionReturn(PETSC_SUCCESS);
170: }

172: /*
173:   PetscByteSwapDouble - Swap bytes in a double
174: */
175: PetscErrorCode PetscByteSwapDouble(double *buff, PetscInt n)
176: {
177:   PetscInt i, j;
178:   double   tmp, *buff1 = (double *)buff;
179:   char    *ptr1, *ptr2 = (char *)&tmp;

181:   PetscFunctionBegin;
182:   for (j = 0; j < n; j++) {
183:     ptr1 = (char *)(buff1 + j);
184:     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr2[i] = ptr1[sizeof(double) - 1 - i];
185:     for (i = 0; i < (PetscInt)sizeof(double); i++) ptr1[i] = ptr2[i];
186:   }
187:   PetscFunctionReturn(PETSC_SUCCESS);
188: }

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

199:   PetscFunctionBegin;
200:   for (j = 0; j < n; j++) {
201:     ptr1 = (char *)(buff1 + j);
202:     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr2[i] = ptr1[sizeof(float) - 1 - i];
203:     for (i = 0; i < (PetscInt)sizeof(float); i++) ptr1[i] = ptr2[i];
204:   }
205:   PetscFunctionReturn(PETSC_SUCCESS);
206: }

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

225: /*@C
226:    PetscBinaryRead - Reads from a binary file.

228:    Not Collective

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

235:    Output Parameters:
236: +  data - the buffer, this is an array of the type that matches the value in `type`
237: -  count - the number of items read, optional

239:    Level: developer

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

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

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

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

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

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

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

294:   m *= typesize;

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

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

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

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

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

335: /*@C
336:    PetscBinaryWrite - Writes to a binary file.

338:    Not Collective

340:    Input Parameters:
341: +  fd     - the file
342: .  p      - the buffer, an array of the type that matches the value in `type`
343: .  n      - the number of items to write
344: -  type   - the type of items to read (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

346:    Level: advanced

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

356:    If running with `__float128` precision the output of `PETSC_REAL` is in `__float128` unless one uses the `-binary_write_double` option

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

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

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

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

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

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

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

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

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

441:   while (m) {
442:     wsize = (m < maxblock) ? m : maxblock;
443:     err   = write(fd, pp, wsize);
444:     if (err < 0 && errno == EINTR) continue;
445:     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);
446:     m -= wsize;
447:     pp += wsize;
448:   }

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

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

459: /*@C
460:    PetscBinaryOpen - Opens a PETSc binary file.

462:    Not Collective

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

468:    Output Parameter:
469: .  fd - the file

471:    Level: advanced

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

496: /*@
497:    PetscBinaryClose - Closes a PETSc binary file.

499:    Not Collective

501:    Output Parameter:
502: .  fd - the file

504:    Level: advanced

506: .seealso: `PetscBinaryRead()`, `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinarySynchronizedWrite()`, `PetscBinarySynchronizedRead()`,
507:           `PetscBinarySynchronizedSeek()`
508: @*/
509: PetscErrorCode PetscBinaryClose(int fd)
510: {
511:   PetscFunctionBegin;
512:   PetscCheck(!close(fd), PETSC_COMM_SELF, PETSC_ERR_SYS, "close() failed on file descriptor");
513:   PetscFunctionReturn(PETSC_SUCCESS);
514: }

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

519:    Not Collective

521:    Input Parameters:
522: +  fd - the file
523: .  off - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
524:             etc. in your calculation rather than `sizeof()` to compute byte lengths.
525: -  whence - see `PetscBinarySeekType` for possible values

527:    Output Parameter:
528: .   offset - new offset in file

530:    Level: developer

532: .seealso: `PetscBinaryRead()`, `PetscBinarySeekType`, `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:   PetscFunctionBegin;
540:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
541:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
542:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
543:   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Unknown seek location");
544: #if defined(PETSC_HAVE_LSEEK)
545:   *offset = lseek(fd, off, iwhence);
546: #elif defined(PETSC_HAVE__LSEEK)
547:   *offset = _lseek(fd, (long)off, iwhence);
548: #else
549:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "System does not have a way of seeking on a file");
550: #endif
551:   PetscFunctionReturn(PETSC_SUCCESS);
552: }

554: /*@C
555:    PetscBinarySynchronizedRead - Reads from a binary file, all MPI processes get the same values

557:    Collective

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

565:    Output Parameters:
566: +  data - the buffer, an array of the type that matches the value in `type`
567: -  count - the number of items read, optional

569:    Level: developer

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

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

577:    `PetscBinarySynchronizedRead()` uses byte swapping to work on all machines.
578:    The files  are written using big-endian ordering to the file. On little-endian machines the numbers
579:    are converted to the big-endian format when they are written to disk.
580:    When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
581:    file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
582:    is used.

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

595:   PetscFunctionBegin;
596:   if (type == PETSC_FUNCTION) {
597:     num   = 64;
598:     type  = PETSC_CHAR;
599:     fname = (char *)malloc(num * sizeof(char));
600:     fptr  = data;
601:     data  = (void *)fname;
602:     PetscCheck(fname, PETSC_COMM_SELF, PETSC_ERR_MEM, "Cannot allocate space for function name");
603:   }

605:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
606:   PetscCallMPI(MPI_Comm_size(comm, &size));
607:   if (rank == 0) ibuf[0] = PetscBinaryRead(fd, data, num, count ? &ibuf[1] : NULL, type);
608:   PetscCallMPI(MPI_Bcast(ibuf, 2, MPIU_INT, 0, comm));
609:   PetscCall((PetscErrorCode)ibuf[0]);

611:   /* 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 */
612:   if (size > 1) {
613:     PetscCall(PetscDataTypeToMPIDataType(type, &mtype));
614:     PetscCallMPI(MPI_Bcast(data, count ? ibuf[1] : num, mtype, 0, comm));
615:   }
616:   if (count) *count = ibuf[1];

618:   if (type == PETSC_FUNCTION) {
619: #if defined(PETSC_SERIALIZE_FUNCTIONS)
620:     PetscCall(PetscDLLibrarySym(PETSC_COMM_SELF, &PetscDLLibrariesLoaded, NULL, fname, (void **)fptr));
621: #else
622:     *(void **)fptr = NULL;
623: #endif
624:     free(fname);
625:   }
626:   PetscFunctionReturn(PETSC_SUCCESS);
627: }

629: /*@C
630:    PetscBinarySynchronizedWrite - writes to a binary file.

632:    Collective

634:    Input Parameters:
635: +  comm - the MPI communicator
636: .  fd - the file
637: .  n  - the number of items to write
638: .  p - the buffer, an array of the type that matches the value in `type`
639: -  type - the type of items to write (`PETSC_INT`, `PETSC_REAL` or `PETSC_SCALAR`)

641:    Level: developer

643:    Notes:
644:    MPI rank 0 does a `PetscBinaryWrite()` the values on other MPI processes are not used

646:    The files  are written using big-endian ordering to the file. On little-endian machines the numbers
647:    are converted to the big-endian format when they are written to disk.
648:    When PETSc is configured using `./configure with --with-64-bit-indices` the integers are written to the
649:    file as 64-bit integers, this means they can only be read back in when the option `--with-64-bit-indices`
650:    is used.

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

654:    WARNING:
655:    This is NOT like `PetscSynchronizedFPrintf()`! This routine ignores calls on all but MPI rank 0,
656:    while `PetscSynchronizedFPrintf()` has all MPI processes print their strings in order.

658: .seealso: `PetscBinaryWrite()`, `PetscBinaryOpen()`, `PetscBinaryClose()`, `PetscBinaryRead()`, `PetscBinarySynchronizedRead()`,
659:           `PetscBinarySynchronizedSeek()`
660: @*/
661: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm, int fd, const void *p, PetscInt n, PetscDataType type)
662: {
663:   PetscMPIInt rank;

665:   PetscFunctionBegin;
666:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
667:   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
668:   PetscFunctionReturn(PETSC_SUCCESS);
669: }

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

674:    Input Parameters:
675: +  fd - the file
676: .  whence -  see `PetscBinarySeekType` for possible values
677: -  off    - number of bytes to move. Use `PETSC_BINARY_INT_SIZE`, `PETSC_BINARY_SCALAR_SIZE`,
678:             etc. in your calculation rather than `sizeof()` to compute byte lengths.

680:    Output Parameter:
681: .   offset - new offset in file

683:    Level: developer

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

692:   PetscFunctionBegin;
693:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
694:   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
695:   PetscFunctionReturn(PETSC_SUCCESS);
696: }

698: #if defined(PETSC_HAVE_MPIIO)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

758:   PetscFunctionBegin;
759:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
760:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
761:   PetscCallMPI(MPI_File_write_all(fd, data, cnt, dtype, status));
762:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
763:   PetscFunctionReturn(PETSC_SUCCESS);
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:   PetscFunctionBegin;
771:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
772:   PetscCallMPI(MPI_File_read_all(fd, data, cnt, dtype, status));
773:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
774:   PetscFunctionReturn(PETSC_SUCCESS);
775: }

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

781:   PetscFunctionBegin;
782:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
783:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
784:   PetscCallMPI(MPI_File_write_at(fd, off, data, cnt, dtype, status));
785:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
786:   PetscFunctionReturn(PETSC_SUCCESS);
787: }

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

793:   PetscFunctionBegin;
794:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
795:   PetscCallMPI(MPI_File_read_at(fd, off, data, cnt, dtype, status));
796:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
797:   PetscFunctionReturn(PETSC_SUCCESS);
798: }

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

804:   PetscFunctionBegin;
805:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
806:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
807:   PetscCallMPI(MPI_File_write_at_all(fd, off, data, cnt, dtype, status));
808:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
809:   PetscFunctionReturn(PETSC_SUCCESS);
810: }

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

816:   PetscFunctionBegin;
817:   PetscCall(PetscMPIDataTypeToPetscDataType(dtype, &pdtype));
818:   PetscCallMPI(MPI_File_read_at_all(fd, off, data, cnt, dtype, status));
819:   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(data, pdtype, cnt));
820:   PetscFunctionReturn(PETSC_SUCCESS);
821: }

823: #endif