diff mbox

[3/7] Add support for glib based threading and convert qemu thread to use it

Message ID 1295902845-29807-4-git-send-email-aliguori@us.ibm.com
State New
Headers show

Commit Message

Anthony Liguori Jan. 24, 2011, 9 p.m. UTC
GLib is an extremely common library that has a portable thread implementation
along with tons of other goodies.

GLib and GObject have a fantastic amount of infrastructure we can leverage in
QEMU including an object oriented programming infrastructure.

Short term, it has a very nice thread pool implementation that we could leverage
in something like virtio-9p.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

Comments

Aurelien Jarno Jan. 25, 2011, 2:24 p.m. UTC | #1
On Mon, Jan 24, 2011 at 03:00:41PM -0600, Anthony Liguori wrote:
> GLib is an extremely common library that has a portable thread implementation
> along with tons of other goodies.
> 
> GLib and GObject have a fantastic amount of infrastructure we can leverage in
> QEMU including an object oriented programming infrastructure.
> 
> Short term, it has a very nice thread pool implementation that we could leverage
> in something like virtio-9p.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> 
> diff --git a/Makefile b/Makefile
> index 6d601ee..bf24d1b 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -104,6 +104,8 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
>  
>  QEMU_CFLAGS+=$(CURL_CFLAGS)
>  
> +QEMU_CFLAGS+=$(GLIB_CFLAGS)
> +
>  ui/cocoa.o: ui/cocoa.m
>  
>  ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
> diff --git a/Makefile.objs b/Makefile.objs
> index c3e52c5..283e62a 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -316,3 +316,5 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>  
>  vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>  
> +vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
> +
> diff --git a/Makefile.target b/Makefile.target
> index e15b1c4..2c1c90e 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -204,6 +204,7 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>  QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
>  QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
>  QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
> +QEMU_CFLAGS += $(GLIB_CFLAGS)
>  
>  # xen backend driver support
>  obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
> diff --git a/configure b/configure
> index d5ac074..820fde9 100755
> --- a/configure
> +++ b/configure
> @@ -1658,6 +1658,17 @@ EOF
>  fi
>  
>  ##########################################
> +# glib support probe
> +if $pkg_config --modversion gthread-2.0 > /dev/null 2>&1 ; then
> +    glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
> +    glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
> +    libs_softmmu="$glib_libs $libs_softmmu"
> +else
> +    echo "glib-2.0 required to compile QEMU"
> +    exit 1
> +fi
> +
> +##########################################
>  # kvm probe
>  if test "$kvm" != "no" ; then
>      cat > $TMPC <<EOF
> @@ -2677,6 +2688,7 @@ if test "$bluez" = "yes" ; then
>    echo "CONFIG_BLUEZ=y" >> $config_host_mak
>    echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
>  fi
> +echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
>  if test "$xen" = "yes" ; then
>    echo "CONFIG_XEN=y" >> $config_host_mak
>  fi
> diff --git a/qemu-thread.c b/qemu-thread.c
> index fbc78fe..2c521ab 100644
> --- a/qemu-thread.c
> +++ b/qemu-thread.c
> @@ -10,183 +10,142 @@
>   * See the COPYING file in the top-level directory.
>   *
>   */
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <errno.h>
> -#include <time.h>
> -#include <signal.h>
> -#include <stdint.h>
> -#include <string.h>

Why removing <signal.h>?

