Author: bonefish Date: 2011-05-10 00:10:22 +0200 (Tue, 10 May 2011) New Revision: 41407 Changeset: https://dev.haiku-os.org/changeset/41407 Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp Log: * Thread: - Added constructor/destructor and moved the code from creation/deletion functions to them. - Derived from BReferenceable. - Added mutex fLock and locking methods. Not used yet. * Changed sThreadHash from C khash to BOpenHashTable. Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 2011-05-09 18:11:12 UTC (rev 41406) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 2011-05-09 22:10:22 UTC (rev 41407) @@ -330,7 +330,7 @@ }; -struct Thread { +struct Thread : BReferenceable { int32 flags; // summary of events relevant in interrupt // handlers (signals pending, user debugging // enabled, etc.) @@ -440,6 +440,31 @@ // architecture dependent section struct arch_thread arch_info; + +public: + Thread() {} + // dummy for the idle threads + Thread(const char *name, thread_id threadID, + struct cpu_ent *cpu); + ~Thread(); + + void* operator new(size_t size); + void* operator new(size_t, void* pointer); + void operator delete(void* pointer, size_t size); + + status_t Init(bool idleThread); + + void ResetSignals(); + + bool Lock() + { mutex_lock(&fLock); return true; } + bool TryLock() + { return mutex_trylock(&fLock) == B_OK; } + void Unlock() + { mutex_unlock(&fLock); } + +private: + mutex fLock; }; Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp 2011-05-09 18:11:12 UTC (rev 41406) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp 2011-05-09 22:10:22 UTC (rev 41407) @@ -23,7 +23,6 @@ #include <OS.h> #include <util/AutoLock.h> -#include <util/khash.h> #include <arch/debug.h> #include <boot/kernel_args.h> @@ -60,16 +59,43 @@ #define THREAD_MAX_MESSAGE_SIZE 65536 -struct thread_key { - thread_id id; +// #pragma mark - ThreadHashDefinition + + +struct ThreadHashDefinition { + typedef thread_id KeyType; + typedef Thread ValueType; + + size_t HashKey(thread_id key) const + { + return key; + } + + size_t Hash(Thread* value) const + { + return HashKey(value->id); + } + + bool Compare(thread_id key, Thread* value) const + { + return value->id == key; + } + + Thread*& GetLink(Thread* value) const + { + return value->all_next; + } }; +typedef BOpenHashTable<ThreadHashDefinition> ThreadHashTable; + + // global spinlock gThreadSpinlock = B_SPINLOCK_INITIALIZER; // thread list static Thread sIdleThreads[B_MAX_CPU_COUNT]; -static hash_table *sThreadHash = NULL; +static ThreadHashTable sThreadHash; static thread_id sNextThreadID = 2; // ID 1 is allocated for the kernel by Team::Team() behind our back @@ -140,195 +166,201 @@ static void thread_kthread_exit(void); -/*! Inserts a thread into a team. - The caller must hold the team's lock and the global threads spinlock. -*/ -static void -insert_thread_into_team(Team *team, Thread *thread) -{ - thread->team_next = team->thread_list; - team->thread_list = thread; - team->num_threads++; +// #pragma mark - Thread - if (team->num_threads == 1) { - // this was the first thread - team->main_thread = thread; - } - thread->team = team; -} +/*! Constructs a thread. -/*! Removes a thread from a team. - The caller must hold the team's lock and the global threads spinlock. + \param name The thread's name. + \param threadID The ID to be assigned to the new thread. If + \code < 0 \endcode a fresh one is allocated. + \param cpu The CPU the thread shall be assigned. */ -static void -remove_thread_from_team(Team *team, Thread *thread) +Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu) + : + flags(0), + all_next(NULL), + team_next(NULL), + queue_next(NULL), + id(threadID >= 0 ? threadID : allocate_thread_id()), + priority(-1), + next_priority(-1), + io_priority(-1), + cpu(cpu), + previous_cpu(NULL), + pinned_to_cpu(0), + in_kernel(true), + was_yielded(false), + user_thread(NULL), + fault_handler(0), + page_faults_allowed(1), + args1(NULL), + args2(NULL), + team(NULL), + select_infos(NULL), + kernel_stack_area(-1), + kernel_stack_base(0), + user_stack_area(-1), + user_stack_base(0), + user_local_storage(0), + kernel_errno(0), + user_time(0), + kernel_time(0), + last_time(0), + post_interrupt_callback(NULL), + post_interrupt_data(NULL) { - Thread *temp, *last = NULL; + // init lock + char lockName[32]; + snprintf(lockName, sizeof(lockName), "Thread:%" B_PRId32, id); + mutex_init_etc(&fLock, lockName, MUTEX_FLAG_CLONE_NAME); - for (temp = team->thread_list; temp != NULL; temp = temp->team_next) { - if (temp == thread) { - if (last == NULL) - team->thread_list = temp->team_next; - else - last->team_next = temp->team_next; + // init name + if (name != NULL) + strlcpy(this->name, name, B_OS_NAME_LENGTH); + else + strcpy(this->name, "unnamed thread"); - team->num_threads--; - break; - } - last = temp; - } + alarm.period = 0; + + exit.status = 0; + exit.reason = 0; + exit.signal = 0; + + list_init(&exit.waiters); + + ResetSignals(); + + exit.sem = -1; + msg.write_sem = -1; + msg.read_sem = -1; } -static int -thread_struct_compare(void *_t, const void *_key) +Thread::~Thread() { - Thread *thread = (Thread*)_t; - const struct thread_key *key = (const struct thread_key*)_key; + if (exit.sem >= 0) + delete_sem(exit.sem); + if (msg.write_sem >= 0) + delete_sem(msg.write_sem); + if (msg.read_sem >= 0) + delete_sem(msg.read_sem); - if (thread->id == key->id) - return 0; + scheduler_on_thread_destroy(this); - return 1; + mutex_destroy(&fLock); } -static uint32 -thread_struct_hash(void *_t, const void *_key, uint32 range) +void* +Thread::operator new(size_t size) { - Thread *thread = (Thread*)_t; - const struct thread_key *key = (const struct thread_key*)_key; + return object_cache_alloc(sThreadCache, 0); +} - if (thread != NULL) - return thread->id % range; - return (uint32)key->id % range; +void* +Thread::operator new(size_t, void* pointer) +{ + return pointer; } -static void -reset_signals(Thread *thread) +void +Thread::operator delete(void* pointer, size_t size) { - thread->sig_pending = 0; - thread->sig_block_mask = 0; - thread->sig_temp_enabled = 0; - memset(thread->sig_action, 0, 32 * sizeof(struct sigaction)); - thread->signal_stack_base = 0; - thread->signal_stack_size = 0; - thread->signal_stack_enabled = false; + object_cache_free(sThreadCache, pointer, 0); } -/*! Allocates and fills in thread structure. +status_t +Thread::Init(bool idleThread) +{ + // TODO: Not initializing the scheduler structure for the idle threads is + // weird. Pass on the flag and let the scheduler decide. + // TODO: The function should return an error code. The affine scheduler + // panic()s instead! + if (!idleThread) + scheduler_on_thread_create(this); - \param threadID The ID to be assigned to the new thread. If - \code < 0 \endcode a fresh one is allocated. - \param thread initialize this thread struct if nonnull -*/ -static Thread * -create_thread_struct(Thread *inthread, const char *name, - thread_id threadID, struct cpu_ent *cpu) -{ - Thread *thread; char temp[64]; + sprintf(temp, "thread_%ld_retcode_sem", id); + exit.sem = create_sem(0, temp); + if (exit.sem < 0) + return exit.sem; - if (inthread == NULL) { - thread = (Thread*)object_cache_alloc(sThreadCache, 0); - if (thread == NULL) - return NULL; + sprintf(temp, "%s send", name); + msg.write_sem = create_sem(1, temp); + if (msg.write_sem < 0) + return msg.write_sem; - scheduler_on_thread_create(thread); - // TODO: We could use the object cache object - // constructor/destructor! - } else - thread = inthread; + sprintf(temp, "%s receive", name); + msg.read_sem = create_sem(0, temp); + if (msg.read_sem < 0) + return msg.read_sem; - if (name != NULL) - strlcpy(thread->name, name, B_OS_NAME_LENGTH); - else - strcpy(thread->name, "unnamed thread"); + status_t error = arch_thread_init_thread_struct(this); + if (error != B_OK) + return error; - thread->flags = 0; - thread->id = threadID >= 0 ? threadID : allocate_thread_id(); - thread->team = NULL; - thread->cpu = cpu; - thread->previous_cpu = NULL; - thread->pinned_to_cpu = 0; - thread->fault_handler = 0; - thread->page_faults_allowed = 1; - thread->kernel_stack_area = -1; - thread->kernel_stack_base = 0; - thread->user_stack_area = -1; - thread->user_stack_base = 0; - thread->user_local_storage = 0; - thread->kernel_errno = 0; - thread->team_next = NULL; - thread->queue_next = NULL; - thread->priority = thread->next_priority = -1; - thread->io_priority = -1; - thread->args1 = NULL; thread->args2 = NULL; - thread->alarm.period = 0; - reset_signals(thread); - thread->in_kernel = true; - thread->was_yielded = false; - thread->user_time = 0; - thread->kernel_time = 0; - thread->last_time = 0; - thread->exit.status = 0; - thread->exit.reason = 0; - thread->exit.signal = 0; - list_init(&thread->exit.waiters); - thread->select_infos = NULL; - thread->post_interrupt_callback = NULL; - thread->post_interrupt_data = NULL; - thread->user_thread = NULL; + return B_OK; +} - sprintf(temp, "thread_%ld_retcode_sem", thread->id); - thread->exit.sem = create_sem(0, temp); - if (thread->exit.sem < B_OK) - goto err1; - sprintf(temp, "%s send", thread->name); - thread->msg.write_sem = create_sem(1, temp); - if (thread->msg.write_sem < B_OK) - goto err2; +void +Thread::ResetSignals() +{ + sig_pending = 0; + sig_block_mask = 0; + sig_temp_enabled = 0; + memset(sig_action, 0, 32 * sizeof(struct sigaction)); + signal_stack_base = 0; + signal_stack_size = 0; + signal_stack_enabled = false; +} - sprintf(temp, "%s receive", thread->name); - thread->msg.read_sem = create_sem(0, temp); - if (thread->msg.read_sem < B_OK) - goto err3; - if (arch_thread_init_thread_struct(thread) < B_OK) - goto err4; +// #pragma mark - private functions - return thread; -err4: - delete_sem(thread->msg.read_sem); -err3: - delete_sem(thread->msg.write_sem); -err2: - delete_sem(thread->exit.sem); -err1: - if (inthread == NULL) { - scheduler_on_thread_destroy(thread); - object_cache_free(sThreadCache, thread, 0); +/*! Inserts a thread into a team. + The caller must hold the team's lock and the global threads spinlock. +*/ +static void +insert_thread_into_team(Team *team, Thread *thread) +{ + thread->team_next = team->thread_list; + team->thread_list = thread; + team->num_threads++; + + if (team->num_threads == 1) { + // this was the first thread + team->main_thread = thread; } - - return NULL; + thread->team = team; } +/*! Removes a thread from a team. + The caller must hold the team's lock and the global threads spinlock. +*/ static void -delete_thread_struct(Thread *thread) +remove_thread_from_team(Team *team, Thread *thread) { - delete_sem(thread->exit.sem); - delete_sem(thread->msg.write_sem); - delete_sem(thread->msg.read_sem); + Thread *temp, *last = NULL; - scheduler_on_thread_destroy(thread); - object_cache_free(sThreadCache, thread, 0); + for (temp = team->thread_list; temp != NULL; temp = temp->team_next) { + if (temp == thread) { + if (last == NULL) + team->thread_list = temp->team_next; + else + last->team_next = temp->team_next; + + team->num_threads--; + break; + } + last = temp; + } } @@ -412,10 +444,14 @@ TRACE(("create_thread(%s, id = %ld, %s)\n", attributes.name, attributes.thread, kernel ? "kernel" : "user")); - thread = create_thread_struct(NULL, attributes.name, attributes.thread, - NULL); + thread = new Thread(attributes.name, attributes.thread, NULL); if (thread == NULL) return B_NO_MEMORY; + status = thread->Init(false); + if (status != B_OK) { + delete thread; + return status; + } thread->priority = attributes.priority == -1 ? B_NORMAL_PRIORITY : attributes.priority; @@ -442,7 +478,7 @@ dprintf("create_thread: error creating kernel stack: %s!\n", strerror(status)); - delete_thread_struct(thread); + thread->ReleaseReference(); return status; } @@ -463,7 +499,7 @@ if (abort) { delete_area(thread->kernel_stack_area); - delete_thread_struct(thread); + thread->ReleaseReference(); return B_BAD_TEAM_ID; } @@ -490,7 +526,7 @@ } // insert into global list - hash_insert(sThreadHash, thread); + sThreadHash.InsertUnchecked(thread); sUsedThreads++; scheduler_on_thread_init(thread); @@ -616,7 +652,7 @@ kernelTeamLocker.Unlock(); // free the thread structure - delete_thread_struct(thread); + thread->ReleaseReference(); } // never can get here @@ -853,8 +889,6 @@ static int make_thread_unreal(int argc, char **argv) { - Thread *thread; - struct hash_iterator i; int32 id = -1; if (argc > 2) { @@ -865,9 +899,8 @@ if (argc > 1) id = strtoul(argv[1], NULL, 0); - hash_open(sThreadHash, &i); - - while ((thread = (Thread*)hash_next(sThreadHash, &i)) != NULL) { + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (id != -1 && thread->id != id) continue; @@ -877,7 +910,6 @@ } } - hash_close(sThreadHash, &i, false); return 0; } @@ -885,8 +917,6 @@ static int set_thread_prio(int argc, char **argv) { - Thread *thread; - struct hash_iterator i; int32 id; int32 prio; @@ -906,19 +936,19 @@ else id = thread_get_current_thread()->id; - hash_open(sThreadHash, &i); - - while ((thread = (Thread*)hash_next(sThreadHash, &i)) != NULL) { + bool found = false; + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (thread->id != id) continue; thread->priority = thread->next_priority = prio; kprintf("thread %ld set to priority %ld\n", id, prio); + found = true; break; } - if (!thread) + if (!found) kprintf("thread %ld (%#lx) not found\n", id, id); - hash_close(sThreadHash, &i, false); return 0; } @@ -926,8 +956,6 @@ static int make_thread_suspended(int argc, char **argv) { - Thread *thread; - struct hash_iterator i; int32 id; if (argc > 2) { @@ -940,20 +968,20 @@ else id = strtoul(argv[1], NULL, 0); - hash_open(sThreadHash, &i); - - while ((thread = (Thread*)hash_next(sThreadHash, &i)) != NULL) { + bool found = false; + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (thread->id != id) continue; thread->next_state = B_THREAD_SUSPENDED; kprintf("thread %ld suspended\n", id); + found = true; break; } - if (!thread) + if (!found) kprintf("thread %ld (%#lx) not found\n", id, id); - hash_close(sThreadHash, &i, false); return 0; } @@ -961,8 +989,6 @@ static int make_thread_resumed(int argc, char **argv) { - Thread *thread; - struct hash_iterator i; int32 id; if (argc != 2) { @@ -974,9 +1000,9 @@ // the current thread is usually not intended id = strtoul(argv[1], NULL, 0); - hash_open(sThreadHash, &i); - - while ((thread = (Thread*)hash_next(sThreadHash, &i)) != NULL) { + bool found = false; + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (thread->id != id) continue; @@ -984,12 +1010,12 @@ scheduler_enqueue_in_run_queue(thread); kprintf("thread %ld resumed\n", thread->id); } + found = true; break; } - if (!thread) + if (!found) kprintf("thread %ld (%#lx) not found\n", id, id); - hash_close(sThreadHash, &i, false); return 0; } @@ -1265,17 +1291,14 @@ // walk through the thread list, trying to match name or id bool found = false; - struct hash_iterator i; - hash_open(sThreadHash, &i); - Thread *thread; - while ((thread = (Thread*)hash_next(sThreadHash, &i)) != NULL) { + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (!strcmp(name, thread->name) || thread->id == id) { _dump_thread_info(thread, shortInfo); found = true; break; } } - hash_close(sThreadHash, &i, false); if (!found) kprintf("thread \"%s\" (%ld) doesn't exist!\n", name, id); @@ -1288,8 +1311,6 @@ static int dump_thread_list(int argc, char **argv) { - Thread *thread; - struct hash_iterator i; bool realTimeOnly = false; bool calling = false; const char *callSymbol = NULL; @@ -1332,8 +1353,8 @@ print_thread_list_table_head(); - hash_open(sThreadHash, &i); - while ((thread = (Thread*)hash_next(sThreadHash, &i)) != NULL) { + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { // filter out threads not matching the search criteria if ((requiredState && thread->state != requiredState) || (calling && !arch_debug_contains_call(thread, callSymbol, @@ -1345,7 +1366,6 @@ _dump_thread_info(thread, true); } - hash_close(sThreadHash, &i, false); return 0; } @@ -1540,7 +1560,7 @@ GRAB_THREAD_LOCK(); // remove thread from hash, so it's no longer accessible - hash_remove(sThreadHash, thread); + sThreadHash.RemoveUnchecked(thread); sUsedThreads--; // Stop debugging for this thread @@ -1668,11 +1688,7 @@ Thread * thread_get_thread_struct_locked(thread_id id) { - struct thread_key key; - - key.id = id; - - return (Thread*)hash_lookup(sThreadHash, &key); + return sThreadHash.Lookup(id); } @@ -1751,7 +1767,7 @@ { Thread *thread = thread_get_current_thread(); - reset_signals(thread); + thread->ResetSignals(); // Note: We don't cancel an alarm. It is supposed to survive exec*(). } @@ -1831,19 +1847,13 @@ Thread* thread_iterate_through_threads(thread_iterator_callback callback, void* cookie) { - struct hash_iterator iterator; - hash_open(sThreadHash, &iterator); - - Thread* thread; - while ((thread = (Thread*)hash_next(sThreadHash, &iterator)) - != NULL) { + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (callback(thread, cookie)) - break; + return thread; } - hash_close(sThreadHash, &iterator, false); - - return thread; + return NULL; } @@ -2178,8 +2188,9 @@ TRACE(("thread_init: entry\n")); // create the thread hash table - sThreadHash = hash_init(15, offsetof(Thread, all_next), - &thread_struct_compare, &thread_struct_hash); + new(&sThreadHash) ThreadHashTable(); + if (sThreadHash.Init(32) != B_OK) + panic("thread_init(): failed to init thread hash table!"); // create the thread structure object cache sThreadCache = create_object_cache("threads", sizeof(Thread), 16, NULL, @@ -2202,9 +2213,9 @@ char name[64]; sprintf(name, "idle thread %lu", i + 1); - thread = create_thread_struct(&sIdleThreads[i], name, + thread = new(&sIdleThreads[i]) Thread(name, i == 0 ? team_get_kernel_team_id() : -1, &gCPU[i]); - if (thread == NULL) { + if (thread == NULL || thread->Init(true) != B_OK) { panic("error creating idle thread struct\n"); return B_NO_MEMORY; } @@ -2225,7 +2236,7 @@ thread->kernel_stack_base = (addr_t)info.address; thread->kernel_stack_top = thread->kernel_stack_base + info.size; - hash_insert(sThreadHash, thread); + sThreadHash.InsertUnchecked(thread); insert_thread_into_team(thread->team, thread); } sUsedThreads = args->num_cpus; @@ -2579,10 +2590,8 @@ // TODO: Scanning the whole hash with the thread lock held isn't exactly // cheap -- although this function is probably used very rarely. - struct hash_iterator iterator; - hash_open(sThreadHash, &iterator); - - while (Thread* thread = (Thread*)hash_next(sThreadHash, &iterator)) { + for (ThreadHashTable::Iterator it = sThreadHash.GetIterator(); + Thread* thread = it.Next();) { if (strcmp(thread->name, name) == 0) return thread->id; }