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 !defined(PETSC_WORDS_BIGENDIAN)
22: /* --------------------------------------------------------- */
25: /*
26: PetscByteSwapEnum - Swap bytes in a PETSc Enum
28: */
29: PetscErrorCode PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
30: {
31: PetscInt i,j;
32: PetscEnum tmp = ENUM_DUMMY;
33: PetscEnum *tptr = &tmp; /* Need to access tmp indirectly to get */
34: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
35:
37: for (j=0; j<n; j++) {
38: ptr1 = (char*)(buff + j);
39: for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) {
40: ptr2[i] = ptr1[sizeof(PetscEnum)-1-i];
41: }
42: buff[j] = *tptr;
43: }
44: return(0);
45: }
49: /*
50: PetscByteSwapTruth - Swap bytes in a PETSc Truth
52: */
53: PetscErrorCode PetscByteSwapTruth(PetscTruth *buff,PetscInt n)
54: {
55: PetscInt i,j;
56: PetscTruth tmp = PETSC_FALSE;
57: PetscTruth *tptr = &tmp; /* Need to access tmp indirectly to get */
58: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
59:
61: for (j=0; j<n; j++) {
62: ptr1 = (char*)(buff + j);
63: for (i=0; i<(PetscInt)sizeof(PetscTruth); i++) {
64: ptr2[i] = ptr1[sizeof(PetscTruth)-1-i];
65: }
66: buff[j] = *tptr;
67: }
68: return(0);
69: }
73: /*
74: PetscByteSwapInt - Swap bytes in a PETSc integer (which may be 32 or 64 bits)
76: */
77: PetscErrorCode PetscByteSwapInt(PetscInt *buff,PetscInt n)
78: {
79: PetscInt i,j,tmp = 0;
80: PetscInt *tptr = &tmp; /* Need to access tmp indirectly to get */
81: char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
82:
84: for (j=0; j<n; j++) {
85: ptr1 = (char*)(buff + j);
86: for (i=0; i<(PetscInt)sizeof(PetscInt); i++) {
87: ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
88: }
89: buff[j] = *tptr;
90: }
91: return(0);
92: }
93: /* --------------------------------------------------------- */
96: /*
97: PetscByteSwapShort - Swap bytes in a short
98: */
99: PetscErrorCode PetscByteSwapShort(short *buff,PetscInt n)
100: {
101: PetscInt i,j;
102: short tmp;
103: short *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
104: char *ptr1,*ptr2 = (char*)&tmp;
107: for (j=0; j<n; j++) {
108: ptr1 = (char*)(buff + j);
109: for (i=0; i<(PetscInt) sizeof(short); i++) {
110: ptr2[i] = ptr1[sizeof(int)-1-i];
111: }
112: buff[j] = *tptr;
113: }
114: return(0);
115: }
116: /* --------------------------------------------------------- */
119: /*
120: PetscByteSwapScalar - Swap bytes in a double
121: Complex is dealt with as if array of double twice as long.
122: */
123: PetscErrorCode PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
124: {
125: PetscInt i,j;
126: PetscReal tmp,*buff1 = (PetscReal*)buff;
127: PetscReal *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
128: char *ptr1,*ptr2 = (char*)&tmp;
131: #if defined(PETSC_USE_COMPLEX)
132: n *= 2;
133: #endif
134: for (j=0; j<n; j++) {
135: ptr1 = (char*)(buff1 + j);
136: for (i=0; i<(PetscInt) sizeof(PetscReal); i++) {
137: ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
138: }
139: buff1[j] = *tptr;
140: }
141: return(0);
142: }
143: /* --------------------------------------------------------- */
146: /*
147: PetscByteSwapDouble - Swap bytes in a double
148: */
149: PetscErrorCode PetscByteSwapDouble(double *buff,PetscInt n)
150: {
151: PetscInt i,j;
152: double tmp,*buff1 = (double*)buff;
153: double *tptr = &tmp; /* take care pf bug in DEC-ALPHA g++ */
154: char *ptr1,*ptr2 = (char*)&tmp;
157: for (j=0; j<n; j++) {
158: ptr1 = (char*)(buff1 + j);
159: for (i=0; i<(PetscInt) sizeof(double); i++) {
160: ptr2[i] = ptr1[sizeof(double)-1-i];
161: }
162: buff1[j] = *tptr;
163: }
164: return(0);
165: }
166: #endif
167: /* --------------------------------------------------------- */
170: /*@
171: PetscBinaryRead - Reads from a binary file.
173: Not Collective
175: Input Parameters:
176: + fd - the file
177: . n - the number of items to read
178: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
180: Output Parameters:
181: . p - the buffer
185: Level: developer
187: Notes:
188: PetscBinaryRead() uses byte swapping to work on all machines; the files
189: are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
190: are converted to the small-endian format when they are read in from the file.
191: Integers are stored on the file as 32 bits long, regardless of whether
192: they are stored in the machine as 32 bits or 64 bits, this means the same
193: binary file may be read on any machine.
195: Concepts: files^reading binary
196: Concepts: binary files^reading
198: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
199: PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
200: @*/
201: PetscErrorCode PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
202: {
203: int wsize,err;
204: size_t m = (size_t) n,maxblock = 65536;
205: char *pp = (char*)p;
206: #if !defined(PETSC_WORDS_BIGENDIAN)
207: PetscErrorCode ierr;
208: void *ptmp = p;
209: #endif
212: if (!n) return(0);
214: if (type == PETSC_INT) m *= sizeof(PetscInt);
215: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
216: else if (type == PETSC_DOUBLE) m *= sizeof(double);
217: else if (type == PETSC_SHORT) m *= sizeof(short);
218: else if (type == PETSC_CHAR) m *= sizeof(char);
219: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
220: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
221: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
222: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
223:
224: while (m) {
225: wsize = (m < maxblock) ? m : maxblock;
226: err = read(fd,pp,wsize);
227: if (err < 0 && errno == EINTR) continue;
228: if (!err && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
229: if (err < 0) SETERRQ1(PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
230: m -= err;
231: pp += err;
232: }
233: #if !defined(PETSC_WORDS_BIGENDIAN)
234: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt*)ptmp,n);}
235: else if (type == PETSC_ENUM) {PetscByteSwapEnum((PetscEnum*)ptmp,n);}
236: else if (type == PETSC_TRUTH) {PetscByteSwapTruth((PetscTruth*)ptmp,n);}
237: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
238: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
239: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
240: #endif
242: return(0);
243: }
244: /* --------------------------------------------------------- */
247: /*@
248: PetscBinaryWrite - Writes to a binary file.
250: Not Collective
252: Input Parameters:
253: + fd - the file
254: . p - the buffer
255: . n - the number of items to write
256: . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
257: - istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
259: Level: advanced
261: Notes:
262: PetscBinaryWrite() uses byte swapping to work on all machines; the files
263: are written using big-endian ordering to the file. On small-endian machines the numbers
264: are converted to the big-endian format when they are written to disk.
265: Integers are stored on the file as 32 bits long, regardless of whether
266: they are stored in the machine as 32 bits or 64 bits, this means the same
267: binary file may be read on any machine. It also means that 64 bit integers larger than
268: roughly 2 billion are TRUNCATED/WRONG when written to the file.
270: The Buffer p should be read-write buffer, and not static data.
271: This way, byte-swapping is done in-place, and then the buffer is
272: written to the file.
273:
274: This routine restores the original contents of the buffer, after
275: it is written to the file. This is done by byte-swapping in-place
276: the second time. If the flag istemp is set to PETSC_TRUE, the second
277: byte-swapping operation is not done, thus saving some computation,
278: but the buffer corrupted is corrupted.
280: Concepts: files^writing binary
281: Concepts: binary files^writing
283: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
284: PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
285: @*/
286: PetscErrorCode PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
287: {
288: char *pp = (char*)p;
289: int err,wsize;
290: size_t m = (size_t)n,maxblock=65536;
291: #if !defined(PETSC_WORDS_BIGENDIAN)
293: void *ptmp = p;
294: #endif
297: if (n < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
298: if (!n) return(0);
300: if (type == PETSC_INT) m *= sizeof(PetscInt);
301: else if (type == PETSC_SCALAR) m *= sizeof(PetscScalar);
302: else if (type == PETSC_DOUBLE) m *= sizeof(double);
303: else if (type == PETSC_SHORT) m *= sizeof(short);
304: else if (type == PETSC_CHAR) m *= sizeof(char);
305: else if (type == PETSC_ENUM) m *= sizeof(PetscEnum);
306: else if (type == PETSC_TRUTH) m *= sizeof(PetscTruth);
307: else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
308: else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
310: #if !defined(PETSC_WORDS_BIGENDIAN)
311: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt*)ptmp,n);}
312: else if (type == PETSC_ENUM) {PetscByteSwapEnum((PetscEnum*)ptmp,n);}
313: else if (type == PETSC_TRUTH) {PetscByteSwapTruth((PetscTruth*)ptmp,n);}
314: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
315: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
316: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
317: #endif
319: while (m) {
320: wsize = (m < maxblock) ? m : maxblock;
321: err = write(fd,pp,wsize);
322: if (err < 0 && errno == EINTR) continue;
323: if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
324: m -= wsize;
325: pp += wsize;
326: }
328: #if !defined(PETSC_WORDS_BIGENDIAN)
329: if (!istemp) {
330: if (type == PETSC_INT) {PetscByteSwapInt((PetscInt*)ptmp,n);}
331: else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
332: else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
333: else if (type == PETSC_SHORT) {PetscByteSwapShort((short*)ptmp,n);}
334: else if (type == PETSC_ENUM) {PetscByteSwapEnum((PetscEnum*)ptmp,n);}
335: else if (type == PETSC_TRUTH) {PetscByteSwapTruth((PetscTruth*)ptmp,n);}
336: }
337: #endif
338: return(0);
339: }
343: /*@C
344: PetscBinaryOpen - Opens a PETSc binary file.
346: Not Collective
348: Input Parameters:
349: + name - filename
350: - type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
352: Output Parameter:
353: . fd - the file
355: Level: advanced
357: Concepts: files^opening binary
358: Concepts: binary files^opening
360: Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
361: big-endian format. This means the file can be accessed using PetscBinaryOpen() and
362: PetscBinaryRead() and PetscBinaryWrite() on any machine.
364: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
365: PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
367: @*/
368: PetscErrorCode PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
369: {
371: #if defined(PETSC_HAVE_O_BINARY)
372: if (mode == FILE_MODE_WRITE) {
373: if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
374: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
375: }
376: } else if (mode == FILE_MODE_READ) {
377: if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
378: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
379: }
380: } else if (mode == FILE_MODE_APPEND) {
381: if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
382: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
383: }
384: #else
385: if (mode == FILE_MODE_WRITE) {
386: if ((*fd = creat(name,0666)) == -1) {
387: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
388: }
389: } else if (mode == FILE_MODE_READ) {
390: if ((*fd = open(name,O_RDONLY,0)) == -1) {
391: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
392: }
393: }
394: else if (mode == FILE_MODE_APPEND) {
395: if ((*fd = open(name,O_WRONLY,0)) == -1) {
396: SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
397: }
398: #endif
399: } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
400: return(0);
401: }
405: /*@
406: PetscBinaryClose - Closes a PETSc binary file.
408: Not Collective
410: Output Parameter:
411: . fd - the file
413: Level: advanced
415: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
416: PetscBinarySynchronizedSeek()
417: @*/
418: PetscErrorCode PetscBinaryClose(int fd)
419: {
421: close(fd);
422: return(0);
423: }
428: /*@
429: PetscBinarySeek - Moves the file pointer on a PETSc binary file.
431: Not Collective
433: Input Parameters:
434: + fd - the file
435: . off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
436: etc. in your calculation rather than sizeof() to compute byte lengths.
437: - whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
438: if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
439: if PETSC_BINARY_SEEK_END then off is an offset from the end of file
441: Output Parameter:
442: . offset - new offset in file
444: Level: developer
446: Notes:
447: Integers are stored on the file as 32 long, regardless of whether
448: they are stored in the machine as 32 or 64, this means the same
449: binary file may be read on any machine. Hence you CANNOT use sizeof()
450: to determine the offset or location.
452: Concepts: files^binary seeking
453: Concepts: binary files^seeking
455: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
456: PetscBinarySynchronizedSeek()
457: @*/
458: PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
459: {
460: int iwhence = 0;
463: if (whence == PETSC_BINARY_SEEK_SET) {
464: iwhence = SEEK_SET;
465: } else if (whence == PETSC_BINARY_SEEK_CUR) {
466: iwhence = SEEK_CUR;
467: } else if (whence == PETSC_BINARY_SEEK_END) {
468: iwhence = SEEK_END;
469: } else {
470: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
471: }
472: #if defined(PETSC_HAVE_LSEEK)
473: *offset = lseek(fd,off,iwhence);
474: #elif defined(PETSC_HAVE__LSEEK)
475: *offset = _lseek(fd,(long)off,iwhence);
476: #else
477: SETERRQ(PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
478: #endif
479: return(0);
480: }
484: /*@C
485: PetscBinarySynchronizedRead - Reads from a binary file.
487: Collective on MPI_Comm
489: Input Parameters:
490: + comm - the MPI communicator
491: . fd - the file
492: . n - the number of items to read
493: - type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
495: Output Parameters:
496: . p - the buffer
498: Options Database Key:
499: . -binary_longints - indicates the file was generated on a Cray vector
500: machine (not the T3E/D) and the ints are stored as 64 bit
501: quantities, otherwise they are stored as 32 bit
503: Level: developer
505: Notes:
506: Does a PetscBinaryRead() followed by an MPI_Bcast()
508: PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
509: Integers are stored on the file as 32 long, regardless of whether
510: they are stored in the machine as 32 or 64, this means the same
511: binary file may be read on any machine.
513: Concepts: files^synchronized reading of binary files
514: Concepts: binary files^reading, synchronized
516: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
517: PetscBinarySynchronizedSeek()
518: @*/
519: PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
520: {
522: PetscMPIInt rank;
523: MPI_Datatype mtype;
526: MPI_Comm_rank(comm,&rank);
527: if (!rank) {
528: PetscBinaryRead(fd,p,n,type);
529: }
530: PetscDataTypeToMPIDataType(type,&mtype);
531: MPI_Bcast(p,n,mtype,0,comm);
532: return(0);
533: }
537: /*@C
538: PetscBinarySynchronizedWrite - writes to a binary file.
540: Collective on MPI_Comm
542: Input Parameters:
543: + comm - the MPI communicator
544: . fd - the file
545: . n - the number of items to write
546: . p - the buffer
547: . istemp - the buffer may be changed
548: - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
550: Level: developer
552: Notes:
553: Process 0 does a PetscBinaryWrite()
555: PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
556: Integers are stored on the file as 32 long, regardless of whether
557: they are stored in the machine as 32 or 64, this means the same
558: binary file may be read on any machine.
560: WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
561: while PetscSynchronizedFPrintf() has all processes print their strings in order.
563: Concepts: files^synchronized writing of binary files
564: Concepts: binary files^reading, synchronized
566: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
567: PetscBinarySynchronizedSeek()
568: @*/
569: PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscTruth istemp)
570: {
572: PetscMPIInt rank;
575: MPI_Comm_rank(comm,&rank);
576: if (!rank) {
577: PetscBinaryWrite(fd,p,n,type,istemp);
578: }
579: return(0);
580: }
584: /*@C
585: PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
588: Input Parameters:
589: + fd - the file
590: . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
591: if PETSC_BINARY_SEEK_CUR then size is offset from current location
592: if PETSC_BINARY_SEEK_END then size is offset from end of file
593: - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
594: etc. in your calculation rather than sizeof() to compute byte lengths.
596: Output Parameter:
597: . offset - new offset in file
599: Level: developer
601: Notes:
602: Integers are stored on the file as 32 long, regardless of whether
603: they are stored in the machine as 32 or 64, this means the same
604: binary file may be read on any machine. Hence you CANNOT use sizeof()
605: to determine the offset or location.
607: Concepts: binary files^seeking
608: Concepts: files^seeking in binary
610: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
611: PetscBinarySynchronizedSeek()
612: @*/
613: PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
614: {
616: PetscMPIInt rank;
619: MPI_Comm_rank(comm,&rank);
620: if (!rank) {
621: PetscBinarySeek(fd,off,whence,offset);
622: }
623: return(0);
624: }