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