From 2d8d1cdbaa4448aa12a6e516b34a2e2cda52533b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Dec 2010 01:15:35 +0000 Subject: [PATCH] * Implemented a generic way to associate data with a team which is automatically cleaned up when the team is deleted: Class AssociatedData is the base class for a data item, AssociatedDataOwner a container for them (struct team derives from it). Functions team_associate_data() and team_dissociate_data() add/remove data. * Turned sTeamHash into a BOpenHashTable (necessary since struct team is no longer a POD). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39860 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/team.h | 3 + headers/private/kernel/thread_types.h | 47 ++++- src/system/kernel/team.cpp | 236 +++++++++++++++++++------- 3 files changed, 222 insertions(+), 64 deletions(-) diff --git a/headers/private/kernel/team.h b/headers/private/kernel/team.h index 47be3df72e..510b803f3e 100644 --- a/headers/private/kernel/team.h +++ b/headers/private/kernel/team.h @@ -63,6 +63,9 @@ status_t stop_watching_team(team_id team, void (*hook)(team_id, void *), struct user_thread* team_allocate_user_thread(struct team* team); void team_free_user_thread(struct thread* thread); +bool team_associate_data(AssociatedData* data); +bool team_dissociate_data(AssociatedData* data); + // used in syscalls.c thread_id _user_load_image(const char* const* flatArgs, size_t flatArgsSize, int32 argCount, int32 envCount, int32 priority, uint32 flags, diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 35734ff3c4..42c1cf1be3 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -10,8 +10,11 @@ #ifndef _ASSEMBLER +#include + #include #include +#include #include #include #include @@ -58,6 +61,7 @@ typedef enum job_control_state { struct image; // defined in image.c struct io_context; struct realtime_sem_context; // defined in realtime_sem.cpp +struct scheduler_thread_data; struct select_info; struct user_thread; // defined in libroot/user_thread.h struct xsi_sem_context; // defined in xsi_semaphore.cpp @@ -154,9 +158,48 @@ struct free_user_thread { struct user_thread* thread; }; -struct scheduler_thread_data; -struct team { +class AssociatedDataOwner; + +class AssociatedData : public Referenceable, + public DoublyLinkedListLinkImpl { +public: + AssociatedData(); + virtual ~AssociatedData(); + + AssociatedDataOwner* Owner() const + { return fOwner; } + void SetOwner(AssociatedDataOwner* owner) + { fOwner = owner; } + + virtual void OwnerDeleted(AssociatedDataOwner* owner); + +private: + AssociatedDataOwner* fOwner; +}; + + +class AssociatedDataOwner { +public: + AssociatedDataOwner(); + ~AssociatedDataOwner(); + + bool AddData(AssociatedData* data); + bool RemoveData(AssociatedData* data); + + void PrepareForDeletion(); + +private: + typedef DoublyLinkedList DataList; + +private: + + mutex fLock; + DataList fList; +}; + + +struct team : AssociatedDataOwner { struct team *next; // next in hash struct team *siblings_next; struct team *parent; diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 1384c0a507..5d5eed5b9e 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -100,7 +100,35 @@ public: }; -static hash_table* sTeamHash = NULL; +struct TeamHashDefinition { + typedef team_id KeyType; + typedef struct team ValueType; + + size_t HashKey(team_id key) const + { + return key; + } + + size_t Hash(struct team* value) const + { + return HashKey(value->id); + } + + bool Compare(team_id key, struct team* value) const + { + return value->id == key; + } + + struct team*& GetLink(struct team* value) const + { + return value->next; + } +}; + +typedef BOpenHashTable TeamHashTable; + + +static TeamHashTable sTeamHash; static hash_table* sGroupHash = NULL; static struct team* sKernelTeam = NULL; @@ -368,8 +396,6 @@ _dump_team_info(struct team* team) static int dump_team_info(int argc, char** argv) { - struct hash_iterator iterator; - struct team* team; team_id id = -1; bool found = false; @@ -390,8 +416,8 @@ dump_team_info(int argc, char** argv) } // walk through the thread list, trying to match name or id - hash_open(sTeamHash, &iterator); - while ((team = (struct team*)hash_next(sTeamHash, &iterator)) != NULL) { + for (TeamHashTable::Iterator it = sTeamHash.GetIterator(); + struct team* team = it.Next();) { if ((team->name && strcmp(argv[1], team->name) == 0) || team->id == id) { _dump_team_info(team); @@ -399,7 +425,6 @@ dump_team_info(int argc, char** argv) break; } } - hash_close(sTeamHash, &iterator, false); if (!found) kprintf("team \"%s\" (%ld) doesn't exist!\n", argv[1], id); @@ -410,47 +435,17 @@ dump_team_info(int argc, char** argv) static int dump_teams(int argc, char** argv) { - struct hash_iterator iterator; - struct team* team; - kprintf("team id parent name\n"); - hash_open(sTeamHash, &iterator); - while ((team = (struct team*)hash_next(sTeamHash, &iterator)) != NULL) { + for (TeamHashTable::Iterator it = sTeamHash.GetIterator(); + struct team* team = it.Next();) { kprintf("%p%7ld %p %s\n", team, team->id, team->parent, team->name); } - hash_close(sTeamHash, &iterator, false); return 0; } -static int -team_struct_compare(void* _p, const void* _key) -{ - struct team* p = (struct team*)_p; - const struct team_key* key = (const struct team_key*)_key; - - if (p->id == key->id) - return 0; - - return 1; -} - - -static uint32 -team_struct_hash(void* _p, const void* _key, uint32 range) -{ - struct team* p = (struct team*)_p; - const struct team_key* key = (const struct team_key*)_key; - - if (p != NULL) - return p->id % range; - - return (uint32)key->id % range; -} - - static int process_group_compare(void* _group, const void* _key) { @@ -742,10 +737,10 @@ set_team_name(struct team* team, const char* name) static struct team* create_team_struct(const char* name, bool kernel) { - struct team* team = (struct team*)malloc(sizeof(struct team)); + struct team* team = new(std::nothrow) struct team; if (team == NULL) return NULL; - MemoryDeleter teamDeleter(team); + ObjectDeleter teamDeleter(team); team->next = team->siblings_next = team->children = team->parent = NULL; team->id = allocate_thread_id(); @@ -840,6 +835,9 @@ create_team_struct(const char* name, bool kernel) static void delete_team_struct(struct team* team) { + // get rid of all associated data + team->PrepareForDeletion(); + while (death_entry* threadDeathEntry = (death_entry*)list_remove_head_item( &team->dead_threads)) { free(threadDeathEntry); @@ -860,7 +858,7 @@ delete_team_struct(struct team* team) delete team->continued_children; delete team->stopped_children; delete team->dead_children; - free(team); + delete team; } @@ -1206,7 +1204,7 @@ load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount, // inherit the parent's user/group inherit_parent_user_and_group_locked(team, parent); - hash_insert(sTeamHash, team); + sTeamHash.InsertUnchecked(team); insert_team_into_parent(parent, team); insert_team_into_group(parent->group, team); sUsedTeams++; @@ -1331,7 +1329,7 @@ err1: remove_team_from_group(team); remove_team_from_parent(team->parent, team); - hash_remove(sTeamHash, team); + sTeamHash.RemoveUnchecked(team); RELEASE_TEAM_LOCK(); restore_interrupts(state); @@ -1546,7 +1544,7 @@ fork_team(void) // Inherit the parent's user/group. inherit_parent_user_and_group_locked(team, parentTeam); - hash_insert(sTeamHash, team); + sTeamHash.InsertUnchecked(team); insert_team_into_parent(parentTeam, team); insert_team_into_group(parentTeam->group, team); sUsedTeams++; @@ -1687,7 +1685,7 @@ err1: remove_team_from_group(team); remove_team_from_parent(parentTeam, team); - hash_remove(sTeamHash, team); + sTeamHash.RemoveUnchecked(team); teamLocker.Unlock(); @@ -2058,8 +2056,9 @@ team_init(kernel_args* args) struct process_group* group; // create the team hash table - sTeamHash = hash_init(16, offsetof(struct team, next), - &team_struct_compare, &team_struct_hash); + new(&sTeamHash) TeamHashTable; + if (sTeamHash.Init(32) != B_OK) + panic("Failed to init team hash table!"); sGroupHash = hash_init(16, offsetof(struct process_group, next), &process_group_compare, &process_group_hash); @@ -2099,7 +2098,7 @@ team_init(kernel_args* args) panic("could not create io_context for kernel team!\n"); // stick it in the team hash - hash_insert(sTeamHash, sKernelTeam); + sTeamHash.InsertUnchecked(sKernelTeam); add_debugger_command_etc("team", &dump_team_info, "Dump info about a particular team", @@ -2138,18 +2137,13 @@ team_used_teams(void) struct team* team_iterate_through_teams(team_iterator_callback callback, void* cookie) { - struct hash_iterator iterator; - hash_open(sTeamHash, &iterator); - - struct team* team; - while ((team = (struct team*)hash_next(sTeamHash, &iterator)) != NULL) { + for (TeamHashTable::Iterator it = sTeamHash.GetIterator(); + struct team* team = it.Next();) { if (callback(team, cookie)) - break; + return team; } - hash_close(sTeamHash, &iterator, false); - - return team; + return NULL; } @@ -2204,10 +2198,7 @@ team_is_valid(team_id id) struct team* team_get_team_struct_locked(team_id id) { - struct team_key key; - key.id = id; - - return (struct team*)hash_lookup(sTeamHash, &key); + return sTeamHash.Lookup(id); } @@ -2331,7 +2322,7 @@ team_remove_team(struct team* team) // mutex_lock_threads_lock(), as used in the VFS code to // lock another team's IO context. GRAB_THREAD_LOCK(); - hash_remove(sTeamHash, team); + sTeamHash.RemoveUnchecked(team); RELEASE_THREAD_LOCK(); sUsedTeams--; @@ -2825,6 +2816,127 @@ team_free_user_thread(struct thread* thread) } +// #pragma mark - Associated data interface + + +AssociatedData::AssociatedData() + : + fOwner(NULL) +{ +} + + +AssociatedData::~AssociatedData() +{ +} + + +void +AssociatedData::OwnerDeleted(AssociatedDataOwner* owner) +{ +} + + +AssociatedDataOwner::AssociatedDataOwner() +{ + mutex_init(&fLock, "associated data owner"); +} + + +AssociatedDataOwner::~AssociatedDataOwner() +{ + mutex_destroy(&fLock); +} + + +bool +AssociatedDataOwner::AddData(AssociatedData* data) +{ + MutexLocker locker(fLock); + + if (data->Owner() != NULL) + return false; + + data->AcquireReference(); + fList.Add(data); + data->SetOwner(this); + + return true; +} + + +bool +AssociatedDataOwner::RemoveData(AssociatedData* data) +{ + MutexLocker locker(fLock); + + if (data->Owner() != this) + return false; + + data->SetOwner(NULL); + fList.Remove(data); + + locker.Unlock(); + + data->ReleaseReference(); + + return true; +} + + +void +AssociatedDataOwner::PrepareForDeletion() +{ + MutexLocker locker(fLock); + + // move all data to a temporary list and unset the owner + DataList list; + list.MoveFrom(&fList); + + for (DataList::Iterator it = list.GetIterator(); + AssociatedData* data = it.Next();) { + data->SetOwner(NULL); + } + + locker.Unlock(); + + // call the notification hooks and release our references + while (AssociatedData* data = list.RemoveHead()) { + data->OwnerDeleted(this); + data->ReleaseReference(); + } +} + + +/*! Associates data with the current team. + When the team is deleted, the data object is notified. + The team acquires a reference to the object. + + \param data The data object. + \return \c true on success, \c false otherwise. Fails only when the supplied + data object is already associated with another owner. +*/ +bool +team_associate_data(AssociatedData* data) +{ + return thread_get_current_thread()->team->AddData(data); +} + + +/*! Dissociates data from the current team. + Balances an earlier call to team_associate_data(). + + \param data The data object. + \return \c true on success, \c false otherwise. Fails only when the data + object is not associated with the current team. +*/ +bool +team_dissociate_data(AssociatedData* data) +{ + return thread_get_current_thread()->team->RemoveData(data); +} + + // #pragma mark - Public kernel API