xref: /petsc/src/sys/fileio/sysio.c (revision c094ef4021e955ef5f85f7d8a1bbc6ed64ba7621)
1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
6 #include <petscsys.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #if defined(PETSC_HAVE_UNISTD_H)
10 #include <unistd.h>
11 #endif
12 #if defined(PETSC_HAVE_IO_H)
13 #include <io.h>
14 #endif
15 #include <petscbt.h>
16 
17 const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",0};
18 
19 /* --------------------------------------------------------- */
20 #undef __FUNCT__
21 #define __FUNCT__ "PetscByteSwapEnum"
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(0);
39 }
40 
41 #undef __FUNCT__
42 #define __FUNCT__ "PetscByteSwapBool"
43 /*
44   PetscByteSwapBool - Swap bytes in a  PETSc Bool
45 
46 */
47 PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
48 {
49   PetscInt  i,j;
50   PetscBool tmp = PETSC_FALSE;
51   char      *ptr1,*ptr2 = (char*)&tmp;
52 
53   PetscFunctionBegin;
54   for (j=0; j<n; j++) {
55     ptr1 = (char*)(buff + j);
56     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
57     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
58   }
59   PetscFunctionReturn(0);
60 }
61 
62 #undef __FUNCT__
63 #define __FUNCT__ "PetscByteSwapInt"
64 /*
65   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)
66 
67 */
68 PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
69 {
70   PetscInt i,j,tmp = 0;
71   char     *ptr1,*ptr2 = (char*)&tmp;
72 
73   PetscFunctionBegin;
74   for (j=0; j<n; j++) {
75     ptr1 = (char*)(buff + j);
76     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
77     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
78   }
79   PetscFunctionReturn(0);
80 }
81 /* --------------------------------------------------------- */
82 #undef __FUNCT__
83 #define __FUNCT__ "PetscByteSwapShort"
84 /*
85   PetscByteSwapShort - Swap bytes in a short
86 */
87 PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
88 {
89   PetscInt i,j;
90   short    tmp;
91   char     *ptr1,*ptr2 = (char*)&tmp;
92 
93   PetscFunctionBegin;
94   for (j=0; j<n; j++) {
95     ptr1 = (char*)(buff + j);
96     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
97     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
98   }
99   PetscFunctionReturn(0);
100 }
101 /* --------------------------------------------------------- */
102 #undef __FUNCT__
103 #define __FUNCT__ "PetscByteSwapScalar"
104 /*
105   PetscByteSwapScalar - Swap bytes in a double
106   Complex is dealt with as if array of double twice as long.
107 */
108 PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
109 {
110   PetscInt  i,j;
111   PetscReal tmp,*buff1 = (PetscReal*)buff;
112   char      *ptr1,*ptr2 = (char*)&tmp;
113 
114   PetscFunctionBegin;
115 #if defined(PETSC_USE_COMPLEX)
116   n *= 2;
117 #endif
118   for (j=0; j<n; j++) {
119     ptr1 = (char*)(buff1 + j);
120     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
121     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
122   }
123   PetscFunctionReturn(0);
124 }
125 /* --------------------------------------------------------- */
126 #undef __FUNCT__
127 #define __FUNCT__ "PetscByteSwapDouble"
128 /*
129   PetscByteSwapDouble - Swap bytes in a double
130 */
131 PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
132 {
133   PetscInt i,j;
134   double   tmp,*buff1 = (double*)buff;
135   char     *ptr1,*ptr2 = (char*)&tmp;
136 
137   PetscFunctionBegin;
138   for (j=0; j<n; j++) {
139     ptr1 = (char*)(buff1 + j);
140     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
141     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
142   }
143   PetscFunctionReturn(0);
144 }
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "PetscByteSwapFloat"
148 /*
149   PetscByteSwapFloat - Swap bytes in a float
150 */
151 PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
152 {
153   PetscInt i,j;
154   float    tmp,*buff1 = (float*)buff;
155   char     *ptr1,*ptr2 = (char*)&tmp;
156 
157   PetscFunctionBegin;
158   for (j=0; j<n; j++) {
159     ptr1 = (char*)(buff1 + j);
160     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
161     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
162   }
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "PetscByteSwap"
168 PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
169 {
170   PetscErrorCode ierr;
171 
172   PetscFunctionBegin;
173   if      (pdtype == PETSC_INT)    {ierr = PetscByteSwapInt((PetscInt*)data,count);CHKERRQ(ierr);}
174   else if (pdtype == PETSC_ENUM)   {ierr = PetscByteSwapEnum((PetscEnum*)data,count);CHKERRQ(ierr);}
175   else if (pdtype == PETSC_BOOL)   {ierr = PetscByteSwapBool((PetscBool*)data,count);CHKERRQ(ierr);}
176   else if (pdtype == PETSC_SCALAR) {ierr = PetscByteSwapScalar((PetscScalar*)data,count);CHKERRQ(ierr);}
177   else if (pdtype == PETSC_DOUBLE) {ierr = PetscByteSwapDouble((double*)data,count);CHKERRQ(ierr);}
178   else if (pdtype == PETSC_FLOAT)  {ierr = PetscByteSwapFloat((float*)data,count);CHKERRQ(ierr);}
179   else if (pdtype == PETSC_SHORT)  {ierr = PetscByteSwapShort((short*)data,count);CHKERRQ(ierr);}
180   PetscFunctionReturn(0);
181 }
182 
183 /* --------------------------------------------------------- */
184 #undef __FUNCT__
185 #define __FUNCT__ "PetscBinaryRead"
186 /*@
187    PetscBinaryRead - Reads from a binary file.
188 
189    Not Collective
190 
191    Input Parameters:
192 +  fd - the file
193 .  n  - the number of items to read
194 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
195 
196    Output Parameters:
197 .  p - the buffer
198 
199 
200 
201    Level: developer
202 
203    Notes:
204    PetscBinaryRead() uses byte swapping to work on all machines; the files
205    are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
206    are converted to the small-endian format when they are read in from the file.
207    When PETSc is ./configure with --with-64bit-indices the integers are written to the
208    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
209    is used.
210 
211    Concepts: files^reading binary
212    Concepts: binary files^reading
213 
214 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
215           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
216 @*/
217 PetscErrorCode  PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
218 {
219   int               wsize,err;
220   size_t            m = (size_t) n,maxblock = 65536;
221   char              *pp = (char*)p;
222 #if defined(PETSC_USE_REAL___FLOAT128)
223   PetscBool         readdouble = PETSC_FALSE;
224   double            *ppp;
225 #endif
226 #if !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_REAL___FLOAT128)
227   PetscErrorCode    ierr;
228 #endif
229 #if !defined(PETSC_WORDS_BIGENDIAN)
230   void              *ptmp = p;
231 #endif
232   char              *fname = NULL;
233 
234   PetscFunctionBegin;
235   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
236   if (!n) PetscFunctionReturn(0);
237 
238   if (type == PETSC_FUNCTION) {
239     m            = 64;
240     type         = PETSC_CHAR;
241     fname        = (char*) malloc(m*sizeof(char));
242     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
243     pp           = (char*)fname;
244 #if !defined(PETSC_WORDS_BIGENDIAN)
245     ptmp         = (void*)fname;
246 #endif
247   }
248 
249   if (type == PETSC_INT)          m *= sizeof(PetscInt);
250   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
251   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
252   else if (type == PETSC_FLOAT)   m *= sizeof(float);
253   else if (type == PETSC_SHORT)   m *= sizeof(short);
254   else if (type == PETSC_CHAR)    m *= sizeof(char);
255   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
256   else if (type == PETSC_BOOL)   m *= sizeof(PetscBool);
257   else if (type == PETSC_BIT_LOGICAL) m  = PetscBTLength(m)*sizeof(char);
258   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
259 
260 #if defined(PETSC_USE_REAL___FLOAT128)
261   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);CHKERRQ(ierr);
262   /* If using __float128 precision we still read in doubles from file */
263   if (type == PETSC_SCALAR && readdouble) {
264     m    = m/2;
265     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
266     pp   = (char*)ppp;
267   }
268 #endif
269 
270   while (m) {
271     wsize = (m < maxblock) ? m : maxblock;
272     err   = read(fd,pp,wsize);
273     if (err < 0 && errno == EINTR) continue;
274     if (!err && wsize > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");
275     if (err < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
276     m  -= err;
277     pp += err;
278   }
279 
280 #if defined(PETSC_USE_REAL___FLOAT128)
281   if (type == PETSC_SCALAR && readdouble) {
282     PetscScalar *pv = (PetscScalar*) p;
283     PetscInt    i;
284 #if !defined(PETSC_WORDS_BIGENDIAN)
285     ierr = PetscByteSwapDouble(ppp,n);CHKERRQ(ierr);
286 #endif
287     for (i=0; i<n; i++) pv[i] = ppp[i];
288     ierr = PetscFree(ppp);CHKERRQ(ierr);
289     PetscFunctionReturn(0);
290   }
291 #endif
292 
293 #if !defined(PETSC_WORDS_BIGENDIAN)
294   ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
295 #endif
296 
297   if (type == PETSC_FUNCTION) {
298 #if defined(PETSC_SERIALIZE_FUNCTIONS)
299     ierr = PetscDLSym(NULL,fname,(void**)p);CHKERRQ(ierr);
300 #else
301     *(void**)p = NULL;
302 #endif
303     free(fname);
304   }
305   PetscFunctionReturn(0);
306 }
307 /* --------------------------------------------------------- */
308 #undef __FUNCT__
309 #define __FUNCT__ "PetscBinaryWrite"
310 /*@
311    PetscBinaryWrite - Writes to a binary file.
312 
313    Not Collective
314 
315    Input Parameters:
316 +  fd     - the file
317 .  p      - the buffer
318 .  n      - the number of items to write
319 .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
320 -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
321 
322    Level: advanced
323 
324    Notes:
325    PetscBinaryWrite() uses byte swapping to work on all machines; the files
326    are written using big-endian ordering to the file. On small-endian machines the numbers
327    are converted to the big-endian format when they are written to disk.
328    When PETSc is ./configure with --with-64bit-indices the integers are written to the
329    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
330    is used.
331 
332    If running with __float128 precision the output is in __float128 unless one uses the -binary_read_double option
333 
334    The Buffer p should be read-write buffer, and not static data.
335    This way, byte-swapping is done in-place, and then the buffer is
336    written to the file.
337 
338    This routine restores the original contents of the buffer, after
339    it is written to the file. This is done by byte-swapping in-place
340    the second time. If the flag istemp is set to PETSC_TRUE, the second
341    byte-swapping operation is not done, thus saving some computation,
342    but the buffer is left corrupted.
343 
344    Because byte-swapping may be done on the values in data it cannot be declared const
345 
346    Concepts: files^writing binary
347    Concepts: binary files^writing
348 
349 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
350           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
351 @*/
352 PetscErrorCode  PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
353 {
354   char           *pp = (char*)p;
355   int            err,wsize;
356   size_t         m = (size_t)n,maxblock=65536;
357   PetscErrorCode ierr;
358 #if !defined(PETSC_WORDS_BIGENDIAN)
359   void           *ptmp = p;
360 #endif
361   char           *fname = NULL;
362 #if defined(PETSC_USE_REAL___FLOAT128)
363   PetscBool      writedouble = PETSC_FALSE;
364   double         *ppp;
365   PetscReal      *pv;
366   PetscInt       i;
367 #endif
368 
369   PetscFunctionBegin;
370   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
371   if (!n) PetscFunctionReturn(0);
372 
373   if (type == PETSC_FUNCTION) {
374 #if defined(PETSC_SERIALIZE_FUNCTIONS)
375     const char *fnametmp;
376 #endif
377     m     = 64;
378     fname = (char*)malloc(m*sizeof(char));
379     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
380 #if defined(PETSC_SERIALIZE_FUNCTIONS)
381     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
382     ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
383     ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
384 #else
385     ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
386 #endif
387     type = PETSC_CHAR;
388     pp   = (char*)fname;
389 #if !defined(PETSC_WORDS_BIGENDIAN)
390     ptmp = (void*)fname;
391 #endif
392   }
393 
394 #if defined(PETSC_USE_REAL___FLOAT128)
395   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
396   /* If using __float128 precision we still write in doubles to file */
397   if (type == PETSC_SCALAR && writedouble) {
398     m    = m/2;
399     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
400     pv = (PetscReal*)pp;
401     for (i=0; i<n; i++) {
402       ppp[i] = (double) pv[i];
403     }
404     pp   = (char*)ppp;
405     ptmp = (char*)ppp;
406   }
407 #endif
408 
409   if (type == PETSC_INT)          m *= sizeof(PetscInt);
410   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
411   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
412   else if (type == PETSC_FLOAT)   m *= sizeof(float);
413   else if (type == PETSC_SHORT)   m *= sizeof(short);
414   else if (type == PETSC_CHAR)    m *= sizeof(char);
415   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
416   else if (type == PETSC_BOOL)   m *= sizeof(PetscBool);
417   else if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
418   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
419 
420 #if !defined(PETSC_WORDS_BIGENDIAN)
421   ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
422 #endif
423 
424   while (m) {
425     wsize = (m < maxblock) ? m : maxblock;
426     err   = write(fd,pp,wsize);
427     if (err < 0 && errno == EINTR) continue;
428     if (err != wsize) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file total size %d err %d wsize %d",(int)n,(int)err,(int)wsize);
429     m  -= wsize;
430     pp += wsize;
431   }
432 
433 #if !defined(PETSC_WORDS_BIGENDIAN)
434   if (!istemp) {
435     ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
436   }
437 #endif
438   if (type == PETSC_FUNCTION) {
439     free(fname);
440   }
441 #if defined(PETSC_USE_REAL___FLOAT128)
442   if (type == PETSC_SCALAR && writedouble) {
443     ierr = PetscFree(ppp);CHKERRQ(ierr);
444   }
445 #endif
446   PetscFunctionReturn(0);
447 }
448 
449 #undef __FUNCT__
450 #define __FUNCT__ "PetscBinaryOpen"
451 /*@C
452    PetscBinaryOpen - Opens a PETSc binary file.
453 
454    Not Collective
455 
456    Input Parameters:
457 +  name - filename
458 -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
459 
460    Output Parameter:
461 .  fd - the file
462 
463    Level: advanced
464 
465   Concepts: files^opening binary
466   Concepts: binary files^opening
467 
468    Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
469    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
470    PetscBinaryRead() and PetscBinaryWrite() on any machine.
471 
472 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
473           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
474 
475 @*/
476 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
477 {
478   PetscFunctionBegin;
479 #if defined(PETSC_HAVE_O_BINARY)
480   if (mode == FILE_MODE_WRITE) {
481     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
482   } else if (mode == FILE_MODE_READ) {
483     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
484   } else if (mode == FILE_MODE_APPEND) {
485     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
486 #else
487   if (mode == FILE_MODE_WRITE) {
488     if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
489   } else if (mode == FILE_MODE_READ) {
490     if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
491   }
492   else if (mode == FILE_MODE_APPEND) {
493     if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
494 #endif
495   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
496   PetscFunctionReturn(0);
497 }
498 
499 #undef __FUNCT__
500 #define __FUNCT__ "PetscBinaryClose"
501 /*@
502    PetscBinaryClose - Closes a PETSc binary file.
503 
504    Not Collective
505 
506    Output Parameter:
507 .  fd - the file
508 
509    Level: advanced
510 
511 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
512           PetscBinarySynchronizedSeek()
513 @*/
514 PetscErrorCode  PetscBinaryClose(int fd)
515 {
516   PetscFunctionBegin;
517   close(fd);
518   PetscFunctionReturn(0);
519 }
520 
521 
522 #undef __FUNCT__
523 #define __FUNCT__ "PetscBinarySeek"
524 /*@
525    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
526 
527    Not Collective
528 
529    Input Parameters:
530 +  fd - the file
531 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
532             etc. in your calculation rather than sizeof() to compute byte lengths.
533 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
534             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
535             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
536 
537    Output Parameter:
538 .   offset - new offset in file
539 
540    Level: developer
541 
542    Notes:
543    Integers are stored on the file as 32 long, regardless of whether
544    they are stored in the machine as 32 or 64, this means the same
545    binary file may be read on any machine. Hence you CANNOT use sizeof()
546    to determine the offset or location.
547 
548    Concepts: files^binary seeking
549    Concepts: binary files^seeking
550 
551 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
552           PetscBinarySynchronizedSeek()
553 @*/
554 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
555 {
556   int iwhence = 0;
557 
558   PetscFunctionBegin;
559   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
560   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
561   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
562   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
563 #if defined(PETSC_HAVE_LSEEK)
564   *offset = lseek(fd,off,iwhence);
565 #elif defined(PETSC_HAVE__LSEEK)
566   *offset = _lseek(fd,(long)off,iwhence);
567 #else
568   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
569 #endif
570   PetscFunctionReturn(0);
571 }
572 
573 #undef __FUNCT__
574 #define __FUNCT__ "PetscBinarySynchronizedRead"
575 /*@C
576    PetscBinarySynchronizedRead - Reads from a binary file.
577 
578    Collective on MPI_Comm
579 
580    Input Parameters:
581 +  comm - the MPI communicator
582 .  fd - the file
583 .  n  - the number of items to read
584 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
585 
586    Output Parameters:
587 .  p - the buffer
588 
589    Level: developer
590 
591    Notes:
592    Does a PetscBinaryRead() followed by an MPI_Bcast()
593 
594    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
595    Integers are stored on the file as 32 long, regardless of whether
596    they are stored in the machine as 32 or 64, this means the same
597    binary file may be read on any machine.
598 
599    Concepts: files^synchronized reading of binary files
600    Concepts: binary files^reading, synchronized
601 
602 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
603           PetscBinarySynchronizedSeek()
604 @*/
605 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
606 {
607   PetscErrorCode ierr;
608   PetscMPIInt    rank;
609   MPI_Datatype   mtype;
610   char           *fname = NULL;
611   void           *ptmp = NULL;
612 
613   PetscFunctionBegin;
614   if (type == PETSC_FUNCTION) {
615     n            = 64;
616     type         = PETSC_CHAR;
617     ptmp         = p;
618     fname        = (char*)malloc(n*sizeof(char));
619     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
620     p            = (void*)fname;
621   }
622 
623   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
624   if (!rank) {
625     ierr = PetscBinaryRead(fd,p,n,type);CHKERRQ(ierr);
626   }
627   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
628   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
629 
630   if (type == PETSC_FUNCTION) {
631 #if defined(PETSC_SERIALIZE_FUNCTIONS)
632     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)ptmp);CHKERRQ(ierr);
633 #else
634     *(void**)ptmp = NULL;
635 #endif
636     free(fname);
637   }
638   PetscFunctionReturn(0);
639 }
640 
641 #undef __FUNCT__
642 #define __FUNCT__ "PetscBinarySynchronizedWrite"
643 /*@C
644    PetscBinarySynchronizedWrite - writes to a binary file.
645 
646    Collective on MPI_Comm
647 
648    Input Parameters:
649 +  comm - the MPI communicator
650 .  fd - the file
651 .  n  - the number of items to write
652 .  p - the buffer
653 .  istemp - the buffer may be changed
654 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
655 
656    Level: developer
657 
658    Notes:
659    Process 0 does a PetscBinaryWrite()
660 
661    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
662    Integers are stored on the file as 32 long, regardless of whether
663    they are stored in the machine as 32 or 64, this means the same
664    binary file may be read on any machine.
665 
666    Notes: because byte-swapping may be done on the values in data it cannot be declared const
667 
668    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
669    while PetscSynchronizedFPrintf() has all processes print their strings in order.
670 
671    Concepts: files^synchronized writing of binary files
672    Concepts: binary files^reading, synchronized
673 
674 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
675           PetscBinarySynchronizedSeek()
676 @*/
677 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp)
678 {
679   PetscErrorCode ierr;
680   PetscMPIInt    rank;
681 
682   PetscFunctionBegin;
683   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
684   if (!rank) {
685     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
686   }
687   PetscFunctionReturn(0);
688 }
689 
690 #undef __FUNCT__
691 #define __FUNCT__ "PetscBinarySynchronizedSeek"
692 /*@C
693    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
694 
695 
696    Input Parameters:
697 +  fd - the file
698 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
699             if PETSC_BINARY_SEEK_CUR then size is offset from current location
700             if PETSC_BINARY_SEEK_END then size is offset from end of file
701 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
702             etc. in your calculation rather than sizeof() to compute byte lengths.
703 
704    Output Parameter:
705 .   offset - new offset in file
706 
707    Level: developer
708 
709    Notes:
710    Integers are stored on the file as 32 long, regardless of whether
711    they are stored in the machine as 32 or 64, this means the same
712    binary file may be read on any machine. Hence you CANNOT use sizeof()
713    to determine the offset or location.
714 
715    Concepts: binary files^seeking
716    Concepts: files^seeking in binary
717 
718 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
719           PetscBinarySynchronizedSeek()
720 @*/
721 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
722 {
723   PetscErrorCode ierr;
724   PetscMPIInt    rank;
725 
726   PetscFunctionBegin;
727   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
728   if (!rank) {
729     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
730   }
731   PetscFunctionReturn(0);
732 }
733 
734 #if defined(PETSC_HAVE_MPIIO)
735 #if !defined(PETSC_WORDS_BIGENDIAN)
736 
737 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
738 /*
739       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
740     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
741 
742     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
743 
744     The next three routines are not used because MPICH does not support their use
745 
746 */
747 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
748 {
749   MPI_Aint    ub;
750   PetscMPIInt ierr;
751 
752   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
753   return ierr;
754 }
755 
756 PETSC_EXTERN PetscMPIInt PetscDataRep_read_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;
761 
762   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
763   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
764 
765   /* offset is given in units of MPI_Datatype */
766   userbuf = ((char*)userbuf) + dsize*position;
767 
768   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
769   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
770   return ierr;
771 }
772 
773 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
774 {
775   PetscDataType pdtype;
776   PetscMPIInt   ierr;
777   size_t        dsize;
778 
779   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
780   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
781 
782   /* offset is given in units of MPI_Datatype */
783   userbuf = ((char*)userbuf) + dsize*position;
784 
785   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
786   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
787   return ierr;
788 }
789 #endif
790 
791 #undef __FUNCT__
792 #define __FUNCT__ "MPIU_File_write_all"
793 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
794 {
795   PetscErrorCode ierr;
796   PetscDataType  pdtype;
797 
798   PetscFunctionBegin;
799   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
800   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
801   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
802   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
803   PetscFunctionReturn(0);
804 }
805 
806 #undef __FUNCT__
807 #define __FUNCT__ "MPIU_File_read_all"
808 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
809 {
810   PetscErrorCode ierr;
811   PetscDataType  pdtype;
812 
813   PetscFunctionBegin;
814   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
815   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
816   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
817   PetscFunctionReturn(0);
818 }
819 #endif
820 #endif
821