Some cleanup.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11306 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+108
-100
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2004, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2002-2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||||
@@ -40,7 +40,7 @@ struct sem_entry {
|
|||||||
// when slot in use
|
// when slot in use
|
||||||
struct {
|
struct {
|
||||||
int count;
|
int count;
|
||||||
struct thread_queue q;
|
struct thread_queue queue;
|
||||||
char *name;
|
char *name;
|
||||||
team_id owner; // if set to -1, means owned by a port
|
team_id owner; // if set to -1, means owned by a port
|
||||||
} used;
|
} used;
|
||||||
@@ -68,7 +68,7 @@ static spinlock sem_spinlock = 0;
|
|||||||
#define GRAB_SEM_LOCK(s) acquire_spinlock(&(s).lock)
|
#define GRAB_SEM_LOCK(s) acquire_spinlock(&(s).lock)
|
||||||
#define RELEASE_SEM_LOCK(s) release_spinlock(&(s).lock)
|
#define RELEASE_SEM_LOCK(s) release_spinlock(&(s).lock)
|
||||||
|
|
||||||
static int remove_thread_from_sem(struct thread *t, struct sem_entry *sem,
|
static int remove_thread_from_sem(struct thread *thread, struct sem_entry *sem,
|
||||||
struct thread_queue *queue, status_t acquireStatus);
|
struct thread_queue *queue, status_t acquireStatus);
|
||||||
|
|
||||||
struct sem_timeout_args {
|
struct sem_timeout_args {
|
||||||
@@ -101,8 +101,8 @@ dump_sem(struct sem_entry *sem)
|
|||||||
dprintf("name: '%s'\n", sem->u.used.name);
|
dprintf("name: '%s'\n", sem->u.used.name);
|
||||||
dprintf("owner: 0x%lx\n", sem->u.used.owner);
|
dprintf("owner: 0x%lx\n", sem->u.used.owner);
|
||||||
dprintf("count: 0x%x\n", sem->u.used.count);
|
dprintf("count: 0x%x\n", sem->u.used.count);
|
||||||
dprintf("queue: head %p tail %p\n", sem->u.used.q.head,
|
dprintf("queue: head %p tail %p\n", sem->u.used.queue.head,
|
||||||
sem->u.used.q.tail);
|
sem->u.used.queue.tail);
|
||||||
} else {
|
} else {
|
||||||
dprintf("next: %p\n", sem->u.unused.next);
|
dprintf("next: %p\n", sem->u.unused.next);
|
||||||
dprintf("next_id: %ld\n", sem->u.unused.next_id);
|
dprintf("next_id: %ld\n", sem->u.unused.next_id);
|
||||||
@@ -151,6 +151,13 @@ dump_sem_info(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
clear_thread_queue(struct thread_queue *queue)
|
||||||
|
{
|
||||||
|
queue->head = queue->tail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** \brief Appends a semaphore slot to the free list.
|
/** \brief Appends a semaphore slot to the free list.
|
||||||
*
|
*
|
||||||
* The semaphore list must be locked.
|
* The semaphore list must be locked.
|
||||||
@@ -181,10 +188,10 @@ free_sem_slot(int slot, sem_id nextID)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
sem_init(kernel_args *ka)
|
sem_init(kernel_args *args)
|
||||||
{
|
{
|
||||||
area_id area;
|
area_id area;
|
||||||
int i;
|
int32 i;
|
||||||
|
|
||||||
TRACE(("sem_init: entry\n"));
|
TRACE(("sem_init: entry\n"));
|
||||||
|
|
||||||
@@ -252,12 +259,12 @@ create_sem_etc(int32 count, const char *name, team_id owner)
|
|||||||
sFreeSemsHead = sem->u.unused.next;
|
sFreeSemsHead = sem->u.unused.next;
|
||||||
if (!sFreeSemsHead)
|
if (!sFreeSemsHead)
|
||||||
sFreeSemsTail = NULL;
|
sFreeSemsTail = NULL;
|
||||||
|
|
||||||
// init the slot
|
// init the slot
|
||||||
GRAB_SEM_LOCK(*sem);
|
GRAB_SEM_LOCK(*sem);
|
||||||
sem->id = sem->u.unused.next_id;
|
sem->id = sem->u.unused.next_id;
|
||||||
sem->u.used.count = count;
|
sem->u.used.count = count;
|
||||||
sem->u.used.q.tail = NULL;
|
clear_thread_queue(&sem->u.used.queue);
|
||||||
sem->u.used.q.head = NULL;
|
|
||||||
sem->u.used.name = tempName;
|
sem->u.used.name = tempName;
|
||||||
sem->u.used.owner = owner;
|
sem->u.used.owner = owner;
|
||||||
id = sem->id;
|
id = sem->id;
|
||||||
@@ -286,12 +293,12 @@ create_sem(int32 count, const char *name)
|
|||||||
status_t
|
status_t
|
||||||
delete_sem(sem_id id)
|
delete_sem(sem_id id)
|
||||||
{
|
{
|
||||||
int slot;
|
struct thread_queue releaseQueue;
|
||||||
int state;
|
int32 releasedThreads;
|
||||||
struct thread *t;
|
struct thread *thread;
|
||||||
int released_threads;
|
cpu_status state;
|
||||||
char *old_name;
|
int32 slot;
|
||||||
struct thread_queue release_queue;
|
char *name;
|
||||||
|
|
||||||
if (sSemsActive == false)
|
if (sSemsActive == false)
|
||||||
return B_NO_MORE_SEMS;
|
return B_NO_MORE_SEMS;
|
||||||
@@ -310,20 +317,20 @@ delete_sem(sem_id id)
|
|||||||
return B_BAD_SEM_ID;
|
return B_BAD_SEM_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
released_threads = 0;
|
releasedThreads = 0;
|
||||||
release_queue.head = release_queue.tail = NULL;
|
clear_thread_queue(&releaseQueue);
|
||||||
|
|
||||||
// free any threads waiting for this semaphore
|
// free any threads waiting for this semaphore
|
||||||
while ((t = thread_dequeue(&sSems[slot].u.used.q)) != NULL) {
|
while ((thread = thread_dequeue(&sSems[slot].u.used.queue)) != NULL) {
|
||||||
t->state = B_THREAD_READY;
|
thread->state = B_THREAD_READY;
|
||||||
t->sem.acquire_status = B_BAD_SEM_ID;
|
thread->sem.acquire_status = B_BAD_SEM_ID;
|
||||||
t->sem.count = 0;
|
thread->sem.count = 0;
|
||||||
thread_enqueue(t, &release_queue);
|
thread_enqueue(thread, &releaseQueue);
|
||||||
released_threads++;
|
releasedThreads++;
|
||||||
}
|
}
|
||||||
|
|
||||||
sSems[slot].id = -1;
|
sSems[slot].id = -1;
|
||||||
old_name = sSems[slot].u.used.name;
|
name = sSems[slot].u.used.name;
|
||||||
sSems[slot].u.used.name = NULL;
|
sSems[slot].u.used.name = NULL;
|
||||||
|
|
||||||
RELEASE_SEM_LOCK(sSems[slot]);
|
RELEASE_SEM_LOCK(sSems[slot]);
|
||||||
@@ -334,10 +341,10 @@ delete_sem(sem_id id)
|
|||||||
atomic_add(&sUsedSems, -1);
|
atomic_add(&sUsedSems, -1);
|
||||||
RELEASE_SEM_LIST_LOCK();
|
RELEASE_SEM_LIST_LOCK();
|
||||||
|
|
||||||
if (released_threads > 0) {
|
if (releasedThreads > 0) {
|
||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
while ((t = thread_dequeue(&release_queue)) != NULL) {
|
while ((thread = thread_dequeue(&releaseQueue)) != NULL) {
|
||||||
scheduler_enqueue_in_run_queue(t);
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
}
|
}
|
||||||
scheduler_reschedule();
|
scheduler_reschedule();
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
@@ -345,7 +352,7 @@ delete_sem(sem_id id)
|
|||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
free(old_name);
|
free(name);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -357,13 +364,13 @@ static int32
|
|||||||
sem_timeout(timer *data)
|
sem_timeout(timer *data)
|
||||||
{
|
{
|
||||||
struct sem_timeout_args *args = (struct sem_timeout_args *)data->entry.prev;
|
struct sem_timeout_args *args = (struct sem_timeout_args *)data->entry.prev;
|
||||||
struct thread *t;
|
struct thread *thread;
|
||||||
int slot;
|
int slot;
|
||||||
int state;
|
int state;
|
||||||
struct thread_queue wakeup_queue;
|
struct thread_queue wakeupQueue;
|
||||||
|
|
||||||
t = thread_get_thread_struct(args->blocked_thread);
|
thread = thread_get_thread_struct(args->blocked_thread);
|
||||||
if (t == NULL)
|
if (thread == NULL)
|
||||||
return B_HANDLED_INTERRUPT;
|
return B_HANDLED_INTERRUPT;
|
||||||
slot = args->blocked_sem_id % sMaxSems;
|
slot = args->blocked_sem_id % sMaxSems;
|
||||||
|
|
||||||
@@ -378,15 +385,15 @@ sem_timeout(timer *data)
|
|||||||
args->blocked_thread, args->blocked_sem_id);
|
args->blocked_thread, args->blocked_sem_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
wakeup_queue.head = wakeup_queue.tail = NULL;
|
clear_thread_queue(&wakeupQueue);
|
||||||
remove_thread_from_sem(t, &sSems[slot], &wakeup_queue, B_TIMED_OUT);
|
remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_TIMED_OUT);
|
||||||
|
|
||||||
RELEASE_SEM_LOCK(sSems[slot]);
|
RELEASE_SEM_LOCK(sSems[slot]);
|
||||||
|
|
||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
// put the threads in the run q here to make sure we dont deadlock in sem_interrupt_thread
|
// put the threads in the run q here to make sure we dont deadlock in sem_interrupt_thread
|
||||||
while ((t = thread_dequeue(&wakeup_queue)) != NULL) {
|
while ((thread = thread_dequeue(&wakeupQueue)) != NULL) {
|
||||||
scheduler_enqueue_in_run_queue(t);
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
}
|
}
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
@@ -432,7 +439,7 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sSems[slot].u.used.count - count < 0 && (flags & B_TIMEOUT) != 0
|
if (sSems[slot].u.used.count - count < 0 && (flags & B_RELATIVE_TIMEOUT) != 0
|
||||||
&& timeout <= 0) {
|
&& timeout <= 0) {
|
||||||
// immediate timeout
|
// immediate timeout
|
||||||
status = B_WOULD_BLOCK;
|
status = B_WOULD_BLOCK;
|
||||||
@@ -441,16 +448,16 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
|||||||
|
|
||||||
if ((sSems[slot].u.used.count -= count) < 0) {
|
if ((sSems[slot].u.used.count -= count) < 0) {
|
||||||
// we need to block
|
// we need to block
|
||||||
struct thread *t = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
timer timeout_timer; // stick it on the stack, since we may be blocking here
|
timer timeout_timer; // stick it on the stack, since we may be blocking here
|
||||||
struct sem_timeout_args args;
|
struct sem_timeout_args args;
|
||||||
|
|
||||||
TRACE_BLOCK(("acquire_sem_etc(id = %ld): block name = %s, thread = %p,"
|
TRACE_BLOCK(("acquire_sem_etc(id = %ld): block name = %s, thread = %p,"
|
||||||
" name = %s\n", id, sSems[slot].u.used.name, t, t->name));
|
" name = %s\n", id, sSems[slot].u.used.name, thread, thread->name));
|
||||||
|
|
||||||
// do a quick check to see if the thread has any pending signals
|
// do a quick check to see if the thread has any pending signals
|
||||||
// this should catch most of the cases where the thread had a signal
|
// this should catch most of the cases where the thread had a signal
|
||||||
if ((flags & B_CAN_INTERRUPT) && t->sig_pending) {
|
if ((flags & B_CAN_INTERRUPT) && thread->sig_pending) {
|
||||||
sSems[slot].u.used.count += count;
|
sSems[slot].u.used.count += count;
|
||||||
status = B_INTERRUPTED;
|
status = B_INTERRUPTED;
|
||||||
goto err;
|
goto err;
|
||||||
@@ -459,22 +466,22 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
|||||||
if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) == 0)
|
if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) == 0)
|
||||||
timeout = B_INFINITE_TIMEOUT;
|
timeout = B_INFINITE_TIMEOUT;
|
||||||
|
|
||||||
t->next_state = B_THREAD_WAITING;
|
thread->next_state = B_THREAD_WAITING;
|
||||||
t->sem.flags = flags;
|
thread->sem.flags = flags;
|
||||||
t->sem.blocking = id;
|
thread->sem.blocking = id;
|
||||||
t->sem.acquire_count = count;
|
thread->sem.acquire_count = count;
|
||||||
t->sem.count = min(-sSems[slot].u.used.count, count);
|
thread->sem.count = min(-sSems[slot].u.used.count, count);
|
||||||
// store the count we need to restore upon release
|
// store the count we need to restore upon release
|
||||||
t->sem.acquire_status = B_NO_ERROR;
|
thread->sem.acquire_status = B_NO_ERROR;
|
||||||
thread_enqueue(t, &sSems[slot].u.used.q);
|
thread_enqueue(thread, &sSems[slot].u.used.queue);
|
||||||
|
|
||||||
if (timeout != B_INFINITE_TIMEOUT) {
|
if (timeout != B_INFINITE_TIMEOUT) {
|
||||||
TRACE(("sem_acquire_etc: setting timeout sem for %Ld usecs, semid %d, tid %d\n",
|
TRACE(("sem_acquire_etc: setting timeout sem for %Ld usecs, semid %d, tid %d\n",
|
||||||
timeout, id, t->id));
|
timeout, id, thread->id));
|
||||||
|
|
||||||
// set up an event to go off with the thread struct as the data
|
// set up an event to go off with the thread struct as the data
|
||||||
args.blocked_sem_id = id;
|
args.blocked_sem_id = id;
|
||||||
args.blocked_thread = t->id;
|
args.blocked_thread = thread->id;
|
||||||
args.sem_count = count;
|
args.sem_count = count;
|
||||||
|
|
||||||
// ToDo: another evil hack: pass the args into timer->entry.prev
|
// ToDo: another evil hack: pass the args into timer->entry.prev
|
||||||
@@ -488,20 +495,20 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
|||||||
GRAB_THREAD_LOCK();
|
GRAB_THREAD_LOCK();
|
||||||
// check again to see if a signal is pending.
|
// check again to see if a signal is pending.
|
||||||
// it may have been delivered while setting up the sem, though it's pretty unlikely
|
// it may have been delivered while setting up the sem, though it's pretty unlikely
|
||||||
if ((flags & B_CAN_INTERRUPT) && t->sig_pending) {
|
if ((flags & B_CAN_INTERRUPT) && thread->sig_pending) {
|
||||||
struct thread_queue wakeup_queue;
|
struct thread_queue wakeupQueue;
|
||||||
// ok, so a tiny race happened where a signal was delivered to this thread while
|
// ok, so a tiny race happened where a signal was delivered to this thread while
|
||||||
// it was setting up the sem. We can only be sure a signal wasn't delivered
|
// it was setting up the sem. We can only be sure a signal wasn't delivered
|
||||||
// here, since the threadlock is held. The previous check would have found most
|
// here, since the threadlock is held. The previous check would have found most
|
||||||
// instances, but there was a race, so we have to handle it. It'll be more messy...
|
// instances, but there was a race, so we have to handle it. It'll be more messy...
|
||||||
wakeup_queue.head = wakeup_queue.tail = NULL;
|
clear_thread_queue(&wakeupQueue);
|
||||||
GRAB_SEM_LOCK(sSems[slot]);
|
GRAB_SEM_LOCK(sSems[slot]);
|
||||||
if (sSems[slot].id == id) {
|
if (sSems[slot].id == id) {
|
||||||
remove_thread_from_sem(t, &sSems[slot], &wakeup_queue, EINTR);
|
remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_INTERRUPTED);
|
||||||
}
|
}
|
||||||
RELEASE_SEM_LOCK(sSems[slot]);
|
RELEASE_SEM_LOCK(sSems[slot]);
|
||||||
while ((t = thread_dequeue(&wakeup_queue)) != NULL) {
|
while ((thread = thread_dequeue(&wakeupQueue)) != NULL) {
|
||||||
scheduler_enqueue_in_run_queue(t);
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
}
|
}
|
||||||
// fall through and reschedule since another thread with a higher priority may have been woken up
|
// fall through and reschedule since another thread with a higher priority may have been woken up
|
||||||
}
|
}
|
||||||
@@ -509,7 +516,7 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
|||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
if (timeout != B_INFINITE_TIMEOUT) {
|
if (timeout != B_INFINITE_TIMEOUT) {
|
||||||
if (t->sem.acquire_status != B_TIMED_OUT) {
|
if (thread->sem.acquire_status != B_TIMED_OUT) {
|
||||||
// cancel the timer event, the sem may have been deleted or interrupted
|
// cancel the timer event, the sem may have been deleted or interrupted
|
||||||
// with the timer still active
|
// with the timer still active
|
||||||
cancel_timer(&timeout_timer);
|
cancel_timer(&timeout_timer);
|
||||||
@@ -519,9 +526,9 @@ acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout)
|
|||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
TRACE_BLOCK(("acquire_sem_etc(id = %ld): exit block name = %s, "
|
TRACE_BLOCK(("acquire_sem_etc(id = %ld): exit block name = %s, "
|
||||||
"thread = %p (%s)\n", id, sSems[slot].u.used.name, t,
|
"thread = %p (%s)\n", id, sSems[slot].u.used.name, thread,
|
||||||
t->name));
|
thread->name));
|
||||||
return t->sem.acquire_status;
|
return thread->sem.acquire_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -567,7 +574,7 @@ 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.
|
||||||
releaseQueue.head = releaseQueue.tail = NULL;
|
clear_thread_queue(&releaseQueue);
|
||||||
|
|
||||||
if (flags & B_RELEASE_ALL) {
|
if (flags & B_RELEASE_ALL) {
|
||||||
count = -sSems[slot].u.used.count;
|
count = -sSems[slot].u.used.count;
|
||||||
@@ -580,13 +587,13 @@ release_sem_etc(sem_id id, int32 count, uint32 flags)
|
|||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
int delta = count;
|
int delta = count;
|
||||||
if (sSems[slot].u.used.count < 0) {
|
if (sSems[slot].u.used.count < 0) {
|
||||||
struct thread *thread = thread_lookat_queue(&sSems[slot].u.used.q);
|
struct thread *thread = thread_lookat_queue(&sSems[slot].u.used.queue);
|
||||||
|
|
||||||
delta = min(count, thread->sem.count);
|
delta = min(count, thread->sem.count);
|
||||||
thread->sem.count -= delta;
|
thread->sem.count -= delta;
|
||||||
if (thread->sem.count <= 0) {
|
if (thread->sem.count <= 0) {
|
||||||
// release this thread
|
// release this thread
|
||||||
thread = thread_dequeue(&sSems[slot].u.used.q);
|
thread = thread_dequeue(&sSems[slot].u.used.queue);
|
||||||
thread_enqueue(thread, &releaseQueue);
|
thread_enqueue(thread, &releaseQueue);
|
||||||
thread->state = B_THREAD_READY;
|
thread->state = B_THREAD_READY;
|
||||||
thread->sem.count = 0;
|
thread->sem.count = 0;
|
||||||
@@ -678,8 +685,8 @@ fill_sem_info(struct sem_entry *sem, sem_info *info, size_t size)
|
|||||||
|
|
||||||
// ToDo: not sure if this is the latest holder, or the next
|
// ToDo: not sure if this is the latest holder, or the next
|
||||||
// holder...
|
// holder...
|
||||||
if (sem->u.used.q.head != NULL)
|
if (sem->u.used.queue.head != NULL)
|
||||||
info->latest_holder = sem->u.used.q.head->id;
|
info->latest_holder = sem->u.used.queue.head->id;
|
||||||
else
|
else
|
||||||
info->latest_holder = -1;
|
info->latest_holder = -1;
|
||||||
}
|
}
|
||||||
@@ -825,76 +832,77 @@ set_sem_owner(sem_id id, team_id team)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
sem_interrupt_thread(struct thread *t)
|
sem_interrupt_thread(struct thread *thread)
|
||||||
{
|
{
|
||||||
int slot;
|
struct thread_queue wakeupQueue;
|
||||||
struct thread_queue wakeup_queue;
|
int32 slot;
|
||||||
|
|
||||||
TRACE(("sem_interrupt_thread: called on thread %p (%d), blocked on sem 0x%x\n",
|
TRACE(("sem_interrupt_thread: called on thread %p (%d), blocked on sem 0x%x\n",
|
||||||
t, t->id, t->sem.blocking));
|
thread, thread->id, thread->sem.blocking));
|
||||||
|
|
||||||
if (t->state != B_THREAD_WAITING || t->sem.blocking < 0)
|
if (thread->state != B_THREAD_WAITING || thread->sem.blocking < 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
if (!(t->sem.flags & B_CAN_INTERRUPT))
|
if ((thread->sem.flags & B_CAN_INTERRUPT) == 0)
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
slot = t->sem.blocking % sMaxSems;
|
slot = thread->sem.blocking % sMaxSems;
|
||||||
|
|
||||||
GRAB_SEM_LOCK(sSems[slot]);
|
GRAB_SEM_LOCK(sSems[slot]);
|
||||||
|
|
||||||
if (sSems[slot].id != t->sem.blocking) {
|
if (sSems[slot].id != thread->sem.blocking) {
|
||||||
panic("sem_interrupt_thread: thread 0x%lx sez it's blocking on sem 0x%lx, but that sem doesn't exist!\n", t->id, t->sem.blocking);
|
panic("sem_interrupt_thread: thread 0x%lx sez it's blocking on sem 0x%lx, but that sem doesn't exist!\n", thread->id, thread->sem.blocking);
|
||||||
}
|
}
|
||||||
|
|
||||||
wakeup_queue.head = wakeup_queue.tail = NULL;
|
clear_thread_queue(&wakeupQueue);
|
||||||
if (remove_thread_from_sem(t, &sSems[slot], &wakeup_queue, EINTR) != B_OK)
|
if (remove_thread_from_sem(thread, &sSems[slot], &wakeupQueue, B_INTERRUPTED) != B_OK) {
|
||||||
panic("sem_interrupt_thread: thread 0x%lx not found in sem 0x%lx's wait queue\n", t->id, t->sem.blocking);
|
panic("sem_interrupt_thread: thread 0x%lx not found in sem 0x%lx's wait queue\n",
|
||||||
|
thread->id, thread->sem.blocking);
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE_SEM_LOCK(sSems[slot]);
|
RELEASE_SEM_LOCK(sSems[slot]);
|
||||||
|
|
||||||
while ((t = thread_dequeue(&wakeup_queue)) != NULL) {
|
while ((thread = thread_dequeue(&wakeupQueue)) != NULL) {
|
||||||
scheduler_enqueue_in_run_queue(t);
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_NO_ERROR;
|
return B_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** forcibly removes a thread from a semaphores wait q. May have to wake up other threads in the
|
/** Forcibly removes a thread from a semaphores wait queue. May have to wake up
|
||||||
* process. All threads that need to be woken up are added to the passed in thread_queue.
|
* other threads in the process. All threads that need to be woken up are added
|
||||||
* must be called with sem lock held
|
* to the passed in thread_queue.
|
||||||
|
* Must be called with semaphore lock held.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
remove_thread_from_sem(struct thread *t, struct sem_entry *sem, struct thread_queue *queue,
|
remove_thread_from_sem(struct thread *thread, struct sem_entry *sem,
|
||||||
status_t acquireStatus)
|
struct thread_queue *queue, status_t acquireStatus)
|
||||||
{
|
{
|
||||||
struct thread *t1;
|
|
||||||
|
|
||||||
// remove the thread from the queue and place it in the supplied queue
|
// remove the thread from the queue and place it in the supplied queue
|
||||||
t1 = thread_dequeue_id(&sem->u.used.q, t->id);
|
if (thread_dequeue_id(&sem->u.used.queue, thread->id) != thread)
|
||||||
if (t != t1)
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
sem->u.used.count += t->sem.acquire_count;
|
sem->u.used.count += thread->sem.acquire_count;
|
||||||
t->state = t->next_state = B_THREAD_READY;
|
thread->state = thread->next_state = B_THREAD_READY;
|
||||||
t->sem.acquire_status = acquireStatus;
|
thread->sem.acquire_status = acquireStatus;
|
||||||
thread_enqueue(t, queue);
|
thread_enqueue(thread, queue);
|
||||||
|
|
||||||
// now see if more threads need to be woken up
|
// now see if more threads need to be woken up
|
||||||
while (sem->u.used.count > 0
|
while (sem->u.used.count > 0
|
||||||
&& (t1 = thread_lookat_queue(&sem->u.used.q))) {
|
&& thread_lookat_queue(&sem->u.used.queue) != NULL) {
|
||||||
int delta = min(t->sem.count, sem->u.used.count);
|
int32 delta = min(thread->sem.count, sem->u.used.count);
|
||||||
|
|
||||||
t->sem.count -= delta;
|
thread->sem.count -= delta;
|
||||||
if (t->sem.count <= 0) {
|
if (thread->sem.count <= 0) {
|
||||||
t = thread_dequeue(&sem->u.used.q);
|
thread = thread_dequeue(&sem->u.used.queue);
|
||||||
t->state = t->next_state = B_THREAD_READY;
|
thread->state = thread->next_state = B_THREAD_READY;
|
||||||
thread_enqueue(t, queue);
|
thread_enqueue(thread, queue);
|
||||||
}
|
}
|
||||||
sem->u.used.count -= delta;
|
sem->u.used.count -= delta;
|
||||||
}
|
}
|
||||||
return B_NO_ERROR;
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user