2000-05-19 03:13:33 +08:00
|
|
|
/********************************************************************
|
|
|
|
*
|
|
|
|
* 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:
|
2001-09-05 01:37:10 +08:00
|
|
|
*
|
|
|
|
* ttsafe_error.h5
|
2000-05-19 03:13:33 +08:00
|
|
|
*
|
|
|
|
* HDF5 APIs exercised in thread:
|
2001-09-05 01:37:10 +08:00
|
|
|
*
|
|
|
|
* H5Screate_simple, H5Tcopy, H5Tset_order, H5Dcreate, H5Dclose,
|
|
|
|
* H5Tclose, H5Sclose.
|
2000-05-19 03:13:33 +08:00
|
|
|
*
|
|
|
|
* Created: Apr 28 2000
|
|
|
|
* Programmer: Chee Wai LEE
|
|
|
|
*
|
|
|
|
* Modification History
|
|
|
|
* --------------------
|
|
|
|
*
|
2000-05-20 07:00:03 +08:00
|
|
|
* 19 May 2000, Bill Wendling
|
|
|
|
* Modified so that it creates a unique HDF5 file and removes it on
|
|
|
|
* cleanup. Also added the num_errs flag and increment it when necessary
|
|
|
|
* to report the errors.
|
|
|
|
*
|
2000-05-19 03:13:33 +08:00
|
|
|
********************************************************************/
|
|
|
|
#include "ttsafe.h"
|
|
|
|
|
|
|
|
#ifndef H5_HAVE_THREADSAFE
|
|
|
|
static int dummy; /* just to create a non-empty object file */
|
|
|
|
#else
|
|
|
|
|
2001-09-05 01:37:10 +08:00
|
|
|
#define NUM_THREAD 16
|
|
|
|
#define FILENAME "ttsafe_error.h5"
|
2000-05-20 07:00:03 +08:00
|
|
|
|
2000-05-19 03:13:33 +08:00
|
|
|
/* Having a common dataset name is an error */
|
2000-05-20 07:00:03 +08:00
|
|
|
#define DATASETNAME "commonname"
|
|
|
|
#define EXPECTED_ERROR_DEPTH 3
|
|
|
|
#define WRITE_NUMBER 37
|
|
|
|
|
2001-09-05 01:37:10 +08:00
|
|
|
static herr_t error_callback(void *);
|
|
|
|
static herr_t walk_error_callback(int, H5E_error_t *, void *);
|
|
|
|
static void *tts_error_thread(void *);
|
2000-05-19 03:13:33 +08:00
|
|
|
|
2001-09-05 01:37:10 +08:00
|
|
|
/* Global variables */
|
2000-05-19 03:13:33 +08:00
|
|
|
hid_t error_file;
|
|
|
|
|
|
|
|
typedef struct err_num_struct {
|
2000-05-20 07:00:03 +08:00
|
|
|
int maj_num;
|
|
|
|
int min_num;
|
2000-05-19 03:13:33 +08:00
|
|
|
} err_num_t;
|
|
|
|
|
2000-05-20 07:00:03 +08:00
|
|
|
err_num_t expected[] = {
|
2001-09-19 04:12:37 +08:00
|
|
|
{H5E_DATASET, H5E_CANTINIT},
|
|
|
|
{H5E_DATASET, H5E_CANTINIT},
|
|
|
|
{H5E_SYM, H5E_EXISTS}
|
2000-05-20 07:00:03 +08:00
|
|
|
};
|
|
|
|
|
2000-05-19 03:13:33 +08:00
|
|
|
int error_flag = 0;
|
|
|
|
int error_count = 0;
|
|
|
|
pthread_mutex_t error_mutex;
|
|
|
|
|
2000-05-20 07:00:03 +08:00
|
|
|
void tts_error(void)
|
|
|
|
{
|
|
|
|
pthread_t threads[NUM_THREAD];
|
|
|
|
pthread_attr_t attribute;
|
|
|
|
H5E_auto_t old_error_cb;
|
|
|
|
void *old_error_client_data;
|
|
|
|
hid_t dataset;
|
|
|
|
int value, i;
|
|
|
|
|
|
|
|
/* set up mutex for global count of errors */
|
|
|
|
pthread_mutex_init(&error_mutex, NULL);
|
|
|
|
|
|
|
|
/* preserve previous error stack handler */
|
|
|
|
H5Eget_auto(&old_error_cb, &old_error_client_data);
|
|
|
|
|
|
|
|
/* set our own auto error stack handler */
|
|
|
|
H5Eset_auto(error_callback, NULL);
|
|
|
|
|
|
|
|
/* make thread scheduling global */
|
|
|
|
pthread_attr_init(&attribute);
|
|
|
|
pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a hdf5 file using H5F_ACC_TRUNC access, default file
|
|
|
|
* creation plist and default file access plist
|
|
|
|
*/
|
|
|
|
error_file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_THREAD; i++)
|
|
|
|
pthread_create(&threads[i], &attribute, tts_error_thread, NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_THREAD; i++)
|
|
|
|
pthread_join(threads[i],NULL);
|
|
|
|
|
|
|
|
if (error_flag) {
|
|
|
|
fprintf(stderr, "Threads reporting different error values!\n");
|
|
|
|
num_errs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error_count != NUM_THREAD - 1) {
|
|
|
|
fprintf(stderr, "Error: %d threads failed instead of %d\n",
|
|
|
|
error_count, NUM_THREAD-1);
|
|
|
|
num_errs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
dataset = H5Dopen(error_file, DATASETNAME);
|
|
|
|
H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &value);
|
|
|
|
|
|
|
|
if (value != WRITE_NUMBER) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Error: Successful thread wrote value %d instead of %d\n",
|
|
|
|
value, WRITE_NUMBER);
|
|
|
|
num_errs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
H5Dclose(dataset);
|
|
|
|
H5Fclose(error_file);
|
|
|
|
|
|
|
|
/* turn our error stack handler off */
|
|
|
|
H5Eset_auto(old_error_cb, old_error_client_data);
|
2000-05-19 03:13:33 +08:00
|
|
|
}
|
|
|
|
|
2001-09-05 01:37:10 +08:00
|
|
|
static
|
2000-05-20 07:00:03 +08:00
|
|
|
void *tts_error_thread(void *arg)
|
|
|
|
{
|
|
|
|
hid_t dataspace, datatype, dataset;
|
|
|
|
hsize_t dimsf[1]; /* dataset dimensions */
|
|
|
|
int value;
|
|
|
|
|
|
|
|
/* define dataspace for dataset */
|
|
|
|
dimsf[0] = 1;
|
|
|
|
dataspace = H5Screate_simple(1,dimsf,NULL);
|
|
|
|
|
|
|
|
/* define datatype for the data using native little endian integers */
|
|
|
|
datatype = H5Tcopy(H5T_NATIVE_INT);
|
|
|
|
H5Tset_order(datatype, H5T_ORDER_LE);
|
|
|
|
|
|
|
|
/* create a new dataset within the file */
|
|
|
|
dataset = H5Dcreate(error_file, DATASETNAME, datatype, dataspace,
|
|
|
|
H5P_DEFAULT);
|
|
|
|
if (dataset >= 0) { /* not an error */
|
|
|
|
value = WRITE_NUMBER;
|
|
|
|
H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL,
|
|
|
|
H5P_DEFAULT, &value);
|
|
|
|
H5Dclose(dataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
H5Tclose(datatype);
|
|
|
|
H5Sclose(dataspace);
|
2001-09-05 01:37:10 +08:00
|
|
|
arg = arg; /* gets rid of annoying warning message */
|
|
|
|
return NULL;
|
2000-05-19 03:13:33 +08:00
|
|
|
}
|
|
|
|
|
2001-09-05 01:37:10 +08:00
|
|
|
static
|
2000-05-20 07:00:03 +08:00
|
|
|
herr_t error_callback(void *client_data)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&error_mutex);
|
|
|
|
error_count++;
|
|
|
|
pthread_mutex_unlock(&error_mutex);
|
2001-09-05 01:37:10 +08:00
|
|
|
client_data = client_data; /* gets rid of annoying warning message */
|
2000-05-20 07:00:03 +08:00
|
|
|
return H5Ewalk(H5E_WALK_DOWNWARD, walk_error_callback, NULL);
|
2000-05-19 03:13:33 +08:00
|
|
|
}
|
|
|
|
|
2001-09-05 01:37:10 +08:00
|
|
|
static
|
2000-05-20 07:00:03 +08:00
|
|
|
herr_t walk_error_callback(int n, H5E_error_t *err_desc, void *client_data)
|
|
|
|
{
|
|
|
|
int maj_num, min_num;
|
|
|
|
|
|
|
|
if (err_desc) {
|
|
|
|
maj_num = err_desc->maj_num;
|
|
|
|
min_num = err_desc->min_num;
|
2000-05-19 03:13:33 +08:00
|
|
|
|
2000-05-20 07:00:03 +08:00
|
|
|
if (n < EXPECTED_ERROR_DEPTH && maj_num == expected[n].maj_num &&
|
|
|
|
min_num == expected[n].min_num)
|
|
|
|
return SUCCEED;
|
|
|
|
}
|
|
|
|
|
|
|
|
error_flag = -1;
|
2001-09-05 01:37:10 +08:00
|
|
|
client_data = client_data; /* gets rid of annoying warning message */
|
2000-05-19 03:13:33 +08:00
|
|
|
return SUCCEED;
|
2000-05-20 07:00:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void cleanup_error(void)
|
|
|
|
{
|
|
|
|
HDunlink(FILENAME);
|
2000-05-19 03:13:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /*H5_HAVE_THREADSAFE*/
|