array: More locking fixes (#400)

* array: More locking fixes

helgrind threw out a couple more locking errors in the logging/array
code and we also need to protect a->max_elements
This commit is contained in:
Chrissie Caulfield 2020-06-08 14:16:58 +01:00 committed by GitHub
parent 08a165dc2c
commit b2acdea2a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -122,14 +122,19 @@ qb_array_index(struct qb_array * a, int32_t idx, void **element_out)
if (idx < 0) {
return -ERANGE;
}
(void)qb_thread_lock(a->grow_lock);
if ((uint32_t) idx >= a->max_elements) {
if (a->autogrow_elements == 0) {
(void)qb_thread_unlock(a->grow_lock);
return -ERANGE;
} else {
/* qb_array_grow gets the lock */
(void)qb_thread_unlock(a->grow_lock);
rc = qb_array_grow(a, idx + 1);
if (rc != 0) {
return rc;
}
(void)qb_thread_lock(a->grow_lock);
}
}
b = BIN_NUM_GET((uint32_t) idx);
@ -138,8 +143,6 @@ qb_array_index(struct qb_array * a, int32_t idx, void **element_out)
if (b >= a->num_bins || a->bin[b] == NULL) {
int32_t bin_alloced = QB_FALSE;
(void)qb_thread_lock(a->grow_lock);
if (b >= a->num_bins) {
rc = _grow_bin_array(a, b + 1);
if (rc < 0) {
@ -154,11 +157,13 @@ qb_array_index(struct qb_array * a, int32_t idx, void **element_out)
}
bin_alloced = QB_TRUE;
}
/* new_bin_cb() needs to be called unlocked so can't extend the lock after the if block */
(void)qb_thread_unlock(a->grow_lock);
if (bin_alloced && a->new_bin_cb) {
a->new_bin_cb(a, b);
}
} else {
(void)qb_thread_unlock(a->grow_lock);
}
elem = ELEM_NUM_GET(idx);
@ -188,10 +193,15 @@ qb_array_new_bin_cb_set(struct qb_array * a, qb_array_new_bin_cb_fn fn)
size_t
qb_array_num_bins_get(struct qb_array * a)
{
size_t bins;
if (a == NULL) {
return -EINVAL;
}
return a->num_bins;
(void)qb_thread_lock(a->grow_lock);
bins = a->num_bins;
(void)qb_thread_unlock(a->grow_lock);
return bins;
}
size_t
@ -212,18 +222,20 @@ qb_array_grow(struct qb_array * a, size_t max_elements)
if (a == NULL || max_elements > QB_ARRAY_MAX_ELEMENTS) {
return -EINVAL;
}
(void)qb_thread_lock(a->grow_lock);
if (max_elements <= a->max_elements) {
(void)qb_thread_unlock(a->grow_lock);
return 0;
}
a->max_elements = max_elements;
b = QB_MIN((max_elements / MAX_ELEMENTS_PER_BIN) + 1, MAX_BINS);
if (b > a->num_bins) {
(void)qb_thread_lock(a->grow_lock);
if (b >= a->num_bins) {
rc = _grow_bin_array(a, b + 1);
}
(void)qb_thread_unlock(a->grow_lock);
}
(void)qb_thread_unlock(a->grow_lock);
return rc;
}
@ -231,6 +243,12 @@ void
qb_array_free(struct qb_array *a)
{
size_t i;
/* In theory we should lock before accessing a->num_bins
* but as we're freeing the whole array here it seems
* a bit pointless as any other threads would segv when we
* unlock anyway
*/
for (i = 0; i < a->num_bins; i++) {
free(a->bin[i]);
}