mirror of
https://github.com/HDFGroup/hdf5.git
synced 2024-12-27 08:01:04 +08:00
fd933f30b1
* Removes Programmer: and Date: fields * Fixes a few Modifications: fields leftover from previous work
266 lines
8.9 KiB
C
266 lines
8.9 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* 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. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/********************************************************************
|
|
*
|
|
* Testing thread safety. Deliberate per-thread errors to test error stack
|
|
* -----------------------------------------------------------------------
|
|
*
|
|
* Create 16 multiple threads to create datasets with the same name. The
|
|
* library should respond with 15 equivalent error stack printouts (one for
|
|
* each bad thread). The final hdf5 file should be a valid file with one
|
|
* entry.
|
|
*
|
|
* Temporary files generated:
|
|
*
|
|
* ttsafe_error.h5
|
|
*
|
|
********************************************************************/
|
|
#include "ttsafe.h"
|
|
|
|
#ifdef H5_HAVE_THREADSAFE
|
|
|
|
#define NUM_THREAD 16
|
|
#define FILENAME "ttsafe_error.h5"
|
|
|
|
/* Having a common dataset name is an error */
|
|
#define DATASETNAME "commonname"
|
|
#define EXPECTED_ERROR_DEPTH 11
|
|
#define WRITE_NUMBER 37
|
|
|
|
/* Typedefs */
|
|
typedef struct err_num_struct {
|
|
hid_t maj_num;
|
|
hid_t min_num;
|
|
} err_num_t;
|
|
|
|
/* Global variables */
|
|
hid_t error_file_g = H5I_INVALID_HID;
|
|
int error_flag_g = 0;
|
|
int error_count_g = 0;
|
|
err_num_t expected_g[EXPECTED_ERROR_DEPTH];
|
|
H5TS_mutex_simple_t error_mutex_g;
|
|
|
|
/* Prototypes */
|
|
static herr_t error_callback(hid_t, void *);
|
|
static herr_t walk_error_callback(unsigned, const H5E_error2_t *, void *);
|
|
static void *tts_error_thread(void *);
|
|
|
|
void
|
|
tts_error(void)
|
|
{
|
|
hid_t def_fapl = H5I_INVALID_HID;
|
|
hid_t vol_id = H5I_INVALID_HID;
|
|
hid_t dataset = H5I_INVALID_HID;
|
|
H5TS_thread_t threads[NUM_THREAD];
|
|
H5TS_attr_t attribute;
|
|
int value, i;
|
|
herr_t status;
|
|
|
|
/* Must initialize these at runtime */
|
|
expected_g[0].maj_num = H5E_DATASET;
|
|
expected_g[0].min_num = H5E_CANTCREATE;
|
|
|
|
expected_g[1].maj_num = H5E_DATASET;
|
|
expected_g[1].min_num = H5E_CANTCREATE;
|
|
|
|
expected_g[2].maj_num = H5E_VOL;
|
|
expected_g[2].min_num = H5E_CANTCREATE;
|
|
|
|
expected_g[3].maj_num = H5E_VOL;
|
|
expected_g[3].min_num = H5E_CANTCREATE;
|
|
|
|
expected_g[4].maj_num = H5E_DATASET;
|
|
expected_g[4].min_num = H5E_CANTINIT;
|
|
|
|
expected_g[5].maj_num = H5E_DATASET;
|
|
expected_g[5].min_num = H5E_CANTINIT;
|
|
|
|
expected_g[6].maj_num = H5E_LINK;
|
|
expected_g[6].min_num = H5E_CANTINIT;
|
|
|
|
expected_g[7].maj_num = H5E_LINK;
|
|
expected_g[7].min_num = H5E_CANTINSERT;
|
|
|
|
expected_g[8].maj_num = H5E_SYM;
|
|
expected_g[8].min_num = H5E_NOTFOUND;
|
|
|
|
expected_g[9].maj_num = H5E_SYM;
|
|
expected_g[9].min_num = H5E_CALLBACK;
|
|
|
|
expected_g[10].maj_num = H5E_LINK;
|
|
expected_g[10].min_num = H5E_EXISTS;
|
|
|
|
/* set up mutex for global count of errors */
|
|
H5TS_mutex_init(&error_mutex_g);
|
|
|
|
/* make thread scheduling global */
|
|
H5TS_attr_init(&attribute);
|
|
|
|
#ifdef H5_HAVE_SYSTEM_SCOPE_THREADS
|
|
/* set thread scope to system */
|
|
H5TS_attr_setscope(&attribute, H5TS_SCOPE_SYSTEM);
|
|
#endif /* H5_HAVE_SYSTEM_SCOPE_THREADS */
|
|
|
|
def_fapl = H5Pcreate(H5P_FILE_ACCESS);
|
|
CHECK(def_fapl, H5I_INVALID_HID, "H5Pcreate");
|
|
|
|
status = H5Pget_vol_id(def_fapl, &vol_id);
|
|
CHECK(status, FAIL, "H5Pget_vol_id");
|
|
|
|
if (vol_id == H5VL_NATIVE) {
|
|
/* Create a hdf5 file using H5F_ACC_TRUNC access, default file
|
|
* creation plist and default file access plist
|
|
*/
|
|
error_file_g = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, def_fapl);
|
|
CHECK(error_file_g, H5I_INVALID_HID, "H5Fcreate");
|
|
|
|
for (i = 0; i < NUM_THREAD; i++)
|
|
threads[i] = H5TS_create_thread(tts_error_thread, &attribute, NULL);
|
|
|
|
for (i = 0; i < NUM_THREAD; i++)
|
|
H5TS_wait_for_thread(threads[i]);
|
|
|
|
if (error_flag_g) {
|
|
TestErrPrintf(
|
|
"At least one thread reported a value that was different from the expected value\n");
|
|
printf(
|
|
"(Update the expected_g[] array in tts_error for this test if the error stack changed!)\n");
|
|
}
|
|
|
|
if (error_count_g != NUM_THREAD - 1)
|
|
TestErrPrintf("Error: %d threads failed instead of %d\n", error_count_g, NUM_THREAD - 1);
|
|
|
|
dataset = H5Dopen2(error_file_g, DATASETNAME, H5P_DEFAULT);
|
|
CHECK(dataset, H5I_INVALID_HID, "H5Dopen2");
|
|
|
|
status = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &value);
|
|
CHECK(status, FAIL, "H5Dread");
|
|
|
|
if (value != WRITE_NUMBER)
|
|
TestErrPrintf("Error: Successful thread wrote value %d instead of %d\n", value, WRITE_NUMBER);
|
|
|
|
status = H5Dclose(dataset);
|
|
CHECK(status, FAIL, "H5Dclose");
|
|
status = H5Fclose(error_file_g);
|
|
CHECK(status, FAIL, "H5Fclose");
|
|
} /* end if */
|
|
else
|
|
printf("Non-native VOL connector used, skipping test\n");
|
|
|
|
status = H5Idec_ref(vol_id);
|
|
CHECK(status, FAIL, "H5Idec_ref");
|
|
|
|
H5TS_attr_destroy(&attribute);
|
|
} /* end tts_error() */
|
|
|
|
static void *
|
|
tts_error_thread(void H5_ATTR_UNUSED *arg)
|
|
{
|
|
hid_t dataspace = H5I_INVALID_HID;
|
|
hid_t datatype = H5I_INVALID_HID;
|
|
hid_t dataset = H5I_INVALID_HID;
|
|
hsize_t dimsf[1]; /* dataset dimensions */
|
|
H5E_auto2_t old_error_cb;
|
|
void *old_error_client_data;
|
|
int value;
|
|
herr_t status;
|
|
|
|
/* preserve previous error stack handler */
|
|
status = H5Eget_auto2(H5E_DEFAULT, &old_error_cb, &old_error_client_data);
|
|
CHECK(status, FAIL, "H5Eget_auto2");
|
|
|
|
/* set each thread's error stack handler */
|
|
status = H5Eset_auto2(H5E_DEFAULT, error_callback, NULL);
|
|
CHECK(status, FAIL, "H5Eset_auto2");
|
|
|
|
/* define dataspace for dataset */
|
|
dimsf[0] = 1;
|
|
dataspace = H5Screate_simple(1, dimsf, NULL);
|
|
CHECK(dataspace, H5I_INVALID_HID, "H5Screate_simple");
|
|
|
|
/* define datatype for the data using native little endian integers */
|
|
datatype = H5Tcopy(H5T_NATIVE_INT);
|
|
CHECK(datatype, H5I_INVALID_HID, "H5Tcopy");
|
|
status = H5Tset_order(datatype, H5T_ORDER_LE);
|
|
CHECK(status, FAIL, "H5Tset_order");
|
|
|
|
/* create a new dataset within the file */
|
|
dataset =
|
|
H5Dcreate2(error_file_g, DATASETNAME, datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
|
/* Most of these will fail, so don't check the error here */
|
|
if (dataset >= 0) {
|
|
value = WRITE_NUMBER;
|
|
status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &value);
|
|
CHECK(status, FAIL, "H5Dwrite");
|
|
status = H5Dclose(dataset);
|
|
CHECK(status, FAIL, "H5Dclose");
|
|
}
|
|
|
|
status = H5Tclose(datatype);
|
|
CHECK(status, FAIL, "H5Tclose");
|
|
status = H5Sclose(dataspace);
|
|
CHECK(status, FAIL, "H5Sclose");
|
|
|
|
/* turn our error stack handler off */
|
|
status = H5Eset_auto2(H5E_DEFAULT, old_error_cb, old_error_client_data);
|
|
CHECK(status, FAIL, "H5Eset_auto2");
|
|
|
|
return NULL;
|
|
} /* end tts_error_thread() */
|
|
|
|
static herr_t
|
|
error_callback(hid_t H5_ATTR_UNUSED estack_id, void *client_data)
|
|
{
|
|
H5TS_mutex_lock_simple(&error_mutex_g);
|
|
error_count_g++;
|
|
H5TS_mutex_unlock_simple(&error_mutex_g);
|
|
return H5Ewalk2(H5E_DEFAULT, H5E_WALK_DOWNWARD, walk_error_callback, client_data);
|
|
}
|
|
|
|
static herr_t
|
|
walk_error_callback(unsigned n, const H5E_error2_t *err_desc, void H5_ATTR_UNUSED *client_data)
|
|
{
|
|
hid_t maj_num = H5I_INVALID_HID;
|
|
hid_t min_num = H5I_INVALID_HID;
|
|
|
|
if (err_desc) {
|
|
maj_num = err_desc->maj_num;
|
|
min_num = err_desc->min_num;
|
|
|
|
if (n <= EXPECTED_ERROR_DEPTH && maj_num == expected_g[n].maj_num && min_num == expected_g[n].min_num)
|
|
return SUCCEED;
|
|
}
|
|
|
|
/* Unexpected error stack entry, print some info and set flag */
|
|
fprintf(stderr, "Unexpected error stack entry!\n");
|
|
fprintf(stderr, "Stack entry: %d\n", n);
|
|
fprintf(stderr,
|
|
"Actual: maj_num = %" PRIxHID ", min_num = %" PRIxHID
|
|
", line = %u, func = '%s', file = '%s', desc = '%s'\n",
|
|
err_desc->maj_num, err_desc->min_num, err_desc->line, err_desc->func_name, err_desc->file_name,
|
|
err_desc->desc);
|
|
fprintf(stderr, "Expected: maj_num = %" PRIxHID ", min_num = %" PRIxHID "\n", expected_g[n].maj_num,
|
|
expected_g[n].min_num);
|
|
error_flag_g = -1;
|
|
|
|
return SUCCEED;
|
|
}
|
|
|
|
void
|
|
cleanup_error(void)
|
|
{
|
|
HDunlink(FILENAME);
|
|
}
|
|
|
|
#endif /*H5_HAVE_THREADSAFE*/
|