Example #1
0
hid_t
dat1GetParentID( hid_t objid, hdsbool_t allow_root, int * status ) {
  hid_t parent_id = -1;
  ssize_t lenstr = 0;
  char * tempstr = NULL;

  if (*status != SAI__OK) return parent_id;

  /* Not sure if there is a specific API for this. For now,
     get the full name of the object and then open the group
     with the lowest part of the path removed */
  tempstr = dat1GetFullName( objid, 0, &lenstr, status );

  if (*status == SAI__OK && lenstr <= 1) {
    *status = DAT__OBJIN;
    emsRep("datParen_0",
           "Object is the HDF5 root group and has no parent "
           "group (possible programming error).", status);
    goto CLEANUP;
  }

  /* Now walk through the name in reverse and nul out the first "/"
     we encounter. */
  if (*status == SAI__OK) {
    ssize_t iposn;
    ssize_t i;
    for (i = 0; i < lenstr; i++) {
      iposn = lenstr - (i+1);
      if (tempstr[iposn] == '/') {
        tempstr[iposn] = '\0';
        break;
      }
    }
  }

  /* if this seems to be the root group we rewrite it to be "/" else,
     optionally return an error. */
  if (tempstr[0] == '\0') {
    if (allow_root) {
      tempstr[0] = '/';
      tempstr[1] = '\0';
    } else if (*status == SAI__OK) {
      *status = DAT__OBJIN;
      emsRep("datParen_1",
             "Object is a top-level object and has no parent "
             "structure (possible programming error).", status);
      goto CLEANUP;
    }
  }

  /* It seems you can open a group on an arbitrary
     item (group or dataset) if you use a fully specified
     path. This means you do not need to get an
     explicit file_id to open the group */
  CALLHDFE( hid_t, parent_id,
          H5Gopen(objid, tempstr, H5P_DEFAULT),
          DAT__HDF5E,
          emsRepf("datParen_2", "Error opening parent structure '%s'",
                  status, tempstr );
          );
Example #2
0
HDSLoc *
dat1ImportFloc ( const char flocator[DAT__SZLOC], int loc_length, int * status) {

  long ptr_as_long = 0;
  HDSLoc * clocator = NULL;

  /* Validate the locator length. */
  if (loc_length != DAT__SZLOC ) {
    if (*status == SAI__OK ) {
       *status = DAT__LOCIN;
       emsRepf( "DAT1_IMPORT_FLOC", "Locator length is %d not %d", status,
                loc_length, DAT__SZLOC);
    }
    return NULL;
  };

  /* Check obvious error conditions */
  if (strncmp( DAT__ROOT, flocator, loc_length) == 0 ){
    if( *status == SAI__OK ) {
       *status = DAT__LOCIN;
       emsRep( "dat1ImportFloc_ROOT",
               "Input HDS Locator corresponds to DAT__ROOT but that can only be used from NDF",
               status );
    }
    return NULL;
  }

  /* Check obvious error conditions */
  if (strncmp( DAT__NOLOC, flocator, loc_length) == 0 ){
    if( *status == SAI__OK ) {
       *status = DAT__LOCIN;
       emsRep( "datImportFloc_NOLOC",
               "Input HDS Locator corresponds to DAT__NOLOC but status is good (Possible programming error)",
               status );
    }
    return NULL;
  }

  /* Everything seems to be okay so now convert the string buffer to the
     required pointer. We ignore status as sometimes we need to try
     to get the value regardless (otherwise DAT_ANNUL from Fortran would
     never succeed). */

  ptr_as_long = strtol( flocator, NULL, 16 );

  if (ptr_as_long == 0) {
    /* This should not have happened */
    if (*status == SAI__OK) {
      *status = DAT__LOCIN;
      emsRep("dat1_import_floc_3",
             "Error importing locator from Fortran", status );
      return NULL;
    }
  }

  /* Do the cast */
  clocator = (HDSLoc *)ptr_as_long;
  return clocator;
}
Example #3
0
void
dat1SetAttrString( hid_t obj_id, const char * attrname,
                   const char * value, int * status ) {

  hid_t attrtype = 0;

  if (*status != SAI__OK) return;

  CALLHDFE( hid_t, attrtype,
           H5Tcopy(H5T_C_S1),
           DAT__HDF5E,
           emsRepf("dat1SetAttrString_1", "Error copying data type during writing of attribute '%s'", status, attrname );
           );
Example #4
0
int
datErase(const HDSLoc   *locator, const char *name_str, int *status) {
  char groupstr[DAT__SZNAM+1];
  char cleanname[DAT__SZNAM+1];

  if (*status != SAI__OK) return *status;

  /* Validate input locator. */
  dat1ValidateLocator( "datErase", 1, locator, 0, status );

  /* containing locator must refer to a group */
  if (locator->group_id <= 0) {
    *status = DAT__OBJIN;
    emsRep("datErase_1", "Input object is not a structure",
           status);
    return *status;
  }

  /* Parent group for error reporting */
  datName( locator, groupstr, status);

  /* Ensure the name is cleaned up before we use it */
  dau1CheckName( name_str, 1, cleanname, sizeof(cleanname), status );

  CALLHDFQ( H5Ldelete( locator->group_id, cleanname, H5P_DEFAULT ));

  /* Remove the handle for the erased component and all sub-components */
  dat1EraseHandle( locator->handle, cleanname, status );

 CLEANUP:
  if (*status != SAI__OK) {
    emsRepf("datErase_2", "Error deleting component %s in group %s",
            status, name_str, groupstr);
  }
  return *status;
}
Example #5
0
static void *
dat1Mmap( size_t nbytes, int prot, int flags, int fd, off_t offset, int *isreg, void **pntr, size_t *actbytes, int * status ) {
  void * mapped = NULL;
  int tries = 0;
  size_t pagesize = 0;
  void * where = NULL;
  off_t off = 0;
  *pntr = NULL;
  *isreg = 0;

  if (*status != SAI__OK) return NULL;

  /* We need to know the pagesize */
  pagesize = sysconf( _SC_PAGESIZE );

  *actbytes = nbytes;
  if (offset > 0) {
    /* Calculate the starting offset into the file and round this down to a     */
    /* multiple of the system page size. Calculate the number of bytes to map,  */
    /* allowing for this rounding.                                              */
    off = offset - ( offset % pagesize );
    *actbytes += ( offset - off );
  }

  while (!mapped) {
    *isreg = 0;
    tries++;
    if (*status != SAI__OK) goto CLEANUP;

    /* Get some anonymous memory - we always have to map read/write
       because we always have to copy data into this space. */
    //printf("mmap(%p, %zu, %d, %d, %d, %zu -> %zu [%d])\n", where, *actbytes, prot, flags, fd, offset, off, pagesize);
    mapped = mmap( where, *actbytes, prot, flags, fd, off );
    if (mapped == MAP_FAILED) {
      emsSyser( "MESSAGE", errno );
      *status = DAT__FILMP;
      emsRep("datMap_2", "Error mapping some memory: ^MESSAGE", status );
      mapped = NULL;
      *pntr = NULL;
      goto CLEANUP;
    }
    /* The pointer we register is the one that has been corrected
       for the shift we applied in the original request */
    *pntr = mapped + (offset - off );

    /* Must register with CNF so the pointer can be used by Fortran */
    *isreg = cnfRegp( *pntr );
    if (*isreg == -1) {
      /* Serious internal error */
      *status = DAT__FILMP;
      emsRep("datMap_3", "Error registering a pointer for mapped data "
             " - internal CNF error", status );
      goto CLEANUP;
    } else if (*isreg == 0) {
      /* Free the memory and try again */
      if ( munmap( mapped, *actbytes ) != 0 ) {
        *status = DAT__FILMP;
        emsSyser( "MESSAGE", errno );
        emsRep("datMap_4", "Error unmapping mapped memory following"
               " failed registration: ^MESSAGE", status);
        goto CLEANUP;
      }
      if (!where) where = mapped;
      where += pagesize;
      mapped = NULL;
      *pntr = NULL;
    }

    if (!mapped && tries > 100) {
      *status = DAT__FILMP;
      emsRepf("datMap_4b", "Failed to register mapped memory with CNF"
             " after %d attempts", status, tries );
      goto CLEANUP;
    }

  }
 CLEANUP:
  return mapped;
}
Example #6
0
int
datMap(HDSLoc *locator, const char *type_str, const char *mode_str, int ndim,
       const hdsdim dims[], void **pntr, int *status) {

  int isprim = 0;
  char normtypestr[DAT__SZTYP+1];
  size_t nbytes = 0;
  hid_t h5type = 0;
  int isreg = 0;
  void *regpntr = NULL;
  void *mapped = NULL;
  hdsmode_t accmode = HDSMODE_UNKNOWN;
  haddr_t offset;
  hdsbool_t try_mmap = HDS_FALSE;
  unsigned intent = 0;
  size_t actbytes = 0;

  if (*status != SAI__OK) return *status;

  /* First have to validate the access mode */
  switch (mode_str[0]) {
  case 'R':
  case 'r':
    accmode = HDSMODE_READ;
    break;
  case 'U':
  case 'u':
    accmode = HDSMODE_UPDATE;
    break;
  case 'W':
  case 'w':
    accmode = HDSMODE_WRITE;
    break;
  default:
    *status = DAT__MODIN;
    emsRepf("datMap_6", "Unrecognized mode string '%s' for datMap",
            status, mode_str);
    goto CLEANUP;
  }

  /* Validate input locator. */
  dat1ValidateLocator( "datMap", 1, locator, (accmode & HDSMODE_READ), status );

  /* Get the HDF5 type code and confirm this is a primitive type */
  isprim = dau1CheckType( 1, type_str, &h5type, normtypestr,
                          sizeof(normtypestr), status );

  if (!isprim) {
    if (*status == SAI__OK) {
      *status = DAT__TYPIN;
      emsRepf("datMap_1", "datGet: Data type must be a primitive type and not '%s'",
              status, normtypestr);
    }
    goto CLEANUP;
  }

  /* Not allowed to map undefined data in READ or UPDATE mode */
  if (accmode == HDSMODE_UPDATE || accmode == HDSMODE_READ) {
    hdsbool_t defined;
    if (*status == SAI__OK) {
      datState( locator, &defined, status );
      if (!defined) {
        *status = DAT__UNSET;
        emsRepf("datMap_6bb", "Can not map an undefined primitive in mode '%s'",
                status, mode_str);
        goto CLEANUP;
      }
    }
  }

  /* How did we open this file? */
  CALLHDFQ( H5Fget_intent( locator->file_id, &intent ));
  if (accmode == HDSMODE_UPDATE || accmode == HDSMODE_WRITE) {
    /* Must check whether the file was opened for write */
    if ( intent == H5F_ACC_RDONLY ) {
      *status = DAT__ACCON;
      emsRepf("datMap_6b", "datMap: Can not map readonly locator in mode '%s'",
             status, mode_str);
      goto CLEANUP;
    }
  }

  /* Verify that the specified dimensions match the locator dimensions */
  if (*status == SAI__OK) {
    hdsdim locdims[DAT__MXDIM];
    int locndims;
    int i;
    datShape(locator, DAT__MXDIM, locdims, &locndims, status );

    /* Note that if we are mapping as a scalar the locator should
       refer to a single element */
    if (ndim == 0) {
      size_t nelem = 1;
      for (i=0; i<locndims; i++) {
        nelem *= locdims[i];
      }
      if (nelem != 1) {
        *status = DAT__DIMIN;
        emsRepf("datMap_6e", "datMap: Attempt to map as a scalar but locator"
                " refers to a primitive with %zu elements",
                status, nelem);
        goto CLEANUP;
      }
    } else {
      if (ndim != locndims) {
        *status = DAT__DIMIN;
        emsRepf("datMap_6c", "datMap: Dimensionality mismatch --"
                " requested number: %d locator number: %d", status,
                ndim, locndims );
        goto CLEANUP;
      }
      for (i=0; i<ndim; i++) {
        if ( locdims[i] != dims[i] ) {
          *status = DAT__DIMIN;
          emsRepf("datMap_6d", "datMap: Dimension %d has size %zu but requested size %zu",
                  status, i, (size_t)locdims[i], (size_t)dims[i]);
          goto CLEANUP;
        }
      }
    }
  }

  /* There is a super-special case for datMap when called with a map
     type of "_CHAR". In that case we need to work out the size ourselves
     and adjust the type size */
  if (strcmp( "_CHAR", normtypestr ) == 0 ) {
    size_t clen = 0;
    char tmpbuff[DAT__SZTYP+1];
    datClen( locator, &clen, status );
    CALLHDFQ( H5Tset_size( h5type, clen ) );
    one_snprintf( tmpbuff, sizeof(tmpbuff), "*%zu",
                  status, clen );
    one_strlcat( normtypestr, tmpbuff, DAT__SZTYP+1, status );
  }

  /* Now we want the HDSTYPE of the requested type so that we can work out how much
     memory we will need to allocate. */
  CALLHDFE( size_t, nbytes,
          H5Tget_size( h5type ),
          DAT__HDF5E,
          emsRep("datLen_size", "datMap: Error obtaining size of requested data type",
                 status)
          );

  {
    int i;
    if (ndim > 0) {
      for (i = 0; i < ndim; i++) {
        nbytes *= dims[i];
      }
    }
  }


  /* Work out whether memory mapping is possible -- at the moment
     I'm pretty sure the only safe use of mmap is when we are reading
     the data and the file itself was opened readonly. I'm not sure what happens
     if other components are removed or added -- will the offset change? Maybe we just try */
  offset = H5Dget_offset( locator->dataset_id );
  if (offset != HADDR_UNDEF) {
    hid_t dataset_h5type = 0;
    /* In theory we can do a memory map so now compare
       the data types of the request and the low-level dataset. */
    CALLHDFE( hid_t, dataset_h5type,
             H5Dget_type( locator->dataset_id ),
             DAT__HDF5E,
             emsRep("datMap_type", "datType: Error obtaining data type of dataset", status)
             );
    if (H5Tequal( dataset_h5type, h5type )) {
      try_mmap = HDS_TRUE;
    }
    H5Tclose(dataset_h5type);
  }

  /* If this is a locator to a slice then for now we can't memory map. In theory
     if we knew the slice was contiguous (e.g a vectorized slice, or a single
     plane of a cube then we could mmap it anyhow. We do not want to have to
     emulate HDF5 dataspaces here */
  if (locator->isslice) try_mmap = 0;

  /* There seem to be issues doing this on files opened for update/write.
     For now only allow mmap for files opened read only */
  if (intent != H5F_ACC_RDONLY) try_mmap = 0;

  /* If mmap has been disabled by tuning the environment we just force it off here. */
  if (!hds1GetUseMmap()) try_mmap = 0;

#if DEBUG_HDS
  {
    char *name_str;
    char * file_str;
    const char * reason;
    name_str = dat1GetFullName( locator->dataset_id, 0, NULL, status );
    file_str = dat1GetFullName( locator->dataset_id, 1, NULL, status );
    if (offset != HADDR_UNDEF) {
      reason = "[HAD offset]";
    } else {
      reason = "[no offset]";
    }
    if (!try_mmap) {
      printf("Will NOT attempt %s to mmap %s:%s\n",reason,file_str,name_str);
    } else {
      printf("WILL TRY %s to mmap OFFSET=%zu %s:%s\n", reason, (size_t)offset, file_str, name_str);
    }
    MEM_FREE(name_str);
  }
#endif

  if (try_mmap) {
    int fd = 0;
    int flags = 0;
    int prot = 0;
    hdsbool_t opened_fd = 0;

    if ( intent == H5F_ACC_RDONLY || accmode == HDSMODE_READ ) {
      flags |= O_RDONLY;
      prot = PROT_READ;
    } else {
      flags |= O_RDWR;
      prot = PROT_READ | PROT_WRITE;
    }

    if (*status == SAI__OK) {
      /* see what file driver we have */
      hid_t fapl_id = -1;
      hid_t fdriv_id = -1;
      void * file_handle = NULL;
      herr_t herr = -1;
      fapl_id = H5Fget_access_plist(locator->file_id);
      fdriv_id = H5Pget_driver(fapl_id);
      if (fdriv_id == H5FD_SEC2 || fdriv_id == H5FD_STDIO) {
        /* If this is a POSIX or STDIO driver we get the handle */
        herr = H5Fget_vfd_handle( locator->file_id, fapl_id, (void**)&file_handle);
        if (herr >= 0) {
          if (fdriv_id == H5FD_SEC2) {
            fd = *((int *)file_handle);
          } else if (fdriv_id == H5FD_STDIO) {
            FILE * fh = (FILE *)file_handle;
            fd = fileno(fh);
          }
        }
      }
      if (fapl_id > 0) H5Pclose( fapl_id );

      if (fd == 0) {
        /* We have to open the file ourselves! */
        char * fname = NULL;
        fname = dat1GetFullName( locator->dataset_id, 1, NULL, status );
        fd = open(fname, flags);
        opened_fd = 1;
        if (fname) MEM_FREE(fname);
      }
      if (fd > 0) {
        /* Set up for memory mapping */
        int mflags = 0;
        mflags = MAP_SHARED | MAP_FILE;
        if (*status == SAI__OK) {
          mapped = dat1Mmap( nbytes, prot, mflags, fd, offset, &isreg, &regpntr, &actbytes, status );
          if (*status == SAI__OK) {
            /* Store the file descriptor in the locator to allow us to close */
            if (mapped) {
              if (opened_fd) locator->fdmap = fd;
              locator->uses_true_mmap = 1;
            }
          } else {
            /* Not currently fatal -- we can try without the file */
            if (opened_fd) close(fd);
            emsAnnul(status);
          }
        }
      }
    }
  }

  /* If we have not been able to map anything yet, just get some memory. It is
     zeroed (for WRITE) to match mmap behavior. We rely on the OS to decide when it is reasonable
     to do an anonymous mmap. */

  if (!regpntr) {
    hdsbool_t mustget;
    mustget = (accmode == HDSMODE_READ || accmode == HDSMODE_UPDATE);

    if (mustget) {
      regpntr = cnfMalloc( nbytes );
    } else {
      regpntr = cnfCalloc( 1, nbytes );
    }
    if (!regpntr) {
      *status = DAT__NOMEM;
      emsRepf("datMap_cnf","datMap: Unable to allocate %zu bytes of memory",
              status, nbytes);
      goto CLEANUP;
    }

    /* Populate the memory - check with datState occurred earlier */
    if (mustget) {
      datGet( locator, normtypestr, ndim, dims, regpntr, status );
    }
  }

 CLEANUP:
  /* Cleanups that must happen always */
  if (h5type) H5Tclose(h5type);

  /* cleanups that only happen if status is bad */
  if (*status != SAI__OK) {
    if (mapped) {
      if (isreg == 1) cnfUregp( regpntr );
      if ( munmap( mapped, actbytes ) != 0 ) {
        emsSyser( "MESSAGE", errno );
        emsRep("datMap_4", "Error unmapping mapped memory: ^MESSAGE", status);
      }
      mapped = NULL;
    } else if (regpntr) {
      cnfFree( regpntr );
    }
    regpntr = NULL;
  }

  /* Update the locator to reflect the mapped status */
  if (*status == SAI__OK) {
    int i;
    locator->pntr = mapped;
    locator->regpntr = regpntr;
    locator->bytesmapped = actbytes;
    locator->accmode = accmode;

    /* In order to copy the data back into the underlying HDF5 dataset
       we need to store additional information about how this was mapped
       to allow us to either call datPut later on or at least a new
       dataspace. For now store the arguments so we can pass them straight
       to datPut */
    locator->ndims = ndim;
    for (i=0; i<ndim; i++) {
      (locator->mapdims)[i] = dims[i];
    }
    star_strlcpy( locator->maptype, normtypestr, sizeof(locator->maptype) );
  }

  /* Note that the returned pointer is not necessarily the same as the
     mapped pointer because of pagesize corrections */
  *pntr = regpntr;

  return *status;
}
Example #7
0
Handle *dat1HandleLock( Handle *handle, int oper, int recurs, int rdonly,
                        int *result, int *status ){

/* Local Variables; */
   Handle *child;
   int ichild;
   int top_level;
   pthread_t *locker;
   pthread_t *rlocker;
   int i;
   int j;
   Handle *error_handle = NULL;
   int child_result;

/* initialise */
   *result = 0;

/* Check inherited status. */
   if( *status != SAI__OK ) return error_handle;

/* Validate the supplied Handle */
   if( !dat1ValidateHandle( "dat1HandleLock", handle, status ) ) return error_handle;

/* To avoid deadlocks, we only lock the Handle mutex for top level
   entries to this function. If "oper" is negative, negate it and set a
   flag indicating we do not need to lock the mutex. */
   if( oper < 0 ) {
      oper = -oper;
      top_level = 0;
   } else {
      top_level = 1;
   }

/* For top-level entries to this function, we need to ensure no other thread
   is modifying the details in the handle, so attempt to lock the handle's
   mutex. */
   if( top_level ) pthread_mutex_lock( &(handle->mutex) );

/* Return information about the current lock on the supplied Handle.
   ------------------------------------------------------------------ */
   if( oper == 1 ) {

/* Default: unlocked */

      if( handle->nwrite_lock ) {
         if( pthread_equal( handle->write_locker, pthread_self() )) {

/* Locked for writing by the current thread. */
            *result = 1;
         } else {

/* Locked for writing by another thread. */
            *result = 2;
         }

      } else if( handle->nread_lock ){

/* Locked for reading by one or more other threads (the current thread does
   not have a read lock on the Handle). */
         *result = 4;

/* Now check to see if the current thread has a read lock, changing the
   above result value if it does. */
         locker = handle->read_lockers;
         for( i = 0; i < handle->nread_lock;i++,locker++ ) {
            if( pthread_equal( *locker, pthread_self() )) {

/* Locked for reading by the current thread (other threads may also have
   a read lock on the Handle). */
               *result = 3;
               break;
            }
         }
      }

/* If required, check any child handles. If we already have a status of
   2, (the supplied handle is locked read-write by another thread), we do
   not need to check the children. */
      if( recurs && *result != 2 ){
         for( ichild = 0; ichild < handle->nchild; ichild++ ) {
            child = handle->children[ichild];
            if( child ) {

/* Get the lock status of the child. */
               (void) dat1HandleLock( child, -1, 1, rdonly, &child_result,
                                      status );

/* If it's 2, we can set the final result and exit immediately. */
               if( child_result == 2 ) {
                  *result = 2;
                  break;

/* Otherwise, ensure the child gives the same result as all the others,
   breaking out and returning the catch-all value if not. */
               } else if(  child_result != *result ) {
                  *result = 5;
                  break;
               }
            }
         }
      }





/* Lock the handle for use by the current thread.
   ------------------------------------------------------------------ */
   } else if( oper == 2 ) {

/* A read-only lock requested.... */
      if( rdonly ) {

/* If the current thread has a read-write lock on the Handle, demote it
   to a read-only lock and return 1 (success). In this case, we know
   there will be no other read-locks. Otherwise if any other thread has
   read-write lock, return zero (failure). */
         if( handle->nwrite_lock ) {
            if( pthread_equal( handle->write_locker, pthread_self() )) {

/* If we do not have an array in which to store read lock thread IDs,
   allocate one now with room for NTHREAD locks. It will be extended as
   needed. */
               if( !handle->read_lockers ) {
                  handle->read_lockers = MEM_CALLOC(NTHREAD,sizeof(pthread_t));
                  if( !handle->read_lockers ) {
                     *status = DAT__NOMEM;
                     emsRep( "", "Could not allocate memory for HDS "
                             "Handle read locks list.", status );
                  }
               }

/* If we now have an array, store the current thread in the first element. */
               if( handle->read_lockers ) {
                  handle->read_lockers[ 0 ] = pthread_self();
                  handle->nread_lock = 1;
                  handle->nwrite_lock = 0;
                  *result = 1;
               }
            }

/* If there is no read-write lock on the Handle, add the current thread
   to the list of threads that currently have a read-only lock, but only
   if it is not already there. */
         } else {

/* Set "result" to 1 if the current thread already has a read-only lock. */
            locker = handle->read_lockers;
            for( i = 0; i < handle->nread_lock;i++,locker++ ) {
               if( pthread_equal( *locker, pthread_self() )) {
                  *result = 1;
                  break;
               }
            }

/* If not, extend the read lock thread ID array if necessary, and append
   the current thread ID to the end. */
            if( *result == 0 ) {
               handle->nread_lock++;
               if( handle->maxreaders < handle->nread_lock ) {
                  handle->maxreaders += NTHREAD;
                  handle->read_lockers = MEM_REALLOC( handle->read_lockers,
                                                    handle->maxreaders*sizeof(pthread_t));
                  if( !handle->read_lockers ) {
                     *status = DAT__NOMEM;
                     emsRep( "", "Could not reallocate memory for HDS "
                             "Handle read locks list.", status );
                  }
               }

               if( handle->read_lockers ) {
                  handle->read_lockers[ handle->nread_lock - 1 ] = pthread_self();

/* Indicate the read-only lock was applied successfully. */
                  *result = 1;
               }
            }
         }

/* A read-write lock requested. */
      } else {

/* If there are currently no locks of any kind, apply the lock. */
         if( handle->nread_lock == 0 ) {
            if( handle->nwrite_lock == 0 ) {
               handle->write_locker = pthread_self();
               handle->nwrite_lock = 1;
               *result = 1;

/* If the current thread already has a read-write lock, indicate success. */
            } else if( pthread_equal( handle->write_locker, pthread_self() )) {
               *result = 1;
            }

/* If there is currently only one read-only lock, and it is owned by the
   current thread, then promote it to a read-write lock. */
         } else if( handle->nread_lock == 1 &&
                    pthread_equal( handle->read_lockers[0], pthread_self() )) {
            handle->nread_lock = 0;
            handle->write_locker = pthread_self();
            handle->nwrite_lock = 1;
            *result = 1;
         }
      }

/* If required, and if the above lock operation was successful, lock any
   child handles that can be locked. */
      if( *result ){
         if( recurs ){
            for( ichild = 0; ichild < handle->nchild; ichild++ ) {
               child = handle->children[ichild];
               if( child ) {
                  error_handle = dat1HandleLock( child, -2, 1, rdonly,
                                                 result, status );
                  if( error_handle ) break;
               }
            }
         }

/* If the lock operation failed, return a pointer to the Handle. */
      } else {
         error_handle = handle;
      }




/* Unlock the handle.
   ----------------- */
   } else if( oper == 3 ) {

/* Assume failure. */
      *result = 0;

/* If the current thread has a read-write lock, remove it. */
      if( handle->nwrite_lock ) {
         if( pthread_equal( handle->write_locker, pthread_self() )) {
            handle->nwrite_lock = 0;
            *result = 1;
         } else {
            *result = -1;
         }

/* Otherwise, if the current thread has a read-only lock, remove it. */
      } else {

/* Loop through all the threads that have read-only locks. */
         locker = handle->read_lockers;
         for( i = 0; i < handle->nread_lock; i++,locker++ ) {

/* If the current thread is found, shuffle any remaining threads down one
   slot to fill the gap left by removing the current thread from the list. */
            if( pthread_equal( *locker, pthread_self() )) {
               rlocker = locker + 1;
               for( j = i + 1; j < handle->nread_lock; j++,locker++ ) {
                  *locker = *(rlocker++);
               }

/* Reduce the number of read-only locks. */
               handle->nread_lock--;
               *result = 1;
               break;
            }
         }
      }

/* If required, and if the above unlock operation was successful, unlock any
   child handles that can be unlocked. */
      if( *result == 1 ){
         if( recurs ){
            for( ichild = 0; ichild < handle->nchild; ichild++ ) {
               child = handle->children[ichild];
               if( child ) {
                  error_handle = dat1HandleLock( child, -3, 1, 0,
                                                 result, status );
                  if( error_handle ) break;
               }
            }
         }

/* If the unlock operation failed, return a pointer to the Handle. */
      } else {
         error_handle = handle;
      }




/* Report an error for any other "oper" value. */
   } else if( *status == SAI__OK ) {
      *status = DAT__FATAL;
      emsRepf( " ", "dat1HandleLock: Unknown 'oper' value (%d) supplied - "
               "(internal HDS programming error).", status, oper );
   }

/* If this is a top-level entry, unlock the Handle's mutex so that other
   threads can access the values in the Handle. */
   if( top_level ) pthread_mutex_unlock( &(handle->mutex) );

/* Return the error handle. */
   return error_handle;
}
Example #8
0
hid_t dat1Reopen( hid_t file_id, unsigned int flags, hid_t fapl,
                  int *status ){

/* Local Variables; */
   HDSLoc **loc;
   HDSLoc **loclist;
   char **paths;
   char file[EMS__SZMSG+1];
   char path[EMS__SZMSG+1];
   hid_t *file_ids;
   hid_t id;
   int *isgroup;
   int iloc;
   int nlev;
   int nloc;
   ssize_t size;

/* Return immediately if an error has already occurred. */
   if( *status != SAI__OK ) return file_id;

/* Get a list of any active locators associated with the file. Also get a
   list of file_ids for the same file that have associated locators. */
   hds1GetLocators( file_id, &nloc, &loclist, &file_ids, status );

/* Check that none of the locators are mapped. */
   if( *status == SAI__OK ) {
      loc = loclist;
      for( iloc = 0; iloc < nloc; iloc++,loc++ ) {
         if( (*loc)->regpntr ) {
            hdsTrace( (*loc), &nlev, path, file, status, sizeof(path), sizeof(file) );
            *status = DAT__PRMAP;
            emsRepf( " ", "hdsOpen: Cannot re-open '%s' in read-write mode "
                     "since '%s' is currently mapped.", status, file, path );
            break;
         }
      }
   }

/* Store the path to the HDF5 object associated with each active locator,
   and also a flag indicating if the HDF5 object is a group or dataset.
   Then close the HDF5 objects. */
   paths = MEM_CALLOC( nloc, sizeof( *paths ) );
   isgroup = MEM_CALLOC( nloc, sizeof( *isgroup ) );
   if( paths && isgroup && *status == SAI__OK ) {
      loc = loclist;
      for( iloc = 0; iloc < nloc; iloc++,loc++ ) {
         if( (*loc)->group_id ) {
            isgroup[ iloc ] = 1;
            id = (*loc)->group_id;
         } else {
            isgroup[ iloc ] = 0;
            id = (*loc)->dataset_id;
         }
         if( id ) {
            size = H5Iget_name( id, NULL, 0 );
            paths[ iloc ] = MEM_CALLOC( size + 1, 1 );
            H5Iget_name( id, paths[ iloc ], size + 1 );
         } else {
            hdsTrace( (*loc), &nlev, path, file, status, sizeof(path), sizeof(file) );
            *status = DAT__FATAL;
            emsRepf( " ", "hdsOpen: Locator for '%s.%s' has no group or "
                     "dataset so cannot be reopened.", status, file, path );
            break;
         }
         if( H5Oclose( id ) < 0 ) {
            hdsTrace( (*loc), &nlev, path, file, status, sizeof(path), sizeof(file) );
            *status = DAT__FATAL;
            dat1H5EtoEMS( status );
            emsRepf( " ", "hdsOpen: Failed to close HDF5 object for '%s.%s'.",
                     status, file, path );
            break;
         }
      }
   }

/* Get the path for the file. */
   H5Fget_name( file_id, path, sizeof(path) );

/* Close all HDF5 file_ids associated with file. */
   if( *status == SAI__OK ) {
      int this_closed = 0;

      int i = -1;
      while( file_ids[ ++i ] ) {

         if( file_ids[ i ] == file_id ) this_closed = 1;

         if( H5Fclose( file_ids[ i ] ) < 0 ) {
            *status = DAT__FATAL;
            dat1H5EtoEMS( status );
            emsRepf( " ", "hdsOpen: Failed to close file '%s' prior to "
                     "re-opening it.", status, path );
            break;
         }
      }

/* Close the supplied file_id if it has not already been closed. */
      if( !this_closed ) {
         if( H5Fclose( file_id ) < 0 ) {
            *status = DAT__FATAL;
            dat1H5EtoEMS( status );
            emsRepf( " ", "hdsOpen: Failed to close file '%s' prior to "
                     "re-opening it.", status, path );
         }
      }
   }

/* Re-open it. */
   if( *status == SAI__OK ) {
      file_id = H5Fopen( path, flags, fapl );
      if( file_id < 0 ) {
         *status = DAT__FATAL;
         dat1H5EtoEMS( status );
         emsRepf( " ", "hdsOpen: Failed to reopen file '%s'.",
                  status, path );
      }
   }

/* Update the file, group and dataset id in each locator. */
   if( *status == SAI__OK ) {
      loc = loclist;
      for( iloc = 0; iloc < nloc; iloc++,loc++ ) {
         hds1SetFileId( (*loc), file_id, status );
         if( isgroup[ iloc ] ) {
            (*loc)->group_id = H5Gopen2( file_id, paths[ iloc ], H5P_DEFAULT );
         } else {
            (*loc)->dataset_id = H5Dopen2( file_id, paths[ iloc ], H5P_DEFAULT );
         }
      }
   }

/* Free resources. */
   if( paths ) {
      for( iloc = 0; iloc < nloc; iloc++ ) {
         MEM_FREE( paths[ iloc ] );
      }
      MEM_FREE( paths );
   }
   if( isgroup ) MEM_FREE( isgroup );
   if( loclist ) MEM_FREE( loclist );
   if( file_ids ) MEM_FREE( file_ids );

/* Return the new file id. */
   return file_id;
}
Example #9
0
int
dat1GetBounds( const HDSLoc * locator, hdsdim lower[DAT__MXDIM],
               hdsdim upper[DAT__MXDIM], hdsbool_t * issubset,
               int *actdim, int * status ) {
  int rank = 0;
  hssize_t nblocks = 0;
  hsize_t *blockbuf = NULL;

  *actdim = 0;
  *issubset = 0;
  if (*status != SAI__OK) return *status;



   /* If the supplied locator has a dataspace, then use the bounds of the
      data space. This is done even if the object is a structure, since
      vectorised structure arrays will have a dataspace describing their
      vectorised extent. */
  if( locator->dataspace_id ) {
    int i;
    hsize_t h5lower[DAT__MXDIM];
    hsize_t h5upper[DAT__MXDIM];
    hsize_t h5dims[DAT__MXDIM];

    CALLHDFE( int,
              rank,
              H5Sget_simple_extent_dims( locator->dataspace_id, h5dims, NULL ),
              DAT__DIMIN,
              emsRep("datshape_1", "datShape: Error obtaining shape of object",
                     status)
              );

    /* If we are using datSlice then there should be one (and only one) hyperslab
       for the dataspace and we need to handle that. Should be same dimensionality
       as above. Negative number indicates there were no hyperslabs. */
    if( H5Sget_select_type( locator->dataspace_id ) == H5S_SEL_HYPERSLABS ) {
       nblocks = H5Sget_select_hyper_nblocks( locator->dataspace_id );
    } else {
       nblocks = 0;
    }

    if (nblocks == 1) {
      herr_t h5err = 0;

      *issubset = 1;

      blockbuf = MEM_MALLOC( nblocks * rank * 2 * sizeof(*blockbuf) );

      CALLHDF( h5err,
               H5Sget_select_hyper_blocklist( locator->dataspace_id, 0, 1, blockbuf ),
               DAT__DIMIN,
               emsRep("datShape_2", "datShape: Error obtaining shape of slice", status )
               );

      /* We only go through one block. The buffer is returned in form:
         ndim start coordinates, then ndim opposite corner coordinates
         and repeats for each block (if we had more than one block).
      */
      for (i = 0; i<rank; i++) {
        hsize_t start;
        hsize_t opposite;
        start = blockbuf[i];
        opposite = blockbuf[i+rank];
        /* So update the shape to account for the slice: HDS is 1-based */
        h5lower[i] = start + 1;
        h5upper[i] = opposite + 1;
      }

    } else if (nblocks > 1) {
      if (*status == SAI__OK) {
        *status = DAT__WEIRD;
        emsRepf("datShape_2", "Unexpectedly got %zd hyperblocks from locator. Expected 1."
                " (possible programming error)", status, (ssize_t)nblocks);
        goto CLEANUP;
      }
    } else {
      /* No hyperblock */
      for (i=0; i<rank; i++) {
        h5lower[i] = 1;    /* HDS value 1-based */
        h5upper[i] = h5dims[i];
      }

    }

   dat1ExportDims( rank, h5lower, lower, status );
   dat1ExportDims( rank, h5upper, upper, status );

  /* If no dataspace ia available, and the locator is a structure
     array... */
  } else if (dat1IsStructure( locator, status ) ) {
Example #10
0
int main (void) {

    /*  Local Variables: */
    const char path[] = "hds_ctest";
    int status = DAT__OK;
    hdsdim dim[] = { 10, 20 };
    hdsdim dimd[1];
    const char * chararr[] = { "TEST1", "TEST2", "Longish String" };
    char *retchararr[4];
    char buffer[1024];  /* plenty large enough */
    double darr[] = { 4.5, 2.5 };
    double retdarr[2];
    void *mapv;    /* Mapped void* */
    double *mapd;  /* Mapped _DOUBLE */
    float  *mapf;  /* Mapped _REAL */
    int *mapi;     /* Mapped _INTEGER */
    int64_t *mapi64; /* Mapped _INT64 */
    HDSLoc * loc1 = NULL;
    HDSLoc * loc2 = NULL;
    HDSLoc * loc3 = NULL;
    size_t actval;
    size_t nel;
    size_t nelt;
    size_t nbytes;
    size_t i;
    int n;
    double sumd;
    int sumi;
    int64_t sumi64;
    int64_t test64;
    int64_t testin64;
    const int64_t VAL__BADK = (-9223372036854775807 - 1);

    emsBegin(&status);

    /* Force 64-bit mode */
    hdsTune( "64BIT", 1, &status );

    /* Create a new container file */
    hdsNew( path, "HDS_TEST", "NDF", 0, dim, &loc1, &status );

    /* Some components */
    datNew( loc1, "DATA_ARRAY", "_INTEGER", 2, dim, &status );
    datNew1C( loc1, "ONEDCHAR", 14, 3, &status );
    datNew1D( loc1, "ONEDD", 2, &status );
    datNew0K( loc1, "TESTI64", &status );
    datNew0K( loc1, "TESTBADI64", &status );

    /* Populate */
    testin64 = 9223372036854775800;
    datFind( loc1, "TESTI64", &loc2, &status );
    datPut0K( loc2, testin64, &status );
    datGet0K( loc2, &test64, &status );
    datAnnul( &loc2, &status );
    if (status == DAT__OK) {
        if ( test64 != testin64 ) {
            status = DAT__FATAL;
            emsRepf( "TESTI64", "Test _INT64 value %" PRIi64 " did not match expected %"PRIi64,
                     &status, test64, testin64 );
        }
    }

    datFind( loc1, "TESTBADI64", &loc2, &status );
    datPut0K( loc2, VAL__BADK, &status );
    datGet0K( loc2, &test64, &status );
    datAnnul( &loc2, &status );
    if (status == DAT__OK) {
        if ( test64 != VAL__BADK ) {
            status = DAT__FATAL;
            emsRepf( "TESTBADI64", "Test _INT64 value %" PRIi64 " did not match expected VAL__BADK",
                     &status, test64 );
        }
    }

    datFind( loc1, "ONEDCHAR", &loc2, &status );
    datPutVC( loc2, 3, chararr, &status );

    /* Check contents */
    datGetVC(loc2, 3, 1024, buffer, retchararr, &actval, &status);
    if (status == DAT__OK) {
        if (actval == 3) {
            for (i = 0; i < 3; i++ ) {
                if (strncmp( chararr[i], retchararr[i], strlen(chararr[i]) ) ) {
                    status = DAT__DIMIN;
                    emsSetc( "IN", chararr[i]);
                    emsSetc( "OUT", retchararr[i] );
                    emsRep( "GET1C","Values from Get1C differ (^IN != ^OUT)", &status);
                    break;
                }
            }
        } else {
            status = DAT__DIMIN;
            emsRep( "GET1C","Did not get back as many strings as put in", &status);
        }
    }

    datAnnul( &loc2, &status );

    datFind( loc1, "ONEDD", &loc2, &status );
    datPutVD( loc2, 2, darr, &status );

    /* Check contents */
    datGetVD( loc2, 2, retdarr, &actval, &status);
    if (status == DAT__OK) {
        if (actval == 2) {
            for (i = 0; i < 2; i++ ) {
                if (darr[i] != retdarr[i]) {
                    status = DAT__DIMIN;
                    emsRep( "GETVD","Values from getVD differ", &status);
                    break;
                }
            }
        } else {
            status = DAT__DIMIN;
            emsRep( "GETVD","Did not get back as many values as put in", &status);
        }
    }

    /* Try mapping - _DOUBLE */
    dimd[0] = 2;
    datMapD(loc2, "READ", 1, dimd, &mapd, &status);
    if (status == DAT__OK) {
        for (i = 0; i < 2; i++ ) {
            if (darr[i] != mapd[i]) {
                status = DAT__DIMIN;
                emsRep( "MAPD","Values from MapD differ", &status);
                break;
            }
        }
    }
    datUnmap(loc2, &status);

    /* Try mapping - _FLOAT */
    datMapR(loc2, "READ", 1, dimd, &mapf, &status);
    if (status == DAT__OK) {
        for (i = 0; i < 2; i++ ) {
            if ( (float)darr[i] != mapf[i]) {
                status = DAT__DIMIN;
                emsRep( "MAPR","Values from MapR differ", &status);
                break;
            }
        }
    }
    datUnmap(loc2, &status);

    /* Annul */
    datAnnul( &loc2, &status );

    /* Find and map DATA_ARRAY */
    datFind( loc1, "DATA_ARRAY", &loc2, &status );
    datMapV( loc2, "_REAL", "WRITE", &mapv, &nel, &status );
    mapf = mapv;
    if (status == DAT__OK) {
        nelt = dim[0] * dim[1];
        if ( nelt != nel) {
            status = DAT__FATAL;
            emsSeti( "NEL", (int)nel );
            emsSeti( "NORI", (int)nelt );
            emsRep( "SIZE","Number of elements originally (^NORI) not the same as now (^NEL)", &status);
        }
    }
    sumd = 0.0;
    for (i = 1; i <= nel; i++) {
        mapf[i-1] = (float)i;
        sumd += (double)i;
    }
    datUnmap( loc2, &status );
    datAnnul( &loc2, &status );
    hdsClose( &loc1, &status );

    /* Re-open */
    hdsOpen( path, "UPDATE", &loc1, &status );

    /* Look for the data array and map it */
    datFind( loc1, "DATA_ARRAY", &loc2, &status );
    datVec( loc2, &loc3, &status );
    datSize( loc3, &nel, &status);
    if (status == DAT__OK) {
        nelt = dim[0] * dim[1];
        if ( nelt != nel) {
            status = DAT__FATAL;
            emsSeti( "NEL", (int)nel );
            emsSeti( "NORI", (int)nelt );
            emsRep( "SIZE","Number of elements before (^NORI) not the same as now (^NEL)", &status);
        }
    }

    datPrec( loc3, &nbytes, &status );
    if (status == DAT__OK) {
        if ( nbytes != 4) {
            status = DAT__FATAL;
            emsSeti( "NB", nbytes );
            emsRep( "PREC","Precision for _REAL not 4 bytes but ^NB", &status);
        }
    }

    /* Try hdsShow */
    hdsShow("LOCATORS", &status);
    hdsShow("FILES", &status);
    hdsInfoI(NULL, "LOCATORS", "!HDS_TEST.,YYY", &n, &status );
    hdsInfoI(NULL, "FILES", NULL, &n, &status );

    datAnnul( &loc3, &status );

    datMapV( loc2, "_INTEGER", "READ", &mapv, &nel, &status );
    mapi = mapv;
    if (status == DAT__OK) {
        nelt = dim[0] * dim[1];
        if ( nelt != nel) {
            status = DAT__FATAL;
            emsSeti( "NEL", (int)nel );
            emsSeti( "NORI", (int)nelt );
            emsRep( "SIZE","Number of elements originally (^NORI) not the same as now (^NEL)", &status);
        }
    }
    sumi = 0;
    for (i = 0; i < nel; i++) {
        sumi += mapi[i];
    }
    datUnmap( loc2, &status );

    if (status == DAT__OK) {
        if (sumi != (int)sumd) {
            status = DAT__FATAL;
            emsSeti( "I", sumi );
            emsSeti( "D", (int)sumd );
            emsRep("SUM","Sum was not correct. Got ^I rather than ^D", &status );
        }
    }

    /* _INT64 test */
    datMapV( loc2, "_INT64", "READ", &mapv, &nel, &status );
    mapi64 = mapv;
    if (status == DAT__OK) {
        nelt = dim[0] * dim[1];
        if ( nelt != nel) {
            status = DAT__FATAL;
            emsSeti( "NEL", (int)nel );
            emsSeti( "NORI", (int)nelt );
            emsRep( "SIZE","Number of elements originally (^NORI) not the same as now (^NEL)", &status);
        }
    }
    sumi64 = 0;
    for (i = 0; i < nel; i++) {
        sumi64 += mapi64[i];
    }
    datUnmap( loc2, &status );

    if (status == DAT__OK) {
        if (sumi64 != (int)sumd) {
            status = DAT__FATAL;
            emsSeti( "I", (int)sumi64 );
            emsSeti( "D", (int)sumd );
            emsRep("SUM","Sum was not correct. Got ^I rather than ^D", &status );
        }
    }


    /* Tidy up and close */
    hdsErase( &loc1, &status );

    if (status == DAT__OK) {
        printf("HDS C installation test succeeded\n");
        emsEnd(&status);
        return EXIT_SUCCESS;
    } else {
        printf("HDS C installation test failed\n");
        emsEnd(&status);
        return EXIT_FAILURE;
    }


}
Example #11
0
hdstype_t
dau1HdsType( hid_t h5type, int * status ) {

  H5T_class_t tclass = 0;
  size_t dsize = 0;
  hdstype_t thetype = HDSTYPE_NONE;

  if (*status != SAI__OK) return thetype;

  CALLHDFE( H5T_class_t, tclass,
           H5Tget_class( h5type ),
           DAT__HDF5E,
           emsRep("dat1Type_2", "datType: Error obtaining class of data type", status)
           );

  /* Number of bytes representing the type */
  dsize = H5Tget_size( h5type );

  if (*status == SAI__OK) {
    switch (tclass) {
    case H5T_INTEGER:
      {
        /* then need to know signed or unsigned int */
        H5T_sign_t dsign = H5Tget_sign( h5type );
        if (dsign < 0) {
          *status = DAT__HDF5E;
          emsRep("dat1Type_3", "datType: Error obtaining sign of an integer type", status );
        goto CLEANUP;
        }
        if (dsign == H5T_SGN_NONE) {
          if ( dsize == 1 ) {
            thetype = HDSTYPE_UBYTE;
          } else if (dsize == 2) {
            thetype = HDSTYPE_UWORD;
          } else {
            *status = DAT__TYPIN;
            emsRepf("dat1Type_3a",
                    "Unexpected number of bytes (%zu) in unsigned integer type",
                    status, dsize);
          }
        } else {
          /* Signed types */
          switch (dsize) {
          case 1:
            thetype = HDSTYPE_BYTE;
            break;
          case 2:
            thetype = HDSTYPE_WORD;
            break;
          case 4:
            thetype = HDSTYPE_INTEGER;
            break;
          case 8:
            thetype = HDSTYPE_INT64;
            break;
          default:
            *status = DAT__TYPIN;
            emsRepf("dat1Type_3b", "datType: Unexpected number of bytes in integer (%zu)",
                    status, dsize);
          }
        }
      }
      break;
    case H5T_FLOAT:
      if ( dsize == 4 ) {
        thetype = HDSTYPE_REAL;
      } else if (dsize == 8) {
        thetype = HDSTYPE_DOUBLE;
      } else {
        *status = DAT__FATAL;
        emsRepf("datType_5", "Error reading size of float data type. Got %zu bytes"
                " but only understand 4 and 8", status, dsize);
      }
      break;

    case H5T_STRING:
      thetype = HDSTYPE_CHAR;
      break;

    case H5T_BITFIELD:
      if ( dsize == 1 || dsize == 4 ) { /* on disk and in memory version */
        thetype = HDSTYPE_LOGICAL;
      } else {
        *status = DAT__FATAL;
        emsRepf("datType_5", "Error reading size of logical data type. Got %zu bytes"
                " but only understand 1 or 4", status, dsize);
      }
      break;

    default:
      *status = DAT__TYPIN;
      emsRep("datType_4", "dat1Type: Unexpected type class from dataset", status);
    }
  }

 CLEANUP:
  return thetype;

}