> -#include "qemu-thread.h"
>  
> -static void error_exit(int err, const char *msg)
> -{
> -    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
> -    exit(1);
> -}
> +#include "qemu-common.h"
> +#include "qemu-thread.h"
>  
>  void qemu_mutex_init(QemuMutex *mutex)
>  {
> -    int err;
> -
> -    err = pthread_mutex_init(&mutex->lock, NULL);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_static_mutex_init(&mutex->lock);
>  }
>  
>  void qemu_mutex_destroy(QemuMutex *mutex)
>  {
> -    int err;
> -
> -    err = pthread_mutex_destroy(&mutex->lock);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_static_mutex_free(&mutex->lock);
>  }
>  
>  void qemu_mutex_lock(QemuMutex *mutex)
>  {
> -    int err;
> -
> -    err = pthread_mutex_lock(&mutex->lock);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_static_mutex_lock(&mutex->lock);
>  }
>  
>  int qemu_mutex_trylock(QemuMutex *mutex)
>  {
> -    return pthread_mutex_trylock(&mutex->lock);
> -}
> -
> -static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
> -{
> -    ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
> -    ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
> -    if (ts->tv_nsec >= 1000000000) {
> -        ts->tv_nsec -= 1000000000;
> -        ts->tv_sec++;
> -    }
> -}
> -
> -int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
> -{
> -    int err;
> -    struct timespec ts;
> -
> -    clock_gettime(CLOCK_REALTIME, &ts);
> -    timespec_add_ms(&ts, msecs);
> -
> -    err = pthread_mutex_timedlock(&mutex->lock, &ts);
> -    if (err && err != ETIMEDOUT)
> -        error_exit(err, __func__);
> -    return err;
> +    return g_static_mutex_trylock(&mutex->lock);
>  }
>  
>  void qemu_mutex_unlock(QemuMutex *mutex)
>  {
> -    int err;
> -
> -    err = pthread_mutex_unlock(&mutex->lock);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_static_mutex_unlock(&mutex->lock);
>  }
>  
>  void qemu_cond_init(QemuCond *cond)
>  {
> -    int err;
> -
> -    err = pthread_cond_init(&cond->cond, NULL);
> -    if (err)
> -        error_exit(err, __func__);
> +    cond->cond = g_cond_new();
>  }
>  
>  void qemu_cond_destroy(QemuCond *cond)
>  {
> -    int err;
> -
> -    err = pthread_cond_destroy(&cond->cond);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_cond_free(cond->cond);
>  }
>  
>  void qemu_cond_signal(QemuCond *cond)
>  {
> -    int err;
> -
> -    err = pthread_cond_signal(&cond->cond);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_cond_signal(cond->cond);
>  }
>  
>  void qemu_cond_broadcast(QemuCond *cond)
>  {
> -    int err;
> -
> -    err = pthread_cond_broadcast(&cond->cond);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_cond_broadcast(cond->cond);
>  }
>  
>  void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
>  {
> -    int err;
> -
> -    err = pthread_cond_wait(&cond->cond, &mutex->lock);
> -    if (err)
> -        error_exit(err, __func__);
> +    g_cond_wait(cond->cond, g_static_mutex_get_mutex(&mutex->lock));
>  }
>  
>  int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
>  {
> -    struct timespec ts;
> -    int err;
> +    GTimeVal abs_time;
> +
> +    assert(cond->cond != NULL);
>  
> -    clock_gettime(CLOCK_REALTIME, &ts);
> -    timespec_add_ms(&ts, msecs);
> +    g_get_current_time(&abs_time);
> +    g_time_val_add(&abs_time, msecs * 1000); /* MSEC to USEC */
>  
> -    err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
> -    if (err && err != ETIMEDOUT)
> -        error_exit(err, __func__);
> -    return err;
> +    return g_cond_timed_wait(cond->cond,
> +                             g_static_mutex_get_mutex(&mutex->lock), &abs_time);
> +}
> +
> +struct trampoline_data
> +{
> +    QemuThread *thread;
> +    void *(*startfn)(void *);
> +    void *opaque;
> +    QemuMutex lock;
> +};
> +
> +static gpointer thread_trampoline(gpointer data)
> +{
> +    struct trampoline_data *td = data;
> +    gpointer retval;
> +
> +    td->thread->tid = pthread_self();
> +    qemu_mutex_unlock(&td->lock);
> +
> +    retval = td->startfn(td->opaque);
> +    qemu_free(td);
> +
> +    return retval;
>  }
>  
>  void qemu_thread_create(QemuThread *thread,
> -                       void *(*start_routine)(void*),
> -                       void *arg)
> +                        void *(*start_routine)(void*),
> +                        void *arg)
>  {
> -    int err;
> +    struct trampoline_data *td = qemu_malloc(sizeof(*td));
> +    sigset_t set, old;
>  
> -    /* Leave signal handling to the iothread.  */
> -    sigset_t set, oldset;
> +    td->startfn = start_routine;
> +    td->opaque = arg;
> +    td->thread = thread;
> +    qemu_mutex_init(&td->lock);
> +
> +    /* on behalf of the new thread */
> +    qemu_mutex_lock(&td->lock);
>  
>      sigfillset(&set);

If it is still in use here? This simply doesn't build:

qemu-thread.c: In function ‘q_thread_create_nosignal’:
qemu-thread.c:34: error: implicit declaration of function ‘sigfillset’
qemu-thread.c:34: error: nested extern declaration of ‘sigfillset’
qemu-thread.c:35: error: implicit declaration of function ‘pthread_sigmask’
qemu-thread.c:35: error: nested extern declaration of ‘pthread_sigmask’
qemu-thread.c:35: error: ‘SIG_SETMASK’ undeclared (first use in this function)
qemu-thread.c:35: error: (Each undeclared identifier is reported only once
qemu-thread.c:35: error: for each function it appears in.)
qemu-thread.c: In function ‘qemu_sthread_create’:
qemu-thread.c:80: error: ‘SIG_SETMASK’ undeclared (first use in this function)
qemu-thread.c: In function ‘qemu_sthread_signal’:
qemu-thread.c:96: error: implicit declaration of function ‘pthread_kill’
qemu-thread.c:96: error: nested extern declaration of ‘pthread_kill’


> -    pthread_sigmask(SIG_SETMASK, &set, &oldset);
> -    err = pthread_create(&thread->thread, NULL, start_routine, arg);
> -    if (err)
> -        error_exit(err, __func__);
> +    pthread_sigmask(SIG_SETMASK, &set, &old);
> +    thread->thread = g_thread_create(thread_trampoline, td, TRUE, NULL);
> +    pthread_sigmask(SIG_SETMASK, &old, NULL);
> +
> +    /* we're transfering ownership of this lock to the thread so we no
> +     * longer hold it here */
>  
> -    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
> +    qemu_mutex_lock(&td->lock);
> +    /* validate tid */
> +    qemu_mutex_unlock(&td->lock);
> +
> +    qemu_mutex_destroy(&td->lock);
>  }
>  
>  void qemu_thread_signal(QemuThread *thread, int sig)
>  {
> -    int err;
> -
> -    err = pthread_kill(thread->thread, sig);
> -    if (err)
> -        error_exit(err, __func__);
> +    pthread_kill(thread->tid, sig);
>  }
>  
>  void qemu_thread_self(QemuThread *thread)
>  {
> -    thread->thread = pthread_self();
> +    thread->thread = g_thread_self();
> +    thread->tid = pthread_self();
>  }
>  
>  int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
>  {
> -   return pthread_equal(thread1->thread, thread2->thread);
> +    return (thread1->thread == thread2->thread);
>  }
>  
>  void qemu_thread_exit(void *retval)
>  {
> -    pthread_exit(retval);
> +    g_thread_exit(retval);
>  }
> diff --git a/qemu-thread.h b/qemu-thread.h
> index 19bb30c..dc22a60 100644
> --- a/qemu-thread.h
> +++ b/qemu-thread.h
> @@ -1,18 +1,19 @@
>  #ifndef __QEMU_THREAD_H
>  #define __QEMU_THREAD_H 1
> -#include "semaphore.h"
> -#include "pthread.h"
> +#include <glib.h>
> +#include <pthread.h>
>  
>  struct QemuMutex {
> -    pthread_mutex_t lock;
> +    GStaticMutex lock;
>  };
>  
>  struct QemuCond {
> -    pthread_cond_t cond;
> +    GCond *cond;
>  };
>  
>  struct QemuThread {
> -    pthread_t thread;
> +    GThread *thread;
> +    pthread_t tid;
>  };
>  
>  typedef struct QemuMutex QemuMutex;
> diff --git a/vl.c b/vl.c
> index 0292184..bbe0931 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -165,6 +165,8 @@ int main(int argc, char **argv)
>  
>  #include "ui/qemu-spice.h"
>  
> +#include <glib.h>
> +
>  //#define DEBUG_NET
>  //#define DEBUG_SLIRP
>  
> @@ -1918,6 +1920,8 @@ int main(int argc, char **argv, char **envp)
>      atexit(qemu_run_exit_notifiers);
>      error_set_progname(argv[0]);
>  
> +    g_thread_init(NULL);
> +
>      init_clocks();
>  
>      qemu_cache_utils_init(envp);
> -- 
> 1.7.0.4
> 
> 
>
Anthony Liguori Jan. 25, 2011, 3:34 p.m. UTC | #2
On 01/25/2011 08:24 AM, Aurelien Jarno wrote:
> On Mon, Jan 24, 2011 at 03:00:41PM -0600, Anthony Liguori wrote:
>    
>> GLib is an extremely common library that has a portable thread implementation
>> along with tons of other goodies.
>>
>> GLib and GObject have a fantastic amount of infrastructure we can leverage in
>> QEMU including an object oriented programming infrastructure.
>>
>> Short term, it has a very nice thread pool implementation that we could leverage
>> in something like virtio-9p.
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>
>> diff --git a/Makefile b/Makefile
>> index 6d601ee..bf24d1b 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -104,6 +104,8 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
>>
>>   QEMU_CFLAGS+=$(CURL_CFLAGS)
>>
>> +QEMU_CFLAGS+=$(GLIB_CFLAGS)
>> +
>>   ui/cocoa.o: ui/cocoa.m
>>
>>   ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
>> diff --git a/Makefile.objs b/Makefile.objs
>> index c3e52c5..283e62a 100644
>> --- a/Makefile.objs
>> +++ b/Makefile.objs
>> @@ -316,3 +316,5 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
>>
>>   vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
>>
>> +vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
>> +
>> diff --git a/Makefile.target b/Makefile.target
>> index e15b1c4..2c1c90e 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -204,6 +204,7 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>>   QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
>>   QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
>>   QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
>> +QEMU_CFLAGS += $(GLIB_CFLAGS)
>>
>>   # xen backend driver support
>>   obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
>> diff --git a/configure b/configure
>> index d5ac074..820fde9 100755
>> --- a/configure
>> +++ b/configure
>> @@ -1658,6 +1658,17 @@ EOF
>>   fi
>>
>>   ##########################################
>> +# glib support probe
>> +if $pkg_config --modversion gthread-2.0>  /dev/null 2>&1 ; then
>> +    glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
>> +    glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
>> +    libs_softmmu="$glib_libs $libs_softmmu"
>> +else
>> +    echo "glib-2.0 required to compile QEMU"
>> +    exit 1
>> +fi
>> +
>> +##########################################
>>   # kvm probe
>>   if test "$kvm" != "no" ; then
>>       cat>  $TMPC<<EOF
>> @@ -2677,6 +2688,7 @@ if test "$bluez" = "yes" ; then
>>     echo "CONFIG_BLUEZ=y">>  $config_host_mak
>>     echo "BLUEZ_CFLAGS=$bluez_cflags">>  $config_host_mak
>>   fi
>> +echo "GLIB_CFLAGS=$glib_cflags">>  $config_host_mak
>>   if test "$xen" = "yes" ; then
>>     echo "CONFIG_XEN=y">>  $config_host_mak
>>   fi
>> diff --git a/qemu-thread.c b/qemu-thread.c
>> index fbc78fe..2c521ab 100644
>> --- a/qemu-thread.c
>> +++ b/qemu-thread.c
>> @@ -10,183 +10,142 @@
>>    * See the COPYING file in the top-level directory.
>>    *
>>    */
>> -#include<stdlib.h>
>> -#include<stdio.h>
>> -#include<errno.h>
>> -#include<time.h>
>> -#include<signal.h>
>> -#include<stdint.h>
>> -#include<string.h>
>>      
> Why removing<signal.h>?
>    

