coroutine: add ./configure --disable-coroutine-pool

The 'gthread' coroutine backend was written before the freelist (aka
pool) existed in qemu-coroutine.c.

This means that every thread is expected to exit when its coroutine
terminates.  It is not possible to reuse threads from a pool.

This patch automatically disables the pool when 'gthread' is used.  This
allows the 'gthread' backend to work again (for example,
tests/test-coroutine completes successfully instead of hanging).

I considered implementing thread reuse but I don't want quirks like CPU
affinity differences due to coroutine threads being recycled.  The
'gthread' backend is a reference backend and it's therefore okay to skip
the pool optimization.

Note this patch also makes it easy to toggle the pool for benchmarking
purposes:

  ./configure --with-coroutine-backend=ucontext \
              --disable-coroutine-pool

Reported-by: Gabriel Kerneis <gabriel@kerneis.info>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Gabriel Kerneis <gabriel@kerneis.info>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2013-09-11 16:42:35 +02:00 committed by Kevin Wolf
parent 2c78857bf6
commit 70c60c089f
2 changed files with 42 additions and 14 deletions

24
configure vendored
View file

@ -238,6 +238,7 @@ win_sdk="no"
want_tools="yes" want_tools="yes"
libiscsi="" libiscsi=""
coroutine="" coroutine=""
coroutine_pool=""
seccomp="" seccomp=""
glusterfs="" glusterfs=""
glusterfs_discard="no" glusterfs_discard="no"
@ -888,6 +889,10 @@ for opt do
;; ;;
--with-coroutine=*) coroutine="$optarg" --with-coroutine=*) coroutine="$optarg"
;; ;;
--disable-coroutine-pool) coroutine_pool="no"
;;
--enable-coroutine-pool) coroutine_pool="yes"
;;
--disable-docs) docs="no" --disable-docs) docs="no"
;; ;;
--enable-docs) docs="yes" --enable-docs) docs="yes"
@ -1189,6 +1194,8 @@ echo " --disable-seccomp disable seccomp support"
echo " --enable-seccomp enables seccomp support" echo " --enable-seccomp enables seccomp support"
echo " --with-coroutine=BACKEND coroutine backend. Supported options:" echo " --with-coroutine=BACKEND coroutine backend. Supported options:"
echo " gthread, ucontext, sigaltstack, windows" echo " gthread, ucontext, sigaltstack, windows"
echo " --disable-coroutine-pool disable coroutine freelist (worse performance)"
echo " --enable-coroutine-pool enable coroutine freelist (better performance)"
echo " --enable-glusterfs enable GlusterFS backend" echo " --enable-glusterfs enable GlusterFS backend"
echo " --disable-glusterfs disable GlusterFS backend" echo " --disable-glusterfs disable GlusterFS backend"
echo " --enable-gcov enable test coverage analysis with gcov" echo " --enable-gcov enable test coverage analysis with gcov"
@ -3362,6 +3369,17 @@ else
esac esac
fi fi
if test "$coroutine_pool" = ""; then
if test "$coroutine" = "gthread"; then
coroutine_pool=no
else
coroutine_pool=yes
fi
fi
if test "$coroutine" = "gthread" -a "$coroutine_pool" = "yes"; then
error_exit "'gthread' coroutine backend does not support pool (use --disable-coroutine-pool)"
fi
########################################## ##########################################
# check if we have open_by_handle_at # check if we have open_by_handle_at
@ -3733,6 +3751,7 @@ echo "build guest agent $guest_agent"
echo "QGA VSS support $guest_agent_with_vss" echo "QGA VSS support $guest_agent_with_vss"
echo "seccomp support $seccomp" echo "seccomp support $seccomp"
echo "coroutine backend $coroutine" echo "coroutine backend $coroutine"
echo "coroutine pool $coroutine_pool"
echo "GlusterFS support $glusterfs" echo "GlusterFS support $glusterfs"
echo "virtio-blk-data-plane $virtio_blk_data_plane" echo "virtio-blk-data-plane $virtio_blk_data_plane"
echo "gcov $gcov_tool" echo "gcov $gcov_tool"
@ -4092,6 +4111,11 @@ if test "$rbd" = "yes" ; then
fi fi
echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
if test "$coroutine_pool" = "yes" ; then
echo "CONFIG_COROUTINE_POOL=1" >> $config_host_mak
else
echo "CONFIG_COROUTINE_POOL=0" >> $config_host_mak
fi
if test "$open_by_handle_at" = "yes" ; then if test "$open_by_handle_at" = "yes" ; then
echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak

View file

@ -30,15 +30,17 @@ static unsigned int pool_size;
Coroutine *qemu_coroutine_create(CoroutineEntry *entry) Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
{ {
Coroutine *co; Coroutine *co = NULL;
qemu_mutex_lock(&pool_lock); if (CONFIG_COROUTINE_POOL) {
co = QSLIST_FIRST(&pool); qemu_mutex_lock(&pool_lock);
if (co) { co = QSLIST_FIRST(&pool);
QSLIST_REMOVE_HEAD(&pool, pool_next); if (co) {
pool_size--; QSLIST_REMOVE_HEAD(&pool, pool_next);
pool_size--;
}
qemu_mutex_unlock(&pool_lock);
} }
qemu_mutex_unlock(&pool_lock);
if (!co) { if (!co) {
co = qemu_coroutine_new(); co = qemu_coroutine_new();
@ -51,15 +53,17 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
static void coroutine_delete(Coroutine *co) static void coroutine_delete(Coroutine *co)
{ {
qemu_mutex_lock(&pool_lock); if (CONFIG_COROUTINE_POOL) {
if (pool_size < POOL_MAX_SIZE) { qemu_mutex_lock(&pool_lock);
QSLIST_INSERT_HEAD(&pool, co, pool_next); if (pool_size < POOL_MAX_SIZE) {
co->caller = NULL; QSLIST_INSERT_HEAD(&pool, co, pool_next);
pool_size++; co->caller = NULL;
pool_size++;
qemu_mutex_unlock(&pool_lock);
return;
}
qemu_mutex_unlock(&pool_lock); qemu_mutex_unlock(&pool_lock);
return;
} }
qemu_mutex_unlock(&pool_lock);
qemu_coroutine_delete(co); qemu_coroutine_delete(co);
} }