Actual source code: sysio.c
1: #define PETSC_DLL
3: /*
4: This file contains simple binary read/write routines.
5: */
7: #include petsc.h
8: #include petscsys.h
10: #include <errno.h>
11: #include <fcntl.h>
12: #if defined(PETSC_HAVE_UNISTD_H)
13: #include <unistd.h>
14: #endif
15: #if defined (PETSC_HAVE_IO_H)
16: #include <io.h>
17: #endif
18: #include petscbt.h
20: #if (PETSC_SIZEOF_INT == 8)
21: #define PetscInt32 short
22: #else
23: #define PetscInt32 int
24: #endif
26: #if !defined(PETSC_WORDS_BIGENDIAN)
30: /*
31: PetscByteSwapInt - Swap bytes in a 32 bit integer. NOT a PetscInt! Note that PETSc binary read and write
32: always store and read only 32 bit integers! (See PetscBinaryRead(), PetscBinaryWrite()).
34: */
35: PetscErrorCode PETSC_DLLEXPORT PetscByteSwapInt(PetscInt32 *buff,PetscInt n)
36: {
37: PetscInt i,j,tmp = 0;
38: PetscInt *tptr = &tmp; /* Need to access tmp indirectly to get */
39: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
40:
42: for (j=0; j<n; j++) {
43: ptr1 = (char*)(buff + j);
44: for (i=0; i<(int)sizeof(PetscInt32); i++) {
45: ptr2[i] = ptr1[sizeof(PetscInt32)-1-i];
46: }
47: buff[j] = *tptr;
48: }
49: return(0);
50: }
51: /* --------------------------------------------------------- */
54: /*
55: PetscByteSwapShort - Swap bytes in a short
56: */
57: PetscErrorCode PETSC_DLLEXPORT PetscByteSwapShort(short *buff,PetscInt n)
58: {
59: PetscInt i,j;
60: short tmp;
61: short *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
62: char *ptr1,*ptr2 = (char*)&tmp;
65: for (j=0; j<n; j++) {
66: ptr1 = (char*)(buff + j);
67: for (i=0; i<(int) sizeof(short); i++) {
68: ptr2[i] = ptr1[sizeof(int)-1-i];
69: }
70: buff[j] = *tptr;
71: }
72: return(0);
73: }
74: /* --------------------------------------------------------- */
77: /*
78: PetscByteSwapScalar - Swap bytes in a double
79: Complex is dealt with as if array of double twice as long.
80: */
81: PetscErrorCode PETSC_DLLEXPORT PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
82: {
83: PetscInt i,j;
84: PetscReal tmp,*buff1 = (PetscReal*)buff;
85: PetscReal *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
86: char *ptr1,*ptr2 = (char*)&tmp;
89: #if defined(PETSC_USE_COMPLEX)
90: n *= 2;
91: #endif
92: for (j=0; j<n; j++) {
93: ptr1 = (char*)(buff1 + j);
94: for (i=0; i<(int) sizeof(PetscReal); i++) {
95: ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
96: }
97: buff1[j] = *tptr;
98: }
99: return(0);
100: }
101: /* --------------------------------------------------------- */
104: /*
105: PetscByteSwapDouble - Swap bytes in a double
106: */
107: PetscErrorCode PETSC_DLLEXPORT PetscByteSwapDouble(double *buff,PetscInt n)
108: {
109: PetscInt i,j;
110: double tmp,*buff1 = (double*)buff;
111: double *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
112: char *ptr1,*ptr2 = (char*)&tmp;
115: for (j=0; j<n; j++) {
116: ptr1 = (char*)(buff1 + j);
117: for (i=0; i<(int) sizeof(double); i++) {
118: ptr2[i] = ptr1[sizeof(double)-1-i];
119: }
120: buff1[j] = *tptr;
121: }
122: return(0);
123: }
124: #endif
125: /* --------------------------------------------------------- */
128: /*@C
129: PetscBinaryRead - Reads from a binary file.
131: Not Collective
133: Input Parameters:
134: + fd - the file
135: . n - the number of items to read
136: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
138: Output Parameters:
139: . p - the buffer
143: Level: developer
145: Notes:
146: PetscBinaryRead() uses byte swapping to work on all machines; the files
147: are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
148: are converted to the small-endian format when they are read in from the file.
149: Integers are stored on the file as 32 bits long, regardless of whether
150: they are stored in the machine as 32 bits or 64 bits, this means the same
151: binary file may be read on any machine.
153: Concepts: files^reading binary
154: Concepts: binary files^reading
156: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose()
157: @*/
158: PetscErrorCode PETSC_DLLEXPORT PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
159: {
160: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT) || !defined(PETSC_WORDS_BIGENDIAN)
161: PetscErrorCode ierr;
162: #endif
163: int wsize,err;
164: size_t m = (size_t) n,maxblock = 65536;
165: char *pp = (char*)p;
166: #if (PETSC_SIZEOF_INT == 8) || !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_64BIT_INT)
167: void *ptmp = p;
168: #endif
171: if (!n) return(0);
173: if (type == PETSC_INT){
174: m *= sizeof(PetscInt32);
175: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
176: /* read them in as 32 bit ints, later stretch into ints */
177: PetscMalloc(m,&pp);
178: ptmp = (void*)pp;
179: #endif
180: }
181: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
182: else if (type == PETSC_DOUBLE) m *= sizeof(double);
183: else if (type == PETSC_SHORT) m *= sizeof(short);
184: else if (type == PETSC_CHAR) m *= sizeof(char);
185: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
186: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
187: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
188: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
189:
190: while (m) {
191: wsize = (m < maxblock) ? m : maxblock;
192: err = read(fd,pp,wsize);
193: if (err < 0 && errno == EINTR) continue;
194: if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
195: if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
196: m -= err;
197: pp += err;
198: }
199: #if !defined(PETSC_WORDS_BIGENDIAN)
200: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
201: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
202: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
203: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
204: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
205: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
206: #endif
208: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
209: if (type == PETSC_INT) {
210: PetscInt *p_int = (PetscInt*)p,i;
211: PetscInt32 *p_short = (PetscInt32 *)ptmp;
212: for (i=0; i<n; i++) {
213: p_int[i] = (PetscInt)p_short[i];
214: }
215: PetscFree(ptmp);
216: }
217: #endif
218: return(0);
219: }
220: /* --------------------------------------------------------- */
223: /*@C
224: PetscBinaryWrite - Writes to a binary file.
226: Not Collective
228: Input Parameters:
229: + fd - the file
230: . p - the buffer
231: . n - the number of items to write
232: . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
233: - istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
235: Level: advanced
237: Notes:
238: PetscBinaryWrite() uses byte swapping to work on all machines; the files
239: are written using big-endian ordering to the file. On small-endian machines the numbers
240: are converted to the big-endian format when they are written to disk.
241: Integers are stored on the file as 32 bits long, regardless of whether
242: they are stored in the machine as 32 bits or 64 bits, this means the same
243: binary file may be read on any machine. It also means that 64 bit integers larger than
244: roughly 2 billion are TRUNCATED/WRONG when written to the file.
246: The Buffer p should be read-write buffer, and not static data.
247: This way, byte-swapping is done in-place, and then the buffer is
248: written to the file.
249:
250: This routine restores the original contents of the buffer, after
251: it is written to the file. This is done by byte-swapping in-place
252: the second time. If the flag istemp is set to PETSC_TRUE, the second
253: byte-swapping operation is not done, thus saving some computation,
254: but the buffer corrupted is corrupted.
256: Concepts: files^writing binary
257: Concepts: binary files^writing
259: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose()
260: @*/
261: PetscErrorCode PETSC_DLLEXPORT PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
262: {
263: char *pp = (char*)p;
264: int err,wsize;
265: size_t m = (size_t)n,maxblock=65536;
266: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
268: void *ptmp = p;
269: #endif
272: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
273: if (!n) return(0);
275: if (type == PETSC_INT){
276: m *= sizeof(PetscInt32);
277: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
278: PetscInt *p_int = (PetscInt*)p,i;
279: PetscInt32 *p_short;
280: PetscMalloc(m,&pp);
281: ptmp = (void*)pp;
282: p_short = (PetscInt32*)pp;
284: for (i=0; i<n; i++) {
285: p_short[i] = (PetscInt32) p_int[i];
286: }
287: istemp = PETSC_TRUE;
288: #endif
289: }
290: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
291: else if (type == PETSC_DOUBLE) m *= sizeof(double);
292: else if (type == PETSC_SHORT) m *= sizeof(short);
293: else if (type == PETSC_CHAR) m *= sizeof(char);
294: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
295: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
296: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
297: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
299: #if !defined(PETSC_WORDS_BIGENDIAN)
300: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
301: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
302: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
303: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
304: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
305: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
306: #endif
308: while (m) {
309: wsize = (m < maxblock) ? m : maxblock;
310: err = write(fd,pp,wsize);
311: if (err < 0 && errno == EINTR) continue;
312: if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
313: m -= wsize;
314: pp += wsize;
315: }
317: #if !defined(PETSC_WORDS_BIGENDIAN) && !(PETSC_SIZEOF_INT == 8) && !defined(PETSC_USE_64BIT_INT)
318: if (!istemp) {
319: if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
320: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
321: else if (type == PETSC_INT) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
322: else if (type == PETSC_ENUM) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
323: else if (type == PETSC_TRUTH) {PetscByteSwapInt((PetscInt32*)ptmp,n);}
324: }
325: #endif
327: #if (PETSC_SIZEOF_INT == 8) || defined(PETSC_USE_64BIT_INT)
328: if (type == PETSC_INT){
329: PetscFree(ptmp);
330: }
331: #endif
332: return(0);
333: }
337: /*@C
338: PetscBinaryOpen - Opens a PETSc binary file.
340: Not Collective
342: Input Parameters:
343: + name - filename
344: - type - type of binary file, on of PETSC_FILE_RDONLY, PETSC_FILE_WRONLY, PETSC_FILE_CREATE
346: Output Parameter:
347: . fd - the file
349: Level: advanced
351: Concepts: files^opening binary
352: Concepts: binary files^opening
354: Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
355: big-endian format. This means the file can be accessed using PetscBinaryOpen() and
356: PetscBinaryRead() and PetscBinaryWrite() on any machine.
358: .seealso: PetscBinaryRead(), PetscBinaryWrite()
359: @*/
360: PetscErrorCode PETSC_DLLEXPORT PetscBinaryOpen(const char name[],int type,int *fd)
361: {
363: #if defined(PETSC_HAVE_O_BINARY)
364: if (type == PETSC_FILE_CREATE) {
365: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
366: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
367: }
368: } else if (type == PETSC_FILE_RDONLY) {
369: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
370: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
371: }
372: } else if (type == PETSC_FILE_WRONLY) {
373: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
374: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
375: }
376: #else
377: if (type == PETSC_FILE_CREATE) {
378: if ((*fd = creat(name,0666)) == -1) {
379: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
380: }
381: } else if (type == PETSC_FILE_RDONLY) {
382: if ((*fd = open(name,O_RDONLY,0)) == -1) {
383: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
384: }
385: }
386: else if (type == PETSC_FILE_WRONLY) {
387: if ((*fd = open(name,O_WRONLY,0)) == -1) {
388: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
389: }
390: #endif
391: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file type");
392: return(0);
393: }
397: /*@C
398: PetscBinaryClose - Closes a PETSc binary file.
400: Not Collective
402: Output Parameter:
403: . fd - the file
405: Level: advanced
407: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
408: @*/
409: PetscErrorCode PETSC_DLLEXPORT PetscBinaryClose(int fd)
410: {
412: close(fd);
413: return(0);
414: }
419: /*@C
420: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
422: Not Collective
424: Input Parameters:
425: + fd - the file
426: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
427: if PETSC_BINARY_SEEK_CUR then size is offset from current location
428: if PETSC_BINARY_SEEK_END then size is offset from end of file
429: - size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
430: etc. in your calculation rather than sizeof() to compute byte lengths.
432: Output Parameter:
433: . offset - new offset in file
435: Level: developer
437: Notes:
438: Integers are stored on the file as 32 long, regardless of whether
439: they are stored in the machine as 32 or 64, this means the same
440: binary file may be read on any machine. Hence you CANNOT use sizeof()
441: to determine the offset or location.
443: Concepts: files^binary seeking
444: Concepts: binary files^seeking
446: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
447: @*/
448: PetscErrorCode PETSC_DLLEXPORT PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
449: {
450: #if defined(PETSC_HAVE_LSEEK) || defined(PETSC_HAVE__LSEEK)
451: int iwhence=0;
452: #endif
455: if (whence == PETSC_BINARY_SEEK_SET) {
456: iwhence = SEEK_SET;
457: } else if (whence == PETSC_BINARY_SEEK_CUR) {
458: iwhence = SEEK_CUR;
459: } else if (whence == PETSC_BINARY_SEEK_END) {
460: iwhence = SEEK_END;
461: } else {
462: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
463: }
464: #if defined(PETSC_HAVE_LSEEK)
465: *offset = lseek(fd,off,iwhence);
466: #elif defined(PETSC_HAVE__LSEEK)
467: *offset = _lseek(fd,(long)off,iwhence);
468: #else
469: SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
470: #endif
471: return(0);
472: }
476: /*@C
477: PetscSynchronizedBinaryRead - Reads from a binary file.
479: Collective on MPI_Comm
481: Input Parameters:
482: + comm - the MPI communicator
483: . fd - the file
484: . n - the number of items to read
485: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
487: Output Parameters:
488: . p - the buffer
490: Options Database Key:
491: . -binary_longints - indicates the file was generated on a Cray vector
492: machine (not the T3E/D) and the ints are stored as 64 bit
493: quantities, otherwise they are stored as 32 bit
495: Level: developer
497: Notes:
498: Does a PetscBinaryRead() followed by an MPI_Bcast()
500: PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
501: Integers are stored on the file as 32 long, regardless of whether
502: they are stored in the machine as 32 or 64, this means the same
503: binary file may be read on any machine.
505: Concepts: files^synchronized reading of binary files
506: Concepts: binary files^reading, synchronized
508: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
509: @*/
510: PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
511: {
513: PetscMPIInt rank;
514: MPI_Datatype mtype;
517: MPI_Comm_rank(comm,&rank);
518: if (!rank) {
519: PetscBinaryRead(fd,p,n,type);
520: }
521: PetscDataTypeToMPIDataType(type,&mtype);
522: MPI_Bcast(p,n,mtype,0,comm);
523: return(0);
524: }
528: /*@C
529: PetscSynchronizedBinaryWrite - writes to a binary file.
531: Collective on MPI_Comm
533: Input Parameters:
534: + comm - the MPI communicator
535: . fd - the file
536: . n - the number of items to write
537: . p - the buffer
538: . istemp - the buffer may be changed
539: - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
541: Level: developer
543: Notes:
544: Process 0 does a PetscBinaryWrite()
546: PetscSynchronizedBinaryWrite() uses byte swapping to work on all machines.
547: Integers are stored on the file as 32 long, regardless of whether
548: they are stored in the machine as 32 or 64, this means the same
549: binary file may be read on any machine.
551: Concepts: files^synchronized writing of binary files
552: Concepts: binary files^reading, synchronized
554: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
555: @*/
556: PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedBinaryWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
557: {
559: PetscMPIInt rank;
562: MPI_Comm_rank(comm,&rank);
563: if (!rank) {
564: PetscBinaryWrite(fd,p,n,type,istemp);
565: }
566: return(0);
567: }
571: /*@C
572: PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.
575: Input Parameters:
576: + fd - the file
577: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
578: if PETSC_BINARY_SEEK_CUR then size is offset from current location
579: if PETSC_BINARY_SEEK_END then size is offset from end of file
580: - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
581: etc. in your calculation rather than sizeof() to compute byte lengths.
583: Output Parameter:
584: . offset - new offset in file
586: Level: developer
588: Notes:
589: Integers are stored on the file as 32 long, regardless of whether
590: they are stored in the machine as 32 or 64, this means the same
591: binary file may be read on any machine. Hence you CANNOT use sizeof()
592: to determine the offset or location.
594: Concepts: binary files^seeking
595: Concepts: files^seeking in binary
597: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
598: @*/
599: PetscErrorCode PETSC_DLLEXPORT PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
600: {
602: PetscMPIInt rank;
605: MPI_Comm_rank(comm,&rank);
606: if (!rank) {
607: PetscBinarySeek(fd,off,whence,offset);
608: }
609: return(0);
610: }