diff --git a/include/cconfigspace/binding.h b/include/cconfigspace/binding.h index 3aea6f08..b9832157 100644 --- a/include/cconfigspace/binding.h +++ b/include/cconfigspace/binding.h @@ -8,7 +8,8 @@ extern "C" { /** * @file binding.h * A Binding is set of value in a Context see context.h. Those values can be - * accessed by using the parameter index in the context. + * accessed by using the parameter index in the context. Bindings are immutable + * except from a reference counting and callback management point of view. */ /** @@ -20,6 +21,8 @@ extern "C" { * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p binding is not a valid CCS * object * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p context_ret is NULL + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_get_context(ccs_binding_t binding, ccs_context_t *context_ret); @@ -35,6 +38,8 @@ ccs_binding_get_context(ccs_binding_t binding, ccs_context_t *context_ret); * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p value_ret is NULL * @return #CCS_RESULT_ERROR_OUT_OF_BOUNDS if \p index is greater than the count * of parameters in the context + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_get_value( @@ -59,6 +64,8 @@ ccs_binding_get_value( * num_values is greater than 0; or if \p values is NULL and \p num_values_ret * is NULL; or if \p num_values is less than the number of values that would be * returned + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_get_values( @@ -78,6 +85,8 @@ ccs_binding_get_values( * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p value_ret is NULL * @return #CCS_RESULT_ERROR_INVALID_NAME if no parameter with such \p name * exist in the \p binding context + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_get_value_by_name( @@ -95,6 +104,8 @@ ccs_binding_get_value_by_name( * object * @return #CCS_RESULT_ERROR_INVALID_PARAMETER if \p parameter does not exist in * the \p binding context + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_get_value_by_parameter( @@ -112,6 +123,8 @@ ccs_binding_get_value_by_parameter( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p binding is not a valid CCS * object * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p hash_ret is NULL + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_hash(ccs_binding_t binding, ccs_hash_t *hash_ret); @@ -129,6 +142,8 @@ ccs_binding_hash(ccs_binding_t binding, ccs_hash_t *hash_ret); * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p binding or \p other_binding * are not valid CCS objects * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p cmp_ret is NULL + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_binding_cmp( diff --git a/include/cconfigspace/configuration.h b/include/cconfigspace/configuration.h index 7baa09b6..7aaebe6f 100644 --- a/include/cconfigspace/configuration.h +++ b/include/cconfigspace/configuration.h @@ -8,7 +8,8 @@ extern "C" { /** * @file configuration.h * A configuration is a binding (see binding.h) on a configuration space (see - * configuration_space.h). + * configuration_space.h). Configurations are immutable except from a reference + * counting and callback management point of view. */ /** @@ -29,6 +30,8 @@ extern "C" { * space * @return #CCS_RESULT_ERROR_OUT_OF_MEMORY if there was a lack of memory to * allocate the new configuration + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_create_configuration( @@ -46,6 +49,8 @@ ccs_create_configuration( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration is not a valid * CCS configuration * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p configuration_space_ret is NULL + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_get_configuration_space( @@ -64,6 +69,8 @@ ccs_configuration_get_configuration_space( * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p value_ret is NULL * @return #CCS_RESULT_ERROR_OUT_OF_BOUNDS if \p index is greater than the count * of parameters in the configuration space + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_get_value( @@ -88,6 +95,8 @@ ccs_configuration_get_value( * num_values is greater than 0; or if \p values is NULL and \p num_values_ret * is NULL; or if \p num_values is less than the number of values that would be * returned + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_get_values( @@ -107,6 +116,8 @@ ccs_configuration_get_values( * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p value_ret is NULL * @return #CCS_RESULT_ERROR_INVALID_NAME if no parameter with such \p name * exist in the \p configuration space + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_get_value_by_name( @@ -130,6 +141,8 @@ ccs_configuration_get_value_by_name( * CCS configuration * @return #CCS_RESULT_ERROR_INVALID_CONFIGURATION if \p configuration has * become invalid for the configuration space + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_check( @@ -147,6 +160,8 @@ ccs_configuration_check( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration is not a valid * CCS configuration * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p hash_ret is NULL + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_hash(ccs_configuration_t configuration, ccs_hash_t *hash_ret); @@ -164,6 +179,8 @@ ccs_configuration_hash(ccs_configuration_t configuration, ccs_hash_t *hash_ret); * @return #CCS_RESULT_SUCCESS on success * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration or \p * other_configuration are not a valid CCS object + * @remarks + * This function is thread-safe */ extern ccs_result_t ccs_configuration_cmp( diff --git a/include/cconfigspace/context.h b/include/cconfigspace/context.h index 3af1436e..9e0425df 100644 --- a/include/cconfigspace/context.h +++ b/include/cconfigspace/context.h @@ -9,7 +9,7 @@ extern "C" { * @file context.h * A Context is a collection of parameters defining a value space. Each * parameter has a specific index that can be used to reference it. - * The methods defined in this file can be used on objects who re contexts. + * The methods defined in this file can be used on objects who are contexts. * In practice those are useful for binding to avoid binding the children * methods, whereas a C application would rather use the object class specific * versions in order to benefit from the added type safety. diff --git a/include/cconfigspace/distribution.h b/include/cconfigspace/distribution.h index 22d2a14d..0a14d788 100644 --- a/include/cconfigspace/distribution.h +++ b/include/cconfigspace/distribution.h @@ -678,7 +678,7 @@ ccs_multivariate_distribution_get_distributions( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution is not a valid * CCS distribution; or if \p rng is not a valid CCS rng * @remarks - * This function is thread-safe if \p rng is only used by one thread at a time + * This function is thread-safe */ extern ccs_result_t ccs_distribution_sample( @@ -702,7 +702,7 @@ ccs_distribution_sample( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution is not a valid * CCS distribution; or if \p rng is not a valid CCS rng * @remarks - * This function is thread-safe if \p rng is only used by one thread at a time + * This function is thread-safe */ extern ccs_result_t ccs_distribution_samples( @@ -733,7 +733,7 @@ ccs_distribution_samples( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution is not a valid * CCS distribution; or if \p rng is not a valid CCS rng * @remarks - * This function is thread-safe if \p rng is only used by one thread at a time + * This function is thread-safe */ extern ccs_result_t ccs_distribution_strided_samples( @@ -758,7 +758,7 @@ ccs_distribution_strided_samples( * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution is not a valid * CCS distribution; or if \p rng is not a valid CCS rng * @remarks - * This function is thread-safe if \p rng is only used by one thread at a time + * This function is thread-safe */ extern ccs_result_t ccs_distribution_soa_samples( @@ -787,7 +787,7 @@ ccs_distribution_soa_samples( * CCS distribution; or if \p rng is not a valid CCS rng; or if at least one of * the parameters provided is NULL * @remarks - * This function is thread-safe if \p rng is only used by one thread at a time + * This function is thread-safe */ extern ccs_result_t ccs_distribution_parameters_samples( @@ -812,7 +812,7 @@ ccs_distribution_parameters_samples( * CCS distribution; or if \p rng is not a valid CCS rng; or if at least one of * the parameters provided is NULL * @remarks - * This function is thread-safe if \p rng is only used by one thread at a time + * This function is thread-safe */ extern ccs_result_t ccs_distribution_parameters_sample( diff --git a/include/cconfigspace/map.h b/include/cconfigspace/map.h index 4814318f..ff890892 100644 --- a/include/cconfigspace/map.h +++ b/include/cconfigspace/map.h @@ -36,7 +36,7 @@ ccs_create_map(ccs_map_t *map_ret); * @return #CCS_RESULT_ERROR_OUT_OF_MEMORY if there was not enough memory to * allocate data structures * @remarks - * This function is NOT thread-safe + * This function is thread-safe */ extern ccs_result_t ccs_map_set(ccs_map_t map, ccs_datum_t key, ccs_datum_t value); @@ -79,7 +79,7 @@ ccs_map_get(ccs_map_t map, ccs_datum_t key, ccs_datum_t *value_ret); * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p map is not a valid CCS map * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p key does not exist in \p map * @remarks - * This function is NOT thread-safe + * This function is thread-safe */ extern ccs_result_t ccs_map_del(ccs_map_t map, ccs_datum_t key); @@ -179,7 +179,7 @@ ccs_map_get_pairs( * @return #CCS_RESULT_SUCCESS on success * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p map is not a valid CCS map * @remarks - * This function is NOT thread-safe + * This function is thread-safe */ extern ccs_result_t ccs_map_clear(ccs_map_t map); diff --git a/include/cconfigspace/rng.h b/include/cconfigspace/rng.h index d0c7a1ba..80e80593 100644 --- a/include/cconfigspace/rng.h +++ b/include/cconfigspace/rng.h @@ -68,7 +68,7 @@ ccs_rng_get_type(ccs_rng_t rng, const gsl_rng_type **rng_type_ret); * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p rng is not a valid CCS random * number generator * @remarks - * This function is NOT thread-safe + * This function is thread-safe */ extern ccs_result_t ccs_rng_set_seed(ccs_rng_t rng, unsigned long int seed); @@ -84,7 +84,7 @@ ccs_rng_set_seed(ccs_rng_t rng, unsigned long int seed); * number generator * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p value_ret is NULL * @remarks - * This function is NOT thread-safe + * This function is thread-safe */ extern ccs_result_t ccs_rng_get(ccs_rng_t rng, unsigned long int *value_ret); @@ -100,25 +100,10 @@ ccs_rng_get(ccs_rng_t rng, unsigned long int *value_ret); * number generator * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p value_ret is NULL * @remarks - * This function is NOT thread-safe - */ -extern ccs_result_t -ccs_rng_uniform(ccs_rng_t rng, ccs_float_t *value_ret); - -/** - * Get the underlying gsl random number generator. - * @param [in] rng - * @param [out] gsl_rng_ret a pointer to the variable that will contain a - * pointer to the underlying random number generator - * @return #CCS_RESULT_SUCCESS on success - * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p rng is not a valid CCS random - * number generator - * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p gsl_rng_ret is NULL - * @remarks * This function is thread-safe */ extern ccs_result_t -ccs_rng_get_gsl_rng(ccs_rng_t rng, gsl_rng **gsl_rng_ret); +ccs_rng_uniform(ccs_rng_t rng, ccs_float_t *value_ret); /** * Get the minimum value that can be returned by #ccs_rng_get. diff --git a/src/configuration_space.c b/src/configuration_space.c index 8a9db879..df8fc038 100644 --- a/src/configuration_space.c +++ b/src/configuration_space.c @@ -1151,7 +1151,7 @@ ccs_configuration_space_samples( size_t count = 0; ccs_bool_t found; ccs_configuration_t config = NULL; - CCS_OBJ_WRLOCK(configuration_space); + CCS_OBJ_RDLOCK(configuration_space); CCS_REFUTE_ERR_GOTO( err, !configuration_space->data->graph_ok, CCS_RESULT_ERROR_INVALID_GRAPH, errgraph); diff --git a/src/distribution.c b/src/distribution.c index ae0f5aff..ac5e703f 100644 --- a/src/distribution.c +++ b/src/distribution.c @@ -1,12 +1,6 @@ #include "cconfigspace_internal.h" #include "distribution_internal.h" -static inline _ccs_distribution_ops_t * -_ccs_distribution_get_ops(ccs_distribution_t distribution) -{ - return (_ccs_distribution_ops_t *)distribution->obj.ops; -} - ccs_result_t ccs_distribution_get_type( ccs_distribution_t distribution, @@ -97,9 +91,14 @@ ccs_distribution_sample( CCS_CHECK_OBJ(distribution, CCS_OBJECT_TYPE_DISTRIBUTION); CCS_CHECK_OBJ(rng, CCS_OBJECT_TYPE_RNG); CCS_CHECK_PTR(value_ret); + ccs_result_t err = CCS_RESULT_SUCCESS; _ccs_distribution_ops_t *ops = _ccs_distribution_get_ops(distribution); - CCS_VALIDATE(ops->samples(distribution->data, rng, 1, value_ret)); - return CCS_RESULT_SUCCESS; + CCS_OBJ_WRLOCK(rng); + CCS_VALIDATE_ERR_GOTO(err, ops->samples( + distribution->data, rng, 1, value_ret), end); +end: + CCS_OBJ_UNLOCK(rng); + return err; } ccs_result_t @@ -114,9 +113,14 @@ ccs_distribution_samples( if (!num_values) return CCS_RESULT_SUCCESS; CCS_CHECK_ARY(num_values, values); + ccs_result_t err = CCS_RESULT_SUCCESS; _ccs_distribution_ops_t *ops = _ccs_distribution_get_ops(distribution); - CCS_VALIDATE(ops->samples(distribution->data, rng, num_values, values)); - return CCS_RESULT_SUCCESS; + CCS_OBJ_WRLOCK(rng); + CCS_VALIDATE_ERR_GOTO(err, ops->samples( + distribution->data, rng, num_values, values), end); +end: + CCS_OBJ_UNLOCK(rng); + return err; } ccs_result_t @@ -137,10 +141,14 @@ ccs_distribution_strided_samples( if (!num_values) return CCS_RESULT_SUCCESS; CCS_CHECK_ARY(num_values, values); + ccs_result_t err = CCS_RESULT_SUCCESS; _ccs_distribution_ops_t *ops = _ccs_distribution_get_ops(distribution); - CCS_VALIDATE(ops->strided_samples( - distribution->data, rng, num_values, stride, values)); - return CCS_RESULT_SUCCESS; + CCS_OBJ_WRLOCK(rng); + CCS_VALIDATE_ERR_GOTO(err, ops->strided_samples( + distribution->data, rng, num_values, stride, values), end); +end: + CCS_OBJ_UNLOCK(rng); + return err; } ccs_result_t @@ -155,10 +163,14 @@ ccs_distribution_soa_samples( if (!num_values) return CCS_RESULT_SUCCESS; CCS_CHECK_ARY(num_values, values); + ccs_result_t err = CCS_RESULT_SUCCESS; _ccs_distribution_ops_t *ops = _ccs_distribution_get_ops(distribution); - CCS_VALIDATE( - ops->soa_samples(distribution->data, rng, num_values, values)); - return CCS_RESULT_SUCCESS; + CCS_OBJ_WRLOCK(rng); + CCS_VALIDATE_ERR_GOTO(err, ops->soa_samples( + distribution->data, rng, num_values, values), end); +end: + CCS_OBJ_UNLOCK(rng); + return err; } ccs_result_t @@ -212,11 +224,12 @@ ccs_distribution_parameters_samples( (ccs_numeric_t *)(mem + num_values * dim * sizeof(ccs_datum_t)); for (size_t i = 1; i < dim; i++) p_vs[i] = p_vs[i - 1] + num_values; - CCS_VALIDATE_ERR_GOTO( - err, - ccs_distribution_soa_samples( - distribution, rng, num_values, p_vs), - errmem); + + _ccs_distribution_ops_t *ops = _ccs_distribution_get_ops(distribution); + CCS_OBJ_WRLOCK(rng); + CCS_VALIDATE_ERR_GOTO(err, ops->soa_samples( + distribution->data, rng, num_values, p_vs), errlock); + CCS_OBJ_UNLOCK(rng); for (size_t i = 0; i < dim; i++) CCS_VALIDATE_ERR_GOTO( @@ -271,11 +284,10 @@ ccs_distribution_parameters_samples( *)(mem + buff_len * dim * sizeof(ccs_datum_t)); for (size_t i = 1; i < dim; i++) p_vs[i] = p_vs[i - 1] + buff_len; - CCS_VALIDATE_ERR_GOTO( - err, - ccs_distribution_soa_samples( - distribution, rng, buff_len, p_vs), - errmem); + CCS_OBJ_WRLOCK(rng); + CCS_VALIDATE_ERR_GOTO(err, ops->soa_samples( + distribution->data, rng, buff_len, p_vs), errlock); + CCS_OBJ_UNLOCK(rng); for (size_t i = 0; i < dim; i++) { CCS_VALIDATE_ERR_GOTO( err, @@ -305,6 +317,10 @@ ccs_distribution_parameters_samples( coeff <<= 1; } } + free((void *)mem); + return err; +errlock: + CCS_OBJ_UNLOCK(rng); errmem: free((void *)mem); return err; diff --git a/src/distribution_internal.h b/src/distribution_internal.h index a4a4c524..678bed36 100644 --- a/src/distribution_internal.h +++ b/src/distribution_internal.h @@ -137,4 +137,10 @@ _ccs_distribution_roulette_normalize_areas( roulette_areas[num_areas] = 1.0; } +static inline _ccs_distribution_ops_t * +_ccs_distribution_get_ops(ccs_distribution_t distribution) +{ + return (_ccs_distribution_ops_t *)distribution->obj.ops; +} + #endif //_DISTRIBUTION_INTERNAL_H diff --git a/src/distribution_mixture.c b/src/distribution_mixture.c index dc116742..70c12c88 100644 --- a/src/distribution_mixture.c +++ b/src/distribution_mixture.c @@ -4,6 +4,7 @@ #include #include "cconfigspace_internal.h" #include "distribution_internal.h" +#include "rng_internal.h" struct _ccs_distribution_mixture_data_s { _ccs_distribution_common_data_t common_data; @@ -347,12 +348,6 @@ _ccs_distribution_mixture_get_bounds( return CCS_RESULT_SUCCESS; } -static inline _ccs_distribution_ops_t * -ccs_distribution_get_ops(ccs_distribution_t distribution) -{ - return (_ccs_distribution_ops_t *)distribution->obj.ops; -} - static ccs_result_t _ccs_distribution_mixture_samples( _ccs_distribution_data_t *data, @@ -362,16 +357,14 @@ _ccs_distribution_mixture_samples( { _ccs_distribution_mixture_data_t *d = (_ccs_distribution_mixture_data_t *)data; - size_t dim = d->common_data.dimension; - - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + size_t dim = d->common_data.dimension; + gsl_rng *grng = rng->data->rng; for (size_t i = 0; i < num_values; i++) { ccs_float_t rnd = gsl_rng_uniform(grng); ccs_int_t index = _ccs_dichotomic_search( d->num_distributions, d->weights, rnd); - CCS_VALIDATE(ccs_distribution_get_ops(d->distributions[index]) + CCS_VALIDATE(_ccs_distribution_get_ops(d->distributions[index]) ->samples( d->distributions[index]->data, rng, 1, values + i * dim)); @@ -389,15 +382,13 @@ _ccs_distribution_mixture_strided_samples( { _ccs_distribution_mixture_data_t *d = (_ccs_distribution_mixture_data_t *)data; - - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; for (size_t i = 0; i < num_values; i++) { ccs_float_t rnd = gsl_rng_uniform(grng); ccs_int_t index = _ccs_dichotomic_search( d->num_distributions, d->weights, rnd); - CCS_VALIDATE(ccs_distribution_get_ops(d->distributions[index]) + CCS_VALIDATE(_ccs_distribution_get_ops(d->distributions[index]) ->samples( d->distributions[index]->data, rng, 1, values + i * stride)); @@ -427,8 +418,7 @@ _ccs_distribution_mixture_soa_samples( if (!needed) return CCS_RESULT_SUCCESS; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; for (size_t i = 0; i < num_values; i++) { ccs_float_t rnd = gsl_rng_uniform(grng); @@ -437,7 +427,7 @@ _ccs_distribution_mixture_soa_samples( for (size_t j = 0; j < dim; j++) if (values[j]) p_values[j] = values[j] + i; - CCS_VALIDATE(ccs_distribution_get_ops(d->distributions[index]) + CCS_VALIDATE(_ccs_distribution_get_ops(d->distributions[index]) ->soa_samples( d->distributions[index]->data, rng, 1, p_values)); diff --git a/src/distribution_multivariate.c b/src/distribution_multivariate.c index 16de7073..c105e664 100644 --- a/src/distribution_multivariate.c +++ b/src/distribution_multivariate.c @@ -285,12 +285,6 @@ _ccs_distribution_multivariate_get_bounds( return CCS_RESULT_SUCCESS; } -static inline _ccs_distribution_ops_t * -ccs_distribution_get_ops(ccs_distribution_t distribution) -{ - return (_ccs_distribution_ops_t *)distribution->obj.ops; -} - static ccs_result_t _ccs_distribution_multivariate_samples( _ccs_distribution_data_t *data, @@ -302,7 +296,7 @@ _ccs_distribution_multivariate_samples( (_ccs_distribution_multivariate_data_t *)data; for (size_t i = 0; i < d->num_distributions; i++) { - CCS_VALIDATE(ccs_distribution_get_ops(d->distributions[i]) + CCS_VALIDATE(_ccs_distribution_get_ops(d->distributions[i]) ->strided_samples( d->distributions[i]->data, rng, num_values, @@ -324,7 +318,7 @@ _ccs_distribution_multivariate_strided_samples( (_ccs_distribution_multivariate_data_t *)data; for (size_t i = 0; i < d->num_distributions; i++) { - CCS_VALIDATE(ccs_distribution_get_ops(d->distributions[i]) + CCS_VALIDATE(_ccs_distribution_get_ops(d->distributions[i]) ->strided_samples( d->distributions[i]->data, rng, num_values, stride, values)); @@ -344,7 +338,7 @@ _ccs_distribution_multivariate_soa_samples( (_ccs_distribution_multivariate_data_t *)data; for (size_t i = 0; i < d->num_distributions; i++) { - CCS_VALIDATE(ccs_distribution_get_ops(d->distributions[i]) + CCS_VALIDATE(_ccs_distribution_get_ops(d->distributions[i]) ->soa_samples( d->distributions[i]->data, rng, num_values, values)); diff --git a/src/distribution_normal.c b/src/distribution_normal.c index 9f6be69e..854bebb5 100644 --- a/src/distribution_normal.c +++ b/src/distribution_normal.c @@ -3,6 +3,7 @@ #include #include "cconfigspace_internal.h" #include "distribution_internal.h" +#include "rng_internal.h" struct _ccs_distribution_normal_data_s { _ccs_distribution_common_data_t common_data; @@ -358,8 +359,7 @@ _ccs_distribution_normal_samples( const ccs_float_t mu = d->mu; const ccs_float_t sigma = d->sigma; const int quantize = d->quantize; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; if (data_type == CCS_NUMERIC_TYPE_FLOAT) CCS_VALIDATE(_ccs_distribution_normal_samples_float( grng, scale_type, quantization.f, mu, sigma, quantize, @@ -502,8 +502,7 @@ _ccs_distribution_normal_strided_samples( const ccs_float_t mu = d->mu; const ccs_float_t sigma = d->sigma; const int quantize = d->quantize; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; if (data_type == CCS_NUMERIC_TYPE_FLOAT) CCS_VALIDATE(_ccs_distribution_normal_strided_samples_float( grng, scale_type, quantization.f, mu, sigma, quantize, diff --git a/src/distribution_roulette.c b/src/distribution_roulette.c index 8277ea07..3f28c082 100644 --- a/src/distribution_roulette.c +++ b/src/distribution_roulette.c @@ -3,6 +3,7 @@ #include #include "cconfigspace_internal.h" #include "distribution_internal.h" +#include "rng_internal.h" struct _ccs_distribution_roulette_data_s { _ccs_distribution_common_data_t common_data; @@ -182,8 +183,7 @@ _ccs_distribution_roulette_samples( _ccs_distribution_roulette_data_t *d = (_ccs_distribution_roulette_data_t *)data; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; for (size_t i = 0; i < num_values; i++) { ccs_float_t rnd = gsl_rng_uniform(grng); @@ -205,8 +205,7 @@ _ccs_distribution_roulette_strided_samples( _ccs_distribution_roulette_data_t *d = (_ccs_distribution_roulette_data_t *)data; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; for (size_t i = 0; i < num_values; i++) { ccs_float_t rnd = gsl_rng_uniform(grng); diff --git a/src/distribution_uniform.c b/src/distribution_uniform.c index 2b1f06c8..83f78150 100644 --- a/src/distribution_uniform.c +++ b/src/distribution_uniform.c @@ -3,6 +3,7 @@ #include #include "cconfigspace_internal.h" #include "distribution_internal.h" +#include "rng_internal.h" struct _ccs_distribution_uniform_data_s { _ccs_distribution_common_data_t common_data; @@ -223,8 +224,7 @@ _ccs_distribution_uniform_strided_samples( const ccs_numeric_t internal_lower = d->internal_lower; const ccs_numeric_t internal_upper = d->internal_upper; const int quantize = d->quantize; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; if (data_type == CCS_NUMERIC_TYPE_FLOAT) { for (i = 0; i < num_values; i++) { @@ -303,8 +303,7 @@ _ccs_distribution_uniform_samples( const ccs_numeric_t internal_lower = d->internal_lower; const ccs_numeric_t internal_upper = d->internal_upper; const int quantize = d->quantize; - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; if (data_type == CCS_NUMERIC_TYPE_FLOAT) { for (i = 0; i < num_values; i++) { diff --git a/src/map.c b/src/map.c index b10d5d0c..71bdf059 100644 --- a/src/map.c +++ b/src/map.c @@ -104,18 +104,22 @@ _ccs_map_serialize_size( size_t *cum_size, _ccs_object_serialize_options_t *opts) { + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_RDLOCK(object); switch (format) { case CCS_SERIALIZE_FORMAT_BINARY: *cum_size += _ccs_serialize_bin_size_ccs_map((ccs_map_t)object); break; default: - CCS_RAISE( - CCS_RESULT_ERROR_INVALID_VALUE, + CCS_RAISE_ERR_GOTO( + err, CCS_RESULT_ERROR_INVALID_VALUE, end, "Unsupported serialization format: %d", format); } - CCS_VALIDATE(_ccs_object_serialize_user_data_size( - object, format, cum_size, opts)); - return CCS_RESULT_SUCCESS; + CCS_VALIDATE_ERR_GOTO(err, _ccs_object_serialize_user_data_size( + object, format, cum_size, opts), end); +end: + CCS_OBJ_UNLOCK(object); + return err; } static ccs_result_t @@ -126,19 +130,23 @@ _ccs_map_serialize( char **buffer, _ccs_object_serialize_options_t *opts) { + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_RDLOCK(object); switch (format) { case CCS_SERIALIZE_FORMAT_BINARY: - CCS_VALIDATE(_ccs_serialize_bin_ccs_map( - (ccs_map_t)object, buffer_size, buffer)); + CCS_VALIDATE_ERR_GOTO(err, _ccs_serialize_bin_ccs_map( + (ccs_map_t)object, buffer_size, buffer), end); break; default: - CCS_RAISE( - CCS_RESULT_ERROR_INVALID_VALUE, + CCS_RAISE_ERR_GOTO( + err, CCS_RESULT_ERROR_INVALID_VALUE, end, "Unsupported serialization format: %d", format); } - CCS_VALIDATE(_ccs_object_serialize_user_data( - object, format, buffer_size, buffer, opts)); - return CCS_RESULT_SUCCESS; + CCS_VALIDATE_ERR_GOTO(err, _ccs_object_serialize_user_data( + object, format, buffer_size, buffer, opts), end); +end: + CCS_OBJ_UNLOCK(object); + return err; } static _ccs_map_ops_t _ccs_map_ops = { @@ -205,12 +213,13 @@ ccs_map_set(ccs_map_t map, ccs_datum_t key, ccs_datum_t value) size_t sz2 = 0; _ccs_map_datum_t *old_entry = NULL; _ccs_map_datum_t *entry = NULL; + CCS_OBJ_WRLOCK(map); HASH_FIND(hh, d->map, &key, sizeof(ccs_datum_t), old_entry); if (old_entry) if (!_datum_cmp(&value, &old_entry->value)) - return CCS_RESULT_SUCCESS; + goto end; - CCS_VALIDATE_ERR_GOTO(res, _ccs_map_check_datum(key, &sz, &sz1), err); + CCS_VALIDATE_ERR_GOTO(res, _ccs_map_check_datum(key, &sz, &sz1), end); CCS_VALIDATE_ERR_GOTO( res, _ccs_map_check_datum(value, &sz, &sz2), err_o1); @@ -226,7 +235,7 @@ ccs_map_set(ccs_map_t map, ccs_datum_t key, ccs_datum_t value) if (old_entry) _ccs_map_remove(d, old_entry); HASH_ADD(hh, d->map, key, sizeof(ccs_datum_t), entry); - return CCS_RESULT_SUCCESS; + goto end; err_mem: free(entry); err_o2: @@ -237,7 +246,8 @@ ccs_map_set(ccs_map_t map, ccs_datum_t key, ccs_datum_t value) if (key.type == CCS_DATA_TYPE_OBJECT && !(key.flags & CCS_DATUM_FLAG_ID)) ccs_release_object(key.value.o); -err: +end: + CCS_OBJ_UNLOCK(map); return res; } @@ -247,8 +257,10 @@ ccs_map_exist(ccs_map_t map, ccs_datum_t key, ccs_bool_t *exist) CCS_CHECK_OBJ(map, CCS_OBJECT_TYPE_MAP); CCS_CHECK_PTR(exist); _ccs_map_datum_t *entry; + CCS_OBJ_RDLOCK(map); HASH_FIND(hh, map->data->map, &key, sizeof(ccs_datum_t), entry); *exist = (entry != NULL) ? CCS_TRUE : CCS_FALSE; + CCS_OBJ_UNLOCK(map); return CCS_RESULT_SUCCESS; } @@ -258,11 +270,13 @@ ccs_map_get(ccs_map_t map, ccs_datum_t key, ccs_datum_t *value_ret) CCS_CHECK_OBJ(map, CCS_OBJECT_TYPE_MAP); CCS_CHECK_PTR(value_ret); _ccs_map_datum_t *entry; + CCS_OBJ_RDLOCK(map); HASH_FIND(hh, map->data->map, &key, sizeof(ccs_datum_t), entry); if (entry) *value_ret = entry->value; else *value_ret = ccs_none; + CCS_OBJ_UNLOCK(map); return CCS_RESULT_SUCCESS; } @@ -271,10 +285,14 @@ ccs_map_del(ccs_map_t map, ccs_datum_t key) { CCS_CHECK_OBJ(map, CCS_OBJECT_TYPE_MAP); _ccs_map_datum_t *entry; + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_WRLOCK(map); HASH_FIND(hh, map->data->map, &key, sizeof(ccs_datum_t), entry); - CCS_REFUTE(!entry, CCS_RESULT_ERROR_INVALID_VALUE); + CCS_REFUTE_ERR_GOTO(err, !entry, CCS_RESULT_ERROR_INVALID_VALUE, end); _ccs_map_remove(map->data, entry); - return CCS_RESULT_SUCCESS; +end: + CCS_OBJ_UNLOCK(map); + return err; } ccs_result_t @@ -287,10 +305,13 @@ ccs_map_get_keys( CCS_CHECK_OBJ(map, CCS_OBJECT_TYPE_MAP); CCS_CHECK_ARY(num_keys, keys); CCS_REFUTE(!keys && !num_keys_ret, CCS_RESULT_ERROR_INVALID_VALUE); - size_t num_entries = HASH_COUNT(map->data->map); + CCS_OBJ_RDLOCK(map); + ccs_result_t err = CCS_RESULT_SUCCESS; + size_t num_entries = HASH_COUNT(map->data->map); if (keys) { - CCS_REFUTE( - num_keys < num_entries, CCS_RESULT_ERROR_INVALID_VALUE); + CCS_REFUTE_ERR_GOTO( + err, num_keys < num_entries, + CCS_RESULT_ERROR_INVALID_VALUE, end); _ccs_map_datum_t *current = NULL, *tmp; size_t i = 0; HASH_ITER(hh, map->data->map, current, tmp) @@ -300,7 +321,9 @@ ccs_map_get_keys( } if (num_keys_ret) *num_keys_ret = num_entries; - return CCS_RESULT_SUCCESS; +end: + CCS_OBJ_UNLOCK(map); + return err; } ccs_result_t @@ -313,11 +336,13 @@ ccs_map_get_values( CCS_CHECK_OBJ(map, CCS_OBJECT_TYPE_MAP); CCS_CHECK_ARY(num_values, values); CCS_REFUTE(!values && !num_values_ret, CCS_RESULT_ERROR_INVALID_VALUE); - size_t num_entries = HASH_COUNT(map->data->map); + CCS_OBJ_RDLOCK(map); + ccs_result_t err = CCS_RESULT_SUCCESS; + size_t num_entries = HASH_COUNT(map->data->map); if (values) { - CCS_REFUTE( - num_values < num_entries, - CCS_RESULT_ERROR_INVALID_VALUE); + CCS_REFUTE_ERR_GOTO( + err, num_values < num_entries, + CCS_RESULT_ERROR_INVALID_VALUE, end); _ccs_map_datum_t *current = NULL, *tmp; size_t i = 0; HASH_ITER(hh, map->data->map, current, tmp) @@ -327,7 +352,9 @@ ccs_map_get_values( } if (num_values_ret) *num_values_ret = num_entries; - return CCS_RESULT_SUCCESS; +end: + CCS_OBJ_UNLOCK(map); + return err; } ccs_result_t @@ -342,11 +369,13 @@ ccs_map_get_pairs( CCS_CHECK_ARY(num_pairs, keys); CCS_CHECK_ARY(num_pairs, values); CCS_REFUTE(!keys && !num_pairs_ret, CCS_RESULT_ERROR_INVALID_VALUE); - size_t num_entries = HASH_COUNT(map->data->map); + CCS_OBJ_RDLOCK(map); + ccs_result_t err = CCS_RESULT_SUCCESS; + size_t num_entries = HASH_COUNT(map->data->map); if (keys) { - CCS_REFUTE( - num_pairs < num_entries, - CCS_RESULT_ERROR_INVALID_VALUE); + CCS_REFUTE_ERR_GOTO( + err, num_pairs < num_entries, + CCS_RESULT_ERROR_INVALID_VALUE, end); _ccs_map_datum_t *current = NULL, *tmp; size_t i = 0; HASH_ITER(hh, map->data->map, current, tmp) @@ -361,7 +390,9 @@ ccs_map_get_pairs( } if (num_pairs_ret) *num_pairs_ret = num_entries; - return CCS_RESULT_SUCCESS; +end: + CCS_OBJ_UNLOCK(map); + return err; } ccs_result_t @@ -369,7 +400,9 @@ ccs_map_clear(ccs_map_t map) { CCS_CHECK_OBJ(map, CCS_OBJECT_TYPE_MAP); _ccs_map_datum_t *current = NULL, *tmp; + CCS_OBJ_WRLOCK(map); HASH_ITER(hh, map->data->map, current, tmp) - _ccs_map_remove(map->data, current); + _ccs_map_remove(map->data, current); + CCS_OBJ_UNLOCK(map); return CCS_RESULT_SUCCESS; } diff --git a/src/rng.c b/src/rng.c index c710ee04..bdfeb0ec 100644 --- a/src/rng.c +++ b/src/rng.c @@ -61,18 +61,22 @@ _ccs_rng_serialize_size( size_t *cum_size, _ccs_object_serialize_options_t *opts) { + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_RDLOCK(object); switch (format) { case CCS_SERIALIZE_FORMAT_BINARY: *cum_size += _ccs_serialize_bin_size_ccs_rng((ccs_rng_t)object); break; default: - CCS_RAISE( - CCS_RESULT_ERROR_INVALID_VALUE, + CCS_RAISE_ERR_GOTO( + err, CCS_RESULT_ERROR_INVALID_VALUE, end, "Unsupported serialization format: %d", format); } - CCS_VALIDATE(_ccs_object_serialize_user_data_size( - object, format, cum_size, opts)); - return CCS_RESULT_SUCCESS; + CCS_VALIDATE_ERR_GOTO(err, _ccs_object_serialize_user_data_size( + object, format, cum_size, opts), end); +end: + CCS_OBJ_UNLOCK(object); + return err; } static ccs_result_t @@ -83,19 +87,23 @@ _ccs_rng_serialize( char **buffer, _ccs_object_serialize_options_t *opts) { + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_RDLOCK(object); switch (format) { case CCS_SERIALIZE_FORMAT_BINARY: - CCS_VALIDATE(_ccs_serialize_bin_ccs_rng( - (ccs_rng_t)object, buffer_size, buffer)); + CCS_VALIDATE_ERR_GOTO(err, _ccs_serialize_bin_ccs_rng( + (ccs_rng_t)object, buffer_size, buffer), end); break; default: - CCS_RAISE( - CCS_RESULT_ERROR_INVALID_VALUE, + CCS_RAISE_ERR_GOTO( + err, CCS_RESULT_ERROR_INVALID_VALUE, end, "Unsupported serialization format: %d", format); } - CCS_VALIDATE(_ccs_object_serialize_user_data( - object, format, buffer_size, buffer, opts)); - return CCS_RESULT_SUCCESS; + CCS_VALIDATE_ERR_GOTO(err, _ccs_object_serialize_user_data( + object, format, buffer_size, buffer, opts), end); +end: + CCS_OBJ_UNLOCK(object); + return err; } static struct _ccs_rng_ops_s _rng_ops = { @@ -146,7 +154,9 @@ ccs_result_t ccs_rng_set_seed(ccs_rng_t rng, unsigned long int seed) { CCS_CHECK_OBJ(rng, CCS_OBJECT_TYPE_RNG); + CCS_OBJ_WRLOCK(rng); gsl_rng_set(rng->data->rng, seed); + CCS_OBJ_UNLOCK(rng); return CCS_RESULT_SUCCESS; } @@ -155,7 +165,9 @@ ccs_rng_get(ccs_rng_t rng, unsigned long int *value_ret) { CCS_CHECK_OBJ(rng, CCS_OBJECT_TYPE_RNG); CCS_CHECK_PTR(value_ret); + CCS_OBJ_WRLOCK(rng); *value_ret = gsl_rng_get(rng->data->rng); + CCS_OBJ_UNLOCK(rng); return CCS_RESULT_SUCCESS; } @@ -164,16 +176,9 @@ ccs_rng_uniform(ccs_rng_t rng, ccs_float_t *value_ret) { CCS_CHECK_OBJ(rng, CCS_OBJECT_TYPE_RNG); CCS_CHECK_PTR(value_ret); + CCS_OBJ_WRLOCK(rng); *value_ret = gsl_rng_uniform(rng->data->rng); - return CCS_RESULT_SUCCESS; -} - -ccs_result_t -ccs_rng_get_gsl_rng(ccs_rng_t rng, gsl_rng **gsl_rng_ret) -{ - CCS_CHECK_OBJ(rng, CCS_OBJECT_TYPE_RNG); - CCS_CHECK_PTR(gsl_rng_ret); - *gsl_rng_ret = rng->data->rng; + CCS_OBJ_UNLOCK(rng); return CCS_RESULT_SUCCESS; } diff --git a/src/tree_internal.h b/src/tree_internal.h index 14ebdb7c..b7bd7173 100644 --- a/src/tree_internal.h +++ b/src/tree_internal.h @@ -1,6 +1,7 @@ #ifndef _TREE_INTERNAL_H #define _TREE_INTERNAL_H #include "distribution_internal.h" +#include "rng_internal.h" struct _ccs_tree_data_s; typedef struct _ccs_tree_data_s _ccs_tree_data_t; @@ -38,8 +39,7 @@ _ccs_tree_samples( CCS_REFUTE( data->sum_weights == 0.0, CCS_RESULT_ERROR_INVALID_DISTRIBUTION); - gsl_rng *grng; - CCS_VALIDATE(ccs_rng_get_gsl_rng(rng, &grng)); + gsl_rng *grng = rng->data->rng; for (size_t i = 0; i < num_indices; i++) { ccs_float_t rnd = gsl_rng_uniform(grng); ccs_int_t index = _ccs_dichotomic_search(