Date: 2022-03-31T04:46:06+00:00

Actual source code: sysio.c

      2: /*
      3:    This file contains simple binary read/write routines.
      4:  */

      6: #include <petscsys.h>
      7: #include <petscbt.h>
      8: #include <errno.h>
      9: #include <fcntl.h>
     10: #if defined(PETSC_HAVE_UNISTD_H)
     11: #include <unistd.h>
     12: #endif
     13: #if defined(PETSC_HAVE_IO_H)
     14: #include <io.h>
     15: #endif
     16: #if !defined(PETSC_HAVE_O_BINARY)
     17: #define O_BINARY 0
     18: #endif

     20: const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL};

     22: /* --------------------------------------------------------- */
     23: /*
     24:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

     26: */
     27: PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
     28: {
     29:   PetscInt  i,j;
     30:   PetscEnum tmp = ENUM_DUMMY;
     31:   char      *ptr1,*ptr2 = (char*)&tmp;

     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:   return 0;
     39: }

     41: /*
     42:   PetscByteSwapBool - Swap bytes in a  PETSc Bool

     44: */
     45: PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
     46: {
     47:   PetscInt  i,j;
     48:   PetscBool tmp = PETSC_FALSE;
     49:   char      *ptr1,*ptr2 = (char*)&tmp;

     51:   for (j=0; j<n; j++) {
     52:     ptr1 = (char*)(buff + j);
     53:     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
     54:     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
     55:   }
     56:   return 0;
     57: }

     59: /*
     60:   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)

     62: */
     63: PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
     64: {
     65:   PetscInt i,j,tmp = 0;
     66:   char     *ptr1,*ptr2 = (char*)&tmp;

     68:   for (j=0; j<n; j++) {
     69:     ptr1 = (char*)(buff + j);
     70:     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
     71:     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
     72:   }
     73:   return 0;
     74: }

     76: /*
     77:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)

     79: */
     80: PetscErrorCode  PetscByteSwapInt64(PetscInt64 *buff,PetscInt n)
     81: {
     82:   PetscInt   i,j;
     83:   PetscInt64 tmp = 0;
     84:   char       *ptr1,*ptr2 = (char*)&tmp;

     86:   for (j=0; j<n; j++) {
     87:     ptr1 = (char*)(buff + j);
     88:     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64)-1-i];
     89:     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
     90:   }
     91:   return 0;
     92: }

     94: /* --------------------------------------------------------- */
     95: /*
     96:   PetscByteSwapShort - Swap bytes in a short
     97: */
     98: PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
     99: {
    100:   PetscInt i,j;
    101:   short    tmp;
    102:   char     *ptr1,*ptr2 = (char*)&tmp;

    104:   for (j=0; j<n; j++) {
    105:     ptr1 = (char*)(buff + j);
    106:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
    107:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
    108:   }
    109:   return 0;
    110: }
    111: /*
    112:   PetscByteSwapLong - Swap bytes in a long
    113: */
    114: PetscErrorCode  PetscByteSwapLong(long *buff,PetscInt n)
    115: {
    116:   PetscInt i,j;
    117:   long     tmp;
    118:   char     *ptr1,*ptr2 = (char*)&tmp;

    120:   for (j=0; j<n; j++) {
    121:     ptr1 = (char*)(buff + j);
    122:     for (i=0; i<(PetscInt) sizeof(long); i++) ptr2[i] = ptr1[sizeof(long)-1-i];
    123:     for (i=0; i<(PetscInt) sizeof(long); i++) ptr1[i] = ptr2[i];
    124:   }
    125:   return 0;
    126: }
    127: /* --------------------------------------------------------- */
    128: /*
    129:   PetscByteSwapReal - Swap bytes in a PetscReal
    130: */
    131: PetscErrorCode  PetscByteSwapReal(PetscReal *buff,PetscInt n)
    132: {
    133:   PetscInt  i,j;
    134:   PetscReal tmp,*buff1 = (PetscReal*)buff;
    135:   char      *ptr1,*ptr2 = (char*)&tmp;

    137:   for (j=0; j<n; j++) {
    138:     ptr1 = (char*)(buff1 + j);
    139:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
    140:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
    141:   }
    142:   return 0;
    143: }
    144: /* --------------------------------------------------------- */
    145: /*
    146:   PetscByteSwapScalar - Swap bytes in a PetscScalar
    147:   The complex case is dealt with with an array of PetscReal, twice as long.
    148: */
    149: PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
    150: {
    151:   PetscInt  i,j;
    152:   PetscReal tmp,*buff1 = (PetscReal*)buff;
    153:   char      *ptr1,*ptr2 = (char*)&tmp;

    155: #if defined(PETSC_USE_COMPLEX)
    156:   n *= 2;
    157: #endif
    158:   for (j=0; j<n; j++) {
    159:     ptr1 = (char*)(buff1 + j);
    160:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
    161:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
    162:   }
    163:   return 0;
    164: }
    165: /* --------------------------------------------------------- */
    166: /*
    167:   PetscByteSwapDouble - Swap bytes in a double
    168: */
    169: PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
    170: {
    171:   PetscInt i,j;
    172:   double   tmp,*buff1 = (double*)buff;
    173:   char     *ptr1,*ptr2 = (char*)&tmp;

    175:   for (j=0; j<n; j++) {
    176:     ptr1 = (char*)(buff1 + j);
    177:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
    178:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
    179:   }
    180:   return 0;
    181: }

    183: /*
    184:   PetscByteSwapFloat - Swap bytes in a float
    185: */
    186: PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
    187: {
    188:   PetscInt i,j;
    189:   float    tmp,*buff1 = (float*)buff;
    190:   char     *ptr1,*ptr2 = (char*)&tmp;

    192:   for (j=0; j<n; j++) {
    193:     ptr1 = (char*)(buff1 + j);
    194:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
    195:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
    196:   }
    197:   return 0;
    198: }

    200: PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
    201: {
    202:   if      (pdtype == PETSC_INT)    PetscByteSwapInt((PetscInt*)data,count);
    203:   else if (pdtype == PETSC_ENUM)   PetscByteSwapEnum((PetscEnum*)data,count);
    204:   else if (pdtype == PETSC_BOOL)   PetscByteSwapBool((PetscBool*)data,count);
    205:   else if (pdtype == PETSC_SCALAR) PetscByteSwapScalar((PetscScalar*)data,count);
    206:   else if (pdtype == PETSC_REAL)   PetscByteSwapReal((PetscReal*)data,count);
    207:   else if (pdtype == PETSC_COMPLEX)PetscByteSwapReal((PetscReal*)data,2*count);
    208:   else if (pdtype == PETSC_INT64)  PetscByteSwapInt64((PetscInt64*)data,count);
    209:   else if (pdtype == PETSC_DOUBLE) PetscByteSwapDouble((double*)data,count);
    210:   else if (pdtype == PETSC_FLOAT)  PetscByteSwapFloat((float*)data,count);
    211:   else if (pdtype == PETSC_SHORT)  PetscByteSwapShort((short*)data,count);
    212:   else if (pdtype == PETSC_LONG)   PetscByteSwapLong((long*)data,count);
    213:   return 0;
    214: }

    216: /*@C
    217:    PetscBinaryRead - Reads from a binary file.

    219:    Not Collective

    221:    Input Parameters:
    222: +  fd - the file descriptor
    223: .  num  - the maximum number of items to read
    224: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

    226:    Output Parameters:
    227: +  data - the buffer
    228: -  count - the number of items read, optional

    230:    Level: developer

    232:    Notes:
    233:    If count is not provided and the number of items read is less than
    234:    the maximum number of items to read, then this routine errors.

    236:    PetscBinaryRead() uses byte swapping to work on all machines; the files
    237:    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
    238:    are converted to the little-endian format when they are read in from the file.
    239:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
    240:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
    241:    is used.

    243: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
    244:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
    245: @*/
    246: PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
    247: {
    248:   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
    249:   char              *p = (char*)data;
    250: #if defined(PETSC_USE_REAL___FLOAT128)
    251:   PetscBool         readdouble = PETSC_FALSE;
    252:   double            *pdouble;
    253: #endif
    254:   void              *ptmp = data;
    255:   char              *fname = NULL;

    257:   if (count) *count = 0;
    259:   if (!num) return 0;

    261:   if (type == PETSC_FUNCTION) {
    262:     m     = 64;
    263:     type  = PETSC_CHAR;
    264:     fname = (char*)malloc(m*sizeof(char));
    265:     p     = (char*)fname;
    266:     ptmp  = (void*)fname;
    268:   }
    269:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);

    271:   PetscDataTypeGetSize(type,&typesize);

    273: #if defined(PETSC_USE_REAL___FLOAT128)
    274:   PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);
    275:   /* If using __float128 precision we still read in doubles from file */
    276:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
    277:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
    278:     PetscMalloc1(cnt,&pdouble);
    279:     p = (char*)pdouble;
    280:     typesize /= 2;
    281:   }
    282: #endif

    284:   m *= typesize;

    286:   while (m) {
    287:     size_t len = (m < maxblock) ? m : maxblock;
    288:     int    ret = (int)read(fd,p,len);
    289:     if (ret < 0 && errno == EINTR) continue;
    290:     if (!ret && len > 0) break; /* Proxy for EOF */
    292:     m -= (size_t)ret;
    293:     p += ret;
    294:     n += (size_t)ret;
    295:   }

    298:   num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */
    299:   if (count) *count = num;      /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */

    301: #if defined(PETSC_USE_REAL___FLOAT128)
    302:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
    303:     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
    304:     PetscReal *preal = (PetscReal*)data;
    305:     if (!PetscBinaryBigEndian()) PetscByteSwapDouble(pdouble,cnt);
    306:     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
    307:     PetscFree(pdouble);
    308:     return 0;
    309:   }
    310: #endif

    312:   if (!PetscBinaryBigEndian()) PetscByteSwap(ptmp,type,num);

    314:   if (type == PETSC_FUNCTION) {
    315: #if defined(PETSC_SERIALIZE_FUNCTIONS)
    316:     PetscDLSym(NULL,fname,(void**)data);
    317: #else
    318:     *(void**)data = NULL;
    319: #endif
    320:     free(fname);
    321:   }
    322:   return 0;
    323: }

    325: /*@C
    326:    PetscBinaryWrite - Writes to a binary file.

    328:    Not Collective

    330:    Input Parameters:
    331: +  fd     - the file
    332: .  p      - the buffer
    333: .  n      - the number of items to write
    334: -  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

    336:    Level: advanced

    338:    Notes:
    339:    PetscBinaryWrite() uses byte swapping to work on all machines; the files
    340:    are written using big-endian ordering to the file. On little-endian machines the numbers
    341:    are converted to the big-endian format when they are written to disk.
    342:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
    343:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
    344:    is used.

    346:    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option

    348:    The Buffer p should be read-write buffer, and not static data.
    349:    This way, byte-swapping is done in-place, and then the buffer is
    350:    written to the file.

    352:    This routine restores the original contents of the buffer, after
    353:    it is written to the file. This is done by byte-swapping in-place
    354:    the second time.

    356:    Because byte-swapping may be done on the values in data it cannot be declared const

    358: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
    359:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
    360: @*/
    361: PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
    362: {
    363:   const char     *pp = (char*)p;
    364:   int            err,wsize;
    365:   size_t         m = (size_t)n,maxblock=65536;
    366:   const void     *ptmp = p;
    367:   char           *fname = NULL;
    368: #if defined(PETSC_USE_REAL___FLOAT128)
    369:   PetscBool      writedouble = PETSC_FALSE;
    370:   double         *ppp;
    371:   PetscReal      *pv;
    372:   PetscInt       i;
    373: #endif
    374:   PetscDataType  wtype = type;

    377:   if (!n) return 0;

    379:   if (type == PETSC_FUNCTION) {
    380: #if defined(PETSC_SERIALIZE_FUNCTIONS)
    381:     const char *fnametmp;
    382: #endif
    383:     m     = 64;
    384:     fname = (char*)malloc(m*sizeof(char));
    386: #if defined(PETSC_SERIALIZE_FUNCTIONS)
    388:     PetscFPTFind(*(void**)p,&fnametmp);
    389:     PetscStrncpy(fname,fnametmp,m);
    390: #else
    391:     PetscStrncpy(fname,"",m);
    392: #endif
    393:     wtype = PETSC_CHAR;
    394:     pp    = (char*)fname;
    395:     ptmp  = (void*)fname;
    396:   }

    398: #if defined(PETSC_USE_REAL___FLOAT128)
    399:   PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);
    400:   /* If using __float128 precision we still write in doubles to file */
    401:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
    402:     wtype = PETSC_DOUBLE;
    403:     PetscMalloc1(n,&ppp);
    404:     pv = (PetscReal*)pp;
    405:     for (i=0; i<n; i++) {
    406:       ppp[i] = (double) pv[i];
    407:     }
    408:     pp   = (char*)ppp;
    409:     ptmp = (char*)ppp;
    410:   }
    411: #endif

    413:   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
    414:   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
    415: #if defined(PETSC_HAVE_COMPLEX)
    416:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
    417: #endif
    418:   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
    419:   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
    420:   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
    421:   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
    422:   else if (wtype == PETSC_LONG)    m *= sizeof(long);
    423:   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
    424:   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
    425:   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
    426:   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
    427:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
    428:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

    430:   if (!PetscBinaryBigEndian()) PetscByteSwap((void*)ptmp,wtype,n);

    432:   while (m) {
    433:     wsize = (m < maxblock) ? m : maxblock;
    434:     err   = write(fd,pp,wsize);
    435:     if (err < 0 && errno == EINTR) continue;
    437:     m  -= wsize;
    438:     pp += wsize;
    439:   }

    441:   if (!PetscBinaryBigEndian()) PetscByteSwap((void*)ptmp,wtype,n);

    443:   if (type == PETSC_FUNCTION) {
    444:     free(fname);
    445:   }
    446: #if defined(PETSC_USE_REAL___FLOAT128)
    447:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
    448:     PetscFree(ppp);
    449:   }
    450: #endif
    451:   return 0;
    452: }

    454: /*@C
    455:    PetscBinaryOpen - Opens a PETSc binary file.

    457:    Not Collective

    459:    Input Parameters:
    460: +  name - filename
    461: -  mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND

    463:    Output Parameter:
    464: .  fd - the file

    466:    Level: advanced

    468:    Notes:
    469:     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.

    473: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
    474:           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()

    476: @*/
    477: PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
    478: {
    479:   switch (mode) {
    480:   case FILE_MODE_READ:   *fd = open(name,O_BINARY|O_RDONLY,0); break;
    481:   case FILE_MODE_WRITE:  *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
    482:   case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
    483:   default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
    484:   }
    486:   return 0;
    487: }

    489: /*@
    490:    PetscBinaryClose - Closes a PETSc binary file.

    492:    Not Collective

    494:    Output Parameter:
    495: .  fd - the file

    497:    Level: advanced

    499: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
    500:           PetscBinarySynchronizedSeek()
    501: @*/
    502: PetscErrorCode  PetscBinaryClose(int fd)
    503: {
    505:   return 0;
    506: }

    508: /*@C
    509:    PetscBinarySeek - Moves the file pointer on a PETSc binary file.

    511:    Not Collective

    513:    Input Parameters:
    514: +  fd - the file
    515: .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
    516:             etc. in your calculation rather than sizeof() to compute byte lengths.
    517: -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
    518:             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
    519:             if PETSC_BINARY_SEEK_END then off is an offset from the end of file

    521:    Output Parameter:
    522: .   offset - new offset in file

    524:    Level: developer

    526:    Notes:
    527:    Integers are stored on the file as 32 long, regardless of whether
    528:    they are stored in the machine as 32 or 64, this means the same
    529:    binary file may be read on any machine. Hence you CANNOT use sizeof()
    530:    to determine the offset or location.

    532: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
    533:           PetscBinarySynchronizedSeek()
    534: @*/
    535: PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
    536: {
    537:   int iwhence = 0;

    539:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
    540:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
    541:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
    542:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
    543: #if defined(PETSC_HAVE_LSEEK)
    544:   *offset = lseek(fd,off,iwhence);
    545: #elif defined(PETSC_HAVE__LSEEK)
    546:   *offset = _lseek(fd,(long)off,iwhence);
    547: #else
    548:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
    549: #endif
    550:   return 0;
    551: }

    553: /*@C
    554:    PetscBinarySynchronizedRead - Reads from a binary file.

    556:    Collective

    558:    Input Parameters:
    559: +  comm - the MPI communicator
    560: .  fd - the file descriptor
    561: .  num  - the maximum number of items to read
    562: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

    564:    Output Parameters:
    565: +  data - the buffer
    566: -  count - the number of items read, optional

    568:    Level: developer

    570:    Notes:
    571:    Does a PetscBinaryRead() followed by an MPI_Bcast()

    573:    If count is not provided and the number of items read is less than
    574:    the maximum number of items to read, then this routine errors.

    576:    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
    577:    Integers are stored on the file as 32 long, regardless of whether
    578:    they are stored in the machine as 32 or 64, this means the same
    579:    binary file may be read on any machine.

    581: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
    582:           PetscBinarySynchronizedSeek()
    583: @*/
    584: PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
    585: {
    586:   PetscMPIInt    rank,size;
    587:   MPI_Datatype   mtype;
    588:   PetscInt       ibuf[2] = {0, 0};
    589:   char           *fname = NULL;
    590:   void           *fptr = NULL;

    592:   if (type == PETSC_FUNCTION) {
    593:     num   = 64;
    594:     type  = PETSC_CHAR;
    595:     fname = (char*)malloc(num*sizeof(char));
    596:     fptr  = data;
    597:     data  = (void*)fname;
    599:   }

    601:   MPI_Comm_rank(comm,&rank);
    602:   MPI_Comm_size(comm,&size);
    603:   if (rank == 0) {
    604:     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
    605:   }
    606:   MPI_Bcast(ibuf,2,MPIU_INT,0,comm);
    607:   (PetscErrorCode)ibuf[0];

    609:   /* skip MPI call on potentially huge amounts of data when running with one process; this allows the amount of data to basically unlimited in that case */
    610:   if (size > 1) {
    611:     PetscDataTypeToMPIDataType(type,&mtype);
    612:     MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);
    613:   }
    614:   if (count) *count = ibuf[1];

    616:   if (type == PETSC_FUNCTION) {
    617: #if defined(PETSC_SERIALIZE_FUNCTIONS)
    618:     PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);
    619: #else
    620:     *(void**)fptr = NULL;
    621: #endif
    622:     free(fname);
    623:   }
    624:   return 0;
    625: }

    627: /*@C
    628:    PetscBinarySynchronizedWrite - writes to a binary file.

    630:    Collective

    632:    Input Parameters:
    633: +  comm - the MPI communicator
    634: .  fd - the file
    635: .  n  - the number of items to write
    636: .  p - the buffer
    637: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

    639:    Level: developer

    641:    Notes:
    642:    Process 0 does a PetscBinaryWrite()

    644:    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
    645:    Integers are stored on the file as 32 long, regardless of whether
    646:    they are stored in the machine as 32 or 64, this means the same
    647:    binary file may be read on any machine.

    649:    Notes:
    650:     because byte-swapping may be done on the values in data it cannot be declared const

    652:    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
    653:    while PetscSynchronizedFPrintf() has all processes print their strings in order.

    655: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
    656:           PetscBinarySynchronizedSeek()
    657: @*/
    658: PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
    659: {
    660:   PetscMPIInt    rank;

    662:   MPI_Comm_rank(comm,&rank);
    663:   if (rank == 0) {
    664:     PetscBinaryWrite(fd,p,n,type);
    665:   }
    666:   return 0;
    667: }

    669: /*@C
    670:    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.

    672:    Input Parameters:
    673: +  fd - the file
    674: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
    675:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
    676:             if PETSC_BINARY_SEEK_END then size is offset from end of file
    677: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
    678:             etc. in your calculation rather than sizeof() to compute byte lengths.

    680:    Output Parameter:
    681: .   offset - new offset in file

    683:    Level: developer

    685:    Notes:
    686:    Integers are stored on the file as 32 long, regardless of whether
    687:    they are stored in the machine as 32 or 64, this means the same
    688:    binary file may be read on any machine. Hence you CANNOT use sizeof()
    689:    to determine the offset or location.

    691: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
    692:           PetscBinarySynchronizedSeek()
    693: @*/
    694: PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
    695: {
    696:   PetscMPIInt    rank;

    698:   MPI_Comm_rank(comm,&rank);
    699:   if (rank == 0) {
    700:     PetscBinarySeek(fd,off,whence,offset);
    701:   }
    702:   return 0;
    703: }

    705: #if defined(PETSC_HAVE_MPIIO)

    707: #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
    708: /*
    709:       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
    710:     These are set into MPI in PetscInitialize() via MPI_Register_datarep()

    712:     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)

    714:     The next three routines are not used because MPICH does not support their use

    716: */
    717: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
    718: {
    719:   MPI_Aint    ub;
    720:   PetscMPIInt ierr;

    722:   MPI_Type_get_extent(datatype,&ub,file_extent);
    723:   return ierr;
    724: }

    726: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
    727: {
    728:   PetscDataType pdtype;
    729:   PetscMPIInt   ierr;
    730:   size_t        dsize;

    732:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
    733:   PetscDataTypeGetSize(pdtype,&dsize);

    735:   /* offset is given in units of MPI_Datatype */
    736:   userbuf = ((char*)userbuf) + dsize*position;

    738:   PetscMemcpy(userbuf,filebuf,count*dsize);
    739:   if (!PetscBinaryBigEndian()) PetscByteSwap(userbuf,pdtype,count);
    740:   return ierr;
    741: }

    743: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
    744: {
    745:   PetscDataType pdtype;
    746:   PetscMPIInt   ierr;
    747:   size_t        dsize;

    749:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
    750:   PetscDataTypeGetSize(pdtype,&dsize);

    752:   /* offset is given in units of MPI_Datatype */
    753:   userbuf = ((char*)userbuf) + dsize*position;

    755:   PetscMemcpy(filebuf,userbuf,count*dsize);
    756:   if (!PetscBinaryBigEndian()) PetscByteSwap(filebuf,pdtype,count);
    757:   return ierr;
    758: }
    759: #endif

    761: PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    762: {
    763:   PetscDataType  pdtype;

    765:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    766:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    767:   MPI_File_write_all(fd,data,cnt,dtype,status);
    768:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    769:   return 0;
    770: }

    772: PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    773: {
    774:   PetscDataType  pdtype;

    776:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    777:   MPI_File_read_all(fd,data,cnt,dtype,status);
    778:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    779:   return 0;
    780: }

    782: PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    783: {
    784:   PetscDataType  pdtype;

    786:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    787:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    788:   MPI_File_write_at(fd,off,data,cnt,dtype,status);
    789:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    790:   return 0;
    791: }

    793: PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    794: {
    795:   PetscDataType  pdtype;

    797:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    798:   MPI_File_read_at(fd,off,data,cnt,dtype,status);
    799:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    800:   return 0;
    801: }

    803: PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    804: {
    805:   PetscDataType  pdtype;

    807:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    808:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    809:   MPI_File_write_at_all(fd,off,data,cnt,dtype,status);
    810:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    811:   return 0;
    812: }

    814: PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    815: {
    816:   PetscDataType  pdtype;

    818:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    819:   MPI_File_read_at_all(fd,off,data,cnt,dtype,status);
    820:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
    821:   return 0;
    822: }

    824: #endif