xref: /petsc/src/sys/fileio/sysio.c (revision fbf9dbe564678ed6eff1806adbc4c4f01b9743f4)
1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
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
19 
20 const char *const PetscFileModes[] = {"READ", "WRITE", "APPEND", "UPDATE", "APPEND_UPDATE", "PetscFileMode", "PETSC_FILE_", NULL};
21 
22 /*
23   PetscByteSwapEnum - Swap bytes in a  PETSc Enum
24 
25 */
26 PetscErrorCode PetscByteSwapEnum(PetscEnum *buff, PetscInt n)
27 {
28   PetscInt  i, j;
29   PetscEnum tmp = ENUM_DUMMY;
30   char     *ptr1, *ptr2 = (char *)&tmp;
31 
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 }
40 
41 /*
42   PetscByteSwapBool - Swap bytes in a  PETSc Bool
43 
44 */
45 PetscErrorCode PetscByteSwapBool(PetscBool *buff, PetscInt n)
46 {
47   PetscInt  i, j;
48   PetscBool tmp = PETSC_FALSE;
49   char     *ptr1, *ptr2 = (char *)&tmp;
50 
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 }
59 
60 /*
61   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64-bits)
62 
63 */
64 PetscErrorCode PetscByteSwapInt(PetscInt *buff, PetscInt n)
65 {
66   PetscInt i, j, tmp = 0;
67   char    *ptr1, *ptr2 = (char *)&tmp;
68 
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 }
77 
78 /*
79   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64-bits)
80 
81 */
82 PetscErrorCode PetscByteSwapInt64(PetscInt64 *buff, PetscInt n)
83 {
84   PetscInt   i, j;
85   PetscInt64 tmp = 0;
86   char      *ptr1, *ptr2 = (char *)&tmp;
87 
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 }
96 
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;
105 
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;
122 
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 }
131 
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;
140 
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 }
149 
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;
159 
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 }
171 
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;
180 
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 }
189 
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;
198 
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 }
207 
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 }
224 
225 /*@C
226    PetscBinaryRead - Reads from a binary file.
227 
228    Not Collective
229 
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.)
234 
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
238 
239    Level: developer
240 
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.
244 
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.
251 
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;
265 
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);
270 
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);
280 
281   PetscCall(PetscDataTypeGetSize(type, &typesize));
282 
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
293 
294   m *= typesize;
295 
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 due to \"%s\"", strerror(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");
307 
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 */
310 
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
321 
322   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(ptmp, type, num));
323 
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 }
334 
335 /*@C
336    PetscBinaryWrite - Writes to a binary file.
337 
338    Not Collective
339 
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`)
345 
346    Level: advanced
347 
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.
355 
356    If running with `__float128` precision the output of `PETSC_REAL` is in `__float128` unless one uses the `-binary_write_double` option
357 
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.
361 
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.
365 
366    Because byte-swapping may be done on the values in data it cannot be declared const
367 
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;
385 
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);
389 
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   }
408 
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
421 
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");
438 
439   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));
440 
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 due to \"%s\"", (int)n, (int)err, (int)wsize, strerror(errno));
446     m -= wsize;
447     pp += wsize;
448   }
449 
450   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap((void *)ptmp, wtype, n));
451 
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 }
458 
459 /*@C
460    PetscBinaryOpen - Opens a PETSc binary file.
461 
462    Not Collective
463 
464    Input Parameters:
465 +  name - filename
466 -  mode - open mode of binary file, one of `FILE_MODE_READ`, `FILE_MODE_WRITE`, `FILE_MODE_APPEND``
467 
468    Output Parameter:
469 .  fd - the file
470 
471    Level: advanced
472 
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 due to \"%s\"", name, PetscFileModes[mode], strerror(errno));
493   PetscFunctionReturn(PETSC_SUCCESS);
494 }
495 
496 /*@
497    PetscBinaryClose - Closes a PETSc binary file.
498 
499    Not Collective
500 
501    Output Parameter:
502 .  fd - the file
503 
504    Level: advanced
505 
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 }
515 
516 /*@C
517    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
518 
519    Not Collective
520 
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
526 
527    Output Parameter:
528 .   offset - new offset in file
529 
530    Level: developer
531 
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;
538 
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 }
553 
554 /*@C
555    PetscBinarySynchronizedRead - Reads from a binary file, all MPI processes get the same values
556 
557    Collective
558 
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.)
564 
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
568 
569    Level: developer
570 
571    Notes:
572    Does a `PetscBinaryRead()` followed by an `MPI_Bcast()`
573 
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.
576 
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.
583 
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;
594 
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   }
604 
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]);
610 
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];
617 
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 }
628 
629 /*@C
630    PetscBinarySynchronizedWrite - writes to a binary file.
631 
632    Collective
633 
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`)
640 
641    Level: developer
642 
643    Notes:
644    MPI rank 0 does a `PetscBinaryWrite()` the values on other MPI processes are not used
645 
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.
651 
652    Because byte-swapping may be done on the values in data it cannot be declared const
653 
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.
657 
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;
664 
665   PetscFunctionBegin;
666   PetscCallMPI(MPI_Comm_rank(comm, &rank));
667   if (rank == 0) PetscCall(PetscBinaryWrite(fd, p, n, type));
668   PetscFunctionReturn(PETSC_SUCCESS);
669 }
670 
671 /*@C
672    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
673 
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.
679 
680    Output Parameter:
681 .   offset - new offset in file
682 
683    Level: developer
684 
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;
691 
692   PetscFunctionBegin;
693   PetscCallMPI(MPI_Comm_rank(comm, &rank));
694   if (rank == 0) PetscCall(PetscBinarySeek(fd, off, whence, offset));
695   PetscFunctionReturn(PETSC_SUCCESS);
696 }
697 
698 #if defined(PETSC_HAVE_MPIIO)
699 
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()
704 
705     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
706 
707     The next three routines are not used because MPICH does not support their use
708 
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;
714 
715   ierr = MPI_Type_get_extent(datatype, &ub, file_extent);
716   return ierr;
717 }
718 
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;
724 
725   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
726   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
727 
728   /* offset is given in units of MPI_Datatype */
729   userbuf = ((char *)userbuf) + dsize * position;
730 
731   PetscCall(PetscMemcpy(userbuf, filebuf, count * dsize));
732   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(userbuf, pdtype, count));
733   return ierr;
734 }
735 
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;
741 
742   PetscCall(PetscMPIDataTypeToPetscDataType(datatype, &pdtype));
743   PetscCall(PetscDataTypeGetSize(pdtype, &dsize));
744 
745   /* offset is given in units of MPI_Datatype */
746   userbuf = ((char *)userbuf) + dsize * position;
747 
748   PetscCall(PetscMemcpy(filebuf, userbuf, count * dsize));
749   if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(filebuf, pdtype, count));
750   return ierr;
751 }
752   #endif
753 
754 PetscErrorCode MPIU_File_write_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
755 {
756   PetscDataType pdtype;
757 
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 }
765 
766 PetscErrorCode MPIU_File_read_all(MPI_File fd, void *data, PetscMPIInt cnt, MPI_Datatype dtype, MPI_Status *status)
767 {
768   PetscDataType pdtype;
769 
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 }
776 
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;
780 
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 }
788 
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;
792 
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 }
799 
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;
803 
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 }
811 
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;
815 
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 }
822 
823 #endif
824