aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2019-01-16 08:35:36 +0100
committerJérôme Forissier <jerome.forissier@linaro.org>2019-01-16 15:38:55 +0100
commit60b3990430935a38f7491381690baa7de1000acc (patch)
tree056ef2632a19d1102fdbc5498508e5f1a2c81716 /lib
parent9133478719123b148e605ab559e06b4dd25ce46f (diff)
mempool: fix race in get_pool()
Fixes a race in get_pool() which could leave the pool with zero refences but still owned by the last thread using the pool. Some performance number on Hikey with default configuration: github/master (edbb89f, before this commit): 4006 real 1m 41.11s 4007 real 1m 14.51s 4008 real 0m 0.13s 4009 real 1m 5.68s Revert "mempool: optimize reference counting", before this commit: 4006 real 3m 27.78s 4007 real 0m 50.03s 4008 real 0m 0.13s 4009 real 2m 24.07s With this commit, two runs: 4006 real 1m 37.51s 4007 real 0m 56.67s 4008 real 0m 0.09s 4009 real 1m 3.18s 4006 real 1m 37.61s 4007 real 0m 35.32s 4008 real 0m 0.13s 4009 real 1m 3.15s Numbers are gathered with this script: for a in 4006 4007 4008 4009 ; do \ echo -n $a " " >> time.txt ;\ time -o time.txt.tmp xtest -l 15 $a || break ;\ grep real time.txt.tmp >> time.txt done cat time.txt Reviewed-by: Volodymyr Babchuk <vlad.babchuk@gmail.com> Acked-by: Jerome Forissier <jerome.forissier@linaro.org> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/libutils/ext/mempool.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/lib/libutils/ext/mempool.c b/lib/libutils/ext/mempool.c
index 8419e82b..f9776995 100644
--- a/lib/libutils/ext/mempool.c
+++ b/lib/libutils/ext/mempool.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
- * Copyright (c) 2018, Linaro Limited
+ * Copyright (c) 2018-2019, Linaro Limited
*/
@@ -74,10 +74,15 @@ struct mempool {
static void get_pool(struct mempool *pool __maybe_unused)
{
#if defined(__KERNEL__)
- if (refcount_inc(&pool->refc)) {
- if (pool->owner == thread_get_id())
- return;
- refcount_dec(&pool->refc);
+ /*
+ * Owner matches our thread it cannot be changed. If it doesn't
+ * match it can change any at time we're not holding the mutex to
+ * any value but our thread id.
+ */
+ if (atomic_load_int(&pool->owner) == thread_get_id()) {
+ if (!refcount_inc(&pool->refc))
+ panic();
+ return;
}
mutex_lock(&pool->mu);
@@ -96,12 +101,16 @@ static void get_pool(struct mempool *pool __maybe_unused)
static void put_pool(struct mempool *pool __maybe_unused)
{
#if defined(__KERNEL__)
- assert(pool->owner == thread_get_id());
+ assert(atomic_load_int(&pool->owner) == thread_get_id());
if (refcount_dec(&pool->refc)) {
mutex_lock(&pool->mu);
- pool->owner = THREAD_ID_INVALID;
+ /*
+ * Do an atomic store to match the atomic load in
+ * get_pool() above.
+ */
+ atomic_store_int(&pool->owner, THREAD_ID_INVALID);
condvar_signal(&pool->cv);
/* As the refcount is 0 there should be no items left */