[07/12] qemu-thread: add QemuSemaphore

Submitted by Paolo Bonzini on July 24, 2012, 4:55 p.m.

Details

Message ID 500ED384.5030901@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini July 24, 2012, 4:55 p.m.
Il 16/07/2012 16:20, Paolo Bonzini ha scritto:
>> > ...and that's why you check what needs to be done to handle this race
>> > after grabbing the mutex. IOW, replicate the state information that the
>> > Windows semaphore contains into the emulated condition variable object.
> It is already there (cv->waiters), but it is accessed atomically.  To do
> what you suggest I would need to add a mutex.

FWIW, I found a good condvar implementation in Chromium, but I really
don't have the time to port it over to QEMU right now.  I still would
like to get the semaphore version in 1.2.

Also, the attached pseudo-patch is an example of using semaphores to
limit the size of the critical sections, and also decrease the number of
threads created.  I'm not proposing to include it now, it's just an
example of things that are harder with condition variables than with
semaphores.

Paolo

Patch hide | download patch | download mbox

diff --git a/thread-pool.c b/thread-pool.c
index 7895544..72be971 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -71,20 +72,16 @@  static void *worker_thread(void *unused)
         ThreadPoolElement *req;
         int ret;
 
-        qemu_mutex_lock(&lock);
-        idle_threads++;
-        qemu_mutex_unlock(&lock);
-        ret = qemu_sem_timedwait(&sem, 10000);
-        qemu_mutex_lock(&lock);
-        idle_threads--;
+        atomic_inc(&idle_threads);
+        do {
+            ret = qemu_sem_timedwait(&sem, 10000);
+        } while (ret == -1 && atomic_read(&QTAILQ_FIRST(&request_list)) != NULL);
+        atomic_dec(&idle_threads);
         if (ret == -1) {
-            if (QTAILQ_EMPTY(&request_list)) {
-                break;
-            }
-            qemu_mutex_unlock(&lock);
-            continue;
+            break;
         }
 
+        qemu_mutex_lock(&lock);
         req = QTAILQ_FIRST(&request_list);
         QTAILQ_REMOVE(&request_list, req, reqs);
         req->state = THREAD_ACTIVE;
@@ -226,7 +223,7 @@  BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg,
     trace_thread_pool_submit(req, arg);
 
     qemu_mutex_lock(&lock);
-    if (idle_threads == 0 && cur_threads < max_threads) {
+    if (atomic_read(&idle_threads) == 0 && cur_threads < max_threads) {
         spawn_thread();
     }
     QTAILQ_INSERT_TAIL(&request_list, req, reqs);