Added two experimental release_sem_etc() flags (both should stay, but they

may be renamed):
- B_RELEASE_ALL: the semaphore count is set to 0, all waiting threads are released
  (the "count" argument of release_etc_sem() is ignored then)
- B_RELEASE_IF_WAITING_ONLY: the semaphore count is only decreased if there
  are any waiting threads; ie. the semaphore is signaled
Together, they will make the pthread_cond_*() functions easy to implement, and
they come in handy at other places, too.
Removed release_threads variable in release_sem_etc(), as it was useless.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9330 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-10-13 15:55:30 +00:00
parent 9de969006b
commit 48e64cd7c8
+27 -23
View File
@@ -535,10 +535,9 @@ release_sem(sem_id id)
status_t status_t
release_sem_etc(sem_id id, int32 count, uint32 flags) release_sem_etc(sem_id id, int32 count, uint32 flags)
{ {
int slot = id % sMaxSems; struct thread_queue releaseQueue;
int state; int32 slot = id % sMaxSems;
int released_threads = 0; cpu_status state;
struct thread_queue release_queue;
status_t status = B_OK; status_t status = B_OK;
if (gSemsActive == false) if (gSemsActive == false)
@@ -561,24 +560,27 @@ release_sem_etc(sem_id id, int32 count, uint32 flags)
// put back into the run list. This is done so the thread lock wont be held // put back into the run list. This is done so the thread lock wont be held
// while this sems lock is held since the two locks are grabbed in the other // while this sems lock is held since the two locks are grabbed in the other
// order in sem_interrupt_thread. // order in sem_interrupt_thread.
release_queue.head = release_queue.tail = NULL; releaseQueue.head = releaseQueue.tail = NULL;
if (flags & B_RELEASE_ALL)
count = -gSems[slot].u.used.count;
while (count > 0) { while (count > 0) {
int delta = count; int delta = count;
if (gSems[slot].u.used.count < 0) { if (gSems[slot].u.used.count < 0) {
struct thread *t = thread_lookat_queue(&gSems[slot].u.used.q); struct thread *thread = thread_lookat_queue(&gSems[slot].u.used.q);
delta = min(count, t->sem.count); delta = min(count, thread->sem.count);
t->sem.count -= delta; thread->sem.count -= delta;
if (t->sem.count <= 0) { if (thread->sem.count <= 0) {
// release this thread // release this thread
t = thread_dequeue(&gSems[slot].u.used.q); thread = thread_dequeue(&gSems[slot].u.used.q);
thread_enqueue(t, &release_queue); thread_enqueue(thread, &releaseQueue);
t->state = B_THREAD_READY; thread->state = B_THREAD_READY;
released_threads++; thread->sem.count = 0;
t->sem.count = 0;
} }
} } else if (flags & B_RELEASE_IF_WAITING_ONLY)
break;
gSems[slot].u.used.count += delta; gSems[slot].u.used.count += delta;
count -= delta; count -= delta;
@@ -586,16 +588,18 @@ release_sem_etc(sem_id id, int32 count, uint32 flags)
RELEASE_SEM_LOCK(gSems[slot]); RELEASE_SEM_LOCK(gSems[slot]);
// pull off any items in the release queue and put them in the run queue // pull off any items in the release queue and put them in the run queue
if (released_threads > 0) { if (releaseQueue.head != NULL) {
struct thread *t; struct thread *thread;
int priority; int32 priority;
GRAB_THREAD_LOCK(); GRAB_THREAD_LOCK();
while ((t = thread_dequeue(&release_queue)) != NULL) { while ((thread = thread_dequeue(&releaseQueue)) != NULL) {
// temporarily place thread in a run queue with high priority to boost it up // temporarily place thread in a run queue with high priority to boost it up
priority = t->priority; priority = thread->priority;
t->priority = t->priority >= B_FIRST_REAL_TIME_PRIORITY ? t->priority : B_FIRST_REAL_TIME_PRIORITY; thread->priority = thread->priority >= B_FIRST_REAL_TIME_PRIORITY ?
scheduler_enqueue_in_run_queue(t); thread->priority : B_FIRST_REAL_TIME_PRIORITY;
t->priority = priority; scheduler_enqueue_in_run_queue(thread);
thread->priority = priority;
} }
if ((flags & B_DO_NOT_RESCHEDULE) == 0) if ((flags & B_DO_NOT_RESCHEDULE) == 0)
scheduler_reschedule(); scheduler_reschedule();