/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*------------------------------------------------------------------------- * * Created: H5C.c * June 1 2004 * John Mainzer * * Purpose: Functions in this file implement a generic cache for * things which exist on disk, and which may be * unambiguously referenced by their disk addresses. * * For a detailed overview of the cache, please see the * header comment for H5C_t in H5Cpkg.h. * *------------------------------------------------------------------------- */ /************************************************************************** * * To Do: * * Code Changes: * * - Change protect/unprotect to lock/unlock. * * - Flush entries in increasing address order in * H5C__make_space_in_cache(). * * - Also in H5C__make_space_in_cache(), use high and low water marks * to reduce the number of I/O calls. * * - When flushing, attempt to combine contiguous entries to reduce * I/O overhead. Can't do this just yet as some entries are not * contiguous. Do this in parallel only or in serial as well? * * - Fix nodes in memory to point directly to the skip list node from * the LRU list, eliminating skip list lookups when evicting objects * from the cache. * **************************************************************************/ /****************/ /* Module Setup */ /****************/ #include "H5Cmodule.h" /* This source code file is part of the H5C module */ #define H5F_FRIEND /* suppress error about including H5Fpkg */ /***********/ /* Headers */ /***********/ #include "H5private.h" /* Generic Functions */ #include "H5Cpkg.h" /* Cache */ #include "H5CXprivate.h" /* API Contexts */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* Files */ #include "H5FLprivate.h" /* Free Lists */ #include "H5Iprivate.h" /* IDs */ #include "H5MFprivate.h" /* File memory management */ #include "H5MMprivate.h" /* Memory management */ #include "H5Pprivate.h" /* Property lists */ /****************/ /* Local Macros */ /****************/ #if H5C_DO_MEMORY_SANITY_CHECKS #define H5C_IMAGE_EXTRA_SPACE 8 #define H5C_IMAGE_SANITY_VALUE "DeadBeef" #else /* H5C_DO_MEMORY_SANITY_CHECKS */ #define H5C_IMAGE_EXTRA_SPACE 0 #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ /******************/ /* Local Typedefs */ /******************/ /* Alias for pointer to cache entry, for use when allocating sequences of them */ typedef H5C_cache_entry_t *H5C_cache_entry_ptr_t; /********************/ /* Local Prototypes */ /********************/ static herr_t H5C__pin_entry_from_client(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr); static herr_t H5C__unpin_entry_real(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, hbool_t update_rp); static herr_t H5C__unpin_entry_from_client(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, hbool_t update_rp); static herr_t H5C__auto_adjust_cache_size(H5F_t *f, hbool_t write_permitted); static herr_t H5C__autoadjust__ageout(H5F_t *f, double hit_rate, enum H5C_resize_status *status_ptr, size_t *new_max_cache_size_ptr, hbool_t write_permitted); static herr_t H5C__autoadjust__ageout__cycle_epoch_marker(H5C_t *cache_ptr); static herr_t H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t *f, hbool_t write_permitted); static herr_t H5C__autoadjust__ageout__insert_new_marker(H5C_t *cache_ptr); static herr_t H5C__autoadjust__ageout__remove_all_markers(H5C_t *cache_ptr); static herr_t H5C__autoadjust__ageout__remove_excess_markers(H5C_t *cache_ptr); static herr_t H5C__flash_increase_cache_size(H5C_t *cache_ptr, size_t old_entry_size, size_t new_entry_size); static herr_t H5C__flush_invalidate_cache(H5F_t *f, unsigned flags); static herr_t H5C__flush_invalidate_ring(H5F_t *f, H5C_ring_t ring, unsigned flags); static herr_t H5C__flush_ring(H5F_t *f, H5C_ring_t ring, unsigned flags); static void *H5C__load_entry(H5F_t *f, #ifdef H5_HAVE_PARALLEL hbool_t coll_access, #endif /* H5_HAVE_PARALLEL */ const H5C_class_t *type, haddr_t addr, void *udata); static herr_t H5C__mark_flush_dep_dirty(H5C_cache_entry_t *entry); static herr_t H5C__mark_flush_dep_clean(H5C_cache_entry_t *entry); static herr_t H5C__serialize_ring(H5F_t *f, H5C_ring_t ring); static herr_t H5C__serialize_single_entry(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr); static herr_t H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr); static herr_t H5C__verify_len_eoa(H5F_t *f, const H5C_class_t *type, haddr_t addr, size_t *len, hbool_t actual); #ifndef NDEBUG static void H5C__assert_flush_dep_nocycle(const H5C_cache_entry_t *entry, const H5C_cache_entry_t *base_entry); #endif /* NDEBUG */ /*********************/ /* Package Variables */ /*********************/ /* Declare a free list to manage the tag info struct */ H5FL_DEFINE(H5C_tag_info_t); /*****************************/ /* Library Private Variables */ /*****************************/ /*******************/ /* Local Variables */ /*******************/ /* Declare a free list to manage the H5C_t struct */ H5FL_DEFINE_STATIC(H5C_t); /* Declare a free list to manage arrays of cache entries */ H5FL_SEQ_DEFINE_STATIC(H5C_cache_entry_ptr_t); /*------------------------------------------------------------------------- * Function: H5C_create * * Purpose: Allocate, initialize, and return the address of a new * instance of H5C_t. * * In general, the max_cache_size parameter must be positive, * and the min_clean_size parameter must lie in the closed * interval [0, max_cache_size]. * * The check_write_permitted parameter must either be NULL, * or point to a function of type H5C_write_permitted_func_t. * If it is NULL, the cache will use the write_permitted * flag to determine whether writes are permitted. * * Return: Success: Pointer to the new instance. * * Failure: NULL * * Programmer: John Mainzer * 6/2/04 * * Modifications: * * JRM -- 7/20/04 * Updated for the addition of the hash table. * * JRM -- 10/5/04 * Added call to H5C_reset_cache_hit_rate_stats(). Also * added initialization for cache_is_full flag and for * resize_ctl. * * JRM -- 11/12/04 * Added initialization for the new size_decreased field. * * JRM -- 11/17/04 * Added/updated initialization for the automatic cache * size control data structures. * * JRM -- 6/24/05 * Added support for the new write_permitted field of * the H5C_t structure. * * JRM -- 7/5/05 * Added the new log_flush parameter and supporting code. * * JRM -- 9/21/05 * Added the new aux_ptr parameter and supporting code. * * JRM -- 1/20/06 * Added initialization of the new prefix field in H5C_t. * * JRM -- 3/16/06 * Added initialization for the pinned entry related fields. * * JRM -- 5/31/06 * Added initialization for the trace_file_ptr field. * * JRM -- 8/19/06 * Added initialization for the flush_in_progress field. * * JRM -- 8/25/06 * Added initialization for the slist_len_increase and * slist_size_increase fields. These fields are used * for sanity checking in the flush process, and are not * compiled in unless H5C_DO_SANITY_CHECKS is TRUE. * * JRM -- 3/28/07 * Added initialization for the new is_read_only and * ro_ref_count fields. * * JRM -- 7/27/07 * Added initialization for the new evictions_enabled * field of H5C_t. * * JRM -- 12/31/07 * Added initialization for the new flash cache size increase * related fields of H5C_t. * * JRM -- 11/5/08 * Added initialization for the new clean_index_size and * dirty_index_size fields of H5C_t. * * * Missing entries? * * * JRM -- 4/20/20 * Added initialization for the slist_enabled field. Recall * that the slist is used to flush metadata cache entries * in (roughly) increasing address order. While this is * needed at flush and close, it is not used elsewhere. * The slist_enabled field exists to allow us to construct * the slist when needed, and leave it empty otherwise -- thus * avoiding the overhead of maintaining it. * * JRM -- 4/29/20 * *------------------------------------------------------------------------- */ H5C_t * H5C_create(size_t max_cache_size, size_t min_clean_size, int max_type_id, const H5C_class_t *const *class_table_ptr, H5C_write_permitted_func_t check_write_permitted, hbool_t write_permitted, H5C_log_flush_func_t log_flush, void *aux_ptr) { int i; H5C_t *cache_ptr = NULL; H5C_t *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI(NULL) HDassert(max_cache_size >= H5C__MIN_MAX_CACHE_SIZE); HDassert(max_cache_size <= H5C__MAX_MAX_CACHE_SIZE); HDassert(min_clean_size <= max_cache_size); HDassert(max_type_id >= 0); HDassert(max_type_id < H5C__MAX_NUM_TYPE_IDS); HDassert(class_table_ptr); for (i = 0; i <= max_type_id; i++) { HDassert((class_table_ptr)[i]); HDassert(HDstrlen((class_table_ptr)[i]->name) > 0); } /* end for */ if (NULL == (cache_ptr = H5FL_CALLOC(H5C_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed") if (NULL == (cache_ptr->slist_ptr = H5SL_create(H5SL_TYPE_HADDR, NULL))) HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, NULL, "can't create skip list") cache_ptr->tag_list = NULL; /* If we get this far, we should succeed. Go ahead and initialize all * the fields. */ cache_ptr->magic = H5C__H5C_T_MAGIC; cache_ptr->flush_in_progress = FALSE; if (NULL == (cache_ptr->log_info = (H5C_log_info_t *)H5MM_calloc(sizeof(H5C_log_info_t)))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed") cache_ptr->aux_ptr = aux_ptr; cache_ptr->max_type_id = max_type_id; cache_ptr->class_table_ptr = class_table_ptr; cache_ptr->max_cache_size = max_cache_size; cache_ptr->min_clean_size = min_clean_size; cache_ptr->check_write_permitted = check_write_permitted; cache_ptr->write_permitted = write_permitted; cache_ptr->log_flush = log_flush; cache_ptr->evictions_enabled = TRUE; cache_ptr->close_warning_received = FALSE; cache_ptr->index_len = 0; cache_ptr->index_size = (size_t)0; cache_ptr->clean_index_size = (size_t)0; cache_ptr->dirty_index_size = (size_t)0; for (i = 0; i < H5C_RING_NTYPES; i++) { cache_ptr->index_ring_len[i] = 0; cache_ptr->index_ring_size[i] = (size_t)0; cache_ptr->clean_index_ring_size[i] = (size_t)0; cache_ptr->dirty_index_ring_size[i] = (size_t)0; cache_ptr->slist_ring_len[i] = 0; cache_ptr->slist_ring_size[i] = (size_t)0; } /* end for */ for (i = 0; i < H5C__HASH_TABLE_LEN; i++) (cache_ptr->index)[i] = NULL; cache_ptr->il_len = 0; cache_ptr->il_size = (size_t)0; cache_ptr->il_head = NULL; cache_ptr->il_tail = NULL; /* Tagging Field Initializations */ cache_ptr->ignore_tags = FALSE; cache_ptr->num_objs_corked = 0; /* slist field initializations */ cache_ptr->slist_enabled = !H5C__SLIST_OPT_ENABLED; cache_ptr->slist_changed = FALSE; cache_ptr->slist_len = 0; cache_ptr->slist_size = (size_t)0; /* slist_ring_len, slist_ring_size, and * slist_ptr initialized above. */ #ifdef H5C_DO_SANITY_CHECKS cache_ptr->slist_len_increase = 0; cache_ptr->slist_size_increase = 0; #endif /* H5C_DO_SANITY_CHECKS */ cache_ptr->entries_removed_counter = 0; cache_ptr->last_entry_removed_ptr = NULL; cache_ptr->entry_watched_for_removal = NULL; cache_ptr->pl_len = 0; cache_ptr->pl_size = (size_t)0; cache_ptr->pl_head_ptr = NULL; cache_ptr->pl_tail_ptr = NULL; cache_ptr->pel_len = 0; cache_ptr->pel_size = (size_t)0; cache_ptr->pel_head_ptr = NULL; cache_ptr->pel_tail_ptr = NULL; cache_ptr->LRU_list_len = 0; cache_ptr->LRU_list_size = (size_t)0; cache_ptr->LRU_head_ptr = NULL; cache_ptr->LRU_tail_ptr = NULL; #ifdef H5_HAVE_PARALLEL cache_ptr->coll_list_len = 0; cache_ptr->coll_list_size = (size_t)0; cache_ptr->coll_head_ptr = NULL; cache_ptr->coll_tail_ptr = NULL; cache_ptr->coll_write_list = NULL; #endif /* H5_HAVE_PARALLEL */ #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS cache_ptr->cLRU_list_len = 0; cache_ptr->cLRU_list_size = (size_t)0; cache_ptr->cLRU_head_ptr = NULL; cache_ptr->cLRU_tail_ptr = NULL; cache_ptr->dLRU_list_len = 0; cache_ptr->dLRU_list_size = (size_t)0; cache_ptr->dLRU_head_ptr = NULL; cache_ptr->dLRU_tail_ptr = NULL; #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ cache_ptr->size_increase_possible = FALSE; cache_ptr->flash_size_increase_possible = FALSE; cache_ptr->flash_size_increase_threshold = 0; cache_ptr->size_decrease_possible = FALSE; cache_ptr->resize_enabled = FALSE; cache_ptr->cache_full = FALSE; cache_ptr->size_decreased = FALSE; cache_ptr->resize_in_progress = FALSE; cache_ptr->msic_in_progress = FALSE; (cache_ptr->resize_ctl).version = H5C__CURR_AUTO_SIZE_CTL_VER; (cache_ptr->resize_ctl).rpt_fcn = NULL; (cache_ptr->resize_ctl).set_initial_size = FALSE; (cache_ptr->resize_ctl).initial_size = H5C__DEF_AR_INIT_SIZE; (cache_ptr->resize_ctl).min_clean_fraction = H5C__DEF_AR_MIN_CLEAN_FRAC; (cache_ptr->resize_ctl).max_size = H5C__DEF_AR_MAX_SIZE; (cache_ptr->resize_ctl).min_size = H5C__DEF_AR_MIN_SIZE; (cache_ptr->resize_ctl).epoch_length = H5C__DEF_AR_EPOCH_LENGTH; (cache_ptr->resize_ctl).incr_mode = H5C_incr__off; (cache_ptr->resize_ctl).lower_hr_threshold = H5C__DEF_AR_LOWER_THRESHHOLD; (cache_ptr->resize_ctl).increment = H5C__DEF_AR_INCREMENT; (cache_ptr->resize_ctl).apply_max_increment = TRUE; (cache_ptr->resize_ctl).max_increment = H5C__DEF_AR_MAX_INCREMENT; (cache_ptr->resize_ctl).flash_incr_mode = H5C_flash_incr__off; (cache_ptr->resize_ctl).flash_multiple = 1.0; (cache_ptr->resize_ctl).flash_threshold = 0.25; (cache_ptr->resize_ctl).decr_mode = H5C_decr__off; (cache_ptr->resize_ctl).upper_hr_threshold = H5C__DEF_AR_UPPER_THRESHHOLD; (cache_ptr->resize_ctl).decrement = H5C__DEF_AR_DECREMENT; (cache_ptr->resize_ctl).apply_max_decrement = TRUE; (cache_ptr->resize_ctl).max_decrement = H5C__DEF_AR_MAX_DECREMENT; (cache_ptr->resize_ctl).epochs_before_eviction = H5C__DEF_AR_EPCHS_B4_EVICT; (cache_ptr->resize_ctl).apply_empty_reserve = TRUE; (cache_ptr->resize_ctl).empty_reserve = H5C__DEF_AR_EMPTY_RESERVE; cache_ptr->epoch_markers_active = 0; /* no need to initialize the ring buffer itself */ cache_ptr->epoch_marker_ringbuf_first = 1; cache_ptr->epoch_marker_ringbuf_last = 0; cache_ptr->epoch_marker_ringbuf_size = 0; /* Initialize all epoch marker entries' fields to zero/FALSE/NULL */ HDmemset(cache_ptr->epoch_markers, 0, sizeof(cache_ptr->epoch_markers)); /* Set non-zero/FALSE/NULL fields for epoch markers */ for (i = 0; i < H5C__MAX_EPOCH_MARKERS; i++) { ((cache_ptr->epoch_markers)[i]).magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; ((cache_ptr->epoch_markers)[i]).addr = (haddr_t)i; ((cache_ptr->epoch_markers)[i]).type = H5AC_EPOCH_MARKER; } /* Initialize cache image generation on file close related fields. * Initial value of image_ctl must match H5C__DEFAULT_CACHE_IMAGE_CTL * in H5Cprivate.h. */ cache_ptr->image_ctl.version = H5C__CURR_CACHE_IMAGE_CTL_VER; cache_ptr->image_ctl.generate_image = FALSE; cache_ptr->image_ctl.save_resize_status = FALSE; cache_ptr->image_ctl.entry_ageout = -1; cache_ptr->image_ctl.flags = H5C_CI__ALL_FLAGS; cache_ptr->serialization_in_progress = FALSE; cache_ptr->load_image = FALSE; cache_ptr->image_loaded = FALSE; cache_ptr->delete_image = FALSE; cache_ptr->image_addr = HADDR_UNDEF; cache_ptr->image_len = 0; cache_ptr->image_data_len = 0; cache_ptr->entries_loaded_counter = 0; cache_ptr->entries_inserted_counter = 0; cache_ptr->entries_relocated_counter = 0; cache_ptr->entry_fd_height_change_counter = 0; cache_ptr->num_entries_in_image = 0; cache_ptr->image_entries = NULL; cache_ptr->image_buffer = NULL; /* initialize free space manager related fields: */ cache_ptr->rdfsm_settled = FALSE; cache_ptr->mdfsm_settled = FALSE; if (H5C_reset_cache_hit_rate_stats(cache_ptr) < 0) /* this should be impossible... */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "H5C_reset_cache_hit_rate_stats failed") H5C_stats__reset(cache_ptr); cache_ptr->prefix[0] = '\0'; /* empty string */ #ifndef NDEBUG cache_ptr->get_entry_ptr_from_addr_counter = 0; #endif /* NDEBUG */ /* Set return value */ ret_value = cache_ptr; done: if (NULL == ret_value) { if (cache_ptr != NULL) { if (cache_ptr->slist_ptr != NULL) H5SL_close(cache_ptr->slist_ptr); HASH_CLEAR(hh, cache_ptr->tag_list); cache_ptr->tag_list = NULL; if (cache_ptr->log_info != NULL) H5MM_xfree(cache_ptr->log_info); cache_ptr->magic = 0; cache_ptr = H5FL_FREE(H5C_t, cache_ptr); } } FUNC_LEAVE_NOAPI(ret_value) } /* H5C_create() */ /*------------------------------------------------------------------------- * Function: H5C_def_auto_resize_rpt_fcn * * Purpose: Print results of a automatic cache resize. * * This function should only be used where HDprintf() behaves * well -- i.e. not on Windows. * * Return: void * * Programmer: John Mainzer * 10/27/04 * *------------------------------------------------------------------------- */ void H5C_def_auto_resize_rpt_fcn(H5C_t *cache_ptr, #ifndef NDEBUG int32_t version, #else /* NDEBUG */ int32_t H5_ATTR_UNUSED version, #endif /* NDEBUG */ double hit_rate, enum H5C_resize_status status, size_t old_max_cache_size, size_t new_max_cache_size, size_t old_min_clean_size, size_t new_min_clean_size) { HDassert(cache_ptr != NULL); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(version == H5C__CURR_AUTO_RESIZE_RPT_FCN_VER); switch (status) { case in_spec: HDfprintf(stdout, "%sAuto cache resize -- no change. (hit rate = %lf)\n", cache_ptr->prefix, hit_rate); break; case increase: HDassert(hit_rate < (cache_ptr->resize_ctl).lower_hr_threshold); HDassert(old_max_cache_size < new_max_cache_size); HDfprintf(stdout, "%sAuto cache resize -- hit rate (%lf) out of bounds low (%6.5lf).\n", cache_ptr->prefix, hit_rate, (cache_ptr->resize_ctl).lower_hr_threshold); HDfprintf(stdout, "%scache size increased from (%zu/%zu) to (%zu/%zu).\n", cache_ptr->prefix, old_max_cache_size, old_min_clean_size, new_max_cache_size, new_min_clean_size); break; case flash_increase: HDassert(old_max_cache_size < new_max_cache_size); HDfprintf(stdout, "%sflash cache resize(%d) -- size threshold = %zu.\n", cache_ptr->prefix, (int)((cache_ptr->resize_ctl).flash_incr_mode), cache_ptr->flash_size_increase_threshold); HDfprintf(stdout, "%s cache size increased from (%zu/%zu) to (%zu/%zu).\n", cache_ptr->prefix, old_max_cache_size, old_min_clean_size, new_max_cache_size, new_min_clean_size); break; case decrease: HDassert(old_max_cache_size > new_max_cache_size); switch ((cache_ptr->resize_ctl).decr_mode) { case H5C_decr__off: HDfprintf(stdout, "%sAuto cache resize -- decrease off. HR = %lf\n", cache_ptr->prefix, hit_rate); break; case H5C_decr__threshold: HDassert(hit_rate > (cache_ptr->resize_ctl).upper_hr_threshold); HDfprintf(stdout, "%sAuto cache resize -- decrease by threshold. HR = %lf > %6.5lf\n", cache_ptr->prefix, hit_rate, (cache_ptr->resize_ctl).upper_hr_threshold); HDfprintf(stdout, "%sout of bounds high (%6.5lf).\n", cache_ptr->prefix, (cache_ptr->resize_ctl).upper_hr_threshold); break; case H5C_decr__age_out: HDfprintf(stdout, "%sAuto cache resize -- decrease by ageout. HR = %lf\n", cache_ptr->prefix, hit_rate); break; case H5C_decr__age_out_with_threshold: HDassert(hit_rate > (cache_ptr->resize_ctl).upper_hr_threshold); HDfprintf(stdout, "%sAuto cache resize -- decrease by ageout with threshold. HR = %lf > %6.5lf\n", cache_ptr->prefix, hit_rate, (cache_ptr->resize_ctl).upper_hr_threshold); break; default: HDfprintf(stdout, "%sAuto cache resize -- decrease by unknown mode. HR = %lf\n", cache_ptr->prefix, hit_rate); } HDfprintf(stdout, "%s cache size decreased from (%zu/%zu) to (%zu/%zu).\n", cache_ptr->prefix, old_max_cache_size, old_min_clean_size, new_max_cache_size, new_min_clean_size); break; case at_max_size: HDfprintf(stdout, "%sAuto cache resize -- hit rate (%lf) out of bounds low (%6.5lf).\n", cache_ptr->prefix, hit_rate, (cache_ptr->resize_ctl).lower_hr_threshold); HDfprintf(stdout, "%s cache already at maximum size so no change.\n", cache_ptr->prefix); break; case at_min_size: HDfprintf(stdout, "%sAuto cache resize -- hit rate (%lf) -- can't decrease.\n", cache_ptr->prefix, hit_rate); HDfprintf(stdout, "%s cache already at minimum size.\n", cache_ptr->prefix); break; case increase_disabled: HDfprintf(stdout, "%sAuto cache resize -- increase disabled -- HR = %lf.", cache_ptr->prefix, hit_rate); break; case decrease_disabled: HDfprintf(stdout, "%sAuto cache resize -- decrease disabled -- HR = %lf.\n", cache_ptr->prefix, hit_rate); break; case not_full: HDassert(hit_rate < (cache_ptr->resize_ctl).lower_hr_threshold); HDfprintf(stdout, "%sAuto cache resize -- hit rate (%lf) out of bounds low (%6.5lf).\n", cache_ptr->prefix, hit_rate, (cache_ptr->resize_ctl).lower_hr_threshold); HDfprintf(stdout, "%s cache not full so no increase in size.\n", cache_ptr->prefix); break; default: HDfprintf(stdout, "%sAuto cache resize -- unknown status code.\n", cache_ptr->prefix); break; } } /* H5C_def_auto_resize_rpt_fcn() */ /*------------------------------------------------------------------------- * * Function: H5C_prep_for_file_close * * Purpose: This function should be called just prior to the cache * flushes at file close. There should be no protected * entries in the cache at this point. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 7/3/15 * *------------------------------------------------------------------------- */ herr_t H5C_prep_for_file_close(H5F_t *f) { H5C_t *cache_ptr; hbool_t image_generated = FALSE; /* Whether a cache image was generated */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(f); HDassert(f->shared); HDassert(f->shared->cache); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* For now at least, it is possible to receive the * close warning more than once -- the following * if statement handles this. */ if (cache_ptr->close_warning_received) HGOTO_DONE(SUCCEED) cache_ptr->close_warning_received = TRUE; /* Make certain there aren't any protected entries */ HDassert(cache_ptr->pl_len == 0); /* Prepare cache image */ if (H5C__prep_image_for_file_close(f, &image_generated) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "can't create cache image") #ifdef H5_HAVE_PARALLEL if ((H5F_INTENT(f) & H5F_ACC_RDWR) && (!image_generated) && (cache_ptr->aux_ptr != NULL) && (f->shared->fs_persist)) { /* If persistent free space managers are enabled, flushing the * metadata cache may result in the deletion, insertion, and/or * dirtying of entries. * * This is a problem in PHDF5, as it breaks two invariants of * our management of the metadata cache across all processes: * * 1) Entries will not be dirtied, deleted, inserted, or moved * during flush in the parallel case. * * 2) All processes contain the same set of dirty metadata * entries on entry to a sync point. * * To solve this problem for the persistent free space managers, * serialize the metadata cache on all processes prior to the * first sync point on file shutdown. The shutdown warning is * a convenient location for this call. * * This is sufficient since: * * 1) FSM settle routines are only invoked on file close. Since * serialization make the same settle calls as flush on file * close, and since the close warning is issued after all * non FSM related space allocations and just before the * first sync point on close, this call will leave the caches * in a consistent state across the processes if they were * consistent before. * * 2) Since the FSM settle routines are only invoked once during * file close, invoking them now will prevent their invocation * during a flush, and thus avoid any resulting entry dirties, * deletions, insertion, or moves during the flush. */ if (H5C__serialize_cache(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "serialization of the cache failed") } /* end if */ #endif /* H5_HAVE_PARALLEL */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_prep_for_file_close() */ /*------------------------------------------------------------------------- * Function: H5C_dest * * Purpose: Flush all data to disk and destroy the cache. * * This function fails if any object are protected since the * resulting file might not be consistent. * * Note that *cache_ptr has been freed upon successful return. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 6/2/04 * * Modifications: * * JRM -- 5/15/20 * * Updated the function to enable the slist prior to the * call to H5C__flush_invalidate_cache(). * * Arguably, it shouldn't be necessary to re-enable the * slist after the call to H5C__flush_invalidate_cache(), as * the metadata cache should be discarded. However, in the * test code, we make multiple calls to H5C_dest(). Thus * we re-enable the slist on failure if it and the cache * still exist. * *------------------------------------------------------------------------- */ herr_t H5C_dest(H5F_t *f) { H5C_t *cache_ptr = f->shared->cache; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(cache_ptr->close_warning_received); #if H5AC_DUMP_IMAGE_STATS_ON_CLOSE if (H5C_image_stats(cache_ptr, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't display cache image stats") #endif /* H5AC_DUMP_IMAGE_STATS_ON_CLOSE */ /* Enable the slist, as it is needed in the flush */ if (H5C_set_slist_enabled(f->shared->cache, TRUE, FALSE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed") /* Flush and invalidate all cache entries */ if (H5C__flush_invalidate_cache(f, H5C__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush cache") /* Generate & write cache image if requested */ if (cache_ptr->image_ctl.generate_image) { if (H5C__generate_cache_image(f, cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTCREATE, FAIL, "Can't generate metadata cache image") } /* Question: Is it possible for cache_ptr->slist be non-null at this * point? If no, shouldn't this if statement be an assert? */ if (cache_ptr->slist_ptr != NULL) { HDassert(cache_ptr->slist_len == 0); HDassert(cache_ptr->slist_size == 0); H5SL_close(cache_ptr->slist_ptr); cache_ptr->slist_ptr = NULL; } H5C_tag_info_t *item = NULL; H5C_tag_info_t *tmp = NULL; HASH_ITER(hh, cache_ptr->tag_list, item, tmp) { HASH_DELETE(hh, cache_ptr->tag_list, item); item = H5FL_FREE(H5C_tag_info_t, item); } if (cache_ptr->log_info != NULL) H5MM_xfree(cache_ptr->log_info); #ifndef NDEBUG #ifdef H5C_DO_SANITY_CHECKS if (cache_ptr->get_entry_ptr_from_addr_counter > 0) { HDfprintf(stdout, "*** %" PRId64 " calls to H5C_get_entry_ptr_from_add(). ***\n", cache_ptr->get_entry_ptr_from_addr_counter); } #endif /* H5C_DO_SANITY_CHECKS */ cache_ptr->magic = 0; #endif /* NDEBUG */ cache_ptr = H5FL_FREE(H5C_t, cache_ptr); done: if ((ret_value < 0) && (cache_ptr) && (cache_ptr->slist_ptr)) { /* need this for test code -- see change note for details */ if (H5C_set_slist_enabled(f->shared->cache, FALSE, FALSE) < 0) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "disable slist on flush dest failure failed") } FUNC_LEAVE_NOAPI(ret_value) } /* H5C_dest() */ /*------------------------------------------------------------------------- * Function: H5C_evict * * Purpose: Evict all except pinned entries in the cache * * Return: Non-negative on success/Negative on failure * * Programmer: Vailin Choi * Dec 2013 * * Modifications: * * JRM -- 5/5/20 * * Added code to enable the skip list prior to the call * to H5C__flush_invalidate_cache(), and disable it * afterwards. * *------------------------------------------------------------------------- */ herr_t H5C_evict(H5F_t *f) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ HDassert(f); /* Enable the slist, as it is needed in the flush */ if (H5C_set_slist_enabled(f->shared->cache, TRUE, FALSE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist enabled failed") /* Flush and invalidate all cache entries except the pinned entries */ if (H5C__flush_invalidate_cache(f, H5C__EVICT_ALLOW_LAST_PINS_FLAG) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to evict entries in the cache") /* Disable the slist */ if (H5C_set_slist_enabled(f->shared->cache, FALSE, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "set slist disabled failed") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_evict() */ /*------------------------------------------------------------------------- * Function: H5C_expunge_entry * * Purpose: Use this function to tell the cache to expunge an entry * from the cache without writing it to disk even if it is * dirty. The entry may not be either pinned or protected. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 6/29/06 * *------------------------------------------------------------------------- */ herr_t H5C_expunge_entry(H5F_t *f, const H5C_class_t *type, haddr_t addr, unsigned flags) { H5C_t *cache_ptr; H5C_cache_entry_t *entry_ptr = NULL; unsigned flush_flags = (H5C__FLUSH_INVALIDATE_FLAG | H5C__FLUSH_CLEAR_ONLY_FLAG); herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) HDassert(f); HDassert(f->shared); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(type); HDassert(H5F_addr_defined(addr)); #ifdef H5C_DO_EXTREME_SANITY_CHECKS if (H5C_validate_lru_list(cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "LRU extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* Look for entry in cache */ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, FAIL) if ((entry_ptr == NULL) || (entry_ptr->type != type)) /* the target doesn't exist in the cache, so we are done. */ HGOTO_DONE(SUCCEED) HDassert(entry_ptr->addr == addr); HDassert(entry_ptr->type == type); /* Check for entry being pinned or protected */ if (entry_ptr->is_protected) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "Target entry is protected") if (entry_ptr->is_pinned) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "Target entry is pinned") /* If we get this far, call H5C__flush_single_entry() with the * H5C__FLUSH_INVALIDATE_FLAG and the H5C__FLUSH_CLEAR_ONLY_FLAG. * This will clear the entry, and then delete it from the cache. */ /* Pass along 'free file space' flag */ flush_flags |= (flags & H5C__FREE_FILE_SPACE_FLAG); /* Delete the entry from the skip list on destroy */ flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG; if (H5C__flush_single_entry(f, entry_ptr, flush_flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTEXPUNGE, FAIL, "can't flush entry") done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if (H5C_validate_lru_list(cache_ptr) < 0) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "LRU extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_expunge_entry() */ /*------------------------------------------------------------------------- * Function: H5C_flush_cache * * Purpose: Flush (and possibly destroy) the entries contained in the * specified cache. * * If the cache contains protected entries, the function will * fail, as protected entries cannot be flushed. However * all unprotected entries should be flushed before the * function returns failure. * * Return: Non-negative on success/Negative on failure or if there was * a request to flush all items and something was protected. * * Programmer: John Mainzer * 6/2/04 * * Changes: Modified function to test for slist chamges in * pre_serialize and serialize callbacks, and re-start * scans through the slist when such changes occur. * * This has been a potential problem for some time, * and there has been code in this function to deal * with elements of this issue. However the shift * to the V3 cache in combination with the activities * of some of the cache clients (in particular the * free space manager and the fractal heap) have * made this re-work necessary. * * JRM -- 12/13/14 * * Modified function to support rings. Basic idea is that * every entry in the cache is assigned to a ring. Entries * in the outermost ring are flushed first, followed by * those in the next outermost ring, and so on until the * innermost ring is flushed. See header comment on * H5C_ring_t in H5Cprivate.h for a more detailed * discussion. * * JRM -- 8/30/15 * * Modified function to call the free space manager * settling functions. * JRM -- 6/9/16 * *------------------------------------------------------------------------- */ herr_t H5C_flush_cache(H5F_t *f, unsigned flags) { #ifdef H5C_DO_SANITY_CHECKS int i; uint32_t index_len = 0; size_t index_size = (size_t)0; size_t clean_index_size = (size_t)0; size_t dirty_index_size = (size_t)0; size_t slist_size = (size_t)0; uint32_t slist_len = 0; #endif /* H5C_DO_SANITY_CHECKS */ H5C_ring_t ring; H5C_t *cache_ptr; hbool_t destroy; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(FAIL) HDassert(f); HDassert(f->shared); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(cache_ptr->slist_ptr); #ifdef H5C_DO_SANITY_CHECKS HDassert(cache_ptr->index_ring_len[H5C_RING_UNDEFINED] == 0); HDassert(cache_ptr->index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); HDassert(cache_ptr->clean_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); HDassert(cache_ptr->dirty_index_ring_size[H5C_RING_UNDEFINED] == (size_t)0); HDassert(cache_ptr->slist_ring_len[H5C_RING_UNDEFINED] == 0); HDassert(cache_ptr->slist_ring_size[H5C_RING_UNDEFINED] == (size_t)0); for (i = H5C_RING_USER; i < H5C_RING_NTYPES; i++) { index_len += cache_ptr->index_ring_len[i]; index_size += cache_ptr->index_ring_size[i]; clean_index_size += cache_ptr->clean_index_ring_size[i]; dirty_index_size += cache_ptr->dirty_index_ring_size[i]; slist_len += cache_ptr->slist_ring_len[i]; slist_size += cache_ptr->slist_ring_size[i]; } /* end for */ HDassert(cache_ptr->index_len == index_len); HDassert(cache_ptr->index_size == index_size); HDassert(cache_ptr->clean_index_size == clean_index_size); HDassert(cache_ptr->dirty_index_size == dirty_index_size); HDassert(cache_ptr->slist_len == slist_len); HDassert(cache_ptr->slist_size == slist_size); #endif /* H5C_DO_SANITY_CHECKS */ #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ destroy = ((flags & H5C__FLUSH_INVALIDATE_FLAG) != 0); HDassert(!(destroy && ((flags & H5C__FLUSH_IGNORE_PROTECTED_FLAG) != 0))); HDassert(!(cache_ptr->flush_in_progress)); cache_ptr->flush_in_progress = TRUE; if (destroy) { if (H5C__flush_invalidate_cache(f, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush invalidate failed") } /* end if */ else { /* flush each ring, starting from the outermost ring and * working inward. */ ring = H5C_RING_USER; while (ring < H5C_RING_NTYPES) { /* Only call the free space manager settle routines when close * warning has been received. */ if (cache_ptr->close_warning_received) { switch (ring) { case H5C_RING_USER: break; case H5C_RING_RDFSM: /* Settle raw data FSM */ if (!cache_ptr->rdfsm_settled) if (H5MF_settle_raw_data_fsm(f, &cache_ptr->rdfsm_settled) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "RD FSM settle failed") break; case H5C_RING_MDFSM: /* Settle metadata FSM */ if (!cache_ptr->mdfsm_settled) if (H5MF_settle_meta_data_fsm(f, &cache_ptr->mdfsm_settled) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "MD FSM settle failed") break; case H5C_RING_SBE: case H5C_RING_SB: break; default: HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown ring?!?!") break; } /* end switch */ } /* end if */ if (H5C__flush_ring(f, ring, flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "flush ring failed") ring++; } /* end while */ } /* end else */ done: cache_ptr->flush_in_progress = FALSE; FUNC_LEAVE_NOAPI(ret_value) } /* H5C_flush_cache() */ /*------------------------------------------------------------------------- * Function: H5C_flush_to_min_clean * * Purpose: Flush dirty entries until the caches min clean size is * attained. * * This function is used in the implementation of the * metadata cache in PHDF5. To avoid "messages from the * future", the cache on process 0 can't be allowed to * flush entries until the other processes have reached * the same point in the calculation. If this constraint * is not met, it is possible that the other processes will * read metadata generated at a future point in the * computation. * * * Return: Non-negative on success/Negative on failure or if * write is not permitted. * * Programmer: John Mainzer * 9/16/05 * *------------------------------------------------------------------------- */ herr_t H5C_flush_to_min_clean(H5F_t *f) { H5C_t *cache_ptr; hbool_t write_permitted; herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI(FAIL) HDassert(f); HDassert(f->shared); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); if (cache_ptr->check_write_permitted != NULL) { if ((cache_ptr->check_write_permitted)(f, &write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't get write_permitted") } /* end if */ else write_permitted = cache_ptr->write_permitted; if (!write_permitted) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "cache write is not permitted!?!") if (H5C__make_space_in_cache(f, (size_t)0, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C__make_space_in_cache failed") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_flush_to_min_clean() */ /*------------------------------------------------------------------------- * Function: H5C_insert_entry * * Purpose: Adds the specified thing to the cache. The thing need not * exist on disk yet, but it must have an address and disk * space reserved. * * Observe that this function cannot occasion a read. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 6/2/04 * *------------------------------------------------------------------------- */ herr_t H5C_insert_entry(H5F_t *f, const H5C_class_t *type, haddr_t addr, void *thing, unsigned int flags) { H5C_t *cache_ptr; H5AC_ring_t ring = H5C_RING_UNDEFINED; hbool_t insert_pinned; hbool_t flush_last; #ifdef H5_HAVE_PARALLEL hbool_t coll_access = FALSE; /* whether access to the cache entry is done collectively */ #endif /* H5_HAVE_PARALLEL */ hbool_t set_flush_marker; hbool_t write_permitted = TRUE; size_t empty_space; H5C_cache_entry_t *entry_ptr = NULL; H5C_cache_entry_t *test_entry_ptr; hbool_t entry_tagged = FALSE; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) HDassert(f); HDassert(f->shared); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(type); HDassert(type->mem_type == cache_ptr->class_table_ptr[type->id]->mem_type); HDassert(type->image_len); HDassert(H5F_addr_defined(addr)); HDassert(thing); #ifdef H5C_DO_EXTREME_SANITY_CHECKS /* no need to verify that entry is not already in the index as */ /* we already make that check below. */ if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ set_flush_marker = ((flags & H5C__SET_FLUSH_MARKER_FLAG) != 0); insert_pinned = ((flags & H5C__PIN_ENTRY_FLAG) != 0); flush_last = ((flags & H5C__FLUSH_LAST_FLAG) != 0); /* Get the ring type from the API context */ ring = H5CX_get_ring(); entry_ptr = (H5C_cache_entry_t *)thing; /* verify that the new entry isn't already in the hash table -- scream * and die if it is. */ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL) if (test_entry_ptr != NULL) { if (test_entry_ptr == entry_ptr) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "entry already in cache") else HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "duplicate entry in cache") } /* end if */ entry_ptr->magic = H5C__H5C_CACHE_ENTRY_T_MAGIC; entry_ptr->cache_ptr = cache_ptr; entry_ptr->addr = addr; entry_ptr->type = type; entry_ptr->image_ptr = NULL; entry_ptr->image_up_to_date = FALSE; entry_ptr->is_protected = FALSE; entry_ptr->is_read_only = FALSE; entry_ptr->ro_ref_count = 0; entry_ptr->is_pinned = insert_pinned; entry_ptr->pinned_from_client = insert_pinned; entry_ptr->pinned_from_cache = FALSE; entry_ptr->flush_me_last = flush_last; /* newly inserted entries are assumed to be dirty */ entry_ptr->is_dirty = TRUE; /* not protected, so can't be dirtied */ entry_ptr->dirtied = FALSE; /* Retrieve the size of the thing */ if ((type->image_len)(thing, &(entry_ptr->size)) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGETSIZE, FAIL, "can't get size of thing") HDassert(entry_ptr->size > 0 && entry_ptr->size < H5C_MAX_ENTRY_SIZE); entry_ptr->in_slist = FALSE; #ifdef H5_HAVE_PARALLEL entry_ptr->clear_on_unprotect = FALSE; entry_ptr->flush_immediately = FALSE; #endif /* H5_HAVE_PARALLEL */ entry_ptr->flush_in_progress = FALSE; entry_ptr->destroy_in_progress = FALSE; entry_ptr->ring = ring; /* Initialize flush dependency fields */ entry_ptr->flush_dep_parent = NULL; entry_ptr->flush_dep_nparents = 0; entry_ptr->flush_dep_parent_nalloc = 0; entry_ptr->flush_dep_nchildren = 0; entry_ptr->flush_dep_ndirty_children = 0; entry_ptr->flush_dep_nunser_children = 0; entry_ptr->ht_next = NULL; entry_ptr->ht_prev = NULL; entry_ptr->il_next = NULL; entry_ptr->il_prev = NULL; entry_ptr->next = NULL; entry_ptr->prev = NULL; #if H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS entry_ptr->aux_next = NULL; entry_ptr->aux_prev = NULL; #endif /* H5C_MAINTAIN_CLEAN_AND_DIRTY_LRU_LISTS */ #ifdef H5_HAVE_PARALLEL entry_ptr->coll_next = NULL; entry_ptr->coll_prev = NULL; #endif /* H5_HAVE_PARALLEL */ /* initialize cache image related fields */ entry_ptr->include_in_image = FALSE; entry_ptr->lru_rank = 0; entry_ptr->image_dirty = FALSE; entry_ptr->fd_parent_count = 0; entry_ptr->fd_parent_addrs = NULL; entry_ptr->fd_child_count = 0; entry_ptr->fd_dirty_child_count = 0; entry_ptr->image_fd_height = 0; entry_ptr->prefetched = FALSE; entry_ptr->prefetch_type_id = 0; entry_ptr->age = 0; entry_ptr->prefetched_dirty = FALSE; #ifndef NDEBUG /* debugging field */ entry_ptr->serialization_count = 0; #endif /* NDEBUG */ /* initialize tag list fields */ entry_ptr->tl_next = NULL; entry_ptr->tl_prev = NULL; entry_ptr->tag_info = NULL; /* Apply tag to newly inserted entry */ if (H5C__tag_entry(cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, FAIL, "Cannot tag metadata entry") entry_tagged = TRUE; H5C__RESET_CACHE_ENTRY_STATS(entry_ptr) if (cache_ptr->flash_size_increase_possible && (entry_ptr->size > cache_ptr->flash_size_increase_threshold)) if (H5C__flash_increase_cache_size(cache_ptr, 0, entry_ptr->size) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C__flash_increase_cache_size failed") if (cache_ptr->index_size >= cache_ptr->max_cache_size) empty_space = 0; else empty_space = cache_ptr->max_cache_size - cache_ptr->index_size; if (cache_ptr->evictions_enabled && (((cache_ptr->index_size + entry_ptr->size) > cache_ptr->max_cache_size) || (((empty_space + cache_ptr->clean_index_size) < cache_ptr->min_clean_size)))) { size_t space_needed; if (empty_space <= entry_ptr->size) cache_ptr->cache_full = TRUE; if (cache_ptr->check_write_permitted != NULL) { if ((cache_ptr->check_write_permitted)(f, &write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "Can't get write_permitted") } /* end if */ else write_permitted = cache_ptr->write_permitted; HDassert(entry_ptr->size <= H5C_MAX_ENTRY_SIZE); space_needed = entry_ptr->size; if (space_needed > cache_ptr->max_cache_size) space_needed = cache_ptr->max_cache_size; /* Note that space_needed is just the amount of space that * needed to insert the new entry without exceeding the cache * size limit. The subsequent call to H5C__make_space_in_cache() * may evict the entries required to free more or less space * depending on conditions. It MAY be less if the cache is * currently undersized, or more if the cache is oversized. * * The cache can exceed its maximum size limit via the following * mechanisms: * * First, it is possible for the cache to grow without * bound as long as entries are protected and not unprotected. * * Second, when writes are not permitted it is also possible * for the cache to grow without bound. * * Finally, we usually don't check to see if the cache is * oversized at the end of an unprotect. As a result, it is * possible to have a vastly oversized cache with no protected * entries as long as all the protects precede the unprotects. * * Since items 1 and 2 are not changing any time soon, I see * no point in worrying about the third. */ if (H5C__make_space_in_cache(f, space_needed, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTINS, FAIL, "H5C__make_space_in_cache failed") } /* end if */ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) /* New entries are presumed to be dirty */ HDassert(entry_ptr->is_dirty); entry_ptr->flush_marker = set_flush_marker; H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, FAIL) #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed just before done") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* If the entry's type has a 'notify' callback send a 'after insertion' * notice now that the entry is fully integrated into the cache. */ if (entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_INSERT, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry inserted into cache") H5C__UPDATE_STATS_FOR_INSERTION(cache_ptr, entry_ptr) #ifdef H5_HAVE_PARALLEL if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) coll_access = H5F_get_coll_metadata_reads(f); entry_ptr->coll_access = coll_access; if (coll_access) { H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, FAIL) /* Make sure the size of the collective entries in the cache remain in check */ if (H5P_USER_TRUE == H5F_COLL_MD_READ(f)) { if (cache_ptr->max_cache_size * 80 < cache_ptr->coll_list_size * 100) { if (H5C_clear_coll_entries(cache_ptr, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear collective metadata entries") } /* end if */ } /* end if */ else { if (cache_ptr->max_cache_size * 40 < cache_ptr->coll_list_size * 100) { if (H5C_clear_coll_entries(cache_ptr, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "can't clear collective metadata entries") } /* end if */ } /* end else */ } /* end if */ #endif done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ if (ret_value < 0 && entry_tagged) if (H5C__untag_entry(cache_ptr, entry_ptr) < 0) HDONE_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry from tag list") FUNC_LEAVE_NOAPI(ret_value) } /* H5C_insert_entry() */ /*------------------------------------------------------------------------- * Function: H5C_mark_entry_dirty * * Purpose: Mark a pinned or protected entry as dirty. The target entry * MUST be either pinned or protected, and MAY be both. * * In the protected case, this call is the functional * equivalent of setting the H5C__DIRTIED_FLAG on an unprotect * call. * * In the pinned but not protected case, if the entry is not * already dirty, the function places function marks the entry * dirty and places it on the skip list. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 5/15/06 * * JRM -- 11/5/08 * Added call to H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY() to * update the new clean_index_size and dirty_index_size * fields of H5C_t in the case that the entry was clean * prior to this call, and is pinned and not protected. * *------------------------------------------------------------------------- */ herr_t H5C_mark_entry_dirty(void *thing) { H5C_t *cache_ptr; H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)thing; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry_ptr); HDassert(H5F_addr_defined(entry_ptr->addr)); cache_ptr = entry_ptr->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); if (entry_ptr->is_protected) { HDassert(!((entry_ptr)->is_read_only)); /* set the dirtied flag */ entry_ptr->dirtied = TRUE; /* reset image_up_to_date */ if (entry_ptr->image_up_to_date) { entry_ptr->image_up_to_date = FALSE; if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_unserialized(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") } /* end if */ } /* end if */ else if (entry_ptr->is_pinned) { hbool_t was_clean; /* Whether the entry was previously clean */ hbool_t image_was_up_to_date; /* Remember previous dirty status */ was_clean = !entry_ptr->is_dirty; /* Check if image is up to date */ image_was_up_to_date = entry_ptr->image_up_to_date; /* Mark the entry as dirty if it isn't already */ entry_ptr->is_dirty = TRUE; entry_ptr->image_up_to_date = FALSE; /* Modify cache data structures */ if (was_clean) H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr) if (!entry_ptr->in_slist) H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) /* Update stats for entry being marked dirty */ H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) /* Check for entry changing status and do notifications, etc. */ if (was_clean) { /* If the entry's type has a 'notify' callback send a 'entry dirtied' * notice now that the entry is fully integrated into the cache. */ if (entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set") /* Propagate the dirty flag up the flush dependency chain if appropriate */ if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_dirty(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") } /* end if */ if (image_was_up_to_date) if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_unserialized(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") } /* end if */ else HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Entry is neither pinned nor protected??") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_mark_entry_dirty() */ /*------------------------------------------------------------------------- * Function: H5C_mark_entry_clean * * Purpose: Mark a pinned entry as clean. The target entry MUST be pinned. * * If the entry is not * already clean, the function places function marks the entry * clean and removes it from the skip list. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 7/23/16 * *------------------------------------------------------------------------- */ herr_t H5C_mark_entry_clean(void *_thing) { H5C_t *cache_ptr; H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)_thing; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry_ptr); HDassert(H5F_addr_defined(entry_ptr->addr)); cache_ptr = entry_ptr->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* Operate on pinned entry */ if (entry_ptr->is_protected) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "entry is protected") else if (entry_ptr->is_pinned) { hbool_t was_dirty; /* Whether the entry was previously dirty */ /* Remember previous dirty status */ was_dirty = entry_ptr->is_dirty; /* Mark the entry as clean if it isn't already */ entry_ptr->is_dirty = FALSE; /* Also reset the 'flush_marker' flag, since the entry shouldn't be flushed now */ entry_ptr->flush_marker = FALSE; /* Modify cache data structures */ if (was_dirty) H5C__UPDATE_INDEX_FOR_ENTRY_CLEAN(cache_ptr, entry_ptr) if (entry_ptr->in_slist) H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE) /* Update stats for entry being marked clean */ H5C__UPDATE_STATS_FOR_CLEAR(cache_ptr, entry_ptr) /* Check for entry changing status and do notifications, etc. */ if (was_dirty) { /* If the entry's type has a 'notify' callback send a 'entry cleaned' * notice now that the entry is fully integrated into the cache. */ if (entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared") /* Propagate the clean up the flush dependency chain, if appropriate */ if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_clean(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "Can't propagate flush dep clean") } /* end if */ } /* end if */ else HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKCLEAN, FAIL, "Entry is not pinned??") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_mark_entry_clean() */ /*------------------------------------------------------------------------- * Function: H5C_mark_entry_unserialized * * Purpose: Mark a pinned or protected entry as unserialized. The target * entry MUST be either pinned or protected, and MAY be both. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 12/23/16 * *------------------------------------------------------------------------- */ herr_t H5C_mark_entry_unserialized(void *thing) { H5C_cache_entry_t *entry = (H5C_cache_entry_t *)thing; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry); HDassert(H5F_addr_defined(entry->addr)); if (entry->is_protected || entry->is_pinned) { HDassert(!entry->is_read_only); /* Reset image_up_to_date */ if (entry->image_up_to_date) { entry->image_up_to_date = FALSE; if (entry->flush_dep_nparents > 0) if (H5C__mark_flush_dep_unserialized(entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSET, FAIL, "Can't propagate serialization status to fd parents") } /* end if */ } /* end if */ else HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKUNSERIALIZED, FAIL, "Entry to unserialize is neither pinned nor protected??") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_mark_entry_unserialized() */ /*------------------------------------------------------------------------- * Function: H5C_mark_entry_serialized * * Purpose: Mark a pinned entry as serialized. The target entry MUST be * pinned. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 12/23/16 * *------------------------------------------------------------------------- */ herr_t H5C_mark_entry_serialized(void *_thing) { H5C_cache_entry_t *entry = (H5C_cache_entry_t *)_thing; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry); HDassert(H5F_addr_defined(entry->addr)); /* Operate on pinned entry */ if (entry->is_protected) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "entry is protected") else if (entry->is_pinned) { /* Check for entry changing status and do notifications, etc. */ if (!entry->image_up_to_date) { /* Set the image_up_to_date flag */ entry->image_up_to_date = TRUE; /* Propagate the serialize up the flush dependency chain, if appropriate */ if (entry->flush_dep_nparents > 0) if (H5C__mark_flush_dep_serialized(entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "Can't propagate flush dep serialize") } /* end if */ } /* end if */ else HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKSERIALIZED, FAIL, "Entry is not pinned??") done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_mark_entry_serialized() */ /*------------------------------------------------------------------------- * * Function: H5C_move_entry * * Purpose: Use this function to notify the cache that an entry's * file address changed. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 6/2/04 * *------------------------------------------------------------------------- */ herr_t H5C_move_entry(H5C_t *cache_ptr, const H5C_class_t *type, haddr_t old_addr, haddr_t new_addr) { H5C_cache_entry_t *entry_ptr = NULL; H5C_cache_entry_t *test_entry_ptr = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(type); HDassert(H5F_addr_defined(old_addr)); HDassert(H5F_addr_defined(new_addr)); HDassert(H5F_addr_ne(old_addr, new_addr)); #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ H5C__SEARCH_INDEX(cache_ptr, old_addr, entry_ptr, FAIL) if (entry_ptr == NULL || entry_ptr->type != type) /* the old item doesn't exist in the cache, so we are done. */ HGOTO_DONE(SUCCEED) HDassert(entry_ptr->addr == old_addr); HDassert(entry_ptr->type == type); /* Check for R/W status, otherwise error */ /* (Moving a R/O entry would mark it dirty, which shouldn't * happen. QAK - 2016/12/02) */ if (entry_ptr->is_read_only) HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "can't move R/O entry") H5C__SEARCH_INDEX(cache_ptr, new_addr, test_entry_ptr, FAIL) if (test_entry_ptr != NULL) { /* we are hosed */ if (test_entry_ptr->type == type) HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "target already moved & reinserted???") else HGOTO_ERROR(H5E_CACHE, H5E_CANTMOVE, FAIL, "new address already in use?") } /* end if */ /* If we get this far we have work to do. Remove *entry_ptr from * the hash table (and skip list if necessary), change its address to the * new address, mark it as dirty (if it isn't already) and then re-insert. * * Update the replacement policy for a hit to avoid an eviction before * the moved entry is touched. Update stats for a move. * * Note that we do not check the size of the cache, or evict anything. * Since this is a simple re-name, cache size should be unaffected. * * Check to see if the target entry is in the process of being destroyed * before we delete from the index, etc. If it is, all we do is * change the addr. If the entry is only in the process of being flushed, * don't mark it as dirty either, lest we confuse the flush call back. */ if (!entry_ptr->destroy_in_progress) { H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL) if (entry_ptr->in_slist) { HDassert(cache_ptr->slist_ptr); H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE) } /* end if */ } /* end if */ entry_ptr->addr = new_addr; if (!entry_ptr->destroy_in_progress) { hbool_t was_dirty; /* Whether the entry was previously dirty */ /* Remember previous dirty status */ was_dirty = entry_ptr->is_dirty; /* Mark the entry as dirty if it isn't already */ entry_ptr->is_dirty = TRUE; /* This shouldn't be needed, but it keeps the test code happy */ if (entry_ptr->image_up_to_date) { entry_ptr->image_up_to_date = FALSE; if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_unserialized(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") } /* end if */ /* Modify cache data structures */ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL) H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) /* Skip some actions if we're in the middle of flushing the entry */ if (!entry_ptr->flush_in_progress) { /* Update the replacement policy for the entry */ H5C__UPDATE_RP_FOR_MOVE(cache_ptr, entry_ptr, was_dirty, FAIL) /* Check for entry changing status and do notifications, etc. */ if (!was_dirty) { /* If the entry's type has a 'notify' callback send a 'entry dirtied' * notice now that the entry is fully integrated into the cache. */ if (entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set") /* Propagate the dirty flag up the flush dependency chain if appropriate */ if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_dirty(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") } /* end if */ } /* end if */ } /* end if */ H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr) done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_move_entry() */ /*------------------------------------------------------------------------- * Function: H5C_resize_entry * * Purpose: Resize a pinned or protected entry. * * Resizing an entry dirties it, so if the entry is not * already dirty, the function places the entry on the * skip list. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 7/5/06 * *------------------------------------------------------------------------- */ herr_t H5C_resize_entry(void *thing, size_t new_size) { H5C_t *cache_ptr; H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)thing; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry_ptr); HDassert(H5F_addr_defined(entry_ptr->addr)); cache_ptr = entry_ptr->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* Check for usage errors */ if (new_size <= 0) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "New size is non-positive") if (!(entry_ptr->is_pinned || entry_ptr->is_protected)) HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, FAIL, "Entry isn't pinned or protected??") #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* update for change in entry size if necessary */ if (entry_ptr->size != new_size) { hbool_t was_clean; /* make note of whether the entry was clean to begin with */ was_clean = !entry_ptr->is_dirty; /* mark the entry as dirty if it isn't already */ entry_ptr->is_dirty = TRUE; /* Reset the image up-to-date status */ if (entry_ptr->image_up_to_date) { entry_ptr->image_up_to_date = FALSE; if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_unserialized(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") } /* end if */ /* Release the current image */ if (entry_ptr->image_ptr) entry_ptr->image_ptr = H5MM_xfree(entry_ptr->image_ptr); /* do a flash cache size increase if appropriate */ if (cache_ptr->flash_size_increase_possible) { if (new_size > entry_ptr->size) { size_t size_increase; size_increase = new_size - entry_ptr->size; if (size_increase >= cache_ptr->flash_size_increase_threshold) { if (H5C__flash_increase_cache_size(cache_ptr, entry_ptr->size, new_size) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTRESIZE, FAIL, "flash cache increase failed") } } } /* update the pinned and/or protected entry list */ if (entry_ptr->is_pinned) { H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pel_len), (cache_ptr->pel_size), (entry_ptr->size), (new_size)) } /* end if */ if (entry_ptr->is_protected) { H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->pl_len), (cache_ptr->pl_size), (entry_ptr->size), (new_size)) } /* end if */ #ifdef H5_HAVE_PARALLEL if (entry_ptr->coll_access) { H5C__DLL_UPDATE_FOR_SIZE_CHANGE((cache_ptr->coll_list_len), (cache_ptr->coll_list_size), (entry_ptr->size), (new_size)) } /* end if */ #endif /* H5_HAVE_PARALLEL */ /* update statistics just before changing the entry size */ H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_size); /* update the hash table */ H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_size, entry_ptr, was_clean); /* if the entry is in the skip list, update that too */ if (entry_ptr->in_slist) H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_size); /* finally, update the entry size proper */ entry_ptr->size = new_size; if (!entry_ptr->in_slist) H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) if (entry_ptr->is_pinned) H5C__UPDATE_STATS_FOR_DIRTY_PIN(cache_ptr, entry_ptr) /* Check for entry changing status and do notifications, etc. */ if (was_clean) { /* If the entry's type has a 'notify' callback send a 'entry dirtied' * notice now that the entry is fully integrated into the cache. */ if (entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set") /* Propagate the dirty flag up the flush dependency chain if appropriate */ if (entry_ptr->flush_dep_nparents > 0) if (H5C__mark_flush_dep_dirty(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") } /* end if */ } /* end if */ done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_resize_entry() */ /*------------------------------------------------------------------------- * Function: H5C_pin_protected_entry() * * Purpose: Pin a protected cache entry. The entry must be protected * at the time of call, and must be unpinned. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 4/26/06 * * Changes: Added extreme sanity checks on entry and exit. * JRM -- 4/26/14 * *------------------------------------------------------------------------- */ herr_t H5C_pin_protected_entry(void *thing) { H5C_t *cache_ptr; H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)thing; /* Pointer to entry to pin */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry_ptr); HDassert(H5F_addr_defined(entry_ptr->addr)); cache_ptr = entry_ptr->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* Only protected entries can be pinned */ if (!entry_ptr->is_protected) HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Entry isn't protected") /* Pin the entry from a client */ if (H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client") done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_pin_protected_entry() */ /*------------------------------------------------------------------------- * Function: H5C_protect * * Purpose: If the target entry is not in the cache, load it. If * necessary, attempt to evict one or more entries to keep * the cache within its maximum size. * * Mark the target entry as protected, and return its address * to the caller. The caller must call H5C_unprotect() when * finished with the entry. * * While it is protected, the entry may not be either evicted * or flushed -- nor may it be accessed by another call to * H5C_protect. Any attempt to do so will result in a failure. * * Return: Success: Ptr to the desired entry * Failure: NULL * * Programmer: John Mainzer - 6/2/04 * *------------------------------------------------------------------------- */ void * H5C_protect(H5F_t *f, const H5C_class_t *type, haddr_t addr, void *udata, unsigned flags) { H5C_t *cache_ptr; H5AC_ring_t ring = H5C_RING_UNDEFINED; hbool_t hit; hbool_t have_write_permitted = FALSE; hbool_t read_only = FALSE; hbool_t flush_last; #ifdef H5_HAVE_PARALLEL hbool_t coll_access = FALSE; /* whether access to the cache entry is done collectively */ #endif /* H5_HAVE_PARALLEL */ hbool_t write_permitted = FALSE; hbool_t was_loaded = FALSE; /* Whether the entry was loaded as a result of the protect */ size_t empty_space; void *thing; H5C_cache_entry_t *entry_ptr; void *ret_value = NULL; /* Return value */ FUNC_ENTER_NOAPI(NULL) /* check args */ HDassert(f); HDassert(f->shared); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(type); HDassert(type->mem_type == cache_ptr->class_table_ptr[type->id]->mem_type); HDassert(H5F_addr_defined(addr)); #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* Load the cache image, if requested */ if (cache_ptr->load_image) { cache_ptr->load_image = FALSE; if (H5C__load_cache_image(f) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "Can't load cache image") } /* end if */ read_only = ((flags & H5C__READ_ONLY_FLAG) != 0); flush_last = ((flags & H5C__FLUSH_LAST_FLAG) != 0); /* Get the ring type from the API context */ ring = H5CX_get_ring(); #ifdef H5_HAVE_PARALLEL if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI)) coll_access = H5F_get_coll_metadata_reads(f); #endif /* H5_HAVE_PARALLEL */ /* first check to see if the target is in cache */ H5C__SEARCH_INDEX(cache_ptr, addr, entry_ptr, NULL) if (entry_ptr != NULL) { if (entry_ptr->ring != ring) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "ring type mismatch occurred for cache entry") HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); if (entry_ptr->prefetched) { /* This call removes the prefetched entry from the cache, * and replaces it with an entry deserialized from the * image of the prefetched entry. */ if (H5C__deserialize_prefetched_entry(f, cache_ptr, &entry_ptr, type, addr, udata) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't deserialize prefetched entry") HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(!entry_ptr->prefetched); HDassert(entry_ptr->addr == addr); } /* end if */ /* Check for trying to load the wrong type of entry from an address */ if (entry_ptr->type != type) HGOTO_ERROR(H5E_CACHE, H5E_BADTYPE, NULL, "incorrect cache entry type") /* if this is a collective metadata read, the entry is not marked as collective, and is clean, it is possible that other processes will not have it in its cache and will expect a bcast of the entry from process 0. So process 0 will bcast the entry to all other ranks. Ranks that _do_ have the entry in their cache still have to participate in the bcast. */ #ifdef H5_HAVE_PARALLEL if (coll_access) { if (!(entry_ptr->is_dirty) && !(entry_ptr->coll_access)) { MPI_Comm comm; /* File MPI Communicator */ int mpi_code; /* MPI error code */ int buf_size; if (MPI_COMM_NULL == (comm = H5F_mpi_get_comm(f))) HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "get_comm request failed") if (entry_ptr->image_ptr == NULL) { int mpi_rank; if ((mpi_rank = H5F_mpi_get_rank(f)) < 0) HGOTO_ERROR(H5E_FILE, H5E_CANTGET, NULL, "Can't get MPI rank") if (NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, NULL, "memory allocation failed for on disk image buffer") #if H5C_DO_MEMORY_SANITY_CHECKS H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ if (0 == mpi_rank) { if (H5C__generate_image(f, cache_ptr, entry_ptr) < 0) { /* If image generation fails, push an error but * still participate in the following MPI_Bcast */ HDONE_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "can't generate entry's image") } } } /* end if */ HDassert(entry_ptr->image_ptr); H5_CHECKED_ASSIGN(buf_size, int, entry_ptr->size, size_t); if (MPI_SUCCESS != (mpi_code = MPI_Bcast(entry_ptr->image_ptr, buf_size, MPI_BYTE, 0, comm))) HMPI_GOTO_ERROR(NULL, "MPI_Bcast failed", mpi_code) /* Mark the entry as collective and insert into the collective list */ entry_ptr->coll_access = TRUE; H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, NULL) } /* end if */ else if (entry_ptr->coll_access) { H5C__MOVE_TO_TOP_IN_COLL_LIST(cache_ptr, entry_ptr, NULL) } /* end else-if */ } /* end if */ #endif /* H5_HAVE_PARALLEL */ #ifdef H5C_DO_TAGGING_SANITY_CHECKS { /* Verify tag value */ if (cache_ptr->ignore_tags != TRUE) { haddr_t tag; /* Tag value */ /* The entry is already in the cache, but make sure that the tag value * is still legal. This will ensure that had the entry NOT been in the * cache, tagging was still set up correctly and it would have received * a legal tag value after getting loaded from disk. */ /* Get the tag */ tag = H5CX_get_tag(); if (H5C_verify_tag(entry_ptr->type->id, tag) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTGET, NULL, "tag verification failed") } /* end if */ } #endif hit = TRUE; thing = (void *)entry_ptr; } else { /* must try to load the entry from disk. */ hit = FALSE; if (NULL == (thing = H5C__load_entry(f, #ifdef H5_HAVE_PARALLEL coll_access, #endif /* H5_HAVE_PARALLEL */ type, addr, udata))) HGOTO_ERROR(H5E_CACHE, H5E_CANTLOAD, NULL, "can't load entry") entry_ptr = (H5C_cache_entry_t *)thing; cache_ptr->entries_loaded_counter++; entry_ptr->ring = ring; #ifdef H5_HAVE_PARALLEL if (H5F_HAS_FEATURE(f, H5FD_FEAT_HAS_MPI) && entry_ptr->coll_access) H5C__INSERT_IN_COLL_LIST(cache_ptr, entry_ptr, NULL) #endif /* H5_HAVE_PARALLEL */ /* Apply tag to newly protected entry */ if (H5C__tag_entry(cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTTAG, NULL, "Cannot tag metadata entry") /* If the entry is very large, and we are configured to allow it, * we may wish to perform a flash cache size increase. */ if ((cache_ptr->flash_size_increase_possible) && (entry_ptr->size > cache_ptr->flash_size_increase_threshold)) { if (H5C__flash_increase_cache_size(cache_ptr, 0, entry_ptr->size) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C__flash_increase_cache_size failed") } if (cache_ptr->index_size >= cache_ptr->max_cache_size) empty_space = 0; else empty_space = cache_ptr->max_cache_size - cache_ptr->index_size; /* try to free up if necceary and if evictions are permitted. Note * that if evictions are enabled, we will call H5C__make_space_in_cache() * regardless if the min_free_space requirement is not met. */ if ((cache_ptr->evictions_enabled) && (((cache_ptr->index_size + entry_ptr->size) > cache_ptr->max_cache_size) || ((empty_space + cache_ptr->clean_index_size) < cache_ptr->min_clean_size))) { size_t space_needed; if (empty_space <= entry_ptr->size) cache_ptr->cache_full = TRUE; if (cache_ptr->check_write_permitted != NULL) { if ((cache_ptr->check_write_permitted)(f, &write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Can't get write_permitted 1") else have_write_permitted = TRUE; } /* end if */ else { write_permitted = cache_ptr->write_permitted; have_write_permitted = TRUE; } /* end else */ HDassert(entry_ptr->size <= H5C_MAX_ENTRY_SIZE); space_needed = entry_ptr->size; if (space_needed > cache_ptr->max_cache_size) space_needed = cache_ptr->max_cache_size; /* Note that space_needed is just the amount of space that * needed to insert the new entry without exceeding the cache * size limit. The subsequent call to H5C__make_space_in_cache() * may evict the entries required to free more or less space * depending on conditions. It MAY be less if the cache is * currently undersized, or more if the cache is oversized. * * The cache can exceed its maximum size limit via the following * mechanisms: * * First, it is possible for the cache to grow without * bound as long as entries are protected and not unprotected. * * Second, when writes are not permitted it is also possible * for the cache to grow without bound. * * Third, the user may choose to disable evictions -- causing * the cache to grow without bound until evictions are * re-enabled. * * Finally, we usually don't check to see if the cache is * oversized at the end of an unprotect. As a result, it is * possible to have a vastly oversized cache with no protected * entries as long as all the protects precede the unprotects. * * Since items 1, 2, and 3 are not changing any time soon, I * see no point in worrying about the fourth. */ if (H5C__make_space_in_cache(f, space_needed, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C__make_space_in_cache failed") } /* end if */ /* Insert the entry in the hash table. It can't be dirty yet, so * we don't even check to see if it should go in the skip list. * * This is no longer true -- due to a bug fix, we may modify * data on load to repair a file. * * ******************************************* * * Set the flush_last field * of the newly loaded entry before inserting it into the * index. Must do this, as the index tracked the number of * entries with the flush_last field set, but assumes that * the field will not change after insertion into the index. * * Note that this means that the H5C__FLUSH_LAST_FLAG flag * is ignored if the entry is already in cache. */ entry_ptr->flush_me_last = flush_last; H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, NULL) if ((entry_ptr->is_dirty) && (!(entry_ptr->in_slist))) { H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, NULL) } /* insert the entry in the data structures used by the replacement * policy. We are just going to take it out again when we update * the replacement policy for a protect, but this simplifies the * code. If we do this often enough, we may want to optimize this. */ H5C__UPDATE_RP_FOR_INSERTION(cache_ptr, entry_ptr, NULL) /* Record that the entry was loaded, to trigger a notify callback later */ /* (After the entry is fully added to the cache) */ was_loaded = TRUE; } /* end else */ HDassert(entry_ptr->addr == addr); HDassert(entry_ptr->type == type); if (entry_ptr->is_protected) { if (read_only && entry_ptr->is_read_only) { HDassert(entry_ptr->ro_ref_count > 0); (entry_ptr->ro_ref_count)++; } /* end if */ else HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Target already protected & not read only?!?") } /* end if */ else { H5C__UPDATE_RP_FOR_PROTECT(cache_ptr, entry_ptr, NULL) entry_ptr->is_protected = TRUE; if (read_only) { entry_ptr->is_read_only = TRUE; entry_ptr->ro_ref_count = 1; } /* end if */ entry_ptr->dirtied = FALSE; } /* end else */ H5C__UPDATE_CACHE_HIT_RATE_STATS(cache_ptr, hit) H5C__UPDATE_STATS_FOR_PROTECT(cache_ptr, entry_ptr, hit) ret_value = thing; if ((cache_ptr->evictions_enabled) && ((cache_ptr->size_decreased) || ((cache_ptr->resize_enabled) && (cache_ptr->cache_accesses >= (cache_ptr->resize_ctl).epoch_length)))) { if (!have_write_permitted) { if (cache_ptr->check_write_permitted != NULL) { if ((cache_ptr->check_write_permitted)(f, &write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Can't get write_permitted") else have_write_permitted = TRUE; } else { write_permitted = cache_ptr->write_permitted; have_write_permitted = TRUE; } } if (cache_ptr->resize_enabled && (cache_ptr->cache_accesses >= (cache_ptr->resize_ctl).epoch_length)) { if (H5C__auto_adjust_cache_size(f, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "Cache auto-resize failed") } /* end if */ if (cache_ptr->size_decreased) { cache_ptr->size_decreased = FALSE; /* check to see if the cache is now oversized due to the cache * size reduction. If it is, try to evict enough entries to * bring the cache size down to the current maximum cache size. * * Also, if the min_clean_size requirement is not met, we * should also call H5C__make_space_in_cache() to bring us * into compliance. */ if (cache_ptr->index_size >= cache_ptr->max_cache_size) empty_space = 0; else empty_space = cache_ptr->max_cache_size - cache_ptr->index_size; if ((cache_ptr->index_size > cache_ptr->max_cache_size) || ((empty_space + cache_ptr->clean_index_size) < cache_ptr->min_clean_size)) { if (cache_ptr->index_size > cache_ptr->max_cache_size) cache_ptr->cache_full = TRUE; if (H5C__make_space_in_cache(f, (size_t)0, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPROTECT, NULL, "H5C__make_space_in_cache failed") } } /* end if */ } /* If we loaded the entry and the entry's type has a 'notify' callback, send * an 'after load' notice now that the entry is fully integrated into * the cache and protected. We must wait until it is protected so it is not * evicted during the notify callback. */ if (was_loaded) { /* If the entry's type has a 'notify' callback send a 'after load' * notice now that the entry is fully integrated into the cache. */ if (entry_ptr->type->notify && (entry_ptr->type->notify)(H5C_NOTIFY_ACTION_AFTER_LOAD, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, NULL, "can't notify client about entry inserted into cache") } /* end if */ #ifdef H5_HAVE_PARALLEL /* Make sure the size of the collective entries in the cache remain in check */ if (coll_access) { if (H5P_USER_TRUE == H5F_COLL_MD_READ(f)) { if (cache_ptr->max_cache_size * 80 < cache_ptr->coll_list_size * 100) if (H5C_clear_coll_entries(cache_ptr, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "can't clear collective metadata entries") } /* end if */ else { if (cache_ptr->max_cache_size * 40 < cache_ptr->coll_list_size * 100) if (H5C_clear_coll_entries(cache_ptr, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, NULL, "can't clear collective metadata entries") } /* end else */ } /* end if */ #endif /* H5_HAVE_PARALLEL */ done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, NULL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_protect() */ /*------------------------------------------------------------------------- * * Function: H5C_reset_cache_hit_rate_stats() * * Purpose: Reset the cache hit rate computation fields. * * Return: SUCCEED on success, and FAIL on failure. * * Programmer: John Mainzer, 10/5/04 * *------------------------------------------------------------------------- */ herr_t H5C_reset_cache_hit_rate_stats(H5C_t *cache_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if ((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC)) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry") cache_ptr->cache_hits = 0; cache_ptr->cache_accesses = 0; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_reset_cache_hit_rate_stats() */ /*------------------------------------------------------------------------- * Function: H5C_set_cache_auto_resize_config * * Purpose: Set the cache automatic resize configuration to the * provided values if they are in range, and fail if they * are not. * * If the new configuration enables automatic cache resizing, * coerce the cache max size and min clean size into agreement * with the new policy and re-set the full cache hit rate * stats. * * Return: SUCCEED on success, and FAIL on failure. * * Programmer: John Mainzer * 10/8/04 * *------------------------------------------------------------------------- */ herr_t H5C_set_cache_auto_resize_config(H5C_t *cache_ptr, H5C_auto_size_ctl_t *config_ptr) { size_t new_max_cache_size; size_t new_min_clean_size; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if ((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC)) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "bad cache_ptr on entry") if (config_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL config_ptr on entry") if (config_ptr->version != H5C__CURR_AUTO_SIZE_CTL_VER) HGOTO_ERROR(H5E_CACHE, H5E_BADVALUE, FAIL, "unknown config version") /* check general configuration section of the config: */ if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_GENERAL) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in general configuration fields of new config") /* check size increase control fields of the config: */ if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_INCREMENT) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in the size increase control fields of new config") /* check size decrease control fields of the config: */ if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_DECREMENT) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "error in the size decrease control fields of new config") /* check for conflicts between size increase and size decrease controls: */ if (H5C_validate_resize_config(config_ptr, H5C_RESIZE_CFG__VALIDATE_INTERACTIONS) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "conflicting threshold fields in new config") /* will set the increase possible fields to FALSE later if needed */ cache_ptr->size_increase_possible = TRUE; cache_ptr->flash_size_increase_possible = TRUE; cache_ptr->size_decrease_possible = TRUE; switch (config_ptr->incr_mode) { case H5C_incr__off: cache_ptr->size_increase_possible = FALSE; break; case H5C_incr__threshold: if ((config_ptr->lower_hr_threshold <= 0.0) || (config_ptr->increment <= 1.0) || ((config_ptr->apply_max_increment) && (config_ptr->max_increment <= 0))) cache_ptr->size_increase_possible = FALSE; break; default: /* should be unreachable */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown incr_mode?!?!?") } /* end switch */ /* logically, this is were configuration for flash cache size increases * should go. However, this configuration depends on max_cache_size, so * we wait until the end of the function, when this field is set. */ switch (config_ptr->decr_mode) { case H5C_decr__off: cache_ptr->size_decrease_possible = FALSE; break; case H5C_decr__threshold: if ((config_ptr->upper_hr_threshold >= 1.0) || (config_ptr->decrement >= 1.0) || ((config_ptr->apply_max_decrement) && (config_ptr->max_decrement <= 0))) cache_ptr->size_decrease_possible = FALSE; break; case H5C_decr__age_out: if (((config_ptr->apply_empty_reserve) && (config_ptr->empty_reserve >= 1.0)) || ((config_ptr->apply_max_decrement) && (config_ptr->max_decrement <= 0))) cache_ptr->size_decrease_possible = FALSE; break; case H5C_decr__age_out_with_threshold: if (((config_ptr->apply_empty_reserve) && (config_ptr->empty_reserve >= 1.0)) || ((config_ptr->apply_max_decrement) && (config_ptr->max_decrement <= 0)) || (config_ptr->upper_hr_threshold >= 1.0)) cache_ptr->size_decrease_possible = FALSE; break; default: /* should be unreachable */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown decr_mode?!?!?") } /* end switch */ if (config_ptr->max_size == config_ptr->min_size) { cache_ptr->size_increase_possible = FALSE; cache_ptr->flash_size_increase_possible = FALSE; cache_ptr->size_decrease_possible = FALSE; } /* end if */ /* flash_size_increase_possible is intentionally omitted from the * following: */ cache_ptr->resize_enabled = cache_ptr->size_increase_possible || cache_ptr->size_decrease_possible; cache_ptr->resize_ctl = *config_ptr; /* Resize the cache to the supplied initial value if requested, or as * necessary to force it within the bounds of the current automatic * cache resizing configuration. * * Note that the min_clean_fraction may have changed, so we * go through the exercise even if the current size is within * range and an initial size has not been provided. */ if (cache_ptr->resize_ctl.set_initial_size) new_max_cache_size = cache_ptr->resize_ctl.initial_size; else if (cache_ptr->max_cache_size > cache_ptr->resize_ctl.max_size) new_max_cache_size = cache_ptr->resize_ctl.max_size; else if (cache_ptr->max_cache_size < cache_ptr->resize_ctl.min_size) new_max_cache_size = cache_ptr->resize_ctl.min_size; else new_max_cache_size = cache_ptr->max_cache_size; new_min_clean_size = (size_t)((double)new_max_cache_size * ((cache_ptr->resize_ctl).min_clean_fraction)); /* since new_min_clean_size is of type size_t, we have * * ( 0 <= new_min_clean_size ) * * by definition. */ HDassert(new_min_clean_size <= new_max_cache_size); HDassert(cache_ptr->resize_ctl.min_size <= new_max_cache_size); HDassert(new_max_cache_size <= cache_ptr->resize_ctl.max_size); if (new_max_cache_size < cache_ptr->max_cache_size) cache_ptr->size_decreased = TRUE; cache_ptr->max_cache_size = new_max_cache_size; cache_ptr->min_clean_size = new_min_clean_size; if (H5C_reset_cache_hit_rate_stats(cache_ptr) < 0) /* this should be impossible... */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats failed") /* remove excess epoch markers if any */ if ((config_ptr->decr_mode == H5C_decr__age_out_with_threshold) || (config_ptr->decr_mode == H5C_decr__age_out)) { if (cache_ptr->epoch_markers_active > cache_ptr->resize_ctl.epochs_before_eviction) if (H5C__autoadjust__ageout__remove_excess_markers(cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't remove excess epoch markers") } /* end if */ else if (cache_ptr->epoch_markers_active > 0) { if (H5C__autoadjust__ageout__remove_all_markers(cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error removing all epoch markers") } /* configure flash size increase facility. We wait until the * end of the function, as we need the max_cache_size set before * we start to keep things simple. * * If we haven't already ruled out flash cache size increases above, * go ahead and configure it. */ if (cache_ptr->flash_size_increase_possible) { switch (config_ptr->flash_incr_mode) { case H5C_flash_incr__off: cache_ptr->flash_size_increase_possible = FALSE; break; case H5C_flash_incr__add_space: cache_ptr->flash_size_increase_possible = TRUE; cache_ptr->flash_size_increase_threshold = (size_t)(((double)(cache_ptr->max_cache_size)) * ((cache_ptr->resize_ctl).flash_threshold)); break; default: /* should be unreachable */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?") break; } /* end switch */ } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_set_cache_auto_resize_config() */ /*------------------------------------------------------------------------- * Function: H5C_set_evictions_enabled() * * Purpose: Set cache_ptr->evictions_enabled to the value of the * evictions enabled parameter. * * Return: SUCCEED on success, and FAIL on failure. * * Programmer: John Mainzer * 7/27/07 * *------------------------------------------------------------------------- */ herr_t H5C_set_evictions_enabled(H5C_t *cache_ptr, hbool_t evictions_enabled) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if ((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry") /* There is no fundamental reason why we should not permit * evictions to be disabled while automatic resize is enabled. * However, I can't think of any good reason why one would * want to, and allowing it would greatly complicate testing * the feature. Hence the following: */ if ((evictions_enabled != TRUE) && ((cache_ptr->resize_ctl.incr_mode != H5C_incr__off) || (cache_ptr->resize_ctl.decr_mode != H5C_decr__off))) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't disable evictions when auto resize enabled") cache_ptr->evictions_enabled = evictions_enabled; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_set_evictions_enabled() */ /*------------------------------------------------------------------------- * * Function: H5C_set_slist_enabled() * * Purpose: Enable or disable the slist as directed. * * The slist (skip list) is an address ordered list of * dirty entries in the metadata cache. However, this * list is only needed during flush and close, where we * use it to write entries in more or less increasing * address order. * * This function sets up and enables further operations * on the slist, or disable the slist. This in turn * allows us to avoid the overhead of maintaining the * slist when it is not needed. * * * If the slist_enabled parameter is TRUE, the function * * 1) Verifies that the slist is empty. * * 2) Scans the index list, and inserts all dirty entries * into the slist. * * 3) Sets cache_ptr->slist_enabled = TRUE. * * Note that the clear_slist parameter is ignored if * the slist_enabed parameter is TRUE. * * * If the slist_enabled_parameter is FALSE, the function * shuts down the slist. * * Normally the slist will be empty at this point, however * that need not be the case if H5C_flush_cache() has been * called with the H5C__FLUSH_MARKED_ENTRIES_FLAG. * * Thus shutdown proceeds as follows: * * 1) Test to see if the slist is empty. If it is, proceed * to step 3. * * 2) Test to see if the clear_slist parameter is TRUE. * * If it is, remove all entries from the slist. * * If it isn't, throw an error. * * 3) set cache_ptr->slist_enabled = FALSE. * * Return: SUCCEED on success, and FAIL on failure. * * Programmer: John Mainzer * 5/1/20 * * Modifications: * * None. * *------------------------------------------------------------------------- */ herr_t H5C_set_slist_enabled(H5C_t *cache_ptr, hbool_t slist_enabled, hbool_t clear_slist) { H5C_cache_entry_t *entry_ptr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if ((cache_ptr == NULL) || (cache_ptr->magic != H5C__H5C_T_MAGIC)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Bad cache_ptr on entry") #if H5C__SLIST_OPT_ENABLED if (slist_enabled) { if (cache_ptr->slist_enabled) { HDassert(FALSE); HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist already enabled?") } if ((cache_ptr->slist_len != 0) || (cache_ptr->slist_size != 0)) { HDassert(FALSE); HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist not empty (1)?") } /* set cache_ptr->slist_enabled to TRUE so that the slist * maintenance macros will be enabled. */ cache_ptr->slist_enabled = TRUE; /* scan the index list and insert all dirty entries in the slist */ entry_ptr = cache_ptr->il_head; while (entry_ptr != NULL) { HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); if (entry_ptr->is_dirty) { H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) } entry_ptr = entry_ptr->il_next; } /* we don't maintain a dirty index len, so we can't do a cross * check against it. Note that there is no point in cross checking * against the dirty LRU size, as the dirty LRU may not be maintained, * and in any case, there is no requirement that all dirty entries * will reside on the dirty LRU. */ HDassert(cache_ptr->dirty_index_size == cache_ptr->slist_size); } else { /* take down the skip list */ if (!cache_ptr->slist_enabled) { HDassert(FALSE); HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist already disabled?") } if ((cache_ptr->slist_len != 0) || (cache_ptr->slist_size != 0)) { if (clear_slist) { H5SL_node_t *node_ptr; node_ptr = H5SL_first(cache_ptr->slist_ptr); while (node_ptr != NULL) { entry_ptr = (H5C_cache_entry_t *)H5SL_item(node_ptr); H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE); node_ptr = H5SL_first(cache_ptr->slist_ptr); } } else { HDassert(FALSE); HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "slist not empty (2)?") } } cache_ptr->slist_enabled = FALSE; HDassert(0 == cache_ptr->slist_len); HDassert(0 == cache_ptr->slist_size); } #else /* H5C__SLIST_OPT_ENABLED is FALSE */ HDassert(cache_ptr->slist_enabled); #endif /* H5C__SLIST_OPT_ENABLED is FALSE */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_set_slist_enabled() */ /*------------------------------------------------------------------------- * Function: H5C_unpin_entry() * * Purpose: Unpin a cache entry. The entry can be either protected or * unprotected at the time of call, but must be pinned. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 3/22/06 * * Changes: Added extreme sanity checks on entry and exit. * JRM -- 4/26/14 * *------------------------------------------------------------------------- */ herr_t H5C_unpin_entry(void *_entry_ptr) { H5C_t *cache_ptr; H5C_cache_entry_t *entry_ptr = (H5C_cache_entry_t *)_entry_ptr; /* Pointer to entry to unpin */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity check */ HDassert(entry_ptr); cache_ptr = entry_ptr->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* Unpin the entry */ if (H5C__unpin_entry_from_client(cache_ptr, entry_ptr, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry from client") done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_unpin_entry() */ /*------------------------------------------------------------------------- * Function: H5C_unprotect * * Purpose: Undo an H5C_protect() call -- specifically, mark the * entry as unprotected, remove it from the protected list, * and give it back to the replacement policy. * * The TYPE and ADDR arguments must be the same as those in * the corresponding call to H5C_protect() and the THING * argument must be the value returned by that call to * H5C_protect(). * * Return: Non-negative on success/Negative on failure * * If the deleted flag is TRUE, simply remove the target entry * from the cache, clear it, and free it without writing it to * disk. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 6/2/04 * * Modifications: * * JRM -- 7/21/04 * Updated for the addition of the hash table. * * JRM -- 10/28/04 * Added code to set cache_full to TRUE whenever we try to * make space in the cache. * * JRM -- 11/12/04 * Added code to call to H5C_make_space_in_cache() after the * call to H5C__auto_adjust_cache_size() if that function * sets the size_decreased flag is TRUE. * * JRM -- 4/25/05 * The size_decreased flag can also be set to TRUE in * H5C_set_cache_auto_resize_config() if a new configuration * forces an immediate reduction in cache size. Modified * the code to deal with this eventuallity. * * JRM -- 6/24/05 * Added support for the new write_permitted field of H5C_t. * * JRM -- 10/22/05 * Hand optimizations. * * JRM -- 5/3/06 * Added code to set the new dirtied field in * H5C_cache_entry_t to FALSE prior to return. * * JRM -- 6/23/06 * Modified code to allow dirty entries to be loaded from * disk. This is necessary as a bug fix in the object * header code requires us to modify a header as it is read. * * JRM -- 3/28/07 * Added the flags parameter and supporting code. At least * for now, this parameter is used to allow the entry to * be protected read only, thus allowing multiple protects. * * Also added code to allow multiple read only protects * of cache entries. * * JRM -- 7/27/07 * Added code supporting the new evictions_enabled field * in H5C_t. * * JRM -- 1/3/08 * Added to do a flash cache size increase if appropriate * when a large entry is loaded. * * JRM -- 11/13/08 * Modified function to call H5C_make_space_in_cache() when * the min_clean_size is violated, not just when there isn't * enough space for and entry that has just been loaded. * * The purpose of this modification is to avoid "metadata * blizzards" in the write only case. In such instances, * the cache was allowed to fill with dirty metadata. When * we finally needed to evict an entry to make space, we had * to flush out a whole cache full of metadata -- which has * interesting performance effects. We hope to avoid (or * perhaps more accurately hide) this effect by maintaining * the min_clean_size, which should force us to start flushing * entries long before we actually have to evict something * to make space. * * * Missing entries? * * * JRM -- 5/8/20 * Updated for the possibility that the slist will be * disabled. * *------------------------------------------------------------------------- */ herr_t H5C_unprotect(H5F_t *f, haddr_t addr, void *thing, unsigned flags) { H5C_t *cache_ptr; hbool_t deleted; hbool_t dirtied; hbool_t set_flush_marker; hbool_t pin_entry; hbool_t unpin_entry; hbool_t free_file_space; hbool_t take_ownership; hbool_t was_clean; #ifdef H5_HAVE_PARALLEL hbool_t clear_entry = FALSE; #endif /* H5_HAVE_PARALLEL */ H5C_cache_entry_t *entry_ptr; H5C_cache_entry_t *test_entry_ptr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) deleted = ((flags & H5C__DELETED_FLAG) != 0); dirtied = ((flags & H5C__DIRTIED_FLAG) != 0); set_flush_marker = ((flags & H5C__SET_FLUSH_MARKER_FLAG) != 0); pin_entry = ((flags & H5C__PIN_ENTRY_FLAG) != 0); unpin_entry = ((flags & H5C__UNPIN_ENTRY_FLAG) != 0); free_file_space = ((flags & H5C__FREE_FILE_SPACE_FLAG) != 0); take_ownership = ((flags & H5C__TAKE_OWNERSHIP_FLAG) != 0); HDassert(f); HDassert(f->shared); cache_ptr = f->shared->cache; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(H5F_addr_defined(addr)); HDassert(thing); HDassert(!(pin_entry && unpin_entry)); /* deleted flag must accompany free_file_space */ HDassert((!free_file_space) || (deleted)); /* deleted flag must accompany take_ownership */ HDassert((!take_ownership) || (deleted)); /* can't have both free_file_space & take_ownership */ HDassert(!(free_file_space && take_ownership)); entry_ptr = (H5C_cache_entry_t *)thing; HDassert(entry_ptr->addr == addr); /* also set the dirtied variable if the dirtied field is set in * the entry. */ dirtied |= entry_ptr->dirtied; was_clean = !(entry_ptr->is_dirty); #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on entry") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ /* if the entry has multiple read only protects, just decrement * the ro_ref_counter. Don't actually unprotect until the ref count * drops to zero. */ if (entry_ptr->ro_ref_count > 1) { /* Sanity check */ HDassert(entry_ptr->is_protected); HDassert(entry_ptr->is_read_only); if (dirtied) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Read only entry modified??") /* Reduce the RO ref count */ (entry_ptr->ro_ref_count)--; /* Pin or unpin the entry as requested. */ if (pin_entry) { /* Pin the entry from a client */ if (H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client") } else if (unpin_entry) { /* Unpin the entry from a client */ if (H5C__unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry by client") } /* end if */ } else { if (entry_ptr->is_read_only) { /* Sanity check */ HDassert(entry_ptr->ro_ref_count == 1); if (dirtied) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Read only entry modified??") entry_ptr->is_read_only = FALSE; entry_ptr->ro_ref_count = 0; } /* end if */ #ifdef H5_HAVE_PARALLEL /* When the H5C code is used to implement the metadata cache in the * PHDF5 case, only the cache on process 0 is allowed to write to file. * All the other metadata caches must hold dirty entries until they * are told that the entries are clean. * * The clear_on_unprotect flag in the H5C_cache_entry_t structure * exists to deal with the case in which an entry is protected when * its cache receives word that the entry is now clean. In this case, * the clear_on_unprotect flag is set, and the entry is flushed with * the H5C__FLUSH_CLEAR_ONLY_FLAG. * * All this is a bit awkward, but until the metadata cache entries * are contiguous, with only one dirty flag, we have to let the supplied * functions deal with the resetting the is_dirty flag. */ if (entry_ptr->clear_on_unprotect) { /* Sanity check */ HDassert(entry_ptr->is_dirty); entry_ptr->clear_on_unprotect = FALSE; if (!dirtied) clear_entry = TRUE; } /* end if */ #endif /* H5_HAVE_PARALLEL */ if (!entry_ptr->is_protected) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Entry already unprotected??") /* Mark the entry as dirty if appropriate */ entry_ptr->is_dirty = (entry_ptr->is_dirty || dirtied); if (dirtied) { if (entry_ptr->image_up_to_date) { entry_ptr->image_up_to_date = FALSE; if (entry_ptr->flush_dep_nparents > 0) { if (H5C__mark_flush_dep_unserialized(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") } /* end if */ } /* end if */ } /* end if */ /* Check for newly dirtied entry */ if (was_clean && entry_ptr->is_dirty) { /* Update index for newly dirtied entry */ H5C__UPDATE_INDEX_FOR_ENTRY_DIRTY(cache_ptr, entry_ptr) /* If the entry's type has a 'notify' callback send a * 'entry dirtied' notice now that the entry is fully * integrated into the cache. */ if ((entry_ptr->type->notify) && ((entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_DIRTIED, entry_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag set") /* Propagate the flush dep dirty flag up the flush dependency chain * if appropriate */ if (entry_ptr->flush_dep_nparents > 0) { if (H5C__mark_flush_dep_dirty(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") } } /* end if */ /* Check for newly clean entry */ else if (!was_clean && !entry_ptr->is_dirty) { /* If the entry's type has a 'notify' callback send a * 'entry cleaned' notice now that the entry is fully * integrated into the cache. */ if ((entry_ptr->type->notify) && ((entry_ptr->type->notify)(H5C_NOTIFY_ACTION_ENTRY_CLEANED, entry_ptr) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry dirty flag cleared") /* Propagate the flush dep clean flag up the flush dependency chain * if appropriate */ if (entry_ptr->flush_dep_nparents > 0) { if (H5C__mark_flush_dep_clean(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTMARKDIRTY, FAIL, "Can't propagate flush dep dirty flag") } } /* end else-if */ /* Pin or unpin the entry as requested. */ if (pin_entry) { /* Pin the entry from a client */ if (H5C__pin_entry_from_client(cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "Can't pin entry by client") } else if (unpin_entry) { /* Unpin the entry from a client */ if (H5C__unpin_entry_from_client(cache_ptr, entry_ptr, FALSE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry by client") } /* end if */ /* H5C__UPDATE_RP_FOR_UNPROTECT will place the unprotected entry on * the pinned entry list if entry_ptr->is_pinned is TRUE. */ H5C__UPDATE_RP_FOR_UNPROTECT(cache_ptr, entry_ptr, FAIL) entry_ptr->is_protected = FALSE; /* if the entry is dirty, 'or' its flush_marker with the set flush flag, * and then add it to the skip list if it isn't there already. */ if (entry_ptr->is_dirty) { entry_ptr->flush_marker |= set_flush_marker; if (!entry_ptr->in_slist) { /* this is a no-op if cache_ptr->slist_enabled is FALSE */ H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL) } } /* end if */ /* this implementation of the "deleted" option is a bit inefficient, as * we re-insert the entry to be deleted into the replacement policy * data structures, only to remove them again. Depending on how often * we do this, we may want to optimize a bit. * * On the other hand, this implementation is reasonably clean, and * makes good use of existing code. * JRM - 5/19/04 */ if (deleted) { unsigned flush_flags = (H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__FLUSH_INVALIDATE_FLAG); /* verify that the target entry is in the cache. */ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL) if (test_entry_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "entry not in hash table?!?") else if (test_entry_ptr != entry_ptr) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "hash table contains multiple entries for addr?!?") /* Set the 'free file space' flag for the flush, if needed */ if (free_file_space) { flush_flags |= H5C__FREE_FILE_SPACE_FLAG; } /* Set the "take ownership" flag for the flush, if needed */ if (take_ownership) { flush_flags |= H5C__TAKE_OWNERSHIP_FLAG; } /* Delete the entry from the skip list on destroy */ flush_flags |= H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG; HDassert((!cache_ptr->slist_enabled) || (((!was_clean) || dirtied) == (entry_ptr->in_slist))); if (H5C__flush_single_entry(f, entry_ptr, flush_flags) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't flush entry") } /* end if */ #ifdef H5_HAVE_PARALLEL else if (clear_entry) { /* verify that the target entry is in the cache. */ H5C__SEARCH_INDEX(cache_ptr, addr, test_entry_ptr, FAIL) if (test_entry_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "entry not in hash table?!?") else if (test_entry_ptr != entry_ptr) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "hash table contains multiple entries for addr?!?") if (H5C__flush_single_entry(f, entry_ptr, H5C__FLUSH_CLEAR_ONLY_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPROTECT, FAIL, "Can't clear entry") } /* end else if */ #endif /* H5_HAVE_PARALLEL */ } H5C__UPDATE_STATS_FOR_UNPROTECT(cache_ptr) done: #ifdef H5C_DO_EXTREME_SANITY_CHECKS if ((H5C_validate_protected_entry_list(cache_ptr) < 0) || (H5C_validate_pinned_entry_list(cache_ptr) < 0) || (H5C_validate_lru_list(cache_ptr) < 0)) HDONE_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "an extreme sanity check failed on exit") #endif /* H5C_DO_EXTREME_SANITY_CHECKS */ FUNC_LEAVE_NOAPI(ret_value) } /* H5C_unprotect() */ /*------------------------------------------------------------------------- * * Function: H5C_unsettle_entry_ring * * Purpose: Advise the metadata cache that the specified entry's free space * manager ring is no longer settled (if it was on entry). * * If the target free space manager ring is already * unsettled, do nothing, and return SUCCEED. * * If the target free space manager ring is settled, and * we are not in the process of a file shutdown, mark * the ring as unsettled, and return SUCCEED. * * If the target free space manager is settled, and we * are in the process of a file shutdown, post an error * message, and return FAIL. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * January 3, 2017 * *------------------------------------------------------------------------- */ herr_t H5C_unsettle_entry_ring(void *_entry) { H5C_cache_entry_t *entry = (H5C_cache_entry_t *)_entry; /* Entry whose ring to unsettle */ H5C_t *cache; /* Cache for file */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry); HDassert(entry->ring != H5C_RING_UNDEFINED); HDassert((H5C_RING_USER == entry->ring) || (H5C_RING_RDFSM == entry->ring) || (H5C_RING_MDFSM == entry->ring)); cache = entry->cache_ptr; HDassert(cache); HDassert(cache->magic == H5C__H5C_T_MAGIC); switch (entry->ring) { case H5C_RING_USER: /* Do nothing */ break; case H5C_RING_RDFSM: if (cache->rdfsm_settled) { if (cache->flush_in_progress || cache->close_warning_received) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected rdfsm ring unsettle") cache->rdfsm_settled = FALSE; } /* end if */ break; case H5C_RING_MDFSM: if (cache->mdfsm_settled) { if (cache->flush_in_progress || cache->close_warning_received) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected mdfsm ring unsettle") cache->mdfsm_settled = FALSE; } /* end if */ break; default: HDassert(FALSE); /* this should be un-reachable */ break; } /* end switch */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_unsettle_entry_ring() */ /*------------------------------------------------------------------------- * Function: H5C_unsettle_ring() * * Purpose: Advise the metadata cache that the specified free space * manager ring is no longer settled (if it was on entry). * * If the target free space manager ring is already * unsettled, do nothing, and return SUCCEED. * * If the target free space manager ring is settled, and * we are not in the process of a file shutdown, mark * the ring as unsettled, and return SUCCEED. * * If the target free space manager is settled, and we * are in the process of a file shutdown, post an error * message, and return FAIL. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 10/15/16 * *------------------------------------------------------------------------- */ herr_t H5C_unsettle_ring(H5F_t *f, H5C_ring_t ring) { H5C_t *cache_ptr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(f); HDassert(f->shared); HDassert(f->shared->cache); HDassert((H5C_RING_RDFSM == ring) || (H5C_RING_MDFSM == ring)); cache_ptr = f->shared->cache; HDassert(H5C__H5C_T_MAGIC == cache_ptr->magic); switch (ring) { case H5C_RING_RDFSM: if (cache_ptr->rdfsm_settled) { if (cache_ptr->close_warning_received) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected rdfsm ring unsettle") cache_ptr->rdfsm_settled = FALSE; } /* end if */ break; case H5C_RING_MDFSM: if (cache_ptr->mdfsm_settled) { if (cache_ptr->close_warning_received) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unexpected mdfsm ring unsettle") cache_ptr->mdfsm_settled = FALSE; } /* end if */ break; default: HDassert(FALSE); /* this should be un-reachable */ break; } /* end switch */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_unsettle_ring() */ /*------------------------------------------------------------------------- * Function: H5C_validate_resize_config() * * Purpose: Run a sanity check on the specified sections of the * provided instance of struct H5C_auto_size_ctl_t. * * Do nothing and return SUCCEED if no errors are detected, * and flag an error and return FAIL otherwise. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer * 3/23/05 * *------------------------------------------------------------------------- */ herr_t H5C_validate_resize_config(H5C_auto_size_ctl_t *config_ptr, unsigned int tests) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) if (config_ptr == NULL) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "NULL config_ptr on entry") if (config_ptr->version != H5C__CURR_AUTO_SIZE_CTL_VER) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown config version") if ((tests & H5C_RESIZE_CFG__VALIDATE_GENERAL) != 0) { if (config_ptr->max_size > H5C__MAX_MAX_CACHE_SIZE) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "max_size too big") if (config_ptr->min_size < H5C__MIN_MAX_CACHE_SIZE) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_size too small") if (config_ptr->min_size > config_ptr->max_size) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_size > max_size") if (config_ptr->set_initial_size && ((config_ptr->initial_size < config_ptr->min_size) || (config_ptr->initial_size > config_ptr->max_size))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "initial_size must be in the interval [min_size, max_size]") if ((config_ptr->min_clean_fraction < 0.0) || (config_ptr->min_clean_fraction > 1.0)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "min_clean_fraction must be in the interval [0.0, 1.0]") if (config_ptr->epoch_length < H5C__MIN_AR_EPOCH_LENGTH) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epoch_length too small") if (config_ptr->epoch_length > H5C__MAX_AR_EPOCH_LENGTH) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epoch_length too big") } /* H5C_RESIZE_CFG__VALIDATE_GENERAL */ if ((tests & H5C_RESIZE_CFG__VALIDATE_INCREMENT) != 0) { if ((config_ptr->incr_mode != H5C_incr__off) && (config_ptr->incr_mode != H5C_incr__threshold)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid incr_mode") if (config_ptr->incr_mode == H5C_incr__threshold) { if ((config_ptr->lower_hr_threshold < 0.0) || (config_ptr->lower_hr_threshold > 1.0)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "lower_hr_threshold must be in the range [0.0, 1.0]") if (config_ptr->increment < 1.0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "increment must be greater than or equal to 1.0") /* no need to check max_increment, as it is a size_t, * and thus must be non-negative. */ } /* H5C_incr__threshold */ switch (config_ptr->flash_incr_mode) { case H5C_flash_incr__off: /* nothing to do here */ break; case H5C_flash_incr__add_space: if ((config_ptr->flash_multiple < 0.1) || (config_ptr->flash_multiple > 10.0)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "flash_multiple must be in the range [0.1, 10.0]") if ((config_ptr->flash_threshold < 0.1) || (config_ptr->flash_threshold > 1.0)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "flash_threshold must be in the range [0.1, 1.0]") break; default: HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid flash_incr_mode") break; } /* end switch */ } /* H5C_RESIZE_CFG__VALIDATE_INCREMENT */ if ((tests & H5C_RESIZE_CFG__VALIDATE_DECREMENT) != 0) { if ((config_ptr->decr_mode != H5C_decr__off) && (config_ptr->decr_mode != H5C_decr__threshold) && (config_ptr->decr_mode != H5C_decr__age_out) && (config_ptr->decr_mode != H5C_decr__age_out_with_threshold)) { HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid decr_mode") } if (config_ptr->decr_mode == H5C_decr__threshold) { if (config_ptr->upper_hr_threshold > 1.0) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "upper_hr_threshold must be <= 1.0") if ((config_ptr->decrement > 1.0) || (config_ptr->decrement < 0.0)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "decrement must be in the interval [0.0, 1.0]") /* no need to check max_decrement as it is a size_t * and thus must be non-negative. */ } /* H5C_decr__threshold */ if ((config_ptr->decr_mode == H5C_decr__age_out) || (config_ptr->decr_mode == H5C_decr__age_out_with_threshold)) { if (config_ptr->epochs_before_eviction < 1) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epochs_before_eviction must be positive") if (config_ptr->epochs_before_eviction > H5C__MAX_EPOCH_MARKERS) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "epochs_before_eviction too big") if ((config_ptr->apply_empty_reserve) && ((config_ptr->empty_reserve > 1.0) || (config_ptr->empty_reserve < 0.0))) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "empty_reserve must be in the interval [0.0, 1.0]") /* no need to check max_decrement as it is a size_t * and thus must be non-negative. */ } /* H5C_decr__age_out || H5C_decr__age_out_with_threshold */ if (config_ptr->decr_mode == H5C_decr__age_out_with_threshold) { if ((config_ptr->upper_hr_threshold > 1.0) || (config_ptr->upper_hr_threshold < 0.0)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "upper_hr_threshold must be in the interval [0.0, 1.0]") } /* H5C_decr__age_out_with_threshold */ } /* H5C_RESIZE_CFG__VALIDATE_DECREMENT */ if ((tests & H5C_RESIZE_CFG__VALIDATE_INTERACTIONS) != 0) { if ((config_ptr->incr_mode == H5C_incr__threshold) && ((config_ptr->decr_mode == H5C_decr__threshold) || (config_ptr->decr_mode == H5C_decr__age_out_with_threshold)) && (config_ptr->lower_hr_threshold >= config_ptr->upper_hr_threshold)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "conflicting threshold fields in config") } /* H5C_RESIZE_CFG__VALIDATE_INTERACTIONS */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_validate_resize_config() */ /*------------------------------------------------------------------------- * Function: H5C_create_flush_dependency() * * Purpose: Initiates a parent<->child entry flush dependency. The parent * entry must be pinned or protected at the time of call, and must * have all dependencies removed before the cache can shut down. * * Note: Flush dependencies in the cache indicate that a child entry * must be flushed to the file before its parent. (This is * currently used to implement Single-Writer/Multiple-Reader (SWMR) * I/O access for data structures in the file). * * Creating a flush dependency between two entries will also pin * the parent entry. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 3/05/09 * *------------------------------------------------------------------------- */ herr_t H5C_create_flush_dependency(void *parent_thing, void *child_thing) { H5C_t *cache_ptr; H5C_cache_entry_t *parent_entry = (H5C_cache_entry_t *)parent_thing; /* Ptr to parent thing's entry */ H5C_cache_entry_t *child_entry = (H5C_cache_entry_t *)child_thing; /* Ptr to child thing's entry */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(parent_entry); HDassert(parent_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(H5F_addr_defined(parent_entry->addr)); HDassert(child_entry); HDassert(child_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(H5F_addr_defined(child_entry->addr)); cache_ptr = parent_entry->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(cache_ptr == child_entry->cache_ptr); #ifndef NDEBUG /* Make sure the parent is not already a parent */ { unsigned u; for (u = 0; u < child_entry->flush_dep_nparents; u++) HDassert(child_entry->flush_dep_parent[u] != parent_entry); } /* end block */ #endif /* NDEBUG */ /* More sanity checks */ if (child_entry == parent_entry) HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Child entry flush dependency parent can't be itself") if (!(parent_entry->is_protected || parent_entry->is_pinned)) HGOTO_ERROR(H5E_CACHE, H5E_CANTDEPEND, FAIL, "Parent entry isn't pinned or protected") /* Check for parent not pinned */ if (!parent_entry->is_pinned) { /* Sanity check */ HDassert(parent_entry->flush_dep_nchildren == 0); HDassert(!parent_entry->pinned_from_client); HDassert(!parent_entry->pinned_from_cache); /* Pin the parent entry */ parent_entry->is_pinned = TRUE; H5C__UPDATE_STATS_FOR_PIN(cache_ptr, parent_entry) } /* end else */ /* Mark the entry as pinned from the cache's action (possibly redundantly) */ parent_entry->pinned_from_cache = TRUE; /* Check if we need to resize the child's parent array */ if (child_entry->flush_dep_nparents >= child_entry->flush_dep_parent_nalloc) { if (child_entry->flush_dep_parent_nalloc == 0) { /* Array does not exist yet, allocate it */ HDassert(!child_entry->flush_dep_parent); if (NULL == (child_entry->flush_dep_parent = H5FL_SEQ_MALLOC(H5C_cache_entry_ptr_t, H5C_FLUSH_DEP_PARENT_INIT))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent list") child_entry->flush_dep_parent_nalloc = H5C_FLUSH_DEP_PARENT_INIT; } /* end if */ else { /* Resize existing array */ HDassert(child_entry->flush_dep_parent); if (NULL == (child_entry->flush_dep_parent = H5FL_SEQ_REALLOC(H5C_cache_entry_ptr_t, child_entry->flush_dep_parent, 2 * child_entry->flush_dep_parent_nalloc))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent list") child_entry->flush_dep_parent_nalloc *= 2; } /* end else */ cache_ptr->entry_fd_height_change_counter++; } /* end if */ /* Add the dependency to the child's parent array */ child_entry->flush_dep_parent[child_entry->flush_dep_nparents] = parent_entry; child_entry->flush_dep_nparents++; /* Increment parent's number of children */ parent_entry->flush_dep_nchildren++; /* Adjust the number of dirty children */ if (child_entry->is_dirty) { /* Sanity check */ HDassert(parent_entry->flush_dep_ndirty_children < parent_entry->flush_dep_nchildren); parent_entry->flush_dep_ndirty_children++; /* If the parent has a 'notify' callback, send a 'child entry dirtied' notice */ if (parent_entry->type->notify && (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_DIRTIED, parent_entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry dirty flag set") } /* end if */ /* adjust the parent's number of unserialized children. Note * that it is possible for and entry to be clean and unserialized. */ if (!child_entry->image_up_to_date) { HDassert(parent_entry->flush_dep_nunser_children < parent_entry->flush_dep_nchildren); parent_entry->flush_dep_nunser_children++; /* If the parent has a 'notify' callback, send a 'child entry unserialized' notice */ if (parent_entry->type->notify && (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_UNSERIALIZED, parent_entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry serialized flag reset") } /* end if */ /* Post-conditions, for successful operation */ HDassert(parent_entry->is_pinned); HDassert(parent_entry->flush_dep_nchildren > 0); HDassert(child_entry->flush_dep_parent); HDassert(child_entry->flush_dep_nparents > 0); HDassert(child_entry->flush_dep_parent_nalloc > 0); #ifndef NDEBUG H5C__assert_flush_dep_nocycle(parent_entry, child_entry); #endif /* NDEBUG */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_create_flush_dependency() */ /*------------------------------------------------------------------------- * Function: H5C_destroy_flush_dependency() * * Purpose: Terminates a parent<-> child entry flush dependency. The * parent entry must be pinned. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 3/05/09 * *------------------------------------------------------------------------- */ herr_t H5C_destroy_flush_dependency(void *parent_thing, void *child_thing) { H5C_t *cache_ptr; H5C_cache_entry_t *parent_entry = (H5C_cache_entry_t *)parent_thing; /* Ptr to parent entry */ H5C_cache_entry_t *child_entry = (H5C_cache_entry_t *)child_thing; /* Ptr to child entry */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(parent_entry); HDassert(parent_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(H5F_addr_defined(parent_entry->addr)); HDassert(child_entry); HDassert(child_entry->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(H5F_addr_defined(child_entry->addr)); cache_ptr = parent_entry->cache_ptr; HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(cache_ptr == child_entry->cache_ptr); /* Usage checks */ if (!parent_entry->is_pinned) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't pinned") if (NULL == child_entry->flush_dep_parent) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Child entry doesn't have a flush dependency parent array") if (0 == parent_entry->flush_dep_nchildren) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry flush dependency ref. count has no child dependencies") /* Search for parent in child's parent array. This is a linear search * because we do not expect large numbers of parents. If this changes, we * may wish to change the parent array to a skip list */ for (u = 0; u < child_entry->flush_dep_nparents; u++) if (child_entry->flush_dep_parent[u] == parent_entry) break; if (u == child_entry->flush_dep_nparents) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNDEPEND, FAIL, "Parent entry isn't a flush dependency parent for child entry") /* Remove parent entry from child's parent array */ if (u < (child_entry->flush_dep_nparents - 1)) HDmemmove(&child_entry->flush_dep_parent[u], &child_entry->flush_dep_parent[u + 1], (child_entry->flush_dep_nparents - u - 1) * sizeof(child_entry->flush_dep_parent[0])); child_entry->flush_dep_nparents--; /* Adjust parent entry's nchildren and unpin parent if it goes to zero */ parent_entry->flush_dep_nchildren--; if (0 == parent_entry->flush_dep_nchildren) { /* Sanity check */ HDassert(parent_entry->pinned_from_cache); /* Check if we should unpin parent entry now */ if (!parent_entry->pinned_from_client) if (H5C__unpin_entry_real(cache_ptr, parent_entry, TRUE) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "Can't unpin entry") /* Mark the entry as unpinned from the cache's action */ parent_entry->pinned_from_cache = FALSE; } /* end if */ /* Adjust parent entry's ndirty_children */ if (child_entry->is_dirty) { /* Sanity check */ HDassert(parent_entry->flush_dep_ndirty_children > 0); parent_entry->flush_dep_ndirty_children--; /* If the parent has a 'notify' callback, send a 'child entry cleaned' notice */ if (parent_entry->type->notify && (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_CLEANED, parent_entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry dirty flag reset") } /* end if */ /* adjust parent entry's number of unserialized children */ if (!child_entry->image_up_to_date) { HDassert(parent_entry->flush_dep_nunser_children > 0); parent_entry->flush_dep_nunser_children--; /* If the parent has a 'notify' callback, send a 'child entry serialized' notice */ if (parent_entry->type->notify && (parent_entry->type->notify)(H5C_NOTIFY_ACTION_CHILD_SERIALIZED, parent_entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify parent about child entry serialized flag set") } /* end if */ /* Shrink or free the parent array if appropriate */ if (child_entry->flush_dep_nparents == 0) { child_entry->flush_dep_parent = H5FL_SEQ_FREE(H5C_cache_entry_ptr_t, child_entry->flush_dep_parent); child_entry->flush_dep_parent_nalloc = 0; } /* end if */ else if (child_entry->flush_dep_parent_nalloc > H5C_FLUSH_DEP_PARENT_INIT && child_entry->flush_dep_nparents <= (child_entry->flush_dep_parent_nalloc / 4)) { if (NULL == (child_entry->flush_dep_parent = H5FL_SEQ_REALLOC(H5C_cache_entry_ptr_t, child_entry->flush_dep_parent, child_entry->flush_dep_parent_nalloc / 4))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for flush dependency parent list") child_entry->flush_dep_parent_nalloc /= 4; } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C_destroy_flush_dependency() */ /*************************************************************************/ /**************************** Private Functions: *************************/ /*************************************************************************/ /*------------------------------------------------------------------------- * Function: H5C__pin_entry_from_client() * * Purpose: Internal routine to pin a cache entry from a client action. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 3/26/09 * *------------------------------------------------------------------------- */ static herr_t H5C__pin_entry_from_client(H5C_t #if !H5C_COLLECT_CACHE_STATS H5_ATTR_UNUSED #endif *cache_ptr, H5C_cache_entry_t *entry_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity checks */ HDassert(cache_ptr); HDassert(entry_ptr); HDassert(entry_ptr->is_protected); /* Check if the entry is already pinned */ if (entry_ptr->is_pinned) { /* Check if the entry was pinned through an explicit pin from a client */ if (entry_ptr->pinned_from_client) HGOTO_ERROR(H5E_CACHE, H5E_CANTPIN, FAIL, "entry is already pinned") } /* end if */ else { entry_ptr->is_pinned = TRUE; H5C__UPDATE_STATS_FOR_PIN(cache_ptr, entry_ptr) } /* end else */ /* Mark that the entry was pinned through an explicit pin from a client */ entry_ptr->pinned_from_client = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C__pin_entry_from_client() */ /*------------------------------------------------------------------------- * Function: H5C__unpin_entry_real() * * Purpose: Internal routine to unpin a cache entry. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 1/6/18 * *------------------------------------------------------------------------- */ static herr_t H5C__unpin_entry_real(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, hbool_t update_rp) { herr_t ret_value = SUCCEED; /* Return value */ #ifdef H5C_DO_SANITY_CHECKS FUNC_ENTER_PACKAGE #else FUNC_ENTER_PACKAGE_NOERR #endif /* Sanity checking */ HDassert(cache_ptr); HDassert(entry_ptr); HDassert(entry_ptr->is_pinned); /* If requested, update the replacement policy if the entry is not protected */ if (update_rp && !entry_ptr->is_protected) H5C__UPDATE_RP_FOR_UNPIN(cache_ptr, entry_ptr, FAIL) /* Unpin the entry now */ entry_ptr->is_pinned = FALSE; /* Update the stats for an unpin operation */ H5C__UPDATE_STATS_FOR_UNPIN(cache_ptr, entry_ptr) #ifdef H5C_DO_SANITY_CHECKS done: #endif FUNC_LEAVE_NOAPI(ret_value) } /* H5C__unpin_entry_real() */ /*------------------------------------------------------------------------- * Function: H5C__unpin_entry_from_client() * * Purpose: Internal routine to unpin a cache entry from a client action. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * 3/24/09 * *------------------------------------------------------------------------- */ static herr_t H5C__unpin_entry_from_client(H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr, hbool_t update_rp) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity checking */ HDassert(cache_ptr); HDassert(entry_ptr); /* Error checking (should be sanity checks?) */ if (!entry_ptr->is_pinned) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "entry isn't pinned") if (!entry_ptr->pinned_from_client) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "entry wasn't pinned by cache client") /* Check if the entry is not pinned from a flush dependency */ if (!entry_ptr->pinned_from_cache) if (H5C__unpin_entry_real(cache_ptr, entry_ptr, update_rp) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTUNPIN, FAIL, "can't unpin entry") /* Mark the entry as explicitly unpinned by the client */ entry_ptr->pinned_from_client = FALSE; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C__unpin_entry_from_client() */ /*------------------------------------------------------------------------- * * Function: H5C__auto_adjust_cache_size * * Purpose: Obtain the current full cache hit rate, and compare it * with the hit rate thresholds for modifying cache size. * If one of the thresholds has been crossed, adjusts the * size of the cache accordingly. * * The function then resets the full cache hit rate * statistics, and exits. * * Return: Non-negative on success/Negative on failure or if there was * an attempt to flush a protected item. * * * Programmer: John Mainzer, 10/7/04 * *------------------------------------------------------------------------- */ static herr_t H5C__auto_adjust_cache_size(H5F_t *f, hbool_t write_permitted) { H5C_t *cache_ptr = f->shared->cache; hbool_t reentrant_call = FALSE; hbool_t inserted_epoch_marker = FALSE; size_t new_max_cache_size = 0; size_t old_max_cache_size = 0; size_t new_min_clean_size = 0; size_t old_min_clean_size = 0; double hit_rate; enum H5C_resize_status status = in_spec; /* will change if needed */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE HDassert(f); HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(cache_ptr->cache_accesses >= (cache_ptr->resize_ctl).epoch_length); HDassert(0.0 <= (cache_ptr->resize_ctl).min_clean_fraction); HDassert((cache_ptr->resize_ctl).min_clean_fraction <= 100.0); /* check to see if cache_ptr->resize_in_progress is TRUE. If it, this * is a re-entrant call via a client callback called in the resize * process. To avoid an infinite recursion, set reentrant_call to * TRUE, and goto done. */ if (cache_ptr->resize_in_progress) { reentrant_call = TRUE; HGOTO_DONE(SUCCEED) } /* end if */ cache_ptr->resize_in_progress = TRUE; if (!cache_ptr->resize_enabled) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Auto cache resize disabled") HDassert(((cache_ptr->resize_ctl).incr_mode != H5C_incr__off) || ((cache_ptr->resize_ctl).decr_mode != H5C_decr__off)); if (H5C_get_cache_hit_rate(cache_ptr, &hit_rate) != SUCCEED) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Can't get hit rate") HDassert((0.0 <= hit_rate) && (hit_rate <= 1.0)); switch ((cache_ptr->resize_ctl).incr_mode) { case H5C_incr__off: if (cache_ptr->size_increase_possible) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "size_increase_possible but H5C_incr__off?!?!?") break; case H5C_incr__threshold: if (hit_rate < (cache_ptr->resize_ctl).lower_hr_threshold) { if (!cache_ptr->size_increase_possible) { status = increase_disabled; } else if (cache_ptr->max_cache_size >= (cache_ptr->resize_ctl).max_size) { HDassert(cache_ptr->max_cache_size == (cache_ptr->resize_ctl).max_size); status = at_max_size; } else if (!cache_ptr->cache_full) { status = not_full; } else { new_max_cache_size = (size_t)(((double)(cache_ptr->max_cache_size)) * (cache_ptr->resize_ctl).increment); /* clip to max size if necessary */ if (new_max_cache_size > (cache_ptr->resize_ctl).max_size) { new_max_cache_size = (cache_ptr->resize_ctl).max_size; } /* clip to max increment if necessary */ if (((cache_ptr->resize_ctl).apply_max_increment) && ((cache_ptr->max_cache_size + (cache_ptr->resize_ctl).max_increment) < new_max_cache_size)) { new_max_cache_size = cache_ptr->max_cache_size + (cache_ptr->resize_ctl).max_increment; } status = increase; } } break; default: HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown incr_mode") } /* If the decr_mode is either age out or age out with threshold, we * must run the marker maintenance code, whether we run the size * reduction code or not. We do this in two places -- here we * insert a new marker if the number of active epoch markers is * is less than the the current epochs before eviction, and after * the ageout call, we cycle the markers. * * However, we can't call the ageout code or cycle the markers * unless there was a full complement of markers in place on * entry. The inserted_epoch_marker flag is used to track this. */ if ((((cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out) || ((cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out_with_threshold)) && (cache_ptr->epoch_markers_active < (cache_ptr->resize_ctl).epochs_before_eviction)) { if (H5C__autoadjust__ageout__insert_new_marker(cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't insert new epoch marker") inserted_epoch_marker = TRUE; } /* don't run the cache size decrease code unless the cache size * increase code is disabled, or the size increase code sees no need * for action. In either case, status == in_spec at this point. */ if (status == in_spec) { switch ((cache_ptr->resize_ctl).decr_mode) { case H5C_decr__off: break; case H5C_decr__threshold: if (hit_rate > (cache_ptr->resize_ctl).upper_hr_threshold) { if (!cache_ptr->size_decrease_possible) { status = decrease_disabled; } else if (cache_ptr->max_cache_size <= (cache_ptr->resize_ctl).min_size) { HDassert(cache_ptr->max_cache_size == (cache_ptr->resize_ctl).min_size); status = at_min_size; } else { new_max_cache_size = (size_t)(((double)(cache_ptr->max_cache_size)) * (cache_ptr->resize_ctl).decrement); /* clip to min size if necessary */ if (new_max_cache_size < (cache_ptr->resize_ctl).min_size) { new_max_cache_size = (cache_ptr->resize_ctl).min_size; } /* clip to max decrement if necessary */ if (((cache_ptr->resize_ctl).apply_max_decrement) && (((cache_ptr->resize_ctl).max_decrement + new_max_cache_size) < cache_ptr->max_cache_size)) { new_max_cache_size = cache_ptr->max_cache_size - (cache_ptr->resize_ctl).max_decrement; } status = decrease; } } break; case H5C_decr__age_out_with_threshold: case H5C_decr__age_out: if (!inserted_epoch_marker) { if (!cache_ptr->size_decrease_possible) status = decrease_disabled; else { if (H5C__autoadjust__ageout(f, hit_rate, &status, &new_max_cache_size, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ageout code failed") } /* end else */ } /* end if */ break; default: HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unknown incr_mode") } } /* cycle the epoch markers here if appropriate */ if ((((cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out) || ((cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out_with_threshold)) && (!inserted_epoch_marker)) { /* move last epoch marker to the head of the LRU list */ if (H5C__autoadjust__ageout__cycle_epoch_marker(cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error cycling epoch marker") } if ((status == increase) || (status == decrease)) { old_max_cache_size = cache_ptr->max_cache_size; old_min_clean_size = cache_ptr->min_clean_size; new_min_clean_size = (size_t)((double)new_max_cache_size * ((cache_ptr->resize_ctl).min_clean_fraction)); /* new_min_clean_size is of size_t, and thus must be non-negative. * Hence we have * * ( 0 <= new_min_clean_size ). * * by definition. */ HDassert(new_min_clean_size <= new_max_cache_size); HDassert((cache_ptr->resize_ctl).min_size <= new_max_cache_size); HDassert(new_max_cache_size <= (cache_ptr->resize_ctl).max_size); cache_ptr->max_cache_size = new_max_cache_size; cache_ptr->min_clean_size = new_min_clean_size; if (status == increase) { cache_ptr->cache_full = FALSE; } else if (status == decrease) { cache_ptr->size_decreased = TRUE; } /* update flash cache size increase fields as appropriate */ if (cache_ptr->flash_size_increase_possible) { switch ((cache_ptr->resize_ctl).flash_incr_mode) { case H5C_flash_incr__off: HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flash_size_increase_possible but H5C_flash_incr__off?!") break; case H5C_flash_incr__add_space: cache_ptr->flash_size_increase_threshold = (size_t)(((double)(cache_ptr->max_cache_size)) * ((cache_ptr->resize_ctl).flash_threshold)); break; default: /* should be unreachable */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "Unknown flash_incr_mode?!?!?") break; } } } if ((cache_ptr->resize_ctl).rpt_fcn != NULL) { (*((cache_ptr->resize_ctl).rpt_fcn))(cache_ptr, H5C__CURR_AUTO_RESIZE_RPT_FCN_VER, hit_rate, status, old_max_cache_size, new_max_cache_size, old_min_clean_size, new_min_clean_size); } if (H5C_reset_cache_hit_rate_stats(cache_ptr) < 0) /* this should be impossible... */ HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "H5C_reset_cache_hit_rate_stats failed") done: /* Sanity checks */ HDassert(cache_ptr->resize_in_progress); if (!reentrant_call) cache_ptr->resize_in_progress = FALSE; HDassert((!reentrant_call) || (cache_ptr->resize_in_progress)); FUNC_LEAVE_NOAPI(ret_value) } /* H5C__auto_adjust_cache_size() */ /*------------------------------------------------------------------------- * * Function: H5C__autoadjust__ageout * * Purpose: Implement the ageout automatic cache size decrement * algorithm. Note that while this code evicts aged out * entries, the code does not change the maximum cache size. * Instead, the function simply computes the new value (if * any change is indicated) and reports this value in * *new_max_cache_size_ptr. * * Return: Non-negative on success/Negative on failure or if there was * an attempt to flush a protected item. * * * Programmer: John Mainzer, 11/18/04 * *------------------------------------------------------------------------- */ static herr_t H5C__autoadjust__ageout(H5F_t *f, double hit_rate, enum H5C_resize_status *status_ptr, size_t *new_max_cache_size_ptr, hbool_t write_permitted) { H5C_t *cache_ptr = f->shared->cache; size_t test_size; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE HDassert(f); HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert((status_ptr) && (*status_ptr == in_spec)); HDassert((new_max_cache_size_ptr) && (*new_max_cache_size_ptr == 0)); /* remove excess epoch markers if any */ if (cache_ptr->epoch_markers_active > (cache_ptr->resize_ctl).epochs_before_eviction) if (H5C__autoadjust__ageout__remove_excess_markers(cache_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "can't remove excess epoch markers") if (((cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out) || (((cache_ptr->resize_ctl).decr_mode == H5C_decr__age_out_with_threshold) && (hit_rate >= (cache_ptr->resize_ctl).upper_hr_threshold))) { if (cache_ptr->max_cache_size > (cache_ptr->resize_ctl).min_size) { /* evict aged out cache entries if appropriate... */ if (H5C__autoadjust__ageout__evict_aged_out_entries(f, write_permitted) < 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "error flushing aged out entries") /* ... and then reduce cache size if appropriate */ if (cache_ptr->index_size < cache_ptr->max_cache_size) { if ((cache_ptr->resize_ctl).apply_empty_reserve) { test_size = (size_t)(((double)cache_ptr->index_size) / (1 - (cache_ptr->resize_ctl).empty_reserve)); if (test_size < cache_ptr->max_cache_size) { *status_ptr = decrease; *new_max_cache_size_ptr = test_size; } } else { *status_ptr = decrease; *new_max_cache_size_ptr = cache_ptr->index_size; } if (*status_ptr == decrease) { /* clip to min size if necessary */ if (*new_max_cache_size_ptr < (cache_ptr->resize_ctl).min_size) { *new_max_cache_size_ptr = (cache_ptr->resize_ctl).min_size; } /* clip to max decrement if necessary */ if (((cache_ptr->resize_ctl).apply_max_decrement) && (((cache_ptr->resize_ctl).max_decrement + *new_max_cache_size_ptr) < cache_ptr->max_cache_size)) { *new_max_cache_size_ptr = cache_ptr->max_cache_size - (cache_ptr->resize_ctl).max_decrement; } } } } else { *status_ptr = at_min_size; } } done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C__autoadjust__ageout() */ /*------------------------------------------------------------------------- * * Function: H5C__autoadjust__ageout__cycle_epoch_marker * * Purpose: Remove the oldest epoch marker from the LRU list, * and reinsert it at the head of the LRU list. Also * remove the epoch marker's index from the head of the * ring buffer, and re-insert it at the tail of the ring * buffer. * * Return: SUCCEED on success/FAIL on failure. * * Programmer: John Mainzer, 11/22/04 * *------------------------------------------------------------------------- */ static herr_t H5C__autoadjust__ageout__cycle_epoch_marker(H5C_t *cache_ptr) { int i; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); if (cache_ptr->epoch_markers_active <= 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "No active epoch markers on entry?!?!?") /* remove the last marker from both the ring buffer and the LRU list */ i = cache_ptr->epoch_marker_ringbuf[cache_ptr->epoch_marker_ringbuf_first]; cache_ptr->epoch_marker_ringbuf_first = (cache_ptr->epoch_marker_ringbuf_first + 1) % (H5C__MAX_EPOCH_MARKERS + 1); if (cache_ptr->epoch_marker_ringbuf_size <= 0) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer underflow") cache_ptr->epoch_marker_ringbuf_size -= 1; if ((cache_ptr->epoch_marker_active)[i] != TRUE) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "unused marker in LRU?!?") H5C__DLL_REMOVE((&((cache_ptr->epoch_markers)[i])), (cache_ptr)->LRU_head_ptr, (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, (cache_ptr)->LRU_list_size, (FAIL)) /* now, re-insert it at the head of the LRU list, and at the tail of * the ring buffer. */ HDassert(((cache_ptr->epoch_markers)[i]).addr == (haddr_t)i); HDassert(((cache_ptr->epoch_markers)[i]).next == NULL); HDassert(((cache_ptr->epoch_markers)[i]).prev == NULL); cache_ptr->epoch_marker_ringbuf_last = (cache_ptr->epoch_marker_ringbuf_last + 1) % (H5C__MAX_EPOCH_MARKERS + 1); (cache_ptr->epoch_marker_ringbuf)[cache_ptr->epoch_marker_ringbuf_last] = i; if (cache_ptr->epoch_marker_ringbuf_size >= H5C__MAX_EPOCH_MARKERS) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "ring buffer overflow") cache_ptr->epoch_marker_ringbuf_size += 1; H5C__DLL_PREPEND((&((cache_ptr->epoch_markers)[i])), (cache_ptr)->LRU_head_ptr, (cache_ptr)->LRU_tail_ptr, (cache_ptr)->LRU_list_len, (cache_ptr)->LRU_list_size, (FAIL)) done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C__autoadjust__ageout__cycle_epoch_marker() */ /*------------------------------------------------------------------------- * * Function: H5C__autoadjust__ageout__evict_aged_out_entries * * Purpose: Evict clean entries in the cache that haven't * been accessed for at least * (cache_ptr->resize_ctl).epochs_before_eviction epochs, * and flush dirty entries that haven't been accessed for * that amount of time. * * Depending on configuration, the function will either * flush or evict all such entries, or all such entries it * encounters until it has freed the maximum amount of space * allowed under the maximum decrement. * * If we are running in parallel mode, writes may not be * permitted. If so, the function simply skips any dirty * entries it may encounter. * * The function makes no attempt to maintain the minimum * clean size, as there is no guarantee that the cache size * will be changed. * * If there is no cache size change, the minimum clean size * constraint will be met through a combination of clean * entries and free space in the cache. * * If there is a cache size reduction, the minimum clean size * will be re-calculated, and will be enforced the next time * we have to make space in the cache. * * Observe that this function cannot occasion a read. * * Return: Non-negative on success/Negative on failure. * * Programmer: John Mainzer, 11/22/04 * *------------------------------------------------------------------------- */ static herr_t H5C__autoadjust__ageout__evict_aged_out_entries(H5F_t *f, hbool_t write_permitted) { H5C_t *cache_ptr = f->shared->cache; size_t eviction_size_limit; size_t bytes_evicted = 0; hbool_t prev_is_dirty = FALSE; hbool_t restart_scan; H5C_cache_entry_t *entry_ptr; H5C_cache_entry_t *next_ptr; H5C_cache_entry_t *prev_ptr; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE HDassert(f); HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); /* if there is a limit on the amount that the cache size can be decrease * in any one round of the cache size reduction algorithm, load that * limit into eviction_size_limit. Otherwise, set eviction_size_limit * to the equivalent of infinity. The current size of the index will * do nicely. */ if ((cache_ptr->resize_ctl).apply_max_decrement) { eviction_size_limit = (cache_ptr->resize_ctl).max_decrement; } else { eviction_size_limit = cache_ptr->index_size; /* i.e. infinity */ } if (write_permitted) { restart_scan = FALSE; entry_ptr = cache_ptr->LRU_tail_ptr; while ((entry_ptr != NULL) && ((entry_ptr->type)->id != H5AC_EPOCH_MARKER_ID) && (bytes_evicted < eviction_size_limit)) { hbool_t skipping_entry = FALSE; HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(!(entry_ptr->is_protected)); HDassert(!(entry_ptr->is_read_only)); HDassert((entry_ptr->ro_ref_count) == 0); next_ptr = entry_ptr->next; prev_ptr = entry_ptr->prev; if (prev_ptr != NULL) prev_is_dirty = prev_ptr->is_dirty; if (entry_ptr->is_dirty) { HDassert(!entry_ptr->prefetched_dirty); /* dirty corked entry is skipped */ if (entry_ptr->tag_info && entry_ptr->tag_info->corked) skipping_entry = TRUE; else { /* reset entries_removed_counter and * last_entry_removed_ptr prior to the call to * H5C__flush_single_entry() so that we can spot * unexpected removals of entries from the cache, * and set the restart_scan flag if proceeding * would be likely to cause us to scan an entry * that is no longer in the cache. */ cache_ptr->entries_removed_counter = 0; cache_ptr->last_entry_removed_ptr = NULL; if (H5C__flush_single_entry(f, entry_ptr, H5C__NO_FLAGS_SET) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush entry") if (cache_ptr->entries_removed_counter > 1 || cache_ptr->last_entry_removed_ptr == prev_ptr) restart_scan = TRUE; } /* end else */ } /* end if */ else if (!entry_ptr->prefetched_dirty) { bytes_evicted += entry_ptr->size; if (H5C__flush_single_entry( f, entry_ptr, H5C__FLUSH_INVALIDATE_FLAG | H5C__DEL_FROM_SLIST_ON_DESTROY_FLAG) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to flush entry") } /* end else-if */ else { HDassert(!entry_ptr->is_dirty); HDassert(entry_ptr->prefetched_dirty); skipping_entry = TRUE; } /* end else */ if (prev_ptr != NULL) { if (skipping_entry) entry_ptr = prev_ptr; else if (restart_scan || (prev_ptr->is_dirty != prev_is_dirty) || (prev_ptr->next != next_ptr) || (prev_ptr->is_protected) || (prev_ptr->is_pinned)) { /* Something has happened to the LRU -- start over * from the tail. */ restart_scan = FALSE; entry_ptr = cache_ptr->LRU_tail_ptr; H5C__UPDATE_STATS_FOR_LRU_SCAN_RESTART(cache_ptr) } /* end else-if */ el [Allow unsupported combinations of configure options])], [ALLOW_UNSUPPORTED=$enableval]) case "X-$ALLOW_UNSUPPORTED" in X-|X-no) AC_MSG_RESULT([no]) ;; X-yes) AC_MSG_RESULT([yes]) ;; *) ;; esac ## ---------------------------------------------------------------------- ## Check if they would like the Fortran interface compiled ## AC_SUBST([HDF5_INTERFACES]) HDF5_INTERFACES="" AC_MSG_CHECKING([if Fortran interface enabled]) AC_ARG_ENABLE([fortran], [AS_HELP_STRING([--enable-fortran], [Compile the Fortran 77/90/95 interface [default=no]])], [HDF_FORTRAN=$enableval]) if test "X$HDF_FORTRAN" = "Xyes"; then echo "yes" else echo "no" fi ## ---------------------------------------------------------------------- ## Check if they would like the Fortran 2003 interface compiled ## AC_MSG_CHECKING([if Fortran 2003 interface enabled]) AC_ARG_ENABLE([fortran2003], [AS_HELP_STRING([--enable-fortran2003], [Compile the Fortran 2003 interface, must also specify --enable-fortran [default=no]])], [HDF_FORTRAN2003=$enableval]) ## ---------------------------------------------------------------------- ## Check to make sure --enable-fortran is present if --enable-fortran2003 ## was specified if test "X$HDF_FORTRAN2003" = "Xyes" && test "X$HDF_FORTRAN" = "Xno"; then echo "no" AC_MSG_ERROR([--enable-fortran must be used with --enable-fortran2003]) else echo "yes" fi HAVE_SIZEOF="no" HAVE_C_SIZEOF="no" HAVE_STORAGE_SIZE="no" FORTRAN_DEFAULT_REALisDBLE="no" if test "X$HDF_FORTRAN" = "Xyes"; then AC_SUBST([FC]) HDF_FORTRAN=yes AC_SUBST([HAVE_FORTRAN_2003]) HDF5_INTERFACES="$HDF5_INTERFACES fortran" ## -------------------------------------------------------------------- ## Default for FORTRAN 2003 compliant compilers ## HAVE_FORTRAN_2003="no" HAVE_F2003_REQUIREMENTS="no" ## -------------------------------------------------------------------- ## HDF5 integer variables for the H5fortran_types.f90 file. ## AC_SUBST([R_LARGE]) AC_SUBST([R_INTEGER]) AC_SUBST([HADDR_T]) AC_SUBST([HSIZE_T]) AC_SUBST([HSSIZE_T]) AC_SUBST([HID_T]) AC_SUBST([SIZE_T]) AC_SUBST([OBJECT_NAMELEN_DEFAULT_F]) ## -------------------------------------------------------------------- ## Fortran source extention ## AC_FC_SRCEXT([f90]) AC_SUBST([F9XSUFFIXFLAG]) AC_SUBST([FSEARCH_DIRS]) ## -------------------------------------------------------------------- ## Check for a Fortran 9X compiler and how to include modules. ## AC_PROG_FC([f90 pgf90 slf90 f95 g95 xlf95 efc ifort ftn],) AC_F9X_MODS ## It seems that libtool (as of Libtool 1.5.14) is trying to ## configure itself for Fortran 77. ## Tell it that our F77 compiler is $FC (actually a F9X compiler) F77=$FC ## Change to the Fortran 90 language AC_LANG_PUSH(Fortran) ## -------------------------------------------------------------------- ## Define wrappers for the C compiler to use Fortran function names ## AC_FC_WRAPPERS ## -------------------------------------------------------------------- ## See if the compiler will support the "-I." option ## dnl AM_FCFLAGS_saved=$AM_FCFLAGS dnl AM_FCFLAGS="${AM_FCFLAGS} -I." dnl AC_MSG_CHECKING(if compiler supports -I. option) dnl AC_TRY_FCOMPILE([ dnl program conftest dnl end dnl ], AC_MSG_RESULT(yes), dnl AC_MSG_RESULT(no) dnl AM_FCFLAGS="$AM_FCFLAGS_saved") ## -------------------------------------------------------------------- ## See if the fortran compiler supports the intrinsic function "SIZEOF" AC_MSG_CHECKING([if Fortran compiler supports intrinsic SIZEOF]) AC_TRY_RUN([ PROGRAM main i = sizeof(x) END PROGRAM ], [AC_MSG_RESULT([yes]) HAVE_SIZEOF="yes"], [AC_MSG_RESULT([no])]) ## See if the fortran compiler supports the intrinsic function "C_SIZEOF" AC_MSG_CHECKING([if Fortran compiler supports intrinsic C_SIZEOF]) AC_TRY_RUN([ PROGRAM main USE ISO_C_BINDING INTEGER(C_INT) :: a INTEGER(C_SIZE_T) :: result result = C_SIZEOF(a) END PROGRAM ], [AC_MSG_RESULT([yes]) HAVE_C_SIZEOF="yes"], [AC_MSG_RESULT([no])]) ## See if the fortran compiler supports the intrinsic function "STORAGE_SIZE" AC_MSG_CHECKING([if Fortran compiler supports intrinsic STORAGE_SIZE]) AC_TRY_RUN([ PROGRAM main INTEGER :: a INTEGER :: result result = STORAGE_SIZE(a) END PROGRAM ], [AC_MSG_RESULT([yes]) HAVE_STORAGE_SIZE="yes"], [AC_MSG_RESULT([no])]) ## Check to see if -r8 was specified to determine if we need to ## compile the DOUBLE PRECISION interfaces. AC_MSG_CHECKING([if Fortran default REAL is DOUBLE PRECISION]) AC_TRY_RUN([ MODULE type_mod INTERFACE h5t MODULE PROCEDURE h5t_real MODULE PROCEDURE h5t_dble END INTERFACE CONTAINS SUBROUTINE h5t_real(r) REAL :: r END SUBROUTINE h5t_real SUBROUTINE h5t_dble(d) DOUBLE PRECISION :: d END SUBROUTINE h5t_dble END MODULE type_mod PROGRAM main USE type_mod REAL :: r DOUBLE PRECISION :: d CALL h5t(r) CALL h5t(d) END PROGRAM main ], [AC_MSG_RESULT([no])], [AC_MSG_RESULT([yes]) FORTRAN_DEFAULT_REALisDBLE="yes"]) if test "X$HDF_FORTRAN2003" = "Xyes"; then ## Checking if the compiler supports the required Fortran 2003 features and ## disable Fortran 2003 if it does not. AC_MSG_CHECKING([if Fortran compiler version compatible with Fortran 2003 HDF]) HAVE_FORTRAN_2003="no" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[ USE iso_c_binding IMPLICIT NONE TYPE(C_PTR) :: ptr TYPE(C_FUNPTR) :: funptr CHARACTER(LEN=80, KIND=c_char), TARGET :: ichr ptr = C_LOC(ichr(1:1)) ])], [AC_MSG_RESULT([yes]) HAVE_F2003_REQUIREMENTS=[yes]], [AC_MSG_RESULT([no])]) if test "X$HAVE_F2003_REQUIREMENTS" = "Xno"; then ## echo $HAVE_FORTRAN_2003 AC_MSG_ERROR([Fortran compiler lacks required Fortran 2003 features; unsupported Fortran 2003 compiler, remove --enable-fortran2003]) else ## echo $HAVE_FORTRAN_2003 HAVE_FORTRAN_2003="yes" fi fi else FC="no" fi ## Change back to the C language AC_LANG_POP(Fortran) AM_CONDITIONAL([FORTRAN_HAVE_SIZEOF], [test "X$HAVE_SIZEOF" = "Xyes"]) AM_CONDITIONAL([FORTRAN_HAVE_C_SIZEOF], [test "X$HAVE_C_SIZEOF" = "Xyes"]) AM_CONDITIONAL([FORTRAN_HAVE_STORAGE_SIZE], [test "X$HAVE_STORAGE_SIZE" = "Xyes"]) AM_CONDITIONAL([FORTRAN_2003_CONDITIONAL_F], [test "X$HAVE_FORTRAN_2003" = "Xyes"]) AM_CONDITIONAL([FORTRAN_DEFAULT_REALisDBLE_F], [test "X$FORTRAN_DEFAULT_REALisDBLE" = "Xyes"]) ## ---------------------------------------------------------------------- ## Check if they would like the C++ interface compiled ## ## We need to check for a C++ compiler unconditionally, since ## AC_PROG_CXX defines some macros that Automake 1.9.x uses and will ## miss even if c++ is not enabled. AC_PROG_CXX AC_PROG_CXXCPP ## this is checked for when AC_HEADER_STDC is done AC_MSG_CHECKING([if c++ interface enabled]) AC_ARG_ENABLE([cxx], [AS_HELP_STRING([--enable-cxx], [Compile the C++ interface [default=no]])], [HDF_CXX=$enableval]) if test "X$HDF_CXX" = "Xyes"; then echo "yes" HDF5_INTERFACES="$HDF5_INTERFACES c++" ## Change to the C++ language AC_LANG_PUSH(C++) AC_MSG_CHECKING([if $CXX needs old style header files in includes]) AC_TRY_RUN([ #include <iostream> int main(void) { return 0; } ], [ echo no ], [ echo yes CXXFLAGS="${CXXFLAGS} -DOLD_HEADER_FILENAME" AM_CXXFLAGS="${AM_CXXFLAGS} -DOLD_HEADER_FILENAME" ]) AC_MSG_CHECKING([if $CXX can handle namespaces]) AC_TRY_RUN([ namespace H5 { int fnord; } int main(void) { using namespace H5; fnord = 37; return 0; } ], [ echo yes ], [ echo no CXXFLAGS="${CXXFLAGS} -DH5_NO_NAMESPACE" AM_CXXFLAGS="${AM_CXXFLAGS} -DH5_NO_NAMESPACE" ]) AC_MSG_CHECKING([if $CXX supports std]) AC_TRY_RUN([ #include <string> using namespace std; int main(void) { string myString("testing namespace std"); return 0; } ], [ echo yes ], [ echo no CXXFLAGS="${CXXFLAGS} -DH5_NO_STD" AM_CXXFLAGS="${AM_CXXFLAGS} -DH5_NO_STD" ]) AC_MSG_CHECKING([if $CXX supports bool types]) AC_TRY_RUN([ int main(void) { bool flag; return 0; } ], [ echo yes ], [ echo no CXXFLAGS="${CXXFLAGS} -DBOOL_NOTDEFINED" AM_CXXFLAGS="${AM_CXXFLAGS} -DBOOL_NOTDEFINED" ]) AC_MSG_CHECKING([if $CXX has offsetof extension]) AC_TRY_COMPILE([ #include <stdio.h> #include <stddef.h> ],[ struct index_st { unsigned char type; unsigned char num; unsigned int len; }; typedef struct index_st index_t; int x,y; x = offsetof(struct index_st, len); y = offsetof(index_t, num) ], AC_DEFINE([CXX_HAVE_OFFSETOF], [1], [Define if C++ compiler recognizes offsetof]) AC_MSG_RESULT([yes]), AC_MSG_RESULT([no])) AC_MSG_CHECKING([if $CXX can handle static cast]) AC_TRY_RUN([ int main(void) { float test_float; int test_int; test_float = 37.0; test_int = static_cast <int> (test_float); return 0; } ], [ echo yes ], [ echo no CXXFLAGS="${CXXFLAGS} -DNO_STATIC_CAST" AM_CXXFLAGS="${AM_CXXFLAGS} -DNO_STATIC_CAST" ]) else echo "no" CXX="no" fi ## Change back to the C language AC_LANG_POP(C++) ## ---------------------------------------------------------------------- ## Check if they have Perl installed on their system. We only need Perl ## if they're using a GNU compiler. ## AC_SUBST([PERL]) PERL="" if test "X$GCC" = "Xyes"; then AC_CHECK_PROGS([PERL], [perl],, [$PATH]) fi ## ---------------------------------------------------------------------- ## Check which archiving tool to use. This needs to be done before ## the AM_PROG_LIBTOOL macro. ## if test -z "$AR"; then AC_CHECK_PROGS([AR], [ar xar], [:], [$PATH]) fi AC_SUBST([AR]) ## Export the AR macro so that it will be placed in the libtool file ## correctly. export AR AC_PROG_MAKE_SET AC_PROG_INSTALL ## ---------------------------------------------------------------------- ## Check that the tr utility is working properly. AC_PATH_PROG([TR], [tr]) TR_TEST=`echo Test | ${TR} ${as_cr_letters}"," ${as_cr_LETTERS}" "` if test "X${TR_TEST}" != "XTEST"; then AC_MSG_ERROR([tr program doesn't work]) fi ## ---------------------------------------------------------------------- ## Check that time can be used with srcdir. This is okay on most systems, ## but seems to cause problems on Cygwin. ## The solution on Cygwin is not to record execution time for tests. AC_MSG_CHECKING([if srcdir= and time commands work together]) AC_SUBST([TIME]) TIME=time TIME_TEST=`foo="bar" ${TIME} echo 'baz' 2> /dev/null | grep baz` if test "X${TIME_TEST}" = "Xbaz"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) TIME= fi ## The following variables are used to distinguish between building a ## serial and parallel library. ## ## HAVE_PARALLEL -- defined in H5config.h if we are building ## a parallel library even if configure wasn't ## able to find some header file or library that ## might be required. This is defined if the ## compiler looks like a parallel compiler (e.g., ## mpicc or mpcc) or if the user explicitly states ## that a parallel library is being built by supplying ## the `--enable-parallel' configure switch. ## ## PARALLEL -- This variable is set to a non-null value if ## configure thinks we're compiling a parallel ## version of the library. ## ## RUNSERIAL -- This is a command which will be prepended to ## the executable name to run the executable using ## a single process. For serial versions of the ## library this will normally be empty. For parallel ## versions it might be something like `mpiexec -n 1'. ## The value of this variable is substituted in *.in ## files. ## ## RUNPARALLEL -- This is a command which will be prepended to ## the executable name to run the executable on ## multiple processors. For the serial library the ## value will normally be the empty string. For ## parallel library it should be something like ## "mpiexec -n \$\${NPROCS:=6}" where NPROCS will ## eventually contain the number of processors on which ## to run the executable (the double dollarsigns are to ## protect the expansion until make executes the ## command). The value of this variable is ## substituted in *.in files. ## AC_SUBST([PARALLEL]) AC_SUBST([RUNSERIAL]) AC_SUBST([RUNPARALLEL]) AC_SUBST([TESTPARALLEL]) ## ---------------------------------------------------------------------- ## If the compiler is obviously a parallel compiler then we're building ## a parallel version of hdf5 and should define HAVE_PARALLEL. Furthermore, ## the name of the compiler might tell us how to run the resulting ## executable. For `mpicc' the executable should be run with `mpiexec' from ## the same directory as mpicc if it exists. ## case "$CC_BASENAME" in mpicc) ## The mpich compiler. Use mpiexec from the same directory if it ## exists. PARALLEL=mpicc AC_MSG_CHECKING([for mpiexec]) ## Find the path where mpicc is located. cmd="`echo $CC | cut -f1 -d' '`" if (echo $cmd | grep / >/dev/null); then path="`echo $cmd | sed 's/\(.*\)\/.*$/\1/'`" else for path in `echo $PATH | ${TR} ":" " "`; do if test -x $path/$cmd; then break fi done fi ## Is there an mpiexec at that path? if test -x $path/mpiexec; then AC_MSG_RESULT([$path/mpiexec]) RUNSERIAL="${RUNSERIAL:-none}" if test -z "$RUNPARALLEL"; then RUNPARALLEL="$path/mpiexec -n \$\${NPROCS:=6}" fi else AC_MSG_RESULT([none]) fi ;; mpcc|mpcc_r) ## The IBM compiler PARALLEL="$CC_BASENAME" ;; *) ## Probably not a parallel compiler, but if `--enable-parallel' ## is defined below then we're still building a parallel hdf5. ;; esac ## ---------------------------------------------------------------------- ## If the Fortran compiler is obviously a parallel compiler then we're ## building a parallel version of hdf5 and should define HAVE_PARALLEL. ## Furthermore, the name of the compiler might tell us how to run the ## resulting executable. For `mpif90' the executable should be run with ## `mpiexec' from the same directory as mpif90 if it exists. ## if test "X$HDF_FORTRAN" = "Xyes" ; then ## Change to the Fortran 90 language AC_LANG_PUSH(Fortran) case "$FC" in *mpif90*) ## The Fortran mpich compiler. Use mpiexec from the same directory ## if it exists. PARALLEL=mpif90 AC_MSG_CHECKING([for mpiexec]) ## Find the path where mpif90 is located. cmd=`echo $FC |cut -f1 -d' '` if (echo $cmd |grep / >/dev/null); then path="`echo $cmd |sed 's/\(.*\)\/.*$/\1/'`" else for path in `echo $PATH | ${TR} ":" " "`; do if test -x $path/$cmd; then break; fi done fi ## Is there an mpiexec at that path? if test -x $path/mpiexec; then AC_MSG_RESULT([$path/mpiexec]) RUNSERIAL="${RUNSERIAL:-none}" if test -z "$RUNPARALLEL"; then RUNPARALLEL="$path/mpiexec -n \$\${NPROCS:=6}" fi else AC_MSG_RESULT([none]) fi ;; *mpxlf* | *mpxlf_r* | *mpxlf90* | *mpxlf90_r* | *mpxlf95* | *mpxlf95_r*) ## The IBM compiler PARALLEL="$FC" ;; *) ## Probably not a parallel compiler, but if `--enable-parallel' ## is defined below then we're still building a parallel hdf5. ;; esac ## Change to the C language AC_LANG_POP(Fortran) fi ## ----------------------------------------------------------------------------- ## If shared libraries are being used with parallel, disable them, unless the ## user explicity enables them via the '--enable-shared' option. if test "X${enable_shared}" = "X" -a "X${enable_parallel}" = "Xyes"; then echo ' shared libraries disabled in parallel' enable_shared="no" elif test "X${enable_shared}" = "Xyes" -a "X${enable_parallel}" = "Xyes"; then echo ' shared libraries explicitly enabled by user' elif test "X${enable_shared}" = "X" -a "X${PARALLEL}" != "X"; then echo ' shared libraries disabled when a parallel compiler is being used' enable_shared="no" elif test "X${enable_shared}" = "Xyes" -a "X${PARALLEL}" != "X"; then echo ' shared libraries explicitly enabled by user' fi ## ---------------------------------------------------------------------- ## Fortran libraries are not currently supported on Mac. Disable them. ## (this is overridable with --enable-unsupported). ## AC_SUBST([H5_FORTRAN_SHARED]) H5_FORTRAN_SHARED="no" if test "X${HDF_FORTRAN}" = "Xyes" && test "X${enable_shared}" != "Xno"; then AC_MSG_CHECKING([if shared Fortran libraries are supported]) H5_FORTRAN_SHARED="yes" ## Disable fortran shared libraries on Mac. (MAM - 03/30/11) case "`uname`" in Darwin*) H5_FORTRAN_SHARED="no" CHECK_WARN="Shared Fortran libraries not currently supported on Mac." ;; esac ## Report results of check(s) if test "X${H5_FORTRAN_SHARED}" = "Xno"; then AC_MSG_RESULT([no]) AC_MSG_WARN([$CHECK_WARN]) if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then AC_MSG_WARN([Disabling shared Fortran libraries.]) AC_MSG_WARN([To override this behavior, please use --enable-unsupported configure option.]) if test "X${enable_static}" = "Xno"; then AC_MSG_ERROR([both static and shared Fortran libraries are disabled]) fi else AC_MSG_WARN([Allowing unsupported Fortran shared libraries due to use of --enable-unsupported flag]) H5_FORTRAN_SHARED="yes" fi else AC_MSG_RESULT([yes]) fi fi AM_CONDITIONAL([FORTRAN_SHARED_CONDITIONAL], [test "X$H5_FORTRAN_SHARED" = "Xyes"]) ## ---------------------------------------------------------------------- ## Disable C++ shared libraries if +DD64 flag is detected. ## AC_SUBST([H5_CXX_SHARED]) H5_CXX_SHARED="no" if test "X${HDF_CXX}" = "Xyes" && test "X${enable_shared}" != "Xno"; then AC_MSG_CHECKING([if shared C++ libraries are supported]) H5_CXX_SHARED="yes" ## Disable C++ shared libraries if DD64 flag is being used. if (echo dummy ${CXX} ${CXXLD} ${CFLAGS} ${CXXFLAGS} ${LDFLAGS} | grep 'DD64') > /dev/null; then H5_CXX_SHARED="no" CHECK_WARN="Shared C++ libraries not currently supported with +DD64 flag." fi ## Report results of check(s) if test "X${H5_CXX_SHARED}" = "Xno"; then AC_MSG_RESULT([no]) AC_MSG_WARN([$CHECK_WARN]) if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then AC_MSG_WARN([Disabling shared C++ libraries.]) AC_MSG_WARN([To override this behavior, please use --enable-unsupported configure option.]) if test "X${enable_static}" = "Xno"; then AC_MSG_ERROR([both static and shared C++ libraries are disabled]) fi else AC_MSG_WARN([Allowing unsupported C++ shared librares due to use of --enable-unsupported flag]) fi else AC_MSG_RESULT([yes]) fi fi AM_CONDITIONAL([CXX_SHARED_CONDITIONAL], [test "X$H5_CXX_SHARED" = "Xyes"]) ## ---------------------------------------------------------------------- ## pgcc version 6.0x have optimization (-O, -O2 or -O3) problem. Detect ## these versions and add option "-Mx,28,0x8" to the compiler to avoid ## the problem if optimization is enabled. ## if (${CC-cc} -V 2>&1 | grep '^pgcc 6.0') > /dev/null && test "X$enable_production" = "Xyes"; then echo 'adding compiler flag to avoid optimization problem in pgcc' CC="${CC-cc} -Mx,28,0x8" fi ## ---------------------------------------------------------------------- ## Shared libraries are not currently supported under Cygwin, so configure ## disables them unless --enable-unsupported has been supplied by the user. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then case "`uname`" in CYGWIN*) if test "X${enable_shared}" = "Xyes"; then echo ' warning: shared libraries are not supported on Cygwin!' echo ' disabling shared libraries' echo ' use --enable-unsupported to override this warning and keep shared libraries enabled' fi enable_shared="no" ;; esac fi ## ---------------------------------------------------------------------- ## Windows won't create DLLs without the following macro. ## AC_LIBTOOL_WIN32_DLL ## ---------------------------------------------------------------------- ## Create libtool. If shared/static libraries are going to be enabled ## or disabled, it should happen before these macros. LT_PREREQ([2.2]) LT_INIT([dlopen]) ## ---------------------------------------------------------------------- ## Check if we should install only statically linked executables. ## This check needs to occur after libtool is initialized because ## we check a libtool cache value and may issue a warning based ## on its result. AC_MSG_CHECKING([if we should install only statically linked executables]) AC_ARG_ENABLE([static_exec], [AS_HELP_STRING([--enable-static-exec], [Install only statically linked executables [default=no]])], [STATIC_EXEC=$enableval]) if test "X$STATIC_EXEC" = "Xyes"; then echo "yes" ## Issue a warning if -static flag is not supported. if test "X$lt_cv_prog_compiler_static_works" = "Xno"; then echo " warning: -static flag not supported on this system; executable won't statically link shared system libraries." LT_STATIC_EXEC="" else LT_STATIC_EXEC="-all-static" fi else echo "no" LT_STATIC_EXEC="" fi AM_CONDITIONAL([USE_PLUGINS_CONDITIONAL], [test "X$LT_STATIC_EXEC" = X]) AC_SUBST([LT_STATIC_EXEC]) ## Fix up the INSTALL macro if it's a relative path. We want the ## full-path to the binary instead. case "$INSTALL" in *install-sh*) INSTALL='\${top_srcdir}/bin/install-sh -c' ;; esac ## ---------------------------------------------------------------------- ## Some users have reported problems with libtool's use of '-Wl,-rpath' to ## link shared libraries in nondefault directories. Allow users to ## disable embedding the rpath information in the executables and to ## instead solely rely on the information in LD_LIBRARY_PATH. AC_MSG_CHECKING([if -Wl,-rpath should be used to link shared libs in nondefault directories]) AC_ARG_ENABLE([sharedlib-rpath], [AS_HELP_STRING([--disable-sharedlib-rpath], [Disable use of the '=Wl,-rpath' linker option])], [RPATH=$enableval]) case "X-$RPATH" in X-no) AC_MSG_RESULT([no]) runpath_var= hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_into_libs=no ;; X-|X-yes) AC_MSG_RESULT([yes]) ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([\'$enableval\' is not a valid rpath type]) ;; esac ## ---------------------------------------------------------------------- ## Sometimes makes think the `.PATH:' appearing before the first rule ## with an action should override the `all' default target. So we have ## to decide what the proper syntax is. ## AC_MSG_CHECKING([how make searches directories]) while true; do #for break ## The most common method is `VPATH=DIR1 DIR2 ...' cat >maketest <<EOF VPATH=$srcdir/config $srcdir/src $srcdir/bin .c.o: cp $< H5.o foo: H5.o rm -f H5.o @echo works EOF if (${MAKE-make} -f maketest foo) >/dev/null 2>&1; then SEARCH_RULE='VPATH=' SEARCH_SEP=' ' AC_MSG_RESULT([VPATH=DIR1 DIR2 ...]) break fi ## The second most common method is like above except with the ## directories separated by colons. cat >maketest <<EOF VPATH=$srcdir/config:$srcdir/src:$srcdir/bin .c.o: cp $< H5.o foo: H5.o rm -f H5.o @echo works EOF if (${MAKE-make} -f maketest foo) >/dev/null 2>&1; then SEARCH_RULE='VPATH=' SEARCH_SEP=':' AC_MSG_RESULT([VPATH=DIR1:DIR2:...]) break fi ## pmake uses the construct `.PATH: DIR1 DIR2 cat >maketest <<EOF .PATH: $srcdir/config $srcdir/src $srcdir/bin .c.o: cp $< H5.o foo: H5.o rm -f H5.o @echo works EOF if (MAKE= ${MAKE-make} -f maketest foo) >/dev/null 2>&1; then SEARCH_RULE='.PATH: ' SEARCH_SEP=' ' AC_MSG_RESULT([.PATH: DIR1 DIR2 ...]) break fi ## No way for make to search directories SEARCH_RULE='## SEARCH DISABLED: ' SEARCH_SEP=' ' AC_MSG_RESULT([it doesn't]) if test ! -f configure; then AC_MSG_ERROR([${MAKE-make} requires the build and source directories to be the same]) fi break done rm maketest ## ---------------------------------------------------------------------- ## pmake will throw an error if variables are undefined in a Makefile. ## These errors can be changed to warnings using the -V flag. ## AC_SUBST([AM_MAKEFLAGS]) AM_MAKEFLAGS="" ## Don't run test if MAKE is defined but is the empty string if test -n "${MAKE-make}"; then AC_MSG_CHECKING([whether make will build with undefined variables]) cat >maketest <<EOF foo: \$(UNDEFINED) \$(UNDEFINED2) @echo \$(UNDEFINED3) works EOF if (${MAKE-make} -f maketest foo) >/dev/null 2>&1; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no, setting -V flag]) AM_MAKEFLAGS="\-V" fi rm maketest fi ## ---------------------------------------------------------------------- ## Production flags? Save the value in $CONFIG_MODE so we have it for ## the record. ## AC_MSG_CHECKING([for production mode]) AC_ARG_ENABLE([production], [AS_HELP_STRING([--enable-production], [Determines how to run the compiler.])]) case "X-$enable_production" in X-yes) enable_production="yes" AC_MSG_RESULT([production]) CONFIG_MODE=production H5_CFLAGS="$H5_CFLAGS $PROD_CFLAGS" H5_CPPFLAGS="$H5_CPPFLAGS $PROD_CPPFLAGS" H5_CXXFLAGS="$H5_CXXFLAGS $PROD_CXXFLAGS" H5_FCFLAGS="$H5_FCFLAGS $PROD_FCFLAGS" ;; X-|X-no) enable_production="no" AC_MSG_RESULT([development]) CONFIG_MODE=development H5_CFLAGS="$H5_CFLAGS $DEBUG_CFLAGS" H5_CPPFLAGS="$H5_CPPFLAGS $DEBUG_CPPFLAGS" H5_CXXFLAGS="$H5_CXXFLAGS $DEBUG_CXXFLAGS" H5_FCFLAGS="$H5_FCFLAGS $DEBUG_FCFLAGS" ;; X-pg|X-profile) enable_production="profile" AC_MSG_RESULT([profile]) CONFIG_MODE=profile H5_CFLAGS="$H5_CFLAGS $PROFILE_CFLAGS" H5_CPPFLAGS="$H5_CPPFLAGS $PROFILE_CPPFLAGS" H5_CXXFLAGS="$H5_CXXFLAGS $PROFILE_CXXFLAGS" H5_FCFLAGS="$H5_FCFLAGS $PROFILE_FCFLAGS" ;; *) enable_production="user-defined" AC_MSG_RESULT([user-defined]) CONFIG_MODE="$enableval" ;; esac ## ---------------------------------------------------------------------- ## Check for system libraries. "dl" stands for dynamically loaded library ## AC_CHECK_LIB([m], [ceil]) AC_CHECK_LIB([dl], [dlopen]) if test "`uname`" = "SunOS" -o "`uname -sr`" = "HP-UX B.11.00"; then ## ...for Solaris AC_CHECK_LIB([socket], [socket]) AC_CHECK_LIB([nsl], [xdr_int]) fi dnl AC_CHECK_LIB([coug], [main]) ## ...for ASCI/Red ## ---------------------------------------------------------------------- ## Check for system header files. ## AC_HEADER_STDC AC_HEADER_TIME ## ---------------------------------------------------------------------- ## Check for these two functions before the time headers are checked ## for, otherwise they are not detected correctly on Solaris (the ## configure test will fail due to multiply-defined symbols). ## AC_CHECK_FUNCS([difftime]) AC_CHECK_FUNCS([gettimeofday], [have_gettime="yes"], [have_gettime="no"]) AC_SEARCH_LIBS([clock_gettime], [rt posix4]) AC_CHECK_FUNCS([clock_gettime],[have_clock_gettime="yes"],[have_clock_gettime="no"]) ## Unix AC_CHECK_HEADERS([sys/resource.h sys/time.h unistd.h sys/ioctl.h sys/stat.h]) AC_CHECK_HEADERS([sys/socket.h sys/types.h]) AC_CHECK_HEADERS([stddef.h setjmp.h features.h]) AC_CHECK_HEADERS([dirent.h]) AC_CHECK_HEADERS([stdint.h], [C9x=yes]) ## Darwin AC_CHECK_HEADERS([mach/mach_time.h]) ## Also need to detect Darwin for pubconf case $host_os in darwin*) AC_DEFINE([HAVE_DARWIN], [1], [Define if Darwin or Mac OS X]) ;; esac ## Windows case "`uname`" in CYGWIN*) AC_CHECK_HEADERS([io.h sys/timeb.h]) ;; MINGW*) AC_CHECK_HEADERS([io.h winsock2.h sys/timeb.h]) AC_HAVE_LIBRARY([ws2_32]) ;; *) AC_CHECK_HEADERS([io.h winsock2.h sys/timeb.h]) ;; esac case "$host" in alpha*-dec*-osf*) ## The <sys/sysinfo.h> and <sys/proc.h> are needed on the DEC ## Alpha to turn off UAC fixing. We do *not* attempt to ## locate these files on other systems because there are too ## many problems with including them. AC_CHECK_HEADERS([sys/sysinfo.h sys/proc.h]) ;; mips*-sgi*-irix*) ## The <sys/fpu.h> is needed on the SGI machines to turn off ## denormalized floating-point values going to zero. We do *not* ## attempt to locate these files on other systems because there ## may be problems with including them. AC_CHECK_HEADERS([sys/fpu.h]) AC_CHECK_FUNCS([get_fpc_csr]) ;; esac ## ---------------------------------------------------------------------- ## Some platforms require that all symbols are resolved when a library ## is linked. We can use the -no-undefined flag to tell libtool that ## it will be able to build shared libraries on these architectures, ## as it will not do so by default. ## if test "X${enable_shared}" = "Xyes"; then AC_MSG_CHECKING([if libtool needs -no-undefined flag to build shared libraries]) case "`uname`" in CYGWIN*|MINGW*|AIX*) ## Add in the -no-undefined flag to LDFLAGS for libtool. AC_MSG_RESULT([yes]) H5_LDFLAGS="$H5_LDFLAGS -no-undefined" ;; *) ## Don't add in anything. AC_MSG_RESULT([no]) ;; esac fi ## ---------------------------------------------------------------------- ## Test for Largefile support. ## AC_MSG_CHECKING([if configure should try to set up large file support]) AC_ARG_ENABLE([largefile], [AS_HELP_STRING([--disable-largefile], [omit support for large files])]) ## If largefile support is enabled, then set up appropriate compiler options. if test "$enable_largefile" != no; then AC_MSG_RESULT([yes]) ## Check for needed compiler options. This check is pulled drectly ## from autoconf's AC_SYS_LARGEFILE macro, as of Autoconf v2.65. AC_CACHE_CHECK([for special C compiler options needed for large files], ac_cv_sys_largefile_CC, [ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do ## IRIX 6.2 and later do not support large files by default, ## so use the C compiler's -n32 option if that helps. AC_LANG_CONFTEST([AC_LANG_PROGRAM([_AC_SYS_LARGEFILE_TEST_INCLUDES])]) AC_COMPILE_IFELSE([], [break]) CC="$CC -n32" AC_COMPILE_IFELSE([], [ac_cv_sys_largefile_CC=' -n32'; break]) break done CC=$ac_save_CC rm -f conftest.$ac_ext fi]) if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi ## Use the macro _AC_SYS_LARGEFILE_MACRO_VALUE to test defines ## that might need to be set for largefile support to behave ## correctly. This macro is defined in acsite.m4 and overrides ## the version provided by Autoconf (as of v2.65). The custom ## macro additionally adds the appropriate defines to AM_CPPFLAGS ## so that later configure checks have them visible. ## Check for _FILE_OFFSET_BITS _AC_SYS_LARGEFILE_MACRO_VALUE([_FILE_OFFSET_BITS], [64], [ac_cv_sys_file_offset_bits], [Number of bits in a file offset, on hosts where this is settable.], [_AC_SYS_LARGEFILE_TEST_INCLUDES]) ## Check for _LARGE_FILES if test "$ac_cv_sys_file_offset_bits" = unknown; then _AC_SYS_LARGEFILE_MACRO_VALUE([_LARGE_FILES], [1], [ac_cv_sys_large_files], [Define for large files, on AIX-style hosts.], [_AC_SYS_LARGEFILE_TEST_INCLUDES]) fi ## Now actually test to see if we can create large files after we've ## checked for any needed defines. AC_MSG_CHECKING([if large (64-bit) files are supported on this system.]) AC_CACHE_VAL([hdf5_cv_have_lfs], [AC_TRY_RUN([ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #define BIG_FILE (off_t)0x80000000UL int main(void) { int fd; if ((fd=open("test.conf", O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) exit(1); if (lseek(fd, BIG_FILE, SEEK_SET)!=BIG_FILE) exit(1); if (5!=write(fd, "hello", (size_t)5)) exit(1); if (lseek(fd, 2*BIG_FILE, SEEK_SET) != 2*BIG_FILE) exit(1); if (5!=write(fd, "hello", (size_t)5)) exit(1); if (unlink("test.conf") < 0) exit(1); exit(0); } ],[hdf5_cv_have_lfs=yes],[hdf5_cv_have_lfs=no],)]) if test "X${hdf5_cv_have_lfs}" = "Xyes"; then AC_MSG_RESULT([yes]) LARGEFILE="yes" fi if test "X${hdf5_cv_have_lfs}" = "Xno"; then AC_MSG_RESULT([no]) LARGEFILE="no" fi else LARGEFILE="no" AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Add necessary defines for Linux Systems. ## case "$host_cpu-$host_vendor-$host_os" in *linux*) ## If largefile support is enabled, then make available various ## LFS-related routines using the following _LARGEFILE*_SOURCE macros. if test "X$LARGEFILE" != "Xno"; then AM_CPPFLAGS="-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE $AM_CPPFLAGS" fi ## Add POSIX support on Linux systems, so <features.h> defines ## __USE_POSIX, which is required to get the prototype for fdopen ## defined correctly in <stdio.h>. ## This flag was removed from h5cc as of 2009-10-17 when it was found ## that the flag broke compiling netCDF-4 code with h5cc, but kept in ## H5_CPPFLAGS because fdopen and HDfdopen fail without it. HDfdopen ## is used only by H5_debug_mask which is used only when debugging in ## H5_init_library (all in H5.c). When the flag was removed this was ## the only compile failure noted. ## This was originally defined as _POSIX_SOURCE which was updated to ## _POSIX_C_SOURCE=199506L to expose a greater amount of POSIX ## functionality so clock_gettime and CLOCK_MONOTONIC are defined ## correctly. ## POSIX feature information can be found in the gcc manual at: ## http://www.gnu.org/s/libc/manual/html_node/Feature-Test-Macros.html H5_CPPFLAGS="-D_POSIX_C_SOURCE=199506L $H5_CPPFLAGS" ## Also add BSD support on Linux systems, so <features.h> defines ## __USE_BSD, which is required to get the prototype for strdup ## defined correctly in <string.h> and snprintf & vsnprintf defined ## correctly in <stdio.h> ## Linking to the bsd-compat library is required as per the gcc manual: ## http://www.gnu.org/s/libc/manual/html_node/Feature-Test-Macros.html ## however, we do not do this since it breaks the big test on some ## older platforms. AM_CPPFLAGS="-D_BSD_SOURCE $AM_CPPFLAGS" ;; esac ## Need to add the AM_ and H5_ into CFLAGS/CPPFLAGS to make them visible ## for configure checks. ## Note: Both will be restored by the end of configure. CPPFLAGS="$H5_CPPFLAGS $AM_CPPFLAGS $CPPFLAGS" CFLAGS="$H5_CFLAGS $AM_CFLAGS $CFLAGS" AC_TRY_COMPILE([#include <sys/types.h>], [off64_t n = 0;], [AC_CHECK_FUNCS([lseek64 fseeko64 ftello64 ftruncate64])], [AC_MSG_RESULT([skipping test for lseek64(), fseeko64 , ftello64, ftruncate64() because off64_t is not defined])]) AC_CHECK_FUNCS([fseeko ftello]) AC_TRY_COMPILE([ #include <sys/types.h> #include <sys/stat.h>], [struct stat64 sb;], [AC_CHECK_FUNCS([stat64 fstat64])], [AC_MSG_RESULT([skipping test for stat64() and fstat64()])]) ## ---------------------------------------------------------------------- ## Data types and their sizes. ## AC_TYPE_OFF_T AC_CHECK_TYPE([size_t], [], [AC_DEFINE_UNQUOTED([size_t], [unsigned long], [Define to `unsigned long' if <sys/types.h> does not define.])]) AC_CHECK_TYPE([ssize_t], [], [AC_DEFINE_UNQUOTED([ssize_t], [long], [Define to `long' if <sys/types.h> does not define.])]) AC_CHECK_TYPE([ptrdiff_t], [], [AC_DEFINE_UNQUOTED([ptrdiff_t], [long], [Define to `long' if <sys/types.h> does not define.])]) AC_C_BIGENDIAN AC_CHECK_SIZEOF([char], [1]) AC_CHECK_SIZEOF([short], [2]) AC_CHECK_SIZEOF([int], [4]) AC_CHECK_SIZEOF([unsigned], [4]) AC_CHECK_SIZEOF([long], [4]) AC_CHECK_SIZEOF([long long], [8]) AC_CHECK_SIZEOF([__int64], [8]) AC_CHECK_SIZEOF([float], [4]) AC_CHECK_SIZEOF([double], [8]) AC_CHECK_SIZEOF([long double], [8]) ## Checkpoint the cache AC_CACHE_SAVE ## Posix.1g types (C9x) cat >>confdefs.h <<\EOF #include <sys/types.h> EOF if test "X$C9x" = "Xyes"; then cat >>confdefs.h <<\EOF #include <stdint.h> EOF fi AC_CHECK_SIZEOF( [int8_t], [1]) AC_CHECK_SIZEOF( [uint8_t], [1]) AC_CHECK_SIZEOF( [int_least8_t], [1]) AC_CHECK_SIZEOF( [uint_least8_t], [1]) AC_CHECK_SIZEOF( [int_fast8_t], [1]) AC_CHECK_SIZEOF( [uint_fast8_t], [1]) AC_CHECK_SIZEOF( [int16_t], [2]) AC_CHECK_SIZEOF( [uint16_t], [2]) AC_CHECK_SIZEOF( [int_least16_t], [2]) AC_CHECK_SIZEOF([uint_least16_t], [2]) AC_CHECK_SIZEOF( [int_fast16_t], [2]) AC_CHECK_SIZEOF( [uint_fast16_t], [2]) AC_CHECK_SIZEOF( [int32_t], [4]) AC_CHECK_SIZEOF( [uint32_t], [4]) AC_CHECK_SIZEOF( [int_least32_t], [4]) AC_CHECK_SIZEOF([uint_least32_t], [4]) AC_CHECK_SIZEOF( [int_fast32_t], [4]) AC_CHECK_SIZEOF( [uint_fast32_t], [4]) AC_CHECK_SIZEOF( [int64_t], [8]) AC_CHECK_SIZEOF( [uint64_t], [8]) AC_CHECK_SIZEOF( [int_least64_t], [8]) AC_CHECK_SIZEOF([uint_least64_t], [8]) AC_CHECK_SIZEOF( [int_fast64_t], [8]) AC_CHECK_SIZEOF( [uint_fast64_t], [8]) AC_CHECK_SIZEOF([size_t], [4]) AC_CHECK_SIZEOF([ssize_t], [4]) AC_CHECK_SIZEOF([ptrdiff_t], [4]) cat >>confdefs.h <<\EOF #include <sys/types.h> /*for off_t definition*/ EOF AC_CHECK_SIZEOF([off_t], [4]) AC_CHECK_SIZEOF([off64_t], [8]) ## Checkpoint the cache AC_CACHE_SAVE ## ---------------------------------------------------------------------- ## Check if the dev_t type is a scalar type (must come after the check for ## sys/types.h) AC_MSG_CHECKING([if dev_t is scalar]) AC_TRY_COMPILE([ #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif ], [dev_t d1, d2; if(d1==d2) return 0;], AC_DEFINE([DEV_T_IS_SCALAR], [1], [Define if `dev_t' is a scalar]) AC_MSG_RESULT([yes]), AC_MSG_RESULT([no]) ) ## ---------------------------------------------------------------------- ## Fake --with-xxx option to allow us to create a help message for the ## following --with-xxx options which can take either a =DIR or =INC,LIB ## specifier. ## AC_ARG_WITH([fnord], [ For the following --with-xxx options, you can specify where the header files and libraries are in two different ways: --with-xxx=INC,LIB - Specify individually the include directory and library directory separated by a comma --with-xxx=DIR - Specify only the directory which contains the include/ and lib/ subdirectories ]) ## ---------------------------------------------------------------------- ## Is the dmalloc present? It has a header file `dmalloc.h' and a library ## `-ldmalloc' and their locations might be specified with the `--with-dmalloc' ## command-line switch. The value is an include path and/or a library path. ## If the library path is specified then it must be preceded by a comma. ## AC_ARG_WITH([dmalloc], [AS_HELP_STRING([--with-dmalloc=DIR], [Use dmalloc memory debugging aid [default=no]])],, [withval=no]) case $withval in yes) HAVE_DMALLOC="yes" AC_CHECK_HEADERS([dmalloc.h],, [unset HAVE_DMALLOC]) if test "x$HAVE_DMALLOC" = "xyes"; then AC_CHECK_LIB([dmalloc], [dmalloc_shutdown],, [unset HAVE_DMALLOC]) fi if test -z "$HAVE_DMALLOC" -a -n "$HDF5_CONFIG_ABORT"; then AC_MSG_ERROR([couldn't find dmalloc library]) fi ;; no) HAVE_DMALLOC="no" AC_MSG_CHECKING([for dmalloc library]) AC_MSG_RESULT([suppressed]) ;; *) HAVE_DMALLOC="yes" case "$withval" in *,*) dmalloc_inc="`echo $withval |cut -f1 -d,`" dmalloc_lib="`echo $withval |cut -f2 -d, -s`" ;; *) if test -n "$withval"; then dmalloc_inc="$withval/include" dmalloc_lib="$withval/lib" fi ;; esac ## Trying to include -I/usr/include and -L/usr/lib is redundant and ## can mess some compilers up. if test "X$dmalloc_inc" = "X/usr/include"; then dmalloc_inc="" fi if test "X$dmalloc_lib" = "X/usr/lib"; then dmalloc_lib="" fi saved_CPPFLAGS="$CPPFLAGS" saved_AM_CPPFLAGS="$AM_CPPFLAGS" saved_LDFLAGS="$LDFLAGS" saved_AM_LDFLAGS="$AM_LDFLAGS" if test -n "$dmalloc_inc"; then CPPFLAGS="$CPPFLAGS -I$dmalloc_inc" AM_CPPFLAGS="$AM_CPPFLAGS -I$dmalloc_inc" fi AC_CHECK_HEADERS([dmalloc.h],,[CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"] [unset HAVE_DMALLOC]) if test "x$HAVE_DMALLOC" = "xyes"; then if test -n "$dmalloc_lib"; then LDFLAGS="$LDFLAGS -L$dmalloc_lib" AM_LDFLAGS="$AM_LDFLAGS -L$dmalloc_lib" fi AC_CHECK_LIB([dmalloc], [dmalloc_shutdown],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset HAVE_DMALLOC]) fi if test -z "$HAVE_DMALLOC" -a -n "$HDF5_CONFIG_ABORT"; then AC_MSG_ERROR([couldn't find dmalloc library]) fi ;; esac ## ---------------------------------------------------------------------- ## Is the GNU zlib present? It has a header file `zlib.h' and a library ## `-lz' and their locations might be specified with the `--with-zlib' ## command-line switch. The value is an include path and/or a library path. ## If the library path is specified then it must be preceded by a comma. ## AC_SUBST([USE_FILTER_DEFLATE]) USE_FILTER_DEFLATE="no" AC_ARG_WITH([zlib], [AS_HELP_STRING([--with-zlib=DIR], [Use zlib library for external deflate I/O filter [default=yes]])],, [withval=yes]) case $withval in yes) HAVE_ZLIB="yes" AC_CHECK_HEADERS([zlib.h], [HAVE_ZLIB_H="yes"], [unset HAVE_ZLIB]) if test "x$HAVE_ZLIB" = "xyes" -a "x$HAVE_ZLIB_H" = "xyes"; then AC_CHECK_LIB([z], [compress2],, [unset HAVE_ZLIB]) fi if test -z "$HAVE_ZLIB"; then if test -n "$HDF5_CONFIG_ABORT"; then AC_MSG_ERROR([couldn't find zlib library]) fi else AC_CHECK_FUNC([compress2], [HAVE_COMPRESS2="yes"]) fi ;; no) HAVE_ZLIB="no" AC_MSG_CHECKING([for GNU zlib]) AC_MSG_RESULT([suppressed]) ;; *) HAVE_ZLIB="yes" case "$withval" in *,*) zlib_inc="`echo $withval | cut -f1 -d,`" zlib_lib="`echo $withval | cut -f2 -d, -s`" ;; *) if test -n "$withval"; then zlib_inc="$withval/include" zlib_lib="$withval/lib" fi ;; esac ## Trying to include -I/usr/include and -L/usr/lib is redundant and ## can mess some compilers up. if test "X$zlib_inc" = "X/usr/include"; then zlib_inc="" fi if test "X$zlib_lib" = "X/usr/lib"; then zlib_lib="" fi saved_CPPFLAGS="$CPPFLAGS" saved_AM_CPPFLAGS="$AM_CPPFLAGS" saved_LDFLAGS="$LDFLAGS" saved_AM_LDFLAGS="$AM_LDFLAGS" if test -n "$zlib_inc"; then CPPFLAGS="$CPPFLAGS -I$zlib_inc" AM_CPPFLAGS="$AM_CPPFLAGS -I$zlib_inc" fi AC_CHECK_HEADERS([zlib.h], [HAVE_ZLIB_H="yes"], [CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"] [unset HAVE_ZLIB]) if test -n "$zlib_lib"; then LDFLAGS="$LDFLAGS -L$zlib_lib" AM_LDFLAGS="$AM_LDFLAGS -L$zlib_lib" fi if test "x$HAVE_ZLIB" = "xyes" -a "x$HAVE_ZLIB_H" = "xyes"; then AC_CHECK_LIB([z], [compress2],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset HAVE_ZLIB]) fi if test -z "$HAVE_ZLIB"; then if test -n "$HDF5_CONFIG_ABORT"; then AC_MSG_ERROR([couldn't find zlib library]) fi else AC_CHECK_FUNC([compress2], [HAVE_COMPRESS2="yes"]) fi ;; esac if test "x$HAVE_ZLIB" = "xyes" -a "x$HAVE_ZLIB_H" = "xyes" -a "x$HAVE_COMPRESS2" = "xyes"; then AC_DEFINE([HAVE_FILTER_DEFLATE], [1], [Define if support for deflate (zlib) filter is enabled]) USE_FILTER_DEFLATE="yes" ## Add "deflate" to external filter list if test "X$EXTERNAL_FILTERS" != "X"; then EXTERNAL_FILTERS="${EXTERNAL_FILTERS}," fi EXTERNAL_FILTERS="${EXTERNAL_FILTERS}deflate(zlib)" fi ## ---------------------------------------------------------------------- ## Is the szlib present? It has a header file `szlib.h' and a library ## `-lsz' and their locations might be specified with the `--with-szlib' ## command-line switch. The value is an include path and/or a library path. ## If the library path is specified then it must be preceded by a comma. ## AC_SUBST([USE_FILTER_SZIP]) USE_FILTER_SZIP="no" AC_ARG_WITH([szlib], [AS_HELP_STRING([--with-szlib=DIR], [Use szlib library for external szlib I/O filter [default=no]])],, [withval=no]) case $withval in yes) HAVE_SZLIB="yes" AC_CHECK_HEADERS([szlib.h], [HAVE_SZLIB_H="yes"], [unset HAVE_SZLIB]) if test "x$HAVE_SZLIB" = "xyes" -a "x$HAVE_SZLIB_H" = "xyes"; then AC_CHECK_LIB([sz], [SZ_BufftoBuffCompress],, [unset HAVE_SZLIB]) fi if test -z "$HAVE_SZLIB" -a -n "$HDF5_CONFIG_ABORT"; then AC_MSG_ERROR([couldn't find szlib library]) fi ;; no) HAVE_SZLIB="no" AC_MSG_CHECKING([for szlib]) AC_MSG_RESULT([suppressed]) ;; *) HAVE_SZLIB="yes" case "$withval" in *,*) szlib_inc="`echo $withval |cut -f1 -d,`" szlib_lib="`echo $withval |cut -f2 -d, -s`" ;; *) if test -n "$withval"; then szlib_inc="$withval/include" szlib_lib="$withval/lib" fi ;; esac ## Trying to include -I/usr/include and -L/usr/lib is redundant and ## can mess some compilers up. if test "X$szlib_inc" = "X/usr/include"; then szlib_inc="" fi if test "X$szlib_lib" = "X/usr/lib"; then szlib_lib="" fi saved_CPPFLAGS="$CPPFLAGS" saved_AM_CPPFLAGS="$AM_CPPFLAGS" saved_LDFLAGS="$LDFLAGS" saved_AM_LDFLAGS="$AM_LDFLAGS" if test -n "$szlib_inc"; then CPPFLAGS="$CPPFLAGS -I$szlib_inc" AM_CPPFLAGS="$AM_CPPFLAGS -I$szlib_inc" fi AC_CHECK_HEADERS([szlib.h], [HAVE_SZLIB_H="yes"], [CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"] [unset HAVE_SZLIB]) if test -n "$szlib_lib"; then LDFLAGS="$LDFLAGS -L$szlib_lib" AM_LDFLAGS="$AM_LDFLAGS -L$szlib_lib" fi if test "x$HAVE_SZLIB" = "xyes" -a "x$HAVE_SZLIB_H" = "xyes"; then AC_CHECK_LIB([sz], [SZ_BufftoBuffCompress],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset HAVE_SZLIB]) fi if test -z "$HAVE_SZLIB" -a -n "$HDF5_CONFIG_ABORT"; then AC_MSG_ERROR([couldn't find szlib library]) fi ;; esac if test "x$HAVE_SZLIB" = "xyes" -a "x$HAVE_SZLIB_H" = "xyes"; then ## SZLIB library is available. Check if it can encode AC_MSG_CHECKING([for szlib encoder]) ## Set LD_LIBRARY_PATH so encoder test can find the library and run. ## Also add LL_PATH substitution to Makefiles so they can use the ## path as well, for testing examples. if test -z "$LD_LIBRARY_PATH"; then export LD_LIBRARY_PATH="$szlib_lib" else export LD_LIBRARY_PATH="$szlib_lib:$LD_LIBRARY_PATH" fi AC_SUBST([LL_PATH]) LL_PATH="$LD_LIBRARY_PATH" AC_CACHE_VAL([hdf5_cv_szlib_can_encode], [AC_TRY_RUN([ #include <szlib.h> int main(void) { /* SZ_encoder_enabled returns 1 if encoder is present */ if(SZ_encoder_enabled() == 1) exit(0); else exit(1); } ], [hdf5_cv_szlib_can_encode=yes], [hdf5_cv_szlib_can_encode=no],)]) AC_DEFINE([HAVE_FILTER_SZIP], [1], [Define if support for szip filter is enabled]) USE_FILTER_SZIP="yes" if test ${hdf5_cv_szlib_can_encode} = "yes"; then AC_MSG_RESULT([yes]) fi if test ${hdf5_cv_szlib_can_encode} = "no"; then AC_MSG_RESULT([no]) fi ## Add "szip" to external filter list if test ${hdf5_cv_szlib_can_encode} = "yes"; then if test "X$EXTERNAL_FILTERS" != "X"; then EXTERNAL_FILTERS="${EXTERNAL_FILTERS}," fi EXTERNAL_FILTERS="${EXTERNAL_FILTERS}szip(encoder)" fi if test ${hdf5_cv_szlib_can_encode} = "no"; then if test "X$EXTERNAL_FILTERS" != "X"; then EXTERNAL_FILTERS="${EXTERNAL_FILTERS}," fi EXTERNAL_FILTERS="${EXTERNAL_FILTERS}szip(no encoder)" fi fi AM_CONDITIONAL([BUILD_SHARED_SZIP_CONDITIONAL], [test "X$USE_FILTER_SZIP" = "Xyes" && test "X$LL_PATH" != "X"]) ## Checkpoint the cache AC_CACHE_SAVE ## ---------------------------------------------------------------------- ## Enable thread-safe version of library. It requires Pthreads support ## on POSIX systems. ## AC_MSG_CHECKING([for thread safe support]) AC_ARG_ENABLE([threadsafe], [AS_HELP_STRING([--enable-threadsafe], [Enable thread-safe capability])], [THREADSAFE=$enableval]) ## The --enable-threadsafe flag is not compatible with --enable-cxx. ## If the user tried to specify both flags, throw an error, unless ## they also provided the --enable-unsupported flag. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then if test "X${HDF_CXX}" = "Xyes" -a "X${enable_threadsafe}" = "Xyes"; then AC_MSG_ERROR([--enable-cxx and --enable-threadsafe flags are incompatible. Use --enable-unsupported to override this error.]) fi fi ## --enable-threadsafe is also incompatible with --enable-fortran, unless ## --enable-unsupported has been specified on the configure line. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then if test "X${HDF_FORTRAN}" = "Xyes" -a "X${enable_threadsafe}" = "Xyes"; then AC_MSG_ERROR([--enable-fortran and --enable-threadsafe flags are incompatible. Use --enable-unsupported to override this error.]) fi fi case "X-$THREADSAFE" in X-|X-no) AC_MSG_RESULT([no]) ;; X-yes) THREADSAFE=yes AC_MSG_RESULT([yes]) ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([\'$enableval\' is not a valid threadsafe type]) ;; esac if test "X$THREADSAFE" = "Xyes"; then AC_DEFINE([HAVE_THREADSAFE], [1], [Define if we have thread safe support]) ## ---------------------------------------------------------------------- ## Is the pthreads library present? It has a header file `pthread.h' and ## a library `-lpthread' and their locations might be specified with the ## `--with-pthread' command-line switch. The value is an include path ## and/or a library path. If the library path is specified then it must ## be preceded by a comma. ## ## Thread-safety in HDF5 only uses Pthreads via configure, so the ## default is "yes", though this only has an effect when ## --enable-threadsafe is specified. AC_SUBST([HAVE_PTHREAD]) HAVE_PTHREAD=yes AC_ARG_WITH([pthread], [AS_HELP_STRING([--with-pthread=DIR], [Specify alternative path to Pthreads library when thread-safe capability is built])],, [withval=yes]) case "$withval" in yes) AC_CHECK_HEADERS([pthread.h],, [unset HAVE_PTHREAD]) if test "x$HAVE_PTHREAD" = "xyes"; then AC_CHECK_LIB([pthread], [pthread_self],, [unset HAVE_PTHREAD]) fi ;; no) AC_MSG_CHECKING([for pthread]) AC_MSG_RESULT([suppressed]) unset HAVE_PTHREAD ;; *) case "$withval" in *,*) pthread_inc="`echo $withval | cut -f1 -d,`" pthread_lib="`echo $withval | cut -f2 -d, -s`" ;; *) if test -n "$withval"; then pthread_inc="$withval/include" pthread_lib="$withval/lib" fi ;; esac ## Trying to include -I/usr/include and -L/usr/lib is redundant and ## can mess some compilers up. if test "X$pthread_inc" = "X/usr/include"; then pthread_inc="" fi if test "X$pthread_lib" = "X/usr/lib"; then pthread_lib="" fi if test -n "$pthread_inc"; then saved_CPPFLAGS="$CPPFLAGS" saved_AM_CPPFLAGS="$AM_CPPFLAGS" CPPFLAGS="$CPPFLAGS -I$pthread_inc" AM_CPPFLAGS="$AM_CPPFLAGS -I$pthread_inc" AC_CHECK_HEADERS([pthread.h],, [CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"; unset HAVE_PTHREAD]) else AC_CHECK_HEADERS([pthread.h],, [unset HAVE_PTHREAD]) fi if test "x$HAVE_PTHREAD" = "xyes"; then if test -n "$pthread_lib"; then saved_LDFLAGS="$LDFLAGS" saved_AM_LDFLAGS="$AM_LDFLAGS" LDFLAGS="$LDFLAGS -L$pthread_lib" AM_LDFLAGS="$AM_LDFLAGS -L$pthread_lib" AC_CHECK_LIB([pthread], [pthread_self],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset HAVE_PTHREAD]) else AC_CHECK_LIB([pthread], [pthread_self],, [unset HAVE_PTHREAD]) fi fi ;; esac fi ## ---------------------------------------------------------------------- ## Check for MONOTONIC_TIMER support (used in clock_gettime). This has ## to be done after any POSIX/BSD defines to ensure that the test gets ## the correct POSIX level on linux. AC_CHECK_DECL([CLOCK_MONOTONIC],[have_clock_monotonic="yes"],[have_clock_monotonic="no"],[[#include <time.h>]]) ## ---------------------------------------------------------------------- ## How does one figure out the local time zone? Anyone know of a ## Posix way to do this? ## ## First check if `struct tm' has a `tm_gmtoff' member. AC_MSG_CHECKING([for tm_gmtoff in struct tm]) AC_TRY_COMPILE([ #include <sys/time.h> #include <time.h>], [struct tm tm; tm.tm_gmtoff=0;], [AC_DEFINE([HAVE_TM_GMTOFF], [1], [Define if `tm_gmtoff' is a member of `struct tm']) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ## check if `struct tm' has a `__tm_gmtoff' member. AC_MSG_CHECKING([for __tm_gmtoff in struct tm]) AC_TRY_COMPILE([ #include <sys/time.h> #include <time.h>], [struct tm tm; tm.__tm_gmtoff=0;], [AC_DEFINE([HAVE___TM_GMTOFF], [1], [Define if `__tm_gmtoff' is a member of `struct tm']) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ## Check whether the global variable `timezone' is defined. AC_MSG_CHECKING([for global timezone variable]) case "`uname`" in CYGWIN*) AC_MSG_RESULT([disabled in CYGWIN]) ;; *) AC_TRY_LINK([ #include <sys/time.h> #include <time.h>], [timezone=0;], [AC_DEFINE([HAVE_TIMEZONE], [1], [Define if `timezone' is a global variable]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ;; esac ## Check whether `struct timezone' is defined. AC_STRUCT_TIMEZONE AC_MSG_CHECKING([for struct timezone]) AC_TRY_COMPILE([ #include <sys/types.h> #include <sys/time.h> #include <time.h>], [struct timezone tz; tz.tz_minuteswest=0;], [AC_DEFINE([HAVE_STRUCT_TIMEZONE], [1], [Define if `struct timezone' is defined]) have_struct_tz="yes" AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ## If gettimeofday() is going to be used, make sure it uses the timezone struct if test "$have_gettime" = "yes" -a "$have_struct_tz" = "yes"; then AC_MSG_CHECKING(whether gettimeofday() gives timezone) AC_CACHE_VAL([hdf5_cv_gettimeofday_tz], [AC_TRY_RUN([ #include <time.h> #include <sys/time.h> int main(void) { struct timeval tv; struct timezone tz; tz.tz_minuteswest = 7777; /* Initialize to an unreasonable number */ tz.tz_dsttime = 7; gettimeofday(&tv, &tz); /* Check whether the function returned any value at all */ if(tz.tz_minuteswest == 7777 && tz.tz_dsttime == 7) exit(1); else exit (0); }], [hdf5_cv_gettimeofday_tz=yes], [hdf5_cv_gettimeofday_tz=no])]) if test ${hdf5_cv_gettimeofday_tz} = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE([GETTIMEOFDAY_GIVES_TZ], [1], [Define if gettimeofday() populates the tz pointer passed in]) else AC_MSG_RESULT([no]) fi fi ## ---------------------------------------------------------------------- ## Does the struct stat have the st_blocks field? This field is not Posix. ## AC_MSG_CHECKING([for st_blocks in struct stat]) AC_TRY_COMPILE([ #include <sys/stat.h>],[struct stat sb; sb.st_blocks=0;], [AC_DEFINE([HAVE_STAT_ST_BLOCKS], [1], [Define if `struct stat' has the `st_blocks' field]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ## ---------------------------------------------------------------------- ## How do we figure out the width of a tty in characters? ## AC_CHECK_FUNCS([_getvideoconfig gettextinfo]) case "`uname`" in CYGWIN*) ;; *) AC_CHECK_FUNCS([GetConsoleScreenBufferInfo]) ;; esac AC_CHECK_FUNCS([_scrsize ioctl]) AC_MSG_CHECKING([for struct videoconfig]) AC_TRY_COMPILE(,[struct videoconfig w; w.numtextcols=0;], [AC_DEFINE([HAVE_STRUCT_VIDEOCONFIG], [1], [Define if `struct videoconfig' is defined]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_MSG_CHECKING([for struct text_info]) AC_TRY_COMPILE(, [struct text_info w; w.screenwidth=0;], [AC_DEFINE([HAVE_STRUCT_TEXT_INFO], [1], [Define if `struct text_info' is defined]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_MSG_CHECKING([for TIOCGWINSZ]) AC_TRY_COMPILE([#include <sys/ioctl.h>],[int w=TIOCGWINSZ;], [AC_DEFINE([HAVE_TIOCGWINSZ], [1], [Define if the ioctl TIOGWINSZ is defined]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_MSG_CHECKING([for TIOCGETD]) AC_TRY_COMPILE([#include <sys/ioctl.h>],[int w=TIOCGETD;], [AC_DEFINE([HAVE_TIOCGETD], [1], [Define if the ioctl TIOCGETD is defined]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ## ---------------------------------------------------------------------- ## Check for functions. ## AC_CHECK_FUNCS([alarm BSDgettimeofday fork frexpf frexpl]) AC_CHECK_FUNCS([gethostname getpwuid getrusage lstat]) AC_CHECK_FUNCS([rand_r random setsysinfo]) AC_CHECK_FUNCS([signal longjmp setjmp siglongjmp sigsetjmp sigprocmask]) AC_CHECK_FUNCS([snprintf srandom strdup symlink system]) AC_CHECK_FUNCS([tmpfile asprintf vasprintf waitpid]) ## Check for vsnprintf() separately, so we can detect situations where it ## doesn't return the correct size for formatted strings that are too large ## for the buffer provided AC_CHECK_FUNCS([vsnprintf], ## Check if vsnprintf() returns correct size for strings that don't fit ## into the size allowed. If vsnprintf() works correctly on this platform, ## it should return a value of 42 for the test below ## ## Note that vsnprintf fails in two different ways: ## - In IRIX64, calls to vnsprintf() with a formatted string that ## is larger than the buffer size allowed incorrectly ## return the size of the buffer minus one. ## - In HP/UX, calls to vsnprintf() with a formatted string that ## is larger than the buffer size allowed incorrectly ## return (-1) AC_MSG_CHECKING([if vsnprintf returns correct value]) AC_CACHE_VAL([hdf5_cv_vsnprintf_works], AC_TRY_RUN([ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> int test_vsnprintf(const char *fmt,...) { va_list ap; char *s = malloc(16); int ret; va_start(ap, fmt); ret=vsnprintf(s,16,"%s",ap); va_end(ap); return(ret!=42 ? 1 : 0); } int main(void) { exit(test_vsnprintf("%s","A string that is longer than 16 characters")); } ],[hdf5_cv_vsnprintf_works=yes],[hdf5_cv_vsnprintf_works=no],)) if test ${hdf5_cv_vsnprintf_works} = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE([VSNPRINTF_WORKS], [1], [Define if vsnprintf() returns the correct value for formatted strings that don't fit into size allowed]) else AC_MSG_RESULT([no]) fi ,) ## ---------------------------------------------------------------------- ## Check that a lone colon can be used as an argument ## This is not true on Cray X1, which interprets a lone colon as a ## system command. ## AC_CACHE_CHECK([if lone colon can be used as an argument], [hdf5_cv_lone_colon], [ echo "int main(int argc, char * argv[]) {return 0;}" > conftest.c $CC $CFLAGS conftest.c -o a.out> /dev/null 2> /dev/null echo "./a.out :" > conftest.sh chmod 700 conftest.sh ./conftest.sh 2> conftest.out rm -f a.out TEST_OUTPUT=`cat conftest.out` if test "X$TEST_OUTPUT" = "X"; then hdf5_cv_lone_colon=yes else hdf5_cv_lone_colon=no fi ]) AC_SUBST([H5_LONE_COLON]) H5_LONE_COLON="$hdf5_cv_lone_colon" ## ---------------------------------------------------------------------- ## Check compiler characteristics ## AC_C_CONST AC_C_INLINE AC_MSG_CHECKING([for __attribute__ extension]) AC_TRY_COMPILE(,[int __attribute__((unused)) x], [AC_DEFINE([HAVE_ATTRIBUTE], [1], [Define if the __attribute__(()) extension is present]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_MSG_CHECKING([for __func__ extension]) AC_TRY_COMPILE(,[ const char *fname = __func__; ], [AC_DEFINE([HAVE_C99_FUNC], [1], [Define if the compiler understands the __func__ keyword]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_MSG_CHECKING([for __FUNCTION__ extension]) AC_TRY_COMPILE(,[ const char *fname = __FUNCTION__; ], [AC_DEFINE([HAVE_FUNCTION], [1], [Define if the compiler understands the __FUNCTION__ keyword]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_MSG_CHECKING([for C99 designated initialization support]) AC_TRY_COMPILE(,[ typedef struct { int x; union { int i; double d; } u; } di_struct_t; di_struct_t x = {0, { .d = 0.0}}; ], [AC_DEFINE([HAVE_C99_DESIGNATED_INITIALIZER], [1], [Define if the compiler understands C99 designated initialization of structs and unions]) AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) ## ---------------------------------------------------------------------- ## Try to figure out how to print `long long'. Some machines use `%lld' ## and others use `%qd'. There may be more! The final `l' is a ## default in case none of the others work. ## AC_MSG_CHECKING([how to print long long]) AC_CACHE_VAL([hdf5_cv_printf_ll], [ for hdf5_cv_printf_ll in l ll L q unknown; do AC_TRY_RUN([ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char *s = malloc(128); long long x = (long long)1048576 * (long long)1048576; sprintf(s,"%${hdf5_cv_printf_ll}d",x); exit(strcmp(s,"1099511627776")); } ], [break],,[continue]) done]) AC_MSG_RESULT([%${hdf5_cv_printf_ll}d and %${hdf5_cv_printf_ll}u]) AC_DEFINE_UNQUOTED([PRINTF_LL_WIDTH], ["$hdf5_cv_printf_ll"], [Width for printf() for type `long long' or `__int64', use `ll']) ## ---------------------------------------------------------------------- ## Check if pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM) ## is supported on this system ## AC_MSG_CHECKING([Threads support system scope]) AC_CACHE_VAL([hdf5_cv_system_scope_threads], [AC_TRY_RUN([ #if STDC_HEADERS #include <stdlib.h> #include <pthread.h> #endif int main(void) { pthread_attr_t attribute; int ret; pthread_attr_init(&attribute); ret=pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM); exit(ret==0 ? 0 : 1); } ], [hdf5_cv_system_scope_threads=yes], [hdf5_cv_system_scope_threads=no],)]) if test ${hdf5_cv_system_scope_threads} = "yes"; then AC_DEFINE([SYSTEM_SCOPE_THREADS], [1], [Define if your system supports pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM) call.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Turn on debugging by setting compiler flags ## This must come after the enable-production since it depends on production. ## AC_MSG_CHECKING([for debug flags]) AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug=all], [Turn on debugging in all packages. One may also specify a comma-separated list of package names without the leading H5 or the word no. The default is most packages if production is disabled; no if it is enabled. ])], [DEBUG_PKG=$enableval]) ## Default to no if producton is enabled if test "X-$DEBUG_PKG" = X- ; then if test "$enable_production" = yes ; then DEBUG_PKG=no else DEBUG_PKG=yes fi fi AC_SUBST([DEBUG_PKG]) all_packages="ac,b,b2,d,e,f,g,hg,hl,i,mf,mm,o,p,s,t,v,z" case "X-$DEBUG_PKG" in X-yes) DEBUG_PKG="d,e,f,g,hg,i,mm,o,p,s,t,v,z" H5_CPPFLAGS="$H5_CPPFLAGS -UNDEBUG" AC_MSG_RESULT([default ($DEBUG_PKG)]) ;; X-all) DEBUG_PKG=$all_packages H5_CPPFLAGS="$H5_CPPFLAGS -UNDEBUG" AC_MSG_RESULT([all ($DEBUG_PKG)]) ;; X-no|X-none) AC_MSG_RESULT([none]) DEBUG_PKG= H5_CPPFLAGS="$H5_CPPFLAGS -DNDEBUG" ;; *) AC_MSG_RESULT([$DEBUG_PKG]) ;; esac if test -n "$DEBUG_PKG"; then for pkg in `echo $DEBUG_PKG | ${TR} ${as_cr_letters}"," ${as_cr_LETTERS}" "`; do H5_CPPFLAGS="$H5_CPPFLAGS -DH5${pkg}_DEBUG" done fi ## ---------------------------------------------------------------------- ## Check if they would like the function stack support compiled in ## AC_MSG_CHECKING([whether function stack tracking is enabled]) AC_ARG_ENABLE([codestack], [AS_HELP_STRING([--enable-codestack], [Enable the function stack tracing (for developer debugging).])], [CODESTACK=$enableval]) case "X-$CODESTACK" in X-yes) CODESTACK=yes AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_CODESTACK], [1], [Define if the function stack tracing code is to be compiled in]) ;; *) CODESTACK=no AC_MSG_RESULT([no]) ;; esac ## ---------------------------------------------------------------------- ## Check if they would like the metadata trace file code compiled in ## AC_MSG_CHECKING([whether metadata trace file code is enabled]) AC_ARG_ENABLE([metadata-trace-file], [AS_HELP_STRING([--enable-metadata-trace-file], [Enable metadata trace file collection.])], [METADATATRACEFILE=$enableval]) case "X-$METADATATRACEFILE" in X-yes) METADATATRACEFILE=yes AC_MSG_RESULT([yes]) AC_DEFINE([METADATA_TRACE_FILE], [1], [Define if the metadata trace file code is to be compiled in]) ;; *) METADATATRACEFILE=no AC_MSG_RESULT([no]) ;; esac ## ---------------------------------------------------------------------- ## Enable tracing of the API ## This must come after the enable-debug since it depends on debug. ## AC_SUBST([TRACE_API]) AC_MSG_CHECKING([for API tracing]); AC_ARG_ENABLE([trace], [AS_HELP_STRING([--enable-trace], [Enable API tracing capability. Default=no if debug is disabled.])], [TRACE=$enableval]) ## Default to no if debug is disabled if test "X-$TRACE" = X- ; then if test -z "$DEBUG_PKG" ; then TRACE=no else TRACE=yes fi fi case "X-$TRACE" in X-yes) AC_MSG_RESULT([yes]) TRACE_API=yes H5_CPPFLAGS="$H5_CPPFLAGS -DH5_DEBUG_API" ;; X-no|*) AC_MSG_RESULT([no]) TRACE_API=no H5_CPPFLAGS="$H5_CPPFLAGS -UH5_DEBUG_API" ;; esac ## ---------------------------------------------------------------------- ## Enable instrumenting of the library's internal operations ## This must come after the enable-debug since it depends on debug. ## AC_SUBST([INSTRUMENT_LIBRARY]) AC_MSG_CHECKING([for instrumented library]); AC_ARG_ENABLE([instrument], [AS_HELP_STRING([--enable-instrument], [Enable library instrumentation of optimization tracing. Default=no if debug is disabled.])], [INSTRUMENT=$enableval]) ## Default to no if debug is disabled if test "X-$INSTRUMENT" = X- ; then if test -z "$DEBUG_PKG" ; then INSTRUMENT=no else INSTRUMENT=yes fi fi case "X-$INSTRUMENT" in X-yes) AC_MSG_RESULT([yes]) INSTRUMENT_LIBRARY=yes AC_DEFINE([HAVE_INSTRUMENTED_LIBRARY], [1], [Define if library will contain instrumentation to detect correct optimization operation]) ;; X-no|*) AC_MSG_RESULT([no]) INSTRUMENT_LIBRARY=no ;; esac ## ---------------------------------------------------------------------- ## Check if they would like to securely clear file buffers before they are ## written. ## AC_SUBST([CLEARFILEBUF]) AC_MSG_CHECKING([whether to clear file buffers]) AC_ARG_ENABLE([clear-file-buffers], [AS_HELP_STRING([--enable-clear-file-buffers], [Securely clear file buffers before writing to file. Default=yes.])], [CLEARFILEBUF=$enableval]) case "X-$CLEARFILEBUF" in *) CLEARFILEBUF=yes AC_MSG_RESULT([yes]) AC_DEFINE([CLEAR_MEMORY], [1], [Define if the memory buffers being written to disk should be cleared before writing.]) ;; X-no) CLEARFILEBUF=no AC_MSG_RESULT([no]) ;; esac ## ---------------------------------------------------------------------- ## Check if they would like to use a memory checking tool (like valgrind's ## 'memcheck' tool, or Rational Purify, etc) and the library should be ## more scrupulous with it's memory operations. Enabling this also ## disables the library's free space manager code. ## AC_SUBST([USINGMEMCHECKER]) AC_MSG_CHECKING([whether a memory checking tool will be used]) AC_ARG_ENABLE([using-memchecker], [AS_HELP_STRING([--enable-using-memchecker], [Enable this option if a memory allocation and/or bounds checking tool will be used on the HDF5 library. Enabling this causes the library to be more picky about it's memory operations and also disables the library's free space manager code. Default=no.])], [USINGMEMCHECKER=$enableval]) case "X-$USINGMEMCHECKER" in X-yes) USINGMEMCHECKER=yes AC_MSG_RESULT([yes]) AC_DEFINE([USING_MEMCHECKER], [1], [Define if a memory checking tool will be used on the library, to cause library to be very picky about memory operations and also disable the internal free list manager code.]) ;; *) USINGMEMCHECKER=no AC_MSG_RESULT([no]) ;; esac ## Checkpoint the cache AC_CACHE_SAVE ## What header files and libraries do we have to look for for parallel ## support? For the most part, search paths are already specified with ## CPPFLAGS and LDFLAGS or are known to the compiler. If the user says ## `--disable-parallel' but specifies a known parallel compiler (like mpicc ## or mpcc) then parallel support is enabled but configure doesn't search ## for any parallel header files or libraries. ## AC_ARG_ENABLE([parallel], [AS_HELP_STRING([--enable-parallel], [Search for MPI-IO and MPI support files])]) ## The --enable-parallel flag is not compatible with --enable-cxx. ## If the user tried to specify both flags, throw an error, unless ## they also provided the --enable-unsupported flag. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then if test "X${HDF_CXX}" = "Xyes" -a "X${enable_parallel}" = "Xyes"; then AC_MSG_ERROR([--enable-cxx and --enable-parallel flags are incompatible. Use --enable-unsupported to override this error.]) fi fi ## --enable-parallel is also incompatible with --enable-threadsafe, unless ## --enable-unsupported has been specified on the configure line. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then if test "X${THREADSAFE}" = "Xyes" -a "X${enable_parallel}" = "Xyes"; then AC_MSG_ERROR([--enable-threadsafe and --enable-parallel flags are incompatible. Use --enable-unsupported to override this error.]) fi fi ## It's possible to build in parallel by specifying a parallel compiler ## without using the --enable-parallel flag. This isn't allowed with ## C++ or threadsafe, either, unless the --enable-unsupported flag ## has also been specified. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then if test "X${PARALLEL}" != "X" -a "X${enable_cxx}" = "Xyes" ; then AC_MSG_ERROR([An MPI compiler is being used; --enable-cxx is not allowed. Use --enable-unsupported to override this error.]) fi if test "X${PARALLEL}" != "X" -a "X${THREADSAFE}" = "Xyes"; then AC_MSG_ERROR([An MPI compiler is being used; --enable-threadsafe is not allowed. Use --enable-unsupported to override this error.]) fi fi AC_MSG_CHECKING([for parallel support files]) case "X-$enable_parallel" in X-|X-no|X-none) ## Either we are not compiling for parallel or the header and ## library files and locations are known to the compiler (this is ## the case for a correct installation of mpicc for instance). AC_MSG_RESULT([skipped]) ;; X-yes) ## We want to compile a parallel library with a compiler that ## may already know how to link with MPI and MPI-IO. AC_MSG_RESULT([provided by compiler]) PARALLEL=yes ## Try link a simple MPI program. If fail, try again with -lmpi and ## -lmpich. AC_TRY_LINK(, [MPI_Init()],, [AC_CHECK_LIB([mpi], [MPI_Init],, [AC_CHECK_LIB([mpich], [MPI_Init],, [PARALLEL=no])])]) ## Then try link a simple MPI-IO program. If fail, try again with ## -lmpio. if test "X$PARALLEL" = "Xyes"; then AC_TRY_LINK(, [MPI_File_open()],, [AC_CHECK_LIB([mpio], [MPI_File_open],, [PARALLEL=no])]) fi if test "X$HDF_FORTRAN" = "Xyes"; then ## Change to the Fortran 90 language AC_LANG_PUSH(Fortran) ## Try link a simple MPI program. If fail, try again with -lmpi. AC_LINK_IFELSE([ program main include 'mpif.h' integer:: ierr call mpi_file_open( ierr ) end],, [AC_CHECK_LIB([mpi], [mpi_file_open],, [PARALLEL=no])]) ## Then try link a simple MPI-IO program. If fail, try again with ## -lmpio. if test "X$PARALLEL" = "Xyes"; then AC_LINK_IFELSE([ program main include 'mpif.h' integer:: ierr call mpi_file_open( ierr ) end],, [AC_CHECK_LIB([mpio], [mpi_file_open],, [PARALLEL=no])]) fi ## Change to the C language AC_LANG_POP(Fortran) fi ## Set RUNPARALLEL to mpiexec if not set yet. ## Check for building on Cray if RUNPARALLEL is not yet set by checking ## for 'aprun' command (which is the parallel job launcher, like mpiexec). if test "X$PARALLEL" = "Xyes" -a -z "$RUNPARALLEL"; then ## Find the path where aprun is located. for path in `echo $PATH | ${TR} ":" " "`; do if test -x $path/aprun; then RUNPARALLEL="aprun -q -n \$\${NPROCS:=6}" break; fi done fi ## Set RUNPARALLEL to mpiexec if not set yet. if test "X$PARALLEL" = "Xyes" -a -z "$RUNPARALLEL"; then RUNPARALLEL="mpiexec -n \$\${NPROCS:=6}" fi ;; *) AC_MSG_RESULT([error]) AC_MSG_ERROR([\'$enable_parallel\' is not a valid parallel search type]) ;; esac ## ---------------------------------------------------------------------- ## Print some other parallel information and do some sanity checks. ## AC_SUBST([ADD_PARALLEL_FILES]) ADD_PARALLEL_FILES="no" if test -n "$PARALLEL"; then ## The 'testpar' directory should participate in the build TESTPARALLEL=testpar ## We are building a parallel library AC_DEFINE([HAVE_PARALLEL], [1], [Define if we have parallel support]) ## Display what we found about running programs AC_MSG_CHECKING([prefix for running on one processor]) AC_MSG_RESULT([$RUNSERIAL]) AC_MSG_CHECKING([prefix for running in parallel]) AC_MSG_RESULT([$RUNPARALLEL]) ## Check that we can link a simple MPI and MPI-IO application AC_MSG_CHECKING([whether a simple MPI-IO program can be linked]) AC_TRY_LINK(, [MPI_Init(); MPI_File_open();], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([unable to link a simple MPI-IO application])]) ## There *must* be some way to run in parallel even if it's just the ## word `none'. if test -z "$RUNPARALLEL"; then AC_MSG_ERROR([no way to run a parallel program]) fi ## If RUNSERIAL or RUNPARALLEL is the word `none' then replace it with ## the empty string. if test "X$RUNSERIAL" = "Xnone"; then RUNSERIAL="" fi if test "X$RUNPARALLEL" = "Xnone"; then RUNPARALLEL="" fi if test "X$HDF_FORTRAN" = "Xyes"; then ADD_PARALLEL_FILES="yes" AC_MSG_CHECKING([for MPI_Comm_c2f and MPI_Comm_f2c functions]) AC_TRY_LINK([#include <mpi.h>], [MPI_Comm c_comm; MPI_Comm_c2f(c_comm)], AC_DEFINE([HAVE_MPI_MULTI_LANG_Comm], [1], [Define if `MPI_Comm_c2f' and `MPI_Comm_f2c' exists]) AC_MSG_RESULT([yes]), AC_MSG_RESULT([no]) ) AC_MSG_CHECKING([for MPI_Info_c2f and MPI_Info_f2c functions]) AC_TRY_LINK([#include <mpi.h>], [MPI_Info c_info; MPI_Info_c2f(c_info)], AC_DEFINE([HAVE_MPI_MULTI_LANG_Info], [1], [Define if `MPI_Info_c2f' and `MPI_Info_f2c' exists]) AC_MSG_RESULT([yes]), AC_MSG_RESULT([no]) ) fi ## -------------------------------------------------------------------- ## Do we want MPE instrumentation feature on? ## ## This must be done after enable-parallel is checked since it depends ## on a mpich compiler. ## MPE=yes AC_ARG_WITH([mpe], [AS_HELP_STRING([--with-mpe=DIR], [Use MPE instrumentation [default=no]])],, [withval=no]) case "X-$withval" in X-|X-no|X-none) AC_MSG_CHECKING([for MPE]) AC_MSG_RESULT([suppressed]) unset MPE ;; X-yes) AC_CHECK_HEADERS([mpe.h],, [unset MPE]) AC_CHECK_LIB([mpe], [MPE_Init_log],, [unset MPE]) AC_CHECK_LIB([lmpe], [MPE_Init_mpi_io],, [unset MPE]) ;; *) case "$withval" in *,*) mpe_inc="`echo $withval | cut -f1 -d,`" mpe_lib="`echo $withval | cut -f2 -d, -s`" ;; *) if test -n "$withval"; then mpe_inc="$withval/include" mpe_lib="$withval/lib" fi ;; esac ## Trying to include -I/usr/include and -L/usr/lib is redundant and ## can mess some compilers up. if test "X$mpe_inc" = "X/usr/include"; then mpe_inc="" fi if test "X$mpe_lib" = "X/usr/lib"; then mpe_lib="" fi if test -n "$mpe_inc"; then saved_CPPFLAGS="$CPPFLAGS" saved_AM_CPPFLAGS="$AM_CPPFLAGS" CPPFLAGS="$CPPFLAGS -I$mpe_inc" AM_CPPFLAGS="$AM_CPPFLAGS -I$mpe_inc" AC_CHECK_HEADERS([mpe.h],, [CPPFLAGS="$saved_CPPFLAGS"; AM_CPPFLAGS="$saved_AM_CPPFLAGS"; unset MPE]) else AC_CHECK_HEADERS([mpe.h],, [unset MPE]) fi if test -n "$mpe_lib"; then saved_LDFLAGS="$LDFLAGS" saved_AM_LDFLAGS="$AM_LDFLAGS" LDFLAGS="$LDFLAGS -L$mpe_lib" AM_LDFLAGS="$AM_LDFLAGS -L$mpe_lib" AC_CHECK_LIB([mpe], [MPE_Init_log],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset MPE]) AC_CHECK_LIB([lmpe], [MPE_Init_mpi_io],, [LDFLAGS="$saved_LDFLAGS"; AM_LDFLAGS="$saved_AM_LDFLAGS"; unset MPE]) else AC_CHECK_LIB([mpe], [MPE_Init_log],, [unset MPE]) AC_CHECK_LIB([lmpe], [MPE_Init_mpi_io],, [unset MPE]) fi ;; esac if test "X-$MPE" = "X-yes"; then AC_DEFINE([HAVE_MPE], [1], [Define if we have MPE support]) fi fi ## ---------------------------------------------------------------------- ## Turn on internal I/O filters by setting macros in header files ## Internal I/O filters are contained entirely within the library and do ## not depend on external headers or libraries. The shuffle filter is ## an example of an internal filter, while the gzip filter is an example of ## an external filter. Each external filter is controlled with an ## "--with-foo=" configure flag. ## AC_SUBST([FILTERS]) AC_SUBST([USE_FILTER_SHUFFLE]) USE_FILTER_SHUFFLE="no" AC_SUBST([USE_FILTER_FLETCHER32]) USE_FILTER_FLETCHER32="no" AC_SUBST([USE_FILTER_NBIT]) USE_FILTER_NBIT="no" AC_SUBST([USE_FILTER_SCALEOFFSET]) USE_FILTER_SCALEOFFSET="no" AC_MSG_CHECKING([for I/O filters]) AC_ARG_ENABLE([filters], [AS_HELP_STRING([--enable-filters=all], [Turn on all internal I/O filters. One may also specify a comma-separated list of filters or the word no. The default is all internal I/O filters.])], [FILTERS=$enableval]) ## Eventually: all_filters="shuffle,foo,bar,baz" all_filters="shuffle,fletcher32,nbit,scaleoffset" case "X-$FILTERS" in X-|X-all) FILTERS=$all_filters AC_MSG_RESULT([all ($FILTERS)]) ;; X-no|X-none) AC_MSG_RESULT([none]) FILTERS="none" ;; *) AC_MSG_RESULT([$FILTERS]) ;; esac if test -n "$FILTERS"; then for filter in `echo $FILTERS | tr ${as_cr_letters}',' ${as_cr_LETTERS}' '`; do ## ------------------------------------------------------------------ ## Have to use separate 'if' construct for each filter, so that ## autoheader can detect the AC_DEFINE for each one... ## if test $filter = "SHUFFLE"; then AC_DEFINE([HAVE_FILTER_SHUFFLE], [1], [Define if support for shuffle filter is enabled]) USE_FILTER_SHUFFLE="yes" fi if test $filter = "FLETCHER32"; then AC_DEFINE([HAVE_FILTER_FLETCHER32], [1], [Define if support for Fletcher32 checksum is enabled]) USE_FILTER_FLETCHER32="yes" fi if test $filter = "NBIT"; then AC_DEFINE([HAVE_FILTER_NBIT], [1], [Define if support for nbit filter is enabled]) USE_FILTER_NBIT="yes" fi if test $filter = "SCALEOFFSET"; then AC_DEFINE([HAVE_FILTER_SCALEOFFSET], [1], [Define if support for scaleoffset filter is enabled]) USE_FILTER_SCALEOFFSET="yes" fi done fi ## ---------------------------------------------------------------------- ## This is defined only when we're using CodeWarrior, since it has a ## broken "open()" call. # if test 1 = 2; then AC_DEFINE([NO_SHARED_WRITING], [1], [Define if shared writing must be disabled (CodeWarrior only)]) fi ## -------------------------------------------------------------------------- ## Should the Default Virtual File Driver be compiled? ## AC_MSG_CHECKING([for Default Virtual File Driver definition]) AC_ARG_WITH([default-vfd], [AS_HELP_STRING([--with-default-vfd=driver], [Specify default file driver [default=sec2]])],, withval=sec2) if test "X$withval" = "Xsec2"; then AC_MSG_RESULT([yes]) default_vfd=yes vfd_define=H5FD_SEC2 elif test "X$withval" = "Xstdio"; then AC_MSG_RESULT([yes]) default_vfd=yes vfd_define=H5FD_STDIO else AC_MSG_RESULT([no]) default_vfd=no fi if test "X$default_vfd" = "Xyes"; then AC_DEFINE_UNQUOTED([DEFAULT_VFD], [$vfd_define], [Define the default virtual file driver to compile]) fi ## ---------------------------------------------------------------------- ## Check if Direct I/O driver is enabled by --enable-direct-vfd ## AC_MSG_CHECKING([for Direct Virtual File Driver support]) AC_ARG_ENABLE([direct-vfd], [AS_HELP_STRING([--enable-direct-vfd], [Build the Direct I/O Virtual File Driver [default=yes]])], [DIRECT_VFD=$enableval], [DIRECT_VFD=yes]) if test "$DIRECT_VFD" = "yes"; then AC_CACHE_VAL([hdf5_cv_direct_io], [AC_TRY_RUN([ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(void) { int fid; if((fid=open("tst_file", O_CREAT | O_TRUNC | O_DIRECT, 0755))<0) exit(1); close(fid); remove("tst_file"); exit (0); }], [AC_TRY_LINK(, [posix_memalign()], [hdf5_cv_direct_io=yes], [hdf5_cv_direct_io=no])], [hdf5_cv_direct_io=no],)]) if test ${hdf5_cv_direct_io} = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_DIRECT], [1], [Define if the direct I/O virtual file driver should be compiled]) else AC_MSG_RESULT([no]) DIRECT_VFD=no fi else AC_MSG_RESULT([suppressed]) fi AM_CONDITIONAL([DIRECT_VFD_CONDITIONAL], [test "X$DIRECT_VFD" = "Xyes"]) ## ---------------------------------------------------------------------- ## Enable custom plugin default path for library. It requires SHARED support. ## AC_MSG_CHECKING([for custom plugin default path definition]) AC_ARG_WITH([default-plugindir], [AS_HELP_STRING([--with-default-plugindir=location], [Specify default location for plugins [default="/usr/local/hdf5/lib/plugin"]])],, withval="/usr/local/hdf5/lib/plugin") if test "X$withval" = "X"; then AC_MSG_RESULT([default]) default_plugindir="/usr/local/hdf5/lib/plugin" else AC_MSG_RESULT([$withval]) default_plugindir=$withval fi AC_DEFINE_UNQUOTED([DEFAULT_PLUGINDIR], ["$default_plugindir"], [Define the default plugins path to compile]) ## ---------------------------------------------------------------------- ## Decide whether the presence of user's exception handling functions is ## checked and data conversion exceptions are returned. This is mainly ## for the speed optimization of hard conversions. Soft conversions can ## actually benefit little. ## AC_MSG_CHECKING([whether exception handling functions is checked during data conversions]) AC_ARG_ENABLE([dconv-exception], [AS_HELP_STRING([--enable-dconv-exception], [if exception handling functions is checked during data conversions [default=yes]])], [DCONV_EXCEPTION=$enableval], [DCONV_EXCEPTION=yes]) if test "$DCONV_EXCEPTION" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE([WANT_DCONV_EXCEPTION], [1], [Check exception handling functions during data conversions]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Decide whether the data accuracy has higher priority during data ## conversions. If not, some hard conversions will still be prefered even ## though the data may be wrong (for example, some compilers don't ## support denormalized floating values) to maximize speed. ## AC_MSG_CHECKING([whether data accuracy is guaranteed during data conversions]) AC_ARG_ENABLE([dconv-accuracy], [AS_HELP_STRING([--enable-dconv-accuracy], [if data accuracy is guaranteed during data conversions [default=yes]])], [DATA_ACCURACY=$enableval], [DATA_ACCURACY=yes]) if test "$DATA_ACCURACY" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE([WANT_DATA_ACCURACY], [1], [Data accuracy is prefered to speed during data conversions]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can handle converting ## denormalized floating-point values. ## (This flag should be set for all machines, except for the Crays, where ## the cache value is set in it's config file) ## AC_MSG_CHECKING([if converting denormalized floating-point values is possible]) AC_CACHE_VAL([hdf5_cv_convert_denormal_float], [hdf5_cv_convert_denormal_float=yes]) if test ${hdf5_cv_convert_denormal_float} = "yes"; then AC_DEFINE([CONVERT_DENORMAL_FLOAT], [1], [Define if your system can handle converting denormalized floating-point values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can handle converting ## floating-point to long long values. ## (This flag should be _unset_ for all machines, except for Windows, where ## it's set in the custom Windows H5pubconf.h file) ## AC_MSG_CHECKING([if converting floating-point values to long long is not working]) AC_CACHE_VAL([hdf5_cv_convert_float_llong_not_works], [hdf5_cv_convert_float_llong_not_works=no]) if test ${hdf5_cv_convert_float_llong_not_works} = "yes"; then AC_DEFINE([HW_FP_TO_LLONG_NOT_WORKS], [1], [Define if your system can't handle converting floating-point values to long long.]) AC_MSG_RESULT([true]) else AC_MSG_RESULT([false]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine has window style pathname, ## that is, "drive-letter:\" (e.g. "C:") or "drive-letter:/" (e.g. "C:/"). ## (This flag should be _unset_ for all machines, except for Windows, where ## it's set in the custom Windows H5pubconf.h file) ## AC_MSG_CHECKING([if the machine has window style path name]) case "`uname`" in MINGW*) AC_DEFINE([HAVE_WINDOW_PATH], [1], [Define if your system has window style path name.]) AC_MSG_RESULT([yes]) ;; *) AC_MSG_RESULT([no]) ;; esac ## ----------------------------------------------------------------------- ## Set flag to indicate that the machine can handle conversion from ## long double to integers accurately. This flag should be set "yes" for ## all machines except all SGIs. For SGIs, some conversions are ## incorrect and its cache value is set "no" in its config/irix6.x and ## irix5.x. ## AC_MSG_CHECKING([if converting from long double to integers is accurate]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_ldouble_to_integer_accurate=${hdf5_cv_ldouble_to_integer_accurate=no} else AC_CACHE_VAL([hdf5_cv_ldouble_to_integer_accurate], [hdf5_cv_ldouble_to_integer_accurate=yes]) fi if test "${hdf5_cv_ldouble_to_integer_accurate}" = "yes"; then AC_DEFINE([LDOUBLE_TO_INTEGER_ACCURATE], [1], [Define if your system can convert long double to integers accurately.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ----------------------------------------------------------------------- ## Set flag to indicate that the machine can do conversion from ## long double to integers regardless of accuracy. This flag should be ## set "yes" for all machines except HP-UX 11.00. For HP-UX 11.00, the ## compiler has 'floating exception' when converting 'long double' to all ## integers except 'unsigned long long'. Other HP-UX systems are unknown ## yet. (1/8/05 - SLU) AC_MSG_CHECKING([if converting from long double to integers works]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_ldouble_to_integer_works=${hdf5_cv_ldouble_to_integer_works=no} else AC_CACHE_VAL([hdf5_cv_ldouble_to_integer_works], [AC_TRY_RUN([ int main(void) { void *align; long double ld= 9701917572145405952.00L; unsigned char v1; short v2; unsigned int v3; int ret = 0; align = (void*)malloc(sizeof(long double)); memcpy(align, &ld, sizeof(long double)); /*For HU-UX11.00, there's floating exception(core dump) when doing some of casting *from 'long double' to integers*/ v1=(unsigned char)(*((long double*)align)); v2=(short)(*((long double*)align)); v3=(unsigned int)(*((long double*)align)); done: exit(ret); } ], [hdf5_cv_ldouble_to_integer_works=yes], [hdf5_cv_ldouble_to_integer_works=no],)]) fi if test ${hdf5_cv_ldouble_to_integer_works} = "yes"; then AC_DEFINE([LDOUBLE_TO_INTEGER_WORKS], [1], [Define if your system can convert from long double to integer values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ----------------------------------------------------------------------- ## Set flag to indicate that the machine can handle conversion from ## integers to long double. (This flag should be set "yes" for all ## machines except all SGIs, where some conversions are ## incorrect and its cache value is set "no" in its config/irix6.x and ## irix5.x) ## AC_MSG_CHECKING([if accurately converting from integers to long double]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_integer_to_ldouble_accurate=${hdf5_cv_integer_to_ldouble_accurate=no} else AC_CACHE_VAL([hdf5_cv_integer_to_ldouble_accurate], [hdf5_cv_integer_to_ldouble_accurate=yes]) fi if test ${hdf5_cv_integer_to_ldouble_accurate} = "yes"; then AC_DEFINE([INTEGER_TO_LDOUBLE_ACCURATE], [1], [Define if your system can accurately convert from integers to long double values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## 'unsigned long' to 'float' values. ## (This flag should be set for all machines, except for Pathscale compiler ## on Sandia's Linux machine where the compiler interprets 'unsigned long' ## values as negative when the first bit of 'unsigned long' is on during ## the conversion to float.) ## AC_MSG_CHECKING([if accurately converting unsigned long to float values]) AC_CACHE_VAL([hdf5_cv_ulong_to_float_accurate], [AC_TRY_RUN([ int main(void) { int ret = 0; unsigned long l1; unsigned long l2; unsigned long l3; float f1; float f2; float f3; if(sizeof(unsigned long)==8) { l1 = 0xffffffffffffffffUL; l2 = 0xffffffffffff0000UL; l3 = 0xf000000000000000UL; f1 = (float)l1; f2 = (float)l2; f3 = (float)l3; if((f1 < 0) || (f2 < 0) || (f3 < 0)) ret = 1; } done: exit(ret); } ], [hdf5_cv_ulong_to_float_accurate=yes], [hdf5_cv_ulong_to_float_accurate=no],)]) if test ${hdf5_cv_ulong_to_float_accurate} = "yes"; then AC_DEFINE([ULONG_TO_FLOAT_ACCURATE], [1], [Define if your system accurately converting unsigned long to float values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## 'unsigned (long) long' values to 'float' and 'double' values. ## (This flag should be set for all machines, except for the SGIs, where ## the cache value is set in the config/irix6.x config file) and Solaris ## 64-bit machines, where the short program below tests if round-up is ## correctly handled. ## AC_MSG_CHECKING([if accurately converting unsigned long long to floating-point values]) if test ${host_os_novers} = "solaris2.x"; then AC_CACHE_VAL([hdf5_cv_ulong_to_fp_bottom_bit_accurate], [AC_TRY_RUN([ int main(void) { unsigned long l1; unsigned long l2; unsigned long l3; unsigned long l4; unsigned long long ld1; unsigned long long ld2; unsigned long long ld3; unsigned long long ld4; double d1, d2, d3, d4; unsigned char s[8]; int ret = 0; if(sizeof(unsigned long)==8) { l1 = 0xf000000000000b00UL; /*Round-down case*/ l2 = 0xf000000000000401UL; /*Round-up case*/ l3 = 0xf000000000000400UL; /*Round-down case*/ l4 = 0xf000000000000c00UL; /*Round-up case*/ d1 = (double)l1; d2 = (double)l2; d3 = (double)l3; d4 = (double)l4; } else if(sizeof(unsigned long long)==8) { ld1 = 0xf000000000000b00ULL; /*Round-down case*/ ld2 = 0xf000000000000401ULL; /*Round-up case*/ ld3 = 0xf000000000000400ULL; /*Round-down case*/ ld4 = 0xf000000000000c00ULL; /*Round-up case*/ d1 = (double)ld1; d2 = (double)ld2; d3 = (double)ld3; d4 = (double)ld4; } else { ret = 1; goto done; } memcpy(s, &d1, 8); if(s[7]!=1) ret = 1; memcpy(s, &d2, 8); if(s[7]!=1) ret = 1; memcpy(s, &d3, 8); if(s[7]!=0) ret = 1; memcpy(s, &d4, 8); if(s[7]!=2) ret = 1; done: exit(ret); } ], [hdf5_cv_ulong_to_fp_bottom_bit_accurate=yes], [hdf5_cv_ulong_to_fp_bottom_bit_accurate=no],)]) else AC_CACHE_VAL([hdf5_cv_ulong_to_fp_bottom_bit_accurate], [hdf5_cv_ulong_to_fp_bottom_bit_accurate=yes]) fi if test ${hdf5_cv_ulong_to_fp_bottom_bit_accurate} = "yes"; then AC_DEFINE([ULONG_TO_FP_BOTTOM_BIT_ACCURATE], [1], [Define if your system can accurately convert unsigned (long) long values to floating-point values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## 'float' or 'double' to 'unsigned long long' values. ## (This flag should be set for all machines, except for PGI compiler ## where round-up happens when the fraction of float-point value is greater ## than 0.5. ## AC_MSG_CHECKING([if accurately roundup converting floating-point to unsigned long long values]) AC_CACHE_VAL([hdf5_cv_fp_to_ullong_accurate], [AC_TRY_RUN([ int main(void) { float f = 111.60f; double d = 222.55L; unsigned long long l1 = (unsigned long long)f; unsigned long long l2 = (unsigned long long)d; int ret = 0; if(l1 == 112) ret = 1; if(l2 == 223) ret = 1; done: exit(ret); } ], [hdf5_cv_fp_to_ullong_accurate=yes], [hdf5_cv_fp_to_ullong_accurate=no],)]) if test ${hdf5_cv_fp_to_ullong_accurate} = "yes"; then AC_DEFINE([FP_TO_ULLONG_ACCURATE], [1], [Define if your system roundup accurately converting floating-point to unsigned long long values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## 'float', 'double' or 'long double' to 'unsigned long long' values. ## (This flag should be set for all machines, except for HP-UX machines ## where the maximal number for unsigned long long is 0x7fffffffffffffff ## during conversion. ## AC_MSG_CHECKING([if right maximum converting floating-point to unsigned long long values]) AC_CACHE_VAL([hdf5_cv_fp_to_ullong_right_maximum], [AC_TRY_RUN([ int main(void) { float f = 9701917572145405952.00f; double d1 = 9701917572145405952.00L; long double d2 = 9701917572145405952.00L; double d3 = 2e40L; unsigned long long l1 = (unsigned long long)f; unsigned long long l2 = (unsigned long long)d1; unsigned long long l3 = (unsigned long long)d2; unsigned long long l4; unsigned long long l5 = 0x7fffffffffffffffULL; int ret = 0; if(l1 <= l5 || l2 <= l5 || l3 <= l5) ret = 1; l4 = (unsigned long long)d3; if(l4 <= l5) ret = 1; done: exit(ret); } ], [hdf5_cv_fp_to_ullong_right_maximum=yes], [hdf5_cv_fp_to_ullong_right_maximum=no],)]) if test ${hdf5_cv_fp_to_ullong_right_maximum} = "yes"; then AC_DEFINE([FP_TO_ULLONG_RIGHT_MAXIMUM], [1], [Define if your system has right maximum convert floating-point to unsigned long long values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## 'long double' to 'unsigned int' values. (This flag should be set for ## all machines, except for some Intel compilers on some Linux.) ## AC_MSG_CHECKING([if correctly converting long double to unsigned int values]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_ldouble_to_uint_accurate=${hdf5_cv_ldouble_to_uint_accurate=no} else AC_CACHE_VAL([hdf5_cv_ldouble_to_uint_accurate], [AC_TRY_RUN([ int main(void) { long double ld = 2733248032.9183987530L; unsigned int i; int ret = 0; i = (unsigned int)ld; if(i!=2733248032 && i!=2733248031 && i!=2733248033) ret = 1; done: exit(ret); } ], [hdf5_cv_ldouble_to_uint_accurate=yes], [hdf5_cv_ldouble_to_uint_accurate=no],)]) fi if test ${hdf5_cv_ldouble_to_uint_accurate} = "yes"; then AC_DEFINE([LDOUBLE_TO_UINT_ACCURATE], [1], [Define if your system can convert long double to unsigned int values correctly.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can _compile_ ## 'unsigned long long' to 'float' and 'double' typecasts. ## (This flag should be set for all machines, except for under Windows when ## compiled with Visual Studio 6, where the macro value is set in the ## src/H5pubconf.h file) ## AC_MSG_CHECKING([if compiling unsigned long long to floating-point typecasts work]) AC_CACHE_VAL([hdf5_cv_ullong_to_fp_cast_works], [hdf5_cv_ullong_to_fp_cast_works=yes]) if test ${hdf5_cv_ullong_to_fp_cast_works} = "yes"; then AC_DEFINE([ULLONG_TO_FP_CAST_WORKS], [1], [Define if your system can compile unsigned long long to floating-point casts.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can _compile_ ## 'long long' to 'float' and 'double' typecasts. ## (This flag should be set for all machines, except for under Windows when ## compiled with Visual Studio 6, where the macro value is set in the ## src/H5pubconf.h file) ## AC_MSG_CHECKING([if compiling long long to floating-point typecasts work]) AC_CACHE_VAL([hdf5_cv_llong_to_fp_cast_works], [hdf5_cv_llong_to_fp_cast_works=yes]) if test ${hdf5_cv_llong_to_fp_cast_works} = "yes"; then AC_DEFINE([LLONG_TO_FP_CAST_WORKS], [1], [Define if your system can compile long long to floating-point casts.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can convert from ## 'unsigned long long' to 'long double' without precision loss. ## (This flag should be set for all machines, except for FreeBSD(sleipnir) ## where the last 2 bytes of mantissa are lost when compiler tries to do ## the conversion, and Cygwin where compiler doesn't do rounding correctly.) ## AC_MSG_CHECKING([if converting unsigned long long to long double with precision]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_ullong_to_ldouble_precision=${hdf5_cv_ullong_to_ldouble_precision=no} else AC_CACHE_VAL([hdf5_cv_ullong_to_ldouble_precision], [AC_TRY_RUN([ #include <stdlib.h> #include <string.h> int main(void) { /* General variables */ int endian; int tst_value = 1; int ret = 0; /* For FreeBSD */ unsigned long long l = 0xa601e80bda85fcefULL; long double ld; unsigned char *c1, *c2; size_t size; /* For Cygwin */ unsigned long long l_cyg = 0xfffffffffffffff0ULL; long double ld_cyg; unsigned char *c2_cyg; size_t size_cyg; /* Determine this system's endianess */ c1 = (unsigned char*)calloc(1, sizeof(int)); memcpy((void*)c1, &tst_value, sizeof(int)); if(c1[0]==1) endian = 0; /* little endian */ else endian = 1; /* big endian */ /* For FreeBSD */ size = sizeof(long double); memset(&ld, 0, size); ld = (long double)l; c2 = (unsigned char*)calloc(1, size); memcpy((void*)c2, &ld, size); /* Test if the last 2 bytes of mantissa are lost. Mainly for FreeBSD on Intel * architecture(sleipnir) where it happens. */ /*if(endian==0 && c2[0]==0 && c2[1]==0)*/ /*little endian*/ if(endian==0 && c2[0]==0) { /*little endian*/ ret = 1; goto done; } /* For Cygwin */ size_cyg = sizeof(long double); memset(&ld_cyg, 0, size); ld_cyg = (long double)l_cyg; c2_cyg = (unsigned char*)calloc(1, size_cyg); memcpy((void*)c2_cyg, &ld_cyg, size_cyg); /* Test if the last 4 bytes(roughly) of mantissa are rounded up. Mainly for Cygwin * where the values like 0xffffffffffffffff, 0xfffffffffffffffe, ..., * 0xfffffffffffff000 ... are rounded up as 0x0000403f8000000000000000 * instead of 0x0000403effffffffffffffff, 0x0000403efffffffffffffffe, ..., * 0x0000403efffffffffffff000 ... */ if(endian==0 && c2_cyg[0]==0 && c2_cyg[1]==0 && c2_cyg[2]==0 && c2_cyg[3]==0) ret = 1; done: if(c1) free(c1); if(c2) free(c2); if(c2_cyg) free(c2_cyg); exit(ret); } ], [hdf5_cv_ullong_to_ldouble_precision=yes], [hdf5_cv_ullong_to_ldouble_precision=no],)]) fi if test ${hdf5_cv_ullong_to_ldouble_precision} = "yes"; then AC_DEFINE([ULLONG_TO_LDOUBLE_PRECISION], [1], [Define if your system can convert unsigned long long to long double with correct precision.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can handle overflow converting ## all floating-point to all integer types. ## (This flag should be set for all machines, except for Cray X1 where ## floating exception is generated when the floating-point value is greater ## than the maximal integer value). ## AC_MSG_CHECKING([if overflows normally converting floating-point to integer values]) AC_CACHE_VAL([hdf5_cv_fp_to_integer_overflow_works], [AC_TRY_RUN([ int main(void) { float f = 2147483648.0f; int i; i = (int)f; done: exit(0); } ], [hdf5_cv_fp_to_integer_overflow_works=yes], [hdf5_cv_fp_to_integer_overflow_works=no],)]) if test ${hdf5_cv_fp_to_integer_overflow_works} = "yes"; then AC_DEFINE([FP_TO_INTEGER_OVERFLOW_WORKS], [1], [Define if your system can handle overflow converting floating-point to integer values.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine is using a special algorithm to convert ## 'long double' to '(unsigned) long' values. (This flag should only be set for ## the IBM Power6 Linux. When the bit sequence of long double is ## 0x4351ccf385ebc8a0bfcc2a3c3d855620, the converted value of (unsigned)long ## is 0x004733ce17af227f, not the same as the library's conversion to 0x004733ce17af2282. ## The machine's conversion gets the correct value. We define the macro and disable ## this kind of test until we figure out what algorithm they use. ## AC_MSG_CHECKING([if using special algorithm to convert long double to (unsigned) long values]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_ldouble_to_long_special=${hdf5_cv_ldouble_to_long_special=no} else AC_CACHE_VAL([hdf5_cv_ldouble_to_long_special], [AC_TRY_RUN([ int main(void) { long double ld = 20041683600089727.779961L; long ll; unsigned long ull; unsigned char s[16]; unsigned char s2[8]; int ret = 1; if(sizeof(long double) == 16 && sizeof(long) == 8) { /*make sure the long double type has 16 bytes in size and * 11 bits of exponent. If it is, *the bit sequence should be like below. It's not *a decent way to check but this info isn't available. */ memcpy(s, &ld, 16); if(s[0]==0x43 && s[1]==0x51 && s[2]==0xcc && s[3]==0xf3 && s[4]==0x85 && s[5]==0xeb && s[6]==0xc8 && s[7]==0xa0 && s[8]==0xbf && s[9]==0xcc && s[10]==0x2a && s[11]==0x3c) { /* Assign the hexadecimal value of long double type. */ s[0]=0x43; s[1]=0x51; s[2]=0xcc; s[3]=0xf3; s[4]=0x85; s[5]=0xeb; s[6]=0xc8; s[7]=0xa0; s[8]=0xbf; s[9]=0xcc; s[10]=0x2a; s[11]=0x3c; s[12]=0x3d; s[13]=0x85; s[14]=0x56; s[15]=0x20; memcpy(&ld, s, 16); ll = (long)ld; memcpy(s2, &ll, 8); /* The library's algorithm converts it to 0x 00 47 33 ce 17 af 22 82 * and gets wrong value 20041683600089730 on the IBM Power6 Linux. * But the IBM Power6 Linux converts it to 0x00 47 33 ce 17 af 22 7f * and gets the correct value 20041683600089727. It uses some special * algorithm. We're going to define the macro and skip the test until * we can figure out how they do it. */ if(s2[0]==0x00 && s2[1]==0x47 && s2[2]==0x33 && s2[3]==0xce && s2[4]==0x17 && s2[5]==0xaf && s2[6]==0x22 && s2[7]==0x7f) ret = 0; ull = (unsigned long)ld; memcpy(s2, &ull, 8); /* The unsigned long is the same as signed long. */ if(s2[0]==0x00 && s2[1]==0x47 && s2[2]==0x33 && s2[3]==0xce && s2[4]==0x17 && s2[5]==0xaf && s2[6]==0x22 && s2[7]==0x7f) ret = 0; } } done: exit(ret); } ], [hdf5_cv_ldouble_to_long_special=yes], [hdf5_cv_ldouble_to_long_special=no],)]) fi if test ${hdf5_cv_ldouble_to_long_special} = "yes"; then AC_DEFINE([LDOUBLE_TO_LONG_SPECIAL], [1], [Define if your system converts long double to (unsigned) long values with special algorithm.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine is using a special algorithm ## to convert some values of '(unsigned) long' to 'long double' values. ## (This flag should be off for all machines, except for IBM Power6 Linux, ## when the bit sequences are 003fff..., 007fff..., 00ffff..., 01ffff..., ## ..., 7fffff..., the compiler uses a unknown algorithm. We define a ## macro and skip the test for now until we know about the algorithm. ## AC_MSG_CHECKING([if using special algorithm to convert (unsigned) long to long double values]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_long_to_ldouble_special=${hdf5_cv_long_to_ldouble_special=no} else AC_CACHE_VAL([hdf5_cv_long_to_ldouble_special], [AC_TRY_RUN([ int main(void) { long double ld; long ll; unsigned long ull; unsigned char s[16]; int flag=0, ret=1; /*Determine if long double has 16 byte in size, 11 bit exponent, and *the bias is 0x3ff */ if(sizeof(long double) == 16) { ld = 1.0L; memcpy(s, &ld, 16); if(s[0]==0x3f && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00) flag = 1; } if(flag==1 && sizeof(long)==8) { ll = 0x003fffffffffffffL; ld = (long double)ll; memcpy(s, &ld, 16); /* The library converts the value to 0x434fffffffffffff8000000000000000. * In decimal it is 18014398509481982.000000, one value short of the original. * The IBM Power6 Linux converts it to 0x4350000000000000bff0000000000000. * The value is correct in decimal. It uses some special * algorithm. We're going to define the macro and skip the test until * we can figure out how they do it. */ if(s[0]==0x43 && s[1]==0x50 && s[2]==0x00 && s[3]==0x00 && s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00 && s[8]==0xbf && s[9]==0xf0 && s[10]==0x00 && s[11]==0x00 && s[12]==0x00 && s[13]==0x00 && s[14]==0x00 && s[15]==0x00) ret = 0; } if(flag==1 && sizeof(unsigned long)==8) { ull = 0xffffffffffffffffUL; ld = (long double)ull; memcpy(s, &ld, 16); /* Use a different value from signed long to test. The problem is the same * for both long and unsigned long. The value is 18446744073709551615. * The library converts the value to 0x43effffffffffffffe000000000000000. * In decimal it's 18446744073709548544.000000, very different from the original. * The IBM Power6 Linux converts it to 0x43f0000000000000bff0000000000000. * The value is correct in decimal. It uses some special * algorithm. We're going to define the macro and skip the test until * we can figure out how they do it. */ if(s[0]==0x43 && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00 && s[8]==0xbf && s[9]==0xf0 && s[10]==0x00 && s[11]==0x00 && s[12]==0x00 && s[13]==0x00 && s[14]==0x00 && s[15]==0x00) ret = 0; } done: exit(ret); } ], [hdf5_cv_long_to_ldouble_special=yes], [hdf5_cv_long_to_ldouble_special=no],)]) fi if test ${hdf5_cv_long_to_ldouble_special} = "yes"; then AC_DEFINE([LONG_TO_LDOUBLE_SPECIAL], [1], [Define if your system can convert (unsigned) long to long double values with special algorithm.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## 'long double' to '(unsigned) long long' values. (This flag should be set for ## all machines, except for Mac OS 10.4 and SGI IRIX64 6.5. When the bit sequence ## of long double is 0x4351ccf385ebc8a0bfcc2a3c..., the values of (unsigned)long long ## start to go wrong on these two machines. Adjusting it higher to ## 0x4351ccf385ebc8a0dfcc... or 0x4351ccf385ebc8a0ffcc... will make the converted ## values wildly wrong. This test detects this wrong behavior and disable the test. ## AC_MSG_CHECKING([if correctly converting long double to (unsigned) long long values]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_ldouble_to_llong_accurate=${hdf5_cv_ldouble_to_llong_accurate=no} else AC_CACHE_VAL([hdf5_cv_ldouble_to_llong_accurate], [AC_TRY_RUN([ int main(void) { long double ld = 20041683600089727.779961L; long long ll; unsigned long long ull; unsigned char s[16]; int ret = 0; if(sizeof(long double) == 16) { /*make sure the long double type is the same as the failing type *which has 16 bytes in size and 11 bits of exponent. If it is, *the bit sequence should be like below. It's not *a decent way to check but this info isn't available. */ memcpy(s, &ld, 16); if(s[0]==0x43 && s[1]==0x51 && s[2]==0xcc && s[3]==0xf3 && s[4]==0x85 && s[5]==0xeb && s[6]==0xc8 && s[7]==0xa0 && s[8]==0xbf && s[9]==0xcc && s[10]==0x2a && s[11]==0x3c) { /*slightly adjust the bit sequence (s[8]=0xdf). The converted *values will go wild on Mac OS 10.4 and IRIX64 6.5.*/ s[0]=0x43; s[1]=0x51; s[2]=0xcc; s[3]=0xf3; s[4]=0x85; s[5]=0xeb; s[6]=0xc8; s[7]=0xa0; s[8]=0xdf; s[9]=0xcc; s[10]=0x2a; s[11]=0x3c; s[12]=0x3d; s[13]=0x85; s[14]=0x56; s[15]=0x20; memcpy(&ld, s, 16); ll = (long long)ld; ull = (unsigned long long)ld; if(ll != 20041683600089728 || ull != 20041683600089728) ret = 1; } } done: exit(ret); } ], [hdf5_cv_ldouble_to_llong_accurate=yes], [hdf5_cv_ldouble_to_llong_accurate=no],)]) fi if test ${hdf5_cv_ldouble_to_llong_accurate} = "yes"; then AC_DEFINE([LDOUBLE_TO_LLONG_ACCURATE], [1], [Define if your system can convert long double to (unsigned) long long values correctly.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine can accurately convert ## '(unsigned) long long' to 'long double' values. (This flag should be set for ## all machines, except for Mac OS 10.4, when the bit sequences are 003fff..., ## 007fff..., 00ffff..., 01ffff..., ..., 7fffff..., the converted values are twice ## as big as they should be. ## AC_MSG_CHECKING([if correctly converting (unsigned) long long to long double values]) if test ${ac_cv_sizeof_long_double} = 0; then hdf5_cv_llong_to_ldouble_correct=${hdf5_cv_llong_to_ldouble_correct=no} else AC_CACHE_VAL([hdf5_cv_llong_to_ldouble_correct], [AC_TRY_RUN([ int main(void) { long double ld; long long ll; unsigned long long ull; unsigned char s[16]; int flag=0, ret=0; /*Determine if long double has 16 byte in size, 11 bit exponent, and *the bias is 0x3ff */ if(sizeof(long double) == 16) { ld = 1.0L; memcpy(s, &ld, 16); if(s[0]==0x3f && s[1]==0xf0 && s[2]==0x00 && s[3]==0x00 && s[4]==0x00 && s[5]==0x00 && s[6]==0x00 && s[7]==0x00) flag = 1; } if(flag==1 && sizeof(long long)==8) { ll = 0x01ffffffffffffffLL; ld = (long double)ll; memcpy(s, &ld, 16); /*Check if the bit sequence is as supposed to be*/ if(s[0]!=0x43 || s[1]!=0x7f || s[2]!=0xff || s[3]!=0xff || s[4]!=0xff || s[5]!=0xff || s[6]!=0xff || s[7]!=0xff || s[8]!=0xf0 || s[9]!=0x00 || s[10]!=0x00 || s[11]!=0x00) ret = 1; } if(flag==1 && sizeof(unsigned long long)==8) { ull = 0x01ffffffffffffffULL; ld = (long double)ull; memcpy(s, &ld, 16); if(s[0]!=0x43 || s[1]!=0x7f || s[2]!=0xff || s[3]!=0xff || s[4]!=0xff || s[5]!=0xff || s[6]!=0xff || s[7]!=0xff || s[8]!=0xf0 || s[9]!=0x00 || s[10]!=0x00 || s[11]!=0x00) ret = 1; } done: exit(ret); } ], [hdf5_cv_llong_to_ldouble_correct=yes], [hdf5_cv_llong_to_ldouble_correct=no],)]) fi if test ${hdf5_cv_llong_to_ldouble_correct} = "yes"; then AC_DEFINE([LLONG_TO_LDOUBLE_CORRECT], [1], [Define if your system can convert (unsigned) long long to long double values correctly.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set the flag to indicate that the machine generates bad code ## for the H5VM_log2_gen() routine in src/H5VMprivate.h ## (This flag should be set to no for all machines, except for SGI IRIX64, ## where the cache value is set to yes in it's config file) ## AC_MSG_CHECKING([if bad code for log2 routine is generated]) AC_CACHE_VAL([hdf5_cv_bad_log2_code_generated], [hdf5_cv_bad_log2_code_generated=no]) if test ${hdf5_cv_bad_log2_code_generated} = "yes"; then AC_DEFINE([BAD_LOG2_CODE_GENERATED], [1], [Define if your system generates wrong code for log2 routine.]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Set some variables for general configuration information to be saved ## and installed with the libraries. ## ## HDF5 version from the first line of the README.txt file. H5_VERSION="`cut -d' ' -f3 $srcdir/README.txt | head -1`" AC_SUBST([H5_VERSION]) ## Configuration date AC_SUBST([CONFIG_DATE]) CONFIG_DATE="`date`" ## User doing the configuration AC_SUBST([CONFIG_USER]) CONFIG_USER="`whoami`@`hostname`" if test -n "$ORGANIZATION"; then CONFIG_USER="$CONFIG_USER at $ORGANIZATION" fi ## Configuration mode (production, development, profile, etc) saved above. AC_SUBST([CONFIG_MODE]) ## Byte sex from the AC_C_BIGENDIAN macro. AC_SUBST([BYTESEX]) if test "X$ac_cv_c_bigendian" = "Xyes"; then BYTESEX="big-endian" else BYTESEX="little-endian" fi if test "X$ac_cv_c_bigendian" = "Xyes"; then WORDS_BIGENDIAN="yes" else WORDS_BIGENDIAN="no" fi AC_SUBST([WORDS_BIGENDIAN]) ## Parallel support? (set above except empty if none) PARALLEL=${PARALLEL:-no} ## Compiler with version information. This consists of the full path ## name of the compiler and the reported version number. AC_SUBST([CC_VERSION]) ## Strip anything that looks like a flag off of $CC CC_NOFLAGS=`echo $CC | sed 's/ -.*//'` if `echo $CC_NOFLAGS | grep ^/ >/dev/null 2>&1`; then CC_VERSION="$CC" else CC_VERSION="$CC"; for x in `echo $PATH | sed -e 's/:/ /g'`; do if test -x $x/$CC_NOFLAGS; then CC_VERSION="$x/$CC" break fi done fi if test -n "$cc_version_info"; then CC_VERSION="$CC_VERSION ( $cc_version_info)" fi AC_SUBST([FC_VERSION]) ## Strip anything that looks like a flag off of $FC FC_NOFLAGS=`echo $FC | sed 's/ -.*//'` if `echo $FC_NOFLAGS | grep ^/ >/dev/null 2>&1`; then FC_VERSION="$FC" else FC_VERSION="$FC"; for x in `echo $PATH | sed -e 's/:/ /g'`; do if test -x $x/$FC_NOFLAGS; then FC_VERSION="$x/$FC" break fi done fi if test -n "$fc_version_info"; then FC_VERSION="$FC_VERSION ( $fc_version_info)" fi AC_SUBST([CXX_VERSION]) ## Strip anything that looks like a flag off of $CXX CXX_NOFLAGS=`echo $CXX | sed 's/ -.*//'` if `echo $CXX_NOFLAGS | grep ^/ >/dev/null 2>&1`; then CXX_VERSION="$CXX" else CXX_VERSION="$FC"; for x in `echo $PATH | sed -e 's/:/ /g'`; do if test -x $x/$CXX_NOFLAGS; then CXX_VERSION="$x/$CXX" break fi done fi if test -n "$cxx_version_info"; then CXX_VERSION="$CXX_VERSION ( $cxx_version_info)" fi ## ---------------------------------------------------------------------- ## Where is the root of the source tree. Give an absolute address so ## we can find it no matter which directory of the distribution is our ## current directory. The built-in pwd fails on some systems, but the ## /bin/pwd version works OK. ## if test -x /bin/pwd; then pwd=/bin/pwd else pwd=pwd fi AC_SUBST([ROOT]) ROOT="`$pwd`" ## ---------------------------------------------------------------------- ## Move any compiler-specific libraries into the main LIBS varaible. ## LIBS="$DEFAULT_LIBS $LIBS" ## ---------------------------------------------------------------------- ## Determine the runtime libraries we may need to include in the ## libtools command so that executables will find the correct dynamic ## libraries. ## AC_SUBST([DYNAMIC_DIRS]) DYNAMIC_DIRS="" if test -n "$AM_LDFLAGS $LDFLAGS"; then for d in $AM_LDFLAGS $LDFLAGS ; do case "$d" in -L*) d="`echo $d | sed -e 's/-L//g'`" case "$d" in .*) ## If the path isn't absolute, make it so by ## prepending the ROOT directory to it. d=${ROOT}/$d ;; esac DYNAMIC_DIRS="-R${d} $DYNAMIC_DIRS" ;; esac done fi if test -n "$AM_CPPFLAGS"; then TEMP_CPPFLAGS="" for d in $AM_CPPFLAGS ; do case "$d" in -I.*) ## If the path isn't absolute, make it so by prepending ## the ROOT directory to it. d="`echo $d | sed -e 's/-I//g'`" d="-I${ROOT}/${d}" ;; esac TEMP_CPPFLAGS="$d $TEMP_CPPFLAGS" done AM_CPPFLAGS=$TEMP_CPPFLAGS fi ## ---------------------------------------------------------------------- ## Check if they would like the High Level library compiled ## AC_SUBST(HL) HL="" ## name of fortran folder inside "hl", if FORTRAN compile is requested AC_SUBST(HL_FOR) HL_FOR="" AC_MSG_CHECKING([if high level library is enabled]) AC_ARG_ENABLE([hl], [AS_HELP_STRING([--enable-hl], [Enable the high level library [default=yes]])], [HDF5_HL=$enableval], [HDF5_HL=yes]) if test "X$HDF5_HL" = "Xyes"; then echo "yes" HL="hl" AC_DEFINE([INCLUDE_HL], [1], [Define if HDF5's high-level library headers should be included in hdf5.h]) ## Check if Fortran's default real is double precision. If it is and HL is being built then configure ## should fail due to bug HDFFV-889. if test "X$FORTRAN_DEFAULT_REALisDBLE" = "Xyes"; then AC_MSG_ERROR([Fortran high-level routines are not supported when the default REAL is DOUBLE PRECISION, use configure option --disable-hl.]) fi else echo "no" fi ## ---------------------------------------------------------------------- ## Some programs shouldn't be built by default (e.g., programs to generate ## data files used by tests, some optional tests). ## Check if they want such programs built anyway. ## AC_MSG_CHECKING([additional programs should be built]) AC_ARG_ENABLE([build-all], [AS_HELP_STRING([--enable-build-all], [Build helper programs that only developers should need [default=no]])], [BUILD_ALL=$enableval], [BUILD_ALL=no]) if test "X$BUILD_ALL" = "Xyes"; then echo "yes" else echo "no" fi AM_CONDITIONAL([BUILD_ALL_CONDITIONAL], [test "X$BUILD_ALL" = "Xyes"]) ## ---------------------------------------------------------------------- ## Enable deprecated public API symbols ## AC_SUBST([DEPRECATED_SYMBOLS]) AC_MSG_CHECKING([if deprecated public symbols are available]); AC_ARG_ENABLE([deprecated-symbols], [AS_HELP_STRING([--enable-deprecated-symbols], [Enable deprecated public API symbols [default=yes]])], [DEPREC_SYMBOLS=$enableval], [DEPREC_SYMBOLS=yes]) case "X-$DEPREC_SYMBOLS" in X-yes) AC_MSG_RESULT([yes]) DEPRECATED_SYMBOLS=yes ;; X-no|*) AC_MSG_RESULT([no]) DEPRECATED_SYMBOLS=no AC_DEFINE([NO_DEPRECATED_SYMBOLS], [1], [Define if deprecated public API symbols are disabled]) ;; esac ## -------------------------------------------------------------------------- ## Which version of the public APIs should the 'base' versioned symbols use? ## AC_SUBST([DEFAULT_API_VERSION]) AC_MSG_CHECKING([which version of public symbols to use by default]) AC_ARG_WITH([default-api-version], [AS_HELP_STRING([--with-default-api-version=(v16|v18|v110)], [Specify default release version of public symbols [default=v110]])],, [withval=v110]) if test "X$withval" = "Xv16"; then AC_MSG_RESULT([v16]) DEFAULT_API_VERSION=v16 AC_DEFINE([USE_16_API_DEFAULT], [1], [Define using v1.6 public API symbols by default]) elif test "X$withval" = "Xv18"; then AC_MSG_RESULT([v18]) DEFAULT_API_VERSION=v18 elif test "X$withval" = "Xv110"; then AC_MSG_RESULT([v110]) DEFAULT_API_VERSION=v110 else AC_MSG_ERROR([invalid version of public symbols given]) fi ## It's an error to try to disable deprecated public API symbols while ## choosing an older version of the public API as the default. However, ## if the user insists on doing this via the --enable-unsupported configure ## flag, we'll let them. if test "X${ALLOW_UNSUPPORTED}" != "Xyes"; then if test "X${DEFAULT_API_VERSION}" != "Xv110" -a "X${DEPRECATED_SYMBOLS}" = "Xno" ; then AC_MSG_ERROR([Removing old public API symbols not allowed when using them as default public API symbols. Use --enable-unsupported to override this error.]) fi fi ## ---------------------------------------------------------------------- ## Enable strict file format checks ## AC_SUBST([STRICT_FORMAT_CHECKS]) AC_MSG_CHECKING([whether to perform strict file format checks]); AC_ARG_ENABLE([strict-format-checks], [AS_HELP_STRING([--enable-strict-format-checks], [Enable strict file format checks, default=yes if debug flag is enabled, no otherwise])], [STRICT_CHECKS=$enableval]) ## Default to yes if debug is enabled if test "X-$STRICT_CHECKS" = X- ; then if test -z "$DEBUG_PKG" ; then STRICT_CHECKS=no else STRICT_CHECKS=yes fi fi case "X-$STRICT_CHECKS" in X-yes) AC_MSG_RESULT([yes]) STRICT_FORMAT_CHECKS=yes AC_DEFINE([STRICT_FORMAT_CHECKS], [1], [Define if strict file format checks are enabled]) ;; X-no|*) AC_MSG_RESULT([no]) STRICT_FORMAT_CHECKS=no ;; esac ## ---------------------------------------------------------------------- ## Enable embedded library information ## AC_MSG_CHECKING([whether to have library information embedded in the executables]) AC_ARG_ENABLE([embedded-libinfo], [AS_HELP_STRING([--enable-embedded-libinfo], [Enable embedded library information [default=yes]])], [enable_embedded_libinfo=$enableval], [enable_embedded_libinfo=yes]) if test "${enable_embedded_libinfo}" = "yes"; then AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_EMBEDDED_LIBINFO], [1], [Define if library information should be embedded in the executables]) else AC_MSG_RESULT([no]) fi ## ---------------------------------------------------------------------- ## Check if pointer alignments are enforced ## AC_MSG_CHECKING([if alignment restrictions are strictly enforced]) AC_RUN_IFELSE([ AC_LANG_PROGRAM([ #include <stdlib.h> #include <string.h> typedef struct { size_t len; void *p; } hvl_t; ], [ char *chp = "beefs"; char **chpp = malloc (2 * sizeof (char *)); char **chpp2; hvl_t vl = { 12345, (void *) chp }; hvl_t *vlp; hvl_t *vlp2; memcpy ((void *) ((char *) chpp + 1), &chp, sizeof (char *)); chpp2 = (char **) ((char *) chpp + 1); if (strcmp (*chpp2, chp)) { free (chpp); return 1; } free (chpp); vlp = malloc (2 * sizeof (hvl_t)); memcpy ((void *) ((char *) vlp + 1), &vl, sizeof (hvl_t)); vlp2 = (hvl_t *) ((char *) vlp + 1); if (vlp2->len != vl.len || vlp2->p != vl.p) { free (vlp); return 1; } free (vlp); ]) ], [ AC_DEFINE([NO_ALIGNMENT_RESTRICTIONS], [1], [Define if we can violate pointer alignment restrictions]) AC_MSG_RESULT([no]) ], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([unknown, assuming yes]) ]) ## ---------------------------------------------------------------------- ## Restore user's CFLAGS. CFLAGS="$saved_user_CFLAGS" FCFLAGS="$saved_user_FCFLAGS" CXXFLAGS="$saved_user_CXXFLAGS" CPPFLAGS="$saved_user_CPPFLAGS" LDFLAGS="$saved_user_LDFLAGS" ## ---------------------------------------------------------------------- ## Create automake conditionals to tell automake makefiles which directories ## need to be compiled AM_CONDITIONAL([BUILD_CXX_CONDITIONAL], [test "X$HDF_CXX" = "Xyes"]) AM_CONDITIONAL([BUILD_PARALLEL_CONDITIONAL], [test -n "$TESTPARALLEL"]) AM_CONDITIONAL([BUILD_FORTRAN_CONDITIONAL], [test "X$HDF_FORTRAN" = "Xyes"]) AM_CONDITIONAL([BUILD_HDF5_HL_CONDITIONAL], [test "X$HDF5_HL" = "Xyes"]) ## ---------------------------------------------------------------------- ## Build the Makefiles. ## ## The directory search list AC_SUBST([SEARCH]) SEARCH='$(srcdir) $(top_builddir)/src $(top_srcdir)/src' cmd='echo $SEARCH |sed "s/ /'$SEARCH_SEP'/g"' SEARCH="$SEARCH_RULE`eval $cmd`" export SEARCH ## We don't need to say when we're entering directories if we're using ## GNU make because make does it for us. if test "X$GMAKE" = "Xyes"; then AC_SUBST([SETX]) SETX=":" else AC_SUBST([SETX]) SETX="set -x" fi ## Some cleanup stuff rm -f conftest conftest.o conftest.c dummy.o *.mod ## Build config.status, touch the stamp files, and build all the Makefiles. ## The order is such that the first `make' does not need to update any ## configuration information. See config/commence.in for the order in which ## things need to be done. ## First the stamp1 file for H5config.h.in mkdir ./config >/dev/null 2>&1 touch ./config/stamp1 ## Then the config.status file (but not makefiles) saved_no_create=$no_create no_create=yes PARALLEL_MAKE="" FORTRAN_PARALLEL_MAKE="" if test -n "$TESTPARALLEL"; then PARALLEL_MAKE="$TESTPARALLEL/Makefile" if test "X$HDF_FORTRAN" = "Xyes"; then FORTRAN_PARALLEL_MAKE=fortran/$TESTPARALLEL/Makefile fi fi LT_OUTPUT no_create=$saved_no_create ## Then the stamp2 file for H5config.h touch ./config/stamp2 ## Finally the makefiles test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 ## Post processing to patch up some deficiencies in libtool case $host_os in linux* | freebsd* ) ## If gcc is not used, need to set $wl to use "-Wl," if $CC -v 2>&1 | grep '^gcc' > /dev/null ; then : using gcc else echo 'fixing $wl in' $ofile ed - $ofile <<EOF 2> /dev/null g/^wl=""/s//wl="-Wl,"/ w q EOF fi ;; esac ## Are we compiling static libraries, shared libraries, or both? This ## is only used for the libhdf5.settings file. We can't just look at ## $enable_static and $enable_shared because if they're yes the ltconfig ## might have decided that one or the other is simply not possible. ## Therefore we have to ask the generated `libtool' shell script ## which 'features' it has enabled. if (./libtool --features | grep '^enable shared libraries' > /dev/null); then enable_shared=yes else enable_shared=no fi if (./libtool --features | grep '^enable static libraries' > /dev/null); then enable_static=yes else enable_static=no fi if test "X$enable_static" = "Xyes" && test "X$enable_shared" = "Xyes"; then STATIC_SHARED="static, shared" elif test "X$enable_static" = "Xyes"; then STATIC_SHARED="static" elif test "X$enable_shared" = "Xyes"; then STATIC_SHARED="shared" else STATIC_SHARED="none" fi ## ---------------------------------------------------------------------- ## Set a macro if shared library is enabled. ## AM_CONDITIONAL([HAVE_SHARED_CONDITIONAL], [test "X$enable_shared" = "Xyes"]) AC_CONFIG_FILES([src/libhdf5.settings Makefile src/Makefile test/Makefile test/testcheck_version.sh test/testerror.sh test/H5srcdir_str.h test/testlibinfo.sh test/testlinks_env.sh test/test_plugin.sh testpar/Makefile perform/Makefile tools/Makefile tools/h5dump/Makefile tools/h5dump/testh5dump.sh tools/h5dump/testh5dumppbits.sh tools/h5dump/testh5dumpxml.sh tools/h5ls/testh5ls.sh tools/h5import/Makefile tools/h5import/h5importtestutil.sh tools/h5diff/Makefile tools/h5diff/testh5diff.sh tools/h5diff/testph5diff.sh tools/h5jam/Makefile tools/h5jam/testh5jam.sh tools/h5repack/Makefile tools/h5repack/h5repack.sh tools/h5repack/h5repack_plugin.sh tools/h5ls/Makefile tools/h5copy/Makefile tools/h5copy/testh5copy.sh tools/lib/Makefile tools/misc/Makefile tools/misc/h5cc tools/misc/testh5mkgrp.sh tools/misc/testh5repart.sh tools/h5stat/testh5stat.sh tools/h5stat/Makefile examples/Makefile examples/run-c-ex.sh examples/testh5cc.sh c++/Makefile c++/src/Makefile c++/src/h5c++ c++/test/Makefile c++/test/H5srcdir_str.h c++/examples/Makefile c++/examples/run-c++-ex.sh c++/examples/testh5c++.sh fortran/Makefile fortran/src/h5fc fortran/src/Makefile fortran/test/Makefile fortran/testpar/Makefile fortran/examples/Makefile fortran/examples/run-fortran-ex.sh fortran/examples/testh5fc.sh hl/Makefile hl/src/Makefile hl/test/Makefile hl/test/H5srcdir_str.h hl/tools/Makefile hl/tools/gif2h5/Makefile hl/tools/gif2h5/h52giftest.sh hl/examples/Makefile hl/examples/run-hlc-ex.sh hl/c++/Makefile hl/c++/src/Makefile hl/c++/test/Makefile hl/c++/examples/Makefile hl/c++/examples/run-hlc++-ex.sh hl/fortran/Makefile hl/fortran/src/Makefile hl/fortran/test/Makefile hl/fortran/examples/Makefile hl/fortran/examples/run-hlfortran-ex.sh]) AC_OUTPUT chmod 755 tools/misc/h5cc if test "X$HDF_FORTRAN" = "Xyes"; then chmod 755 fortran/src/h5fc fi if test "X$HDF_CXX" = "Xyes"; then chmod 755 c++/src/h5c++ fi ## We don't want inline defined for C++ compilers ## Don't worry about the C++ ifdef wrappers in the H5pubconf file, since ## 'H5_inline' isn't a C++ keyword. cat >> src/H5config.h <<EOF #if defined(__cplusplus) && defined(inline) #undef inline #endif EOF ## show the configure settings cat src/libhdf5.settings ) || (cache_ptr->entries_inserted_counter > 0) || (cache_ptr->entries_relocated_counter > 0)) { #if H5C_COLLECT_CACHE_STATS H5C__UPDATE_STATS_FOR_INDEX_SCAN_RESTART(cache_ptr); #endif /* H5C_COLLECT_CACHE_STATS */ /* Reset the counters */ cache_ptr->entries_loaded_counter = 0; cache_ptr->entries_inserted_counter = 0; cache_ptr->entries_relocated_counter = 0; /* Restart scan */ entry_ptr = cache_ptr->il_head; } /* end if */ else /* Advance to next entry */ entry_ptr = entry_ptr->il_next; } /* while ( entry_ptr != NULL ) */ } /* while ( ! done ) */ /* Reset the counters so that we can detect insertions, loads, * moves, and flush dependency height changes caused by the pre_serialize * and serialize callbacks. */ cache_ptr->entries_loaded_counter = 0; cache_ptr->entries_inserted_counter = 0; cache_ptr->entries_relocated_counter = 0; /* At this point, all entries not marked "flush me last" and in * the current ring or outside it should be serialized and have up * to date images. Scan the index list again to serialize the * "flush me last" entries (if they are in the current ring) and to * verify that all other entries have up to date images. */ entry_ptr = cache_ptr->il_head; while (entry_ptr != NULL) { HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(entry_ptr->ring > H5C_RING_UNDEFINED); HDassert(entry_ptr->ring < H5C_RING_NTYPES); HDassert((entry_ptr->ring >= ring) || (entry_ptr->image_up_to_date)); if (entry_ptr->ring == ring) { if (entry_ptr->flush_me_last) { if (!entry_ptr->image_up_to_date) { HDassert(entry_ptr->serialization_count == 0); HDassert(entry_ptr->flush_dep_nunser_children == 0); /* Serialize the entry */ if (H5C__serialize_single_entry(f, cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "entry serialization failed") /* Check for the cache changing */ if ((cache_ptr->entries_loaded_counter > 0) || (cache_ptr->entries_inserted_counter > 0) || (cache_ptr->entries_relocated_counter > 0)) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "flush_me_last entry serialization triggered restart") HDassert(entry_ptr->flush_dep_nunser_children == 0); HDassert(entry_ptr->serialization_count == 0); #ifndef NDEBUG /* Increment serialization counter (to detect multiple serializations) */ entry_ptr->serialization_count++; #endif /* NDEBUG */ } /* end if */ } /* end if */ else { HDassert(entry_ptr->image_up_to_date); HDassert(entry_ptr->serialization_count <= 1); HDassert(entry_ptr->flush_dep_nunser_children == 0); } /* end else */ } /* if ( entry_ptr->ring == ring ) */ entry_ptr = entry_ptr->il_next; } /* while ( entry_ptr != NULL ) */ done: HDassert(cache_ptr->serialization_in_progress); FUNC_LEAVE_NOAPI(ret_value) } /* H5C__serialize_ring() */ /*------------------------------------------------------------------------- * Function: H5C__serialize_single_entry * * Purpose: Serialize the cache entry pointed to by the entry_ptr * parameter. * * Return: Non-negative on success/Negative on failure * * Programmer: John Mainzer, 7/24/15 * *------------------------------------------------------------------------- */ static herr_t H5C__serialize_single_entry(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) { herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE /* Sanity checks */ HDassert(f); HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(entry_ptr); HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(!entry_ptr->prefetched); HDassert(!entry_ptr->image_up_to_date); HDassert(entry_ptr->is_dirty); HDassert(!entry_ptr->is_protected); HDassert(!entry_ptr->flush_in_progress); HDassert(entry_ptr->type); /* Set entry_ptr->flush_in_progress to TRUE so the the target entry * will not be evicted out from under us. Must set it back to FALSE * when we are done. */ entry_ptr->flush_in_progress = TRUE; /* Allocate buffer for the entry image if required. */ if (NULL == entry_ptr->image_ptr) { HDassert(entry_ptr->size > 0); if (NULL == (entry_ptr->image_ptr = H5MM_malloc(entry_ptr->size + H5C_IMAGE_EXTRA_SPACE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer") #if H5C_DO_MEMORY_SANITY_CHECKS H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + image_size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ } /* end if */ /* Generate image for entry */ if (H5C__generate_image(f, cache_ptr, entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTSERIALIZE, FAIL, "Can't generate image for cache entry") /* Reset the flush_in progress flag */ entry_ptr->flush_in_progress = FALSE; done: HDassert((ret_value != SUCCEED) || (!entry_ptr->flush_in_progress)); HDassert((ret_value != SUCCEED) || (entry_ptr->image_up_to_date)); FUNC_LEAVE_NOAPI(ret_value) } /* H5C__serialize_single_entry() */ /*------------------------------------------------------------------------- * Function: H5C__generate_image * * Purpose: Serialize an entry and generate its image. * * Note: This may cause the entry to be re-sized and/or moved in * the cache. * * As we will not update the metadata cache's data structures * until we we finish the write, we must touch up these * data structures for size and location changes even if we * are about to delete the entry from the cache (i.e. on a * flush destroy). * * Return: Non-negative on success/Negative on failure * * Programmer: Mohamad Chaarawi * 2/10/16 * * Changes: Updated sanity checks for the possibility that the skip * list is disabled. * JRM 5/16/20 * *------------------------------------------------------------------------- */ static herr_t H5C__generate_image(H5F_t *f, H5C_t *cache_ptr, H5C_cache_entry_t *entry_ptr) { haddr_t new_addr = HADDR_UNDEF; haddr_t old_addr = HADDR_UNDEF; size_t new_len = 0; unsigned serialize_flags = H5C__SERIALIZE_NO_FLAGS_SET; herr_t ret_value = SUCCEED; FUNC_ENTER_PACKAGE /* Sanity check */ HDassert(f); HDassert(cache_ptr); HDassert(cache_ptr->magic == H5C__H5C_T_MAGIC); HDassert(entry_ptr); HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); HDassert(!entry_ptr->image_up_to_date); HDassert(entry_ptr->is_dirty); HDassert(!entry_ptr->is_protected); HDassert(entry_ptr->type); /* make note of the entry's current address */ old_addr = entry_ptr->addr; /* Call client's pre-serialize callback, if there's one */ if ((entry_ptr->type->pre_serialize) && ((entry_ptr->type->pre_serialize)(f, (void *)entry_ptr, entry_ptr->addr, entry_ptr->size, &new_addr, &new_len, &serialize_flags) < 0)) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to pre-serialize entry") /* Check for any flags set in the pre-serialize callback */ if (serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET) { /* Check for unexpected flags from serialize callback */ if (serialize_flags & ~(H5C__SERIALIZE_RESIZED_FLAG | H5C__SERIALIZE_MOVED_FLAG)) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unknown serialize flag(s)") #ifdef H5_HAVE_PARALLEL /* In the parallel case, resizes and moves in * the serialize operation can cause problems. * If they occur, scream and die. * * At present, in the parallel case, the aux_ptr * will only be set if there is more than one * process. Thus we can use this to detect * the parallel case. * * This works for now, but if we start using the * aux_ptr for other purposes, we will have to * change this test accordingly. * * NB: While this test detects entryies that attempt * to resize or move themselves during a flush * in the parallel case, it will not detect an * entry that dirties, resizes, and/or moves * other entries during its flush. * * From what Quincey tells me, this test is * sufficient for now, as any flush routine that * does the latter will also do the former. * * If that ceases to be the case, further * tests will be necessary. */ if (cache_ptr->aux_ptr != NULL) HGOTO_ERROR(H5E_CACHE, H5E_SYSTEM, FAIL, "resize/move in serialize occurred in parallel case") #endif /* If required, resize the buffer and update the entry and the cache * data structures */ if (serialize_flags & H5C__SERIALIZE_RESIZED_FLAG) { /* Sanity check */ HDassert(new_len > 0); /* Allocate a new image buffer */ if (NULL == (entry_ptr->image_ptr = H5MM_realloc(entry_ptr->image_ptr, new_len + H5C_IMAGE_EXTRA_SPACE))) HGOTO_ERROR(H5E_CACHE, H5E_CANTALLOC, FAIL, "memory allocation failed for on disk image buffer") #if H5C_DO_MEMORY_SANITY_CHECKS H5MM_memcpy(((uint8_t *)entry_ptr->image_ptr) + new_len, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ /* Update statistics for resizing the entry */ H5C__UPDATE_STATS_FOR_ENTRY_SIZE_CHANGE(cache_ptr, entry_ptr, new_len); /* Update the hash table for the size change */ H5C__UPDATE_INDEX_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len, entry_ptr, !(entry_ptr->is_dirty)); /* The entry can't be protected since we are in the process of * flushing it. Thus we must update the replacement policy data * structures for the size change. The macro deals with the pinned * case. */ H5C__UPDATE_RP_FOR_SIZE_CHANGE(cache_ptr, entry_ptr, new_len); /* As we haven't updated the cache data structures for * for the flush or flush destroy yet, the entry should * be in the slist if the slist is enabled. Since * H5C__UPDATE_SLIST_FOR_SIZE_CHANGE() is a no-op if the * slist is enabled, call it un-conditionally. */ HDassert(entry_ptr->is_dirty); HDassert((entry_ptr->in_slist) || (!cache_ptr->slist_enabled)); H5C__UPDATE_SLIST_FOR_SIZE_CHANGE(cache_ptr, entry_ptr->size, new_len); /* Finally, update the entry for its new size */ entry_ptr->size = new_len; } /* end if */ /* If required, udate the entry and the cache data structures * for a move */ if (serialize_flags & H5C__SERIALIZE_MOVED_FLAG) { /* Update stats and entries relocated counter */ H5C__UPDATE_STATS_FOR_MOVE(cache_ptr, entry_ptr) /* We must update cache data structures for the change in address */ if (entry_ptr->addr == old_addr) { /* Delete the entry from the hash table and the slist */ H5C__DELETE_FROM_INDEX(cache_ptr, entry_ptr, FAIL); H5C__REMOVE_ENTRY_FROM_SLIST(cache_ptr, entry_ptr, FALSE); /* Update the entry for its new address */ entry_ptr->addr = new_addr; /* And then reinsert in the index and slist */ H5C__INSERT_IN_INDEX(cache_ptr, entry_ptr, FAIL); H5C__INSERT_ENTRY_IN_SLIST(cache_ptr, entry_ptr, FAIL); } /* end if */ else { /* move is already done for us -- just do sanity checks */ HDassert(entry_ptr->addr == new_addr); } } /* end if */ } /* end if(serialize_flags != H5C__SERIALIZE_NO_FLAGS_SET) */ /* Serialize object into buffer */ if (entry_ptr->type->serialize(f, entry_ptr->image_ptr, entry_ptr->size, (void *)entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTFLUSH, FAIL, "unable to serialize entry") #if H5C_DO_MEMORY_SANITY_CHECKS HDassert(0 == HDmemcmp(((uint8_t *)entry_ptr->image_ptr) + entry_ptr->size, H5C_IMAGE_SANITY_VALUE, H5C_IMAGE_EXTRA_SPACE)); #endif /* H5C_DO_MEMORY_SANITY_CHECKS */ entry_ptr->image_up_to_date = TRUE; /* Propagate the fact that the entry is serialized up the * flush dependency chain if appropriate. Since the image must * have been out of date for this function to have been called * (see assertion on entry), no need to check that -- only check * for flush dependency parents. */ HDassert(entry_ptr->flush_dep_nunser_children == 0); if (entry_ptr->flush_dep_nparents > 0) { if (H5C__mark_flush_dep_serialized(entry_ptr) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "Can't propagate serialization status to fd parents") } done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C__generate_image */ /*------------------------------------------------------------------------- * * Function: H5C_remove_entry * * Purpose: Remove an entry from the cache. Must be not protected, pinned, * dirty, involved in flush dependencies, etc. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol * September 17, 2016 * *------------------------------------------------------------------------- */ herr_t H5C_remove_entry(void *_entry) { H5C_cache_entry_t *entry = (H5C_cache_entry_t *)_entry; /* Entry to remove */ H5C_t *cache; /* Cache for file */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) /* Sanity checks */ HDassert(entry); HDassert(entry->ring != H5C_RING_UNDEFINED); cache = entry->cache_ptr; HDassert(cache); HDassert(cache->magic == H5C__H5C_T_MAGIC); /* Check for error conditions */ if (entry->is_dirty) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove dirty entry from cache") if (entry->is_protected) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove protected entry from cache") if (entry->is_pinned) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove pinned entry from cache") /* NOTE: If these two errors are getting tripped because the entry is * in a flush dependency with a freedspace entry, move the checks * after the "before evict" message is sent, and add the * "child being evicted" message to the "before evict" notify * section below. QAK - 2017/08/03 */ if (entry->flush_dep_nparents > 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry with flush dependency parents from cache") if (entry->flush_dep_nchildren > 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry with flush dependency children from cache") /* Additional internal cache consistency checks */ HDassert(!entry->in_slist); HDassert(!entry->flush_marker); HDassert(!entry->flush_in_progress); /* Note that the algorithm below is (very) similar to the set of operations * in H5C__flush_single_entry() and should be kept in sync with changes * to that code. - QAK, 2016/11/30 */ /* Update stats, as if we are "destroying" and taking ownership of the entry */ H5C__UPDATE_STATS_FOR_EVICTION(cache, entry, TRUE) /* If the entry's type has a 'notify' callback, send a 'before eviction' * notice while the entry is still fully integrated in the cache. */ if (entry->type->notify && (entry->type->notify)(H5C_NOTIFY_ACTION_BEFORE_EVICT, entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTNOTIFY, FAIL, "can't notify client about entry to evict") /* Update the cache internal data structures as appropriate for a destroy. * Specifically: * 1) Delete it from the index * 2) Delete it from the collective read access list * 3) Update the replacement policy for eviction * 4) Remove it from the tag list for this object */ H5C__DELETE_FROM_INDEX(cache, entry, FAIL) #ifdef H5_HAVE_PARALLEL /* Check for collective read access flag */ if (entry->coll_access) { entry->coll_access = FALSE; H5C__REMOVE_FROM_COLL_LIST(cache, entry, FAIL) } /* end if */ #endif /* H5_HAVE_PARALLEL */ H5C__UPDATE_RP_FOR_EVICTION(cache, entry, FAIL) /* Remove entry from tag list */ if (H5C__untag_entry(cache, entry) < 0) HGOTO_ERROR(H5E_CACHE, H5E_CANTREMOVE, FAIL, "can't remove entry from tag list") /* Increment entries_removed_counter and set last_entry_removed_ptr. * As we me be about to free the entry, recall that last_entry_removed_ptr * must NEVER be dereferenced. * * Recall that these fields are maintained to allow functions that perform * scans of lists of entries to detect the unexpected removal of entries * (via expunge, eviction, or take ownership at present), so that they can * re-start their scans if necessary. * * Also check if the entry we are watching for removal is being * removed (usually the 'next' entry for an iteration) and reset * it to indicate that it was removed. */ cache->entries_removed_counter++; cache->last_entry_removed_ptr = entry; if (entry == cache->entry_watched_for_removal) cache->entry_watched_for_removal = NULL; /* Internal cache data structures should now be up to date, and * consistent with the status of the entry. * * Now clean up internal cache fields if appropriate. */ /* Free the buffer for the on disk image */ if (entry->image_ptr != NULL) entry->image_ptr = H5MM_xfree(entry->image_ptr); /* Reset the pointer to the cache the entry is within */ entry->cache_ptr = NULL; /* Client is taking ownership of the entry. Set bad magic here so the * cache will choke unless the entry is re-inserted properly */ entry->magic = H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC; done: FUNC_LEAVE_NOAPI(ret_value) } /* H5C__remove_entry() */