* Use a condition variable when waiting for a syscall to be done calling.

* Use C++ DoublyLinkedList class instead of the struct list.
* Note, this code is untested yet, but I will test it now (Qemu doesn't work
  on Haiku anymore for some reason) :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34382 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-11-30 16:10:11 +00:00
parent a0973602c3
commit be62abafab
1 changed files with 34 additions and 25 deletions

View File

@ -55,19 +55,22 @@
typedef struct generic_syscall generic_syscall; typedef struct generic_syscall generic_syscall;
struct generic_syscall { struct generic_syscall : DoublyLinkedListLinkImpl<generic_syscall> {
list_link link;
char subsystem[B_FILE_NAME_LENGTH]; char subsystem[B_FILE_NAME_LENGTH];
syscall_hook hook; syscall_hook hook;
uint32 version; uint32 version;
uint32 flags; uint32 flags;
int32 use_count; int32 use_count;
bool valid; bool valid;
generic_syscall *previous; ConditionVariable unused_condition;
generic_syscall* previous;
}; };
typedef DoublyLinkedList<generic_syscall> GenericSyscallList;
static mutex sGenericSyscallLock = MUTEX_INITIALIZER("generic syscall"); static mutex sGenericSyscallLock = MUTEX_INITIALIZER("generic syscall");
static struct list sGenericSyscalls; static GenericSyscallList sGenericSyscalls;
#if SYSCALL_TRACING #if SYSCALL_TRACING
@ -78,12 +81,11 @@ static int dump_syscall_tracing(int argc, char** argv);
static generic_syscall* static generic_syscall*
find_generic_syscall(const char* subsystem) find_generic_syscall(const char* subsystem)
{ {
generic_syscall* syscall = NULL;
ASSERT_LOCKED_MUTEX(&sGenericSyscallLock); ASSERT_LOCKED_MUTEX(&sGenericSyscallLock);
while ((syscall = (generic_syscall*)list_get_next_item(&sGenericSyscalls, GenericSyscallList::Iterator iterator = sGenericSyscalls.GetIterator();
syscall)) != NULL) {
while (generic_syscall* syscall = iterator.Next()) {
if (!strcmp(syscall->subsystem, subsystem)) if (!strcmp(syscall->subsystem, subsystem))
return syscall; return syscall;
} }
@ -149,7 +151,9 @@ _user_generic_syscall(const char* userSubsystem, uint32 function,
= syscall->hook(subsystem, function, buffer, bufferSize); = syscall->hook(subsystem, function, buffer, bufferSize);
locker.Lock(); locker.Lock();
syscall->use_count--;
if (--syscall->use_count == 0)
syscall->unused_condition.NotifyAll();
if (status != B_BAD_HANDLER) if (status != B_BAD_HANDLER)
return status; return status;
@ -218,7 +222,7 @@ syscall_dispatcher(uint32 callIndex, void* args, uint64* _returnValue)
status_t status_t
generic_syscall_init(void) generic_syscall_init(void)
{ {
list_init(&sGenericSyscalls); new(&sGenericSyscalls) GenericSyscallList;
#if SYSCALL_TRACING #if SYSCALL_TRACING
add_debugger_command_etc("straced", &dump_syscall_tracing, add_debugger_command_etc("straced", &dump_syscall_tracing,
@ -257,8 +261,7 @@ register_generic_syscall(const char* subsystem, syscall_hook hook,
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
} }
generic_syscall* syscall generic_syscall* syscall = new(std::nothrow) generic_syscall;
= (generic_syscall*)malloc(sizeof(struct generic_syscall));
if (syscall == NULL) if (syscall == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@ -269,10 +272,12 @@ register_generic_syscall(const char* subsystem, syscall_hook hook,
syscall->use_count = 0; syscall->use_count = 0;
syscall->valid = true; syscall->valid = true;
syscall->previous = previous; syscall->previous = previous;
list_add_item(&sGenericSyscalls, syscall); syscall->unused_condition.Init(syscall, "syscall unused");
sGenericSyscalls.Add(syscall);
if (previous != NULL) if (previous != NULL)
list_remove_link(&previous->link); sGenericSyscalls.Remove(previous);
return B_OK; return B_OK;
} }
@ -293,19 +298,23 @@ unregister_generic_syscall(const char* subsystem, uint32 version)
syscall->valid = false; syscall->valid = false;
if (syscall->use_count != 0) { if (syscall->use_count != 0) {
// TODO: we could use a condition variable here instead // Wait until the syscall isn't in use anymore
ConditionVariableEntry entry;
syscall->unused_condition.Add(&entry);
locker.Unlock(); locker.Unlock();
snooze(6000);
entry.Wait();
continue; continue;
} }
if (syscall->previous != NULL) { if (syscall->previous != NULL) {
// reestablish the old syscall // reestablish the old syscall
list_add_item(&sGenericSyscalls, syscall->previous); sGenericSyscalls.Add(syscall->previous);
} }
list_remove_link(&syscall->link); sGenericSyscalls.Remove(syscall);
free(syscall); delete syscall;
return B_OK; return B_OK;
} }