xref: /petsc/src/sys/fileio/sysio.c (revision 5efd42a4d4e0ae8b540c20ac6de7da7f5376070a)
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 PetscScalar
106   The complex case is dealt with with an array of PetscReal, 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_write_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   PetscDataType  wtype = type;
369 
370   PetscFunctionBegin;
371   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
372   if (!n) PetscFunctionReturn(0);
373 
374   if (type == PETSC_FUNCTION) {
375 #if defined(PETSC_SERIALIZE_FUNCTIONS)
376     const char *fnametmp;
377 #endif
378     m     = 64;
379     fname = (char*)malloc(m*sizeof(char));
380     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
381 #if defined(PETSC_SERIALIZE_FUNCTIONS)
382     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
383     ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr);
384     ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr);
385 #else
386     ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr);
387 #endif
388     type = PETSC_CHAR;
389     pp   = (char*)fname;
390 #if !defined(PETSC_WORDS_BIGENDIAN)
391     ptmp = (void*)fname;
392 #endif
393   }
394 
395 #if defined(PETSC_USE_REAL___FLOAT128)
396   ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr);
397   /* If using __float128 precision we still write in doubles to file */
398   if (type == PETSC_SCALAR && writedouble) {
399     wtype = PETSC_DOUBLE;
400     ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr);
401     pv = (PetscReal*)pp;
402     for (i=0; i<n; i++) {
403       ppp[i] = (double) pv[i];
404     }
405     pp   = (char*)ppp;
406     ptmp = (char*)ppp;
407   }
408 #endif
409 
410   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
411   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
412   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
413   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
414   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
415   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
416   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
417   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
418   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
419   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
420 
421 #if !defined(PETSC_WORDS_BIGENDIAN)
422   ierr = PetscByteSwap(ptmp,wtype,n);CHKERRQ(ierr);
423 #endif
424 
425   while (m) {
426     wsize = (m < maxblock) ? m : maxblock;
427     err   = write(fd,pp,wsize);
428     if (err < 0 && errno == EINTR) continue;
429     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);
430     m  -= wsize;
431     pp += wsize;
432   }
433 
434 #if !defined(PETSC_WORDS_BIGENDIAN)
435   if (!istemp) {
436     ierr = PetscByteSwap(ptmp,wtype,n);CHKERRQ(ierr);
437   }
438 #endif
439   if (type == PETSC_FUNCTION) {
440     free(fname);
441   }
442 #if defined(PETSC_USE_REAL___FLOAT128)
443   if (type == PETSC_SCALAR && writedouble) {
444     ierr = PetscFree(ppp);CHKERRQ(ierr);
445   }
446 #endif
447   PetscFunctionReturn(0);
448 }
449 
450 #undef __FUNCT__
451 #define __FUNCT__ "PetscBinaryOpen"
452 /*@C
453    PetscBinaryOpen - Opens a PETSc binary file.
454 
455    Not Collective
456 
457    Input Parameters:
458 +  name - filename
459 -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
460 
461    Output Parameter:
462 .  fd - the file
463 
464    Level: advanced
465 
466   Concepts: files^opening binary
467   Concepts: binary files^opening
468 
469    Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
470    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
471    PetscBinaryRead() and PetscBinaryWrite() on any machine.
472 
473 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
474           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
475 
476 @*/
477 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
478 {
479   PetscFunctionBegin;
480 #if defined(PETSC_HAVE_O_BINARY)
481   if (mode == FILE_MODE_WRITE) {
482     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);
483   } else if (mode == FILE_MODE_READ) {
484     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);
485   } else if (mode == FILE_MODE_APPEND) {
486     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);
487 #else
488   if (mode == FILE_MODE_WRITE) {
489     if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
490   } else if (mode == FILE_MODE_READ) {
491     if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
492   }
493   else if (mode == FILE_MODE_APPEND) {
494     if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
495 #endif
496   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
497   PetscFunctionReturn(0);
498 }
499 
500 #undef __FUNCT__
501 #define __FUNCT__ "PetscBinaryClose"
502 /*@
503    PetscBinaryClose - Closes a PETSc binary file.
504 
505    Not Collective
506 
507    Output Parameter:
508 .  fd - the file
509 
510    Level: advanced
511 
512 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
513           PetscBinarySynchronizedSeek()
514 @*/
515 PetscErrorCode  PetscBinaryClose(int fd)
516 {
517   PetscFunctionBegin;
518   close(fd);
519   PetscFunctionReturn(0);
520 }
521 
522 
523 #undef __FUNCT__
524 #define __FUNCT__ "PetscBinarySeek"
525 /*@
526    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
527 
528    Not Collective
529 
530    Input Parameters:
531 +  fd - the file
532 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
533             etc. in your calculation rather than sizeof() to compute byte lengths.
534 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
535             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
536             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
537 
538    Output Parameter:
539 .   offset - new offset in file
540 
541    Level: developer
542 
543    Notes:
544    Integers are stored on the file as 32 long, regardless of whether
545    they are stored in the machine as 32 or 64, this means the same
546    binary file may be read on any machine. Hence you CANNOT use sizeof()
547    to determine the offset or location.
548 
549    Concepts: files^binary seeking
550    Concepts: binary files^seeking
551 
552 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
553           PetscBinarySynchronizedSeek()
554 @*/
555 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
556 {
557   int iwhence = 0;
558 
559   PetscFunctionBegin;
560   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
561   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
562   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
563   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
564 #if defined(PETSC_HAVE_LSEEK)
565   *offset = lseek(fd,off,iwhence);
566 #elif defined(PETSC_HAVE__LSEEK)
567   *offset = _lseek(fd,(long)off,iwhence);
568 #else
569   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
570 #endif
571   PetscFunctionReturn(0);
572 }
573 
574 #undef __FUNCT__
575 #define __FUNCT__ "PetscBinarySynchronizedRead"
576 /*@C
577    PetscBinarySynchronizedRead - Reads from a binary file.
578 
579    Collective on MPI_Comm
580 
581    Input Parameters:
582 +  comm - the MPI communicator
583 .  fd - the file
584 .  n  - the number of items to read
585 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
586 
587    Output Parameters:
588 .  p - the buffer
589 
590    Level: developer
591 
592    Notes:
593    Does a PetscBinaryRead() followed by an MPI_Bcast()
594 
595    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
596    Integers are stored on the file as 32 long, regardless of whether
597    they are stored in the machine as 32 or 64, this means the same
598    binary file may be read on any machine.
599 
600    Concepts: files^synchronized reading of binary files
601    Concepts: binary files^reading, synchronized
602 
603 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
604           PetscBinarySynchronizedSeek()
605 @*/
606 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
607 {
608   PetscErrorCode ierr;
609   PetscMPIInt    rank;
610   MPI_Datatype   mtype;
611   char           *fname = NULL;
612   void           *ptmp = NULL;
613 
614   PetscFunctionBegin;
615   if (type == PETSC_FUNCTION) {
616     n            = 64;
617     type         = PETSC_CHAR;
618     ptmp         = p;
619     fname        = (char*)malloc(n*sizeof(char));
620     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
621     p            = (void*)fname;
622   }
623 
624   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
625   if (!rank) {
626     ierr = PetscBinaryRead(fd,p,n,type);CHKERRQ(ierr);
627   }
628   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
629   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
630 
631   if (type == PETSC_FUNCTION) {
632 #if defined(PETSC_SERIALIZE_FUNCTIONS)
633     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)ptmp);CHKERRQ(ierr);
634 #else
635     *(void**)ptmp = NULL;
636 #endif
637     free(fname);
638   }
639   PetscFunctionReturn(0);
640 }
641 
642 #undef __FUNCT__
643 #define __FUNCT__ "PetscBinarySynchronizedWrite"
644 /*@C
645    PetscBinarySynchronizedWrite - writes to a binary file.
646 
647    Collective on MPI_Comm
648 
649    Input Parameters:
650 +  comm - the MPI communicator
651 .  fd - the file
652 .  n  - the number of items to write
653 .  p - the buffer
654 .  istemp - the buffer may be changed
655 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
656 
657    Level: developer
658 
659    Notes:
660    Process 0 does a PetscBinaryWrite()
661 
662    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
663    Integers are stored on the file as 32 long, regardless of whether
664    they are stored in the machine as 32 or 64, this means the same
665    binary file may be read on any machine.
666 
667    Notes: because byte-swapping may be done on the values in data it cannot be declared const
668 
669    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
670    while PetscSynchronizedFPrintf() has all processes print their strings in order.
671 
672    Concepts: files^synchronized writing of binary files
673    Concepts: binary files^reading, synchronized
674 
675 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
676           PetscBinarySynchronizedSeek()
677 @*/
678 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp)
679 {
680   PetscErrorCode ierr;
681   PetscMPIInt    rank;
682 
683   PetscFunctionBegin;
684   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
685   if (!rank) {
686     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
687   }
688   PetscFunctionReturn(0);
689 }
690 
691 #undef __FUNCT__
692 #define __FUNCT__ "PetscBinarySynchronizedSeek"
693 /*@C
694    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
695 
696 
697    Input Parameters:
698 +  fd - the file
699 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
700             if PETSC_BINARY_SEEK_CUR then size is offset from current location
701             if PETSC_BINARY_SEEK_END then size is offset from end of file
702 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
703             etc. in your calculation rather than sizeof() to compute byte lengths.
704 
705    Output Parameter:
706 .   offset - new offset in file
707 
708    Level: developer
709 
710    Notes:
711    Integers are stored on the file as 32 long, regardless of whether
712    they are stored in the machine as 32 or 64, this means the same
713    binary file may be read on any machine. Hence you CANNOT use sizeof()
714    to determine the offset or location.
715 
716    Concepts: binary files^seeking
717    Concepts: files^seeking in binary
718 
719 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
720           PetscBinarySynchronizedSeek()
721 @*/
722 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
723 {
724   PetscErrorCode ierr;
725   PetscMPIInt    rank;
726 
727   PetscFunctionBegin;
728   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
729   if (!rank) {
730     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
731   }
732   PetscFunctionReturn(0);
733 }
734 
735 #if defined(PETSC_HAVE_MPIIO)
736 #if !defined(PETSC_WORDS_BIGENDIAN)
737 
738 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
739 /*
740       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
741     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
742 
743     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
744 
745     The next three routines are not used because MPICH does not support their use
746 
747 */
748 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
749 {
750   MPI_Aint    ub;
751   PetscMPIInt ierr;
752 
753   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
754   return ierr;
755 }
756 
757 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
758 {
759   PetscDataType pdtype;
760   PetscMPIInt   ierr;
761   size_t        dsize;
762 
763   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
764   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
765 
766   /* offset is given in units of MPI_Datatype */
767   userbuf = ((char*)userbuf) + dsize*position;
768 
769   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
770   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
771   return ierr;
772 }
773 
774 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
775 {
776   PetscDataType pdtype;
777   PetscMPIInt   ierr;
778   size_t        dsize;
779 
780   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
781   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
782 
783   /* offset is given in units of MPI_Datatype */
784   userbuf = ((char*)userbuf) + dsize*position;
785 
786   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
787   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
788   return ierr;
789 }
790 #endif
791 
792 #undef __FUNCT__
793 #define __FUNCT__ "MPIU_File_write_all"
794 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
795 {
796   PetscErrorCode ierr;
797   PetscDataType  pdtype;
798 
799   PetscFunctionBegin;
800   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
801   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
802   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
803   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
804   PetscFunctionReturn(0);
805 }
806 
807 #undef __FUNCT__
808 #define __FUNCT__ "MPIU_File_read_all"
809 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
810 {
811   PetscErrorCode ierr;
812   PetscDataType  pdtype;
813 
814   PetscFunctionBegin;
815   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
816   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
817   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
818   PetscFunctionReturn(0);
819 }
820 #endif
821 #endif
822