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
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);

Reply via email to