It looked like unnecessary includes crept in so I remove them all.  It 
still built for me but apparently not for you.  I'll update accordingly.

Maybe we should put signal.h in qemu-common.h?

Regards,

Anthony Liguori

>> -#include "qemu-thread.h"
>>
>> -static void error_exit(int err, const char *msg)
>> -{
>> -    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
>> -    exit(1);
>> -}
>> +#include "qemu-common.h"
>> +#include "qemu-thread.h"
>>
>>   void qemu_mutex_init(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_init(&mutex->lock, NULL);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_init(&mutex->lock);
>>   }
>>
>>   void qemu_mutex_destroy(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_destroy(&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_free(&mutex->lock);
>>   }
>>
>>   void qemu_mutex_lock(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_lock(&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_lock(&mutex->lock);
>>   }
>>
>>   int qemu_mutex_trylock(QemuMutex *mutex)
>>   {
>> -    return pthread_mutex_trylock(&mutex->lock);
>> -}
>> -
>> -static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
>> -{
>> -    ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
>> -    ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
>> -    if (ts->tv_nsec>= 1000000000) {
>> -        ts->tv_nsec -= 1000000000;
>> -        ts->tv_sec++;
>> -    }
>> -}
>> -
>> -int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
>> -{
>> -    int err;
>> -    struct timespec ts;
>> -
>> -    clock_gettime(CLOCK_REALTIME,&ts);
>> -    timespec_add_ms(&ts, msecs);
>> -
>> -    err = pthread_mutex_timedlock(&mutex->lock,&ts);
>> -    if (err&&  err != ETIMEDOUT)
>> -        error_exit(err, __func__);
>> -    return err;
>> +    return g_static_mutex_trylock(&mutex->lock);
>>   }
>>
>>   void qemu_mutex_unlock(QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_mutex_unlock(&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_static_mutex_unlock(&mutex->lock);
>>   }
>>
>>   void qemu_cond_init(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_init(&cond->cond, NULL);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    cond->cond = g_cond_new();
>>   }
>>
>>   void qemu_cond_destroy(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_destroy(&cond->cond);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_free(cond->cond);
>>   }
>>
>>   void qemu_cond_signal(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_signal(&cond->cond);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_signal(cond->cond);
>>   }
>>
>>   void qemu_cond_broadcast(QemuCond *cond)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_broadcast(&cond->cond);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_broadcast(cond->cond);
>>   }
>>
>>   void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
>>   {
>> -    int err;
>> -
>> -    err = pthread_cond_wait(&cond->cond,&mutex->lock);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    g_cond_wait(cond->cond, g_static_mutex_get_mutex(&mutex->lock));
>>   }
>>
>>   int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
>>   {
>> -    struct timespec ts;
>> -    int err;
>> +    GTimeVal abs_time;
>> +
>> +    assert(cond->cond != NULL);
>>
>> -    clock_gettime(CLOCK_REALTIME,&ts);
>> -    timespec_add_ms(&ts, msecs);
>> +    g_get_current_time(&abs_time);
>> +    g_time_val_add(&abs_time, msecs * 1000); /* MSEC to USEC */
>>
>> -    err = pthread_cond_timedwait(&cond->cond,&mutex->lock,&ts);
>> -    if (err&&  err != ETIMEDOUT)
>> -        error_exit(err, __func__);
>> -    return err;
>> +    return g_cond_timed_wait(cond->cond,
>> +                             g_static_mutex_get_mutex(&mutex->lock),&abs_time);
>> +}
>> +
>> +struct trampoline_data
>> +{
>> +    QemuThread *thread;
>> +    void *(*startfn)(void *);
>> +    void *opaque;
>> +    QemuMutex lock;
>> +};
>> +
>> +static gpointer thread_trampoline(gpointer data)
>> +{
>> +    struct trampoline_data *td = data;
>> +    gpointer retval;
>> +
>> +    td->thread->tid = pthread_self();
>> +    qemu_mutex_unlock(&td->lock);
>> +
>> +    retval = td->startfn(td->opaque);
>> +    qemu_free(td);
>> +
>> +    return retval;
>>   }
>>
>>   void qemu_thread_create(QemuThread *thread,
>> -                       void *(*start_routine)(void*),
>> -                       void *arg)
>> +                        void *(*start_routine)(void*),
>> +                        void *arg)
>>   {
>> -    int err;
>> +    struct trampoline_data *td = qemu_malloc(sizeof(*td));
>> +    sigset_t set, old;
>>
>> -    /* Leave signal handling to the iothread.  */
>> -    sigset_t set, oldset;
>> +    td->startfn = start_routine;
>> +    td->opaque = arg;
>> +    td->thread = thread;
>> +    qemu_mutex_init(&td->lock);
>> +
>> +    /* on behalf of the new thread */
>> +    qemu_mutex_lock(&td->lock);
>>
>>       sigfillset(&set);
>>      
> If it is still in use here? This simply doesn't build:
>
> qemu-thread.c: In function ‘q_thread_create_nosignal’:
> qemu-thread.c:34: error: implicit declaration of function ‘sigfillset’
> qemu-thread.c:34: error: nested extern declaration of ‘sigfillset’
> qemu-thread.c:35: error: implicit declaration of function ‘pthread_sigmask’
> qemu-thread.c:35: error: nested extern declaration of ‘pthread_sigmask’
> qemu-thread.c:35: error: ‘SIG_SETMASK’ undeclared (first use in this function)
> qemu-thread.c:35: error: (Each undeclared identifier is reported only once
> qemu-thread.c:35: error: for each function it appears in.)
> qemu-thread.c: In function ‘qemu_sthread_create’:
> qemu-thread.c:80: error: ‘SIG_SETMASK’ undeclared (first use in this function)
> qemu-thread.c: In function ‘qemu_sthread_signal’:
> qemu-thread.c:96: error: implicit declaration of function ‘pthread_kill’
> qemu-thread.c:96: error: nested extern declaration of ‘pthread_kill’
>
>
>    
>> -    pthread_sigmask(SIG_SETMASK,&set,&oldset);
>> -    err = pthread_create(&thread->thread, NULL, start_routine, arg);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    pthread_sigmask(SIG_SETMASK,&set,&old);
>> +    thread->thread = g_thread_create(thread_trampoline, td, TRUE, NULL);
>> +    pthread_sigmask(SIG_SETMASK,&old, NULL);
>> +
>> +    /* we're transfering ownership of this lock to the thread so we no
>> +     * longer hold it here */
>>
>> -    pthread_sigmask(SIG_SETMASK,&oldset, NULL);
>> +    qemu_mutex_lock(&td->lock);
>> +    /* validate tid */
>> +    qemu_mutex_unlock(&td->lock);
>> +
>> +    qemu_mutex_destroy(&td->lock);
>>   }
>>
>>   void qemu_thread_signal(QemuThread *thread, int sig)
>>   {
>> -    int err;
>> -
>> -    err = pthread_kill(thread->thread, sig);
>> -    if (err)
>> -        error_exit(err, __func__);
>> +    pthread_kill(thread->tid, sig);
>>   }
>>
>>   void qemu_thread_self(QemuThread *thread)
>>   {
>> -    thread->thread = pthread_self();
>> +    thread->thread = g_thread_self();
>> +    thread->tid = pthread_self();
>>   }
>>
>>   int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
>>   {
>> -   return pthread_equal(thread1->thread, thread2->thread);
>> +    return (thread1->thread == thread2->thread);
>>   }
>>
>>   void qemu_thread_exit(void *retval)
>>   {
>> -    pthread_exit(retval);
>> +    g_thread_exit(retval);
>>   }
>> diff --git a/qemu-thread.h b/qemu-thread.h
>> index 19bb30c..dc22a60 100644
>> --- a/qemu-thread.h
>> +++ b/qemu-thread.h
>> @@ -1,18 +1,19 @@
>>   #ifndef __QEMU_THREAD_H
>>   #define __QEMU_THREAD_H 1
>> -#include "semaphore.h"
>> -#include "pthread.h"
>> +#include<glib.h>
>> +#include<pthread.h>
>>
>>   struct QemuMutex {
>> -    pthread_mutex_t lock;
>> +    GStaticMutex lock;
>>   };
>>
>>   struct QemuCond {
>> -    pthread_cond_t cond;
>> +    GCond *cond;
>>   };
>>
>>   struct QemuThread {
>> -    pthread_t thread;
>> +    GThread *thread;
>> +    pthread_t tid;
>>   };
>>
>>   typedef struct QemuMutex QemuMutex;
>> diff --git a/vl.c b/vl.c
>> index 0292184..bbe0931 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -165,6 +165,8 @@ int main(int argc, char **argv)
>>
>>   #include "ui/qemu-spice.h"
>>
>> +#include<glib.h>
>> +
>>   //#define DEBUG_NET
>>   //#define DEBUG_SLIRP
>>
>> @@ -1918,6 +1920,8 @@ int main(int argc, char **argv, char **envp)
>>       atexit(qemu_run_exit_notifiers);
>>       error_set_progname(argv[0]);
>>
>> +    g_thread_init(NULL);
>> +
>>       init_clocks();
>>
>>       qemu_cache_utils_init(envp);
>> -- 
>> 1.7.0.4
>>
>>
>>
>>      
>
Paolo Bonzini Feb. 2, 2011, 5:32 p.m. UTC | #3
On 01/24/2011 10:00 PM, Anthony Liguori wrote:
>   int qemu_mutex_trylock(QemuMutex *mutex)
>   {
> -    return pthread_mutex_trylock(&mutex->lock);
> +    return g_static_mutex_trylock(&mutex->lock);

This is missing a !

Paolo
Anthony Liguori Feb. 2, 2011, 5:35 p.m. UTC | #4
On 02/02/2011 11:32 AM, Paolo Bonzini wrote:
> On 01/24/2011 10:00 PM, Anthony Liguori wrote:
>>   int qemu_mutex_trylock(QemuMutex *mutex)
>>   {
>> -    return pthread_mutex_trylock(&mutex->lock);
>> +    return g_static_mutex_trylock(&mutex->lock);
>
> This is missing a !

Good catch.

Regards,

Anthony Liguori

>
> Paolo
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 6d601ee..bf24d1b 100644
--- a/Makefile
+++ b/Makefile
@@ -104,6 +104,8 @@  audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
 
 QEMU_CFLAGS+=$(CURL_CFLAGS)
 
+QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
 ui/cocoa.o: ui/cocoa.m
 
 ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
diff --git a/Makefile.objs b/Makefile.objs
index c3e52c5..283e62a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -316,3 +316,5 @@  vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
 
 vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
 
+vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
+
diff --git a/Makefile.target b/Makefile.target
index e15b1c4..2c1c90e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -204,6 +204,7 @@  QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
 QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
 QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
+QEMU_CFLAGS += $(GLIB_CFLAGS)
 
 # xen backend driver support
 obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
diff --git a/configure b/configure
index d5ac074..820fde9 100755
--- a/configure
+++ b/configure
@@ -1658,6 +1658,17 @@  EOF
 fi
 
 ##########################################
+# glib support probe
+if $pkg_config --modversion gthread-2.0 > /dev/null 2>&1 ; then
+    glib_cflags=`$pkg_config --cflags gthread-2.0 2>/dev/null`
+    glib_libs=`$pkg_config --libs gthread-2.0 2>/dev/null`
+    libs_softmmu="$glib_libs $libs_softmmu"
+else
+    echo "glib-2.0 required to compile QEMU"
+    exit 1
+fi
+
+##########################################
 # kvm probe
 if test "$kvm" != "no" ; then
     cat > $TMPC <<EOF
@@ -2677,6 +2688,7 @@  if test "$bluez" = "yes" ; then
   echo "CONFIG_BLUEZ=y" >> $config_host_mak
   echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
 fi
+echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
 if test "$xen" = "yes" ; then
   echo "CONFIG_XEN=y" >> $config_host_mak
 fi
diff --git a/qemu-thread.c b/qemu-thread.c
index fbc78fe..2c521ab 100644
--- a/qemu-thread.c
+++ b/qemu-thread.c
@@ -10,183 +10,142 @@ 
  * See the COPYING file in the top-level directory.
  *
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.h>
-#include <signal.h>
-#include <stdint.h>
-#include <string.h>
-#include "qemu-thread.h"
 
-static void error_exit(int err, const char *msg)
-{
-    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
-    exit(1);
-}
+#include "qemu-common.h"
+#include "qemu-thread.h"
 
 void qemu_mutex_init(QemuMutex *mutex)
 {
-    int err;
-
-    err = pthread_mutex_init(&mutex->lock, NULL);
-    if (err)
-        error_exit(err, __func__);
+    g_static_mutex_init(&mutex->lock);
 }
 
 void qemu_mutex_destroy(QemuMutex *mutex)
 {
-    int err;
-
-    err = pthread_mutex_destroy(&mutex->lock);
-    if (err)
-        error_exit(err, __func__);
+    g_static_mutex_free(&mutex->lock);
 }
 
 void qemu_mutex_lock(QemuMutex *mutex)
 {
-    int err;
-
-    err = pthread_mutex_lock(&mutex->lock);
-    if (err)
-        error_exit(err, __func__);
+    g_static_mutex_lock(&mutex->lock);
 }
 
 int qemu_mutex_trylock(QemuMutex *mutex)
 {
-    return pthread_mutex_trylock(&mutex->lock);
-}
-
-static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
-{
-    ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
-    ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
-    if (ts->tv_nsec >= 1000000000) {
-        ts->tv_nsec -= 1000000000;
-        ts->tv_sec++;
-    }
-}
-
-int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
-{
-    int err;
-    struct timespec ts;
-
-    clock_gettime(CLOCK_REALTIME, &ts);
-    timespec_add_ms(&ts, msecs);
-
-    err = pthread_mutex_timedlock(&mutex->lock, &ts);
-    if (err && err != ETIMEDOUT)
-        error_exit(err, __func__);
-    return err;
+    return g_static_mutex_trylock(&mutex->lock);
 }
 
 void qemu_mutex_unlock(QemuMutex *mutex)
 {
-    int err;
-
-    err = pthread_mutex_unlock(&mutex->lock);
-    if (err)
-        error_exit(err, __func__);
+    g_static_mutex_unlock(&mutex->lock);
 }
 
 void qemu_cond_init(QemuCond *cond)
 {
-    int err;
-
-    err = pthread_cond_init(&cond->cond, NULL);
-    if (err)
-        error_exit(err, __func__);
+    cond->cond = g_cond_new();
 }
 
 void qemu_cond_destroy(QemuCond *cond)
 {
-    int err;
-
-    err = pthread_cond_destroy(&cond->cond);
-    if (err)
-        error_exit(err, __func__);
+    g_cond_free(cond->cond);
 }
 
 void qemu_cond_signal(QemuCond *cond)
 {
-    int err;
-
-    err = pthread_cond_signal(&cond->cond);
-    if (err)
-        error_exit(err, __func__);
+    g_cond_signal(cond->cond);
 }
 
 void qemu_cond_broadcast(QemuCond *cond)
 {
-    int err;
-
-    err = pthread_cond_broadcast(&cond->cond);
-    if (err)
-        error_exit(err, __func__);
+    g_cond_broadcast(cond->cond);
 }
 
 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
 {
-    int err;
-
-    err = pthread_cond_wait(&cond->cond, &mutex->lock);
-    if (err)
-        error_exit(err, __func__);
+    g_cond_wait(cond->cond, g_static_mutex_get_mutex(&mutex->lock));
 }
 
 int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
 {
-    struct timespec ts;
-    int err;
+    GTimeVal abs_time;
+
+    assert(cond->cond != NULL);
 
-    clock_gettime(CLOCK_REALTIME, &ts);
-    timespec_add_ms(&ts, msecs);
+    g_get_current_time(&abs_time);
+    g_time_val_add(&abs_time, msecs * 1000); /* MSEC to USEC */
 
-    err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
-    if (err && err != ETIMEDOUT)
-        error_exit(err, __func__);
-    return err;
+    return g_cond_timed_wait(cond->cond,
+                             g_static_mutex_get_mutex(&mutex->lock), &abs_time);
+}
+
+struct trampoline_data
+{
+    QemuThread *thread;
+    void *(*startfn)(void *);
+    void *opaque;
+    QemuMutex lock;
+};
+
+static gpointer thread_trampoline(gpointer data)
+{
+    struct trampoline_data *td = data;
+    gpointer retval;
+
+    td->thread->tid = pthread_self();
+    qemu_mutex_unlock(&td->lock);
+
+    retval = td->startfn(td->opaque);
+    qemu_free(td);
+
+    return retval;
 }
 
 void qemu_thread_create(QemuThread *thread,
-                       void *(*start_routine)(void*),
-                       void *arg)
+                        void *(*start_routine)(void*),
+                        void *arg)
 {
-    int err;
+    struct trampoline_data *td = qemu_malloc(sizeof(*td));
+    sigset_t set, old;
 
-    /* Leave signal handling to the iothread.  */
-    sigset_t set, oldset;
+    td->startfn = start_routine;
+    td->opaque = arg;
+    td->thread = thread;
+    qemu_mutex_init(&td->lock);
+
+    /* on behalf of the new thread */
+    qemu_mutex_lock(&td->lock);
 
     sigfillset(&set);
-    pthread_sigmask(SIG_SETMASK, &set, &oldset);
-    err = pthread_create(&thread->thread, NULL, start_routine, arg);
-    if (err)
-        error_exit(err, __func__);
+    pthread_sigmask(SIG_SETMASK, &set, &old);
+    thread->thread = g_thread_create(thread_trampoline, td, TRUE, NULL);
+    pthread_sigmask(SIG_SETMASK, &old, NULL);
+
+    /* we're transfering ownership of this lock to the thread so we no
+     * longer hold it here */
 
-    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+    qemu_mutex_lock(&td->lock);
+    /* validate tid */
+    qemu_mutex_unlock(&td->lock);
+
+    qemu_mutex_destroy(&td->lock);
 }
 
 void qemu_thread_signal(QemuThread *thread, int sig)
 {
-    int err;
-
-    err = pthread_kill(thread->thread, sig);
-    if (err)
-        error_exit(err, __func__);
+    pthread_kill(thread->tid, sig);
 }
 
 void qemu_thread_self(QemuThread *thread)
 {
-    thread->thread = pthread_self();
+    thread->thread = g_thread_self();
+    thread->tid = pthread_self();
 }
 
 int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
 {
-   return pthread_equal(thread1->thread, thread2->thread);
+    return (thread1->thread == thread2->thread);
 }
 
 void qemu_thread_exit(void *retval)
 {
-    pthread_exit(retval);
+    g_thread_exit(retval);
 }
diff --git a/qemu-thread.h b/qemu-thread.h
index 19bb30c..dc22a60 100644
--- a/qemu-thread.h
+++ b/qemu-thread.h
@@ -1,18 +1,19 @@ 
 #ifndef __QEMU_THREAD_H
 #define __QEMU_THREAD_H 1
-#include "semaphore.h"
-#include "pthread.h"
+#include <glib.h>
+#include <pthread.h>
 
 struct QemuMutex {
-    pthread_mutex_t lock;
+    GStaticMutex lock;
 };
 
 struct QemuCond {
-    pthread_cond_t cond;
+    GCond *cond;
 };
 
 struct QemuThread {
-    pthread_t thread;
+    GThread *thread;
+    pthread_t tid;
 };
 
 typedef struct QemuMutex QemuMutex;
diff --git a/vl.c b/vl.c
index 0292184..bbe0931 100644
--- a/vl.c
+++ b/vl.c
@@ -165,6 +165,8 @@  int main(int argc, char **argv)
 
 #include "ui/qemu-spice.h"
 
+#include <glib.h>
+
 //#define DEBUG_NET
 //#define DEBUG_SLIRP
 
@@ -1918,6 +1920,8 @@  int main(int argc, char **argv, char **envp)
     atexit(qemu_run_exit_notifiers);
     error_set_progname(argv[0]);
 
+    g_thread_init(NULL);
+
     init_clocks();
 
     qemu_cache_utils_init(envp);