Fixed a hypothetical bug: switch_sem_etc() was using thread_get_current_thread()
in an error message without checking for a NULL pointer (which happens during early boot, and even though it would be impossible to get there at that time, it shouldn't be accidently copied to anywhere else this way). Added a compile time option to monitor the last thread that successfully acquired a semaphore (disabled, though, only enable it when needed). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13998 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+25
-9
@@ -28,12 +28,12 @@
|
|||||||
//#define TRACE_SEM
|
//#define TRACE_SEM
|
||||||
#ifdef TRACE_SEM
|
#ifdef TRACE_SEM
|
||||||
# define TRACE(x) dprintf x
|
# define TRACE(x) dprintf x
|
||||||
# define TRACE_BLOCK(x) dprintf x
|
|
||||||
#else
|
#else
|
||||||
# define TRACE(x) ;
|
# define TRACE(x) ;
|
||||||
# define TRACE_BLOCK(x) ;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//#define DEBUG_LAST_ACQUIRER
|
||||||
|
|
||||||
struct sem_entry {
|
struct sem_entry {
|
||||||
sem_id id;
|
sem_id id;
|
||||||
spinlock lock; // protects only the id field when unused
|
spinlock lock; // protects only the id field when unused
|
||||||
@@ -44,6 +44,9 @@ struct sem_entry {
|
|||||||
struct thread_queue queue;
|
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
|
||||||
|
#ifdef DEBUG_LAST_ACQUIRER
|
||||||
|
thread_id last_acquirer;
|
||||||
|
#endif
|
||||||
} used;
|
} used;
|
||||||
|
|
||||||
// when slot unused
|
// when slot unused
|
||||||
@@ -54,7 +57,7 @@ struct sem_entry {
|
|||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Todo: Compute based on the amount of available memory.
|
// ToDo: Compute based on the amount of available memory.
|
||||||
static int32 sMaxSems = 4096;
|
static int32 sMaxSems = 4096;
|
||||||
static int32 sUsedSems = 0;
|
static int32 sUsedSems = 0;
|
||||||
|
|
||||||
@@ -104,6 +107,9 @@ dump_sem(struct sem_entry *sem)
|
|||||||
kprintf("count: 0x%x\n", sem->u.used.count);
|
kprintf("count: 0x%x\n", sem->u.used.count);
|
||||||
kprintf("queue: head %p tail %p\n", sem->u.used.queue.head,
|
kprintf("queue: head %p tail %p\n", sem->u.used.queue.head,
|
||||||
sem->u.used.queue.tail);
|
sem->u.used.queue.tail);
|
||||||
|
#ifdef DEBUG_LAST_ACQUIRER
|
||||||
|
kprintf("last acquired by: 0x%lx\n", sem->u.used.last_acquirer);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
kprintf("next: %p\n", sem->u.unused.next);
|
kprintf("next: %p\n", sem->u.unused.next);
|
||||||
kprintf("next_id: %ld\n", sem->u.unused.next_id);
|
kprintf("next_id: %ld\n", sem->u.unused.next_id);
|
||||||
@@ -461,7 +467,8 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count,
|
|||||||
// doesn't have any use outside the kernel
|
// doesn't have any use outside the kernel
|
||||||
if ((flags & B_CHECK_PERMISSION) != 0
|
if ((flags & B_CHECK_PERMISSION) != 0
|
||||||
&& sSems[slot].u.used.owner == team_get_kernel_team_id()) {
|
&& sSems[slot].u.used.owner == team_get_kernel_team_id()) {
|
||||||
dprintf("thread %ld tried to acquire kernel semaphore.\n", thread_get_current_thread()->id);
|
dprintf("thread %ld tried to acquire kernel semaphore.\n",
|
||||||
|
thread_get_current_thread_id());
|
||||||
status = B_NOT_ALLOWED;
|
status = B_NOT_ALLOWED;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -479,8 +486,8 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count,
|
|||||||
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(("acquire_sem_etc(id = %ld): block name = %s, thread = %p,"
|
||||||
" name = %s\n", id, sSems[slot].u.used.name, thread, thread->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
|
||||||
@@ -558,12 +565,21 @@ switch_sem_etc(sem_id semToBeReleased, sem_id id, int32 count,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_LAST_ACQUIRER
|
||||||
|
if (thread->sem.acquire_status >= B_OK)
|
||||||
|
sSems[slot].u.used.last_acquirer = thread_get_current_thread_id();
|
||||||
|
#endif
|
||||||
|
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
TRACE_BLOCK(("acquire_sem_etc(id = %ld): exit block name = %s, "
|
TRACE(("acquire_sem_etc(id = %ld): exit block name = %s, "
|
||||||
"thread = %p (%s)\n", id, sSems[slot].u.used.name, thread,
|
"thread = %p (%s)\n", id, sSems[slot].u.used.name, thread,
|
||||||
thread->name));
|
thread->name));
|
||||||
return thread->sem.acquire_status;
|
return thread->sem.acquire_status;
|
||||||
|
} else {
|
||||||
|
#ifdef DEBUG_LAST_ACQUIRER
|
||||||
|
sSems[slot].u.used.last_acquirer = thread_get_current_thread_id();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
|||||||
Reference in New Issue
Block a user