* 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
This commit is contained in:
Ingo Weinhold 2010-12-16 01:15:35 +00:00
parent eeecbf6fb8
commit 2d8d1cdbaa
3 changed files with 222 additions and 64 deletions

View File

@ -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); struct user_thread* team_allocate_user_thread(struct team* team);
void team_free_user_thread(struct thread* thread); void team_free_user_thread(struct thread* thread);
bool team_associate_data(AssociatedData* data);
bool team_dissociate_data(AssociatedData* data);
// used in syscalls.c // used in syscalls.c
thread_id _user_load_image(const char* const* flatArgs, size_t flatArgsSize, thread_id _user_load_image(const char* const* flatArgs, size_t flatArgsSize,
int32 argCount, int32 envCount, int32 priority, uint32 flags, int32 argCount, int32 envCount, int32 priority, uint32 flags,

View File

@ -10,8 +10,11 @@
#ifndef _ASSEMBLER #ifndef _ASSEMBLER
#include <Referenceable.h>
#include <arch/thread_types.h> #include <arch/thread_types.h>
#include <condition_variable.h> #include <condition_variable.h>
#include <lock.h>
#include <signal.h> #include <signal.h>
#include <smp.h> #include <smp.h>
#include <thread_defs.h> #include <thread_defs.h>
@ -58,6 +61,7 @@ typedef enum job_control_state {
struct image; // defined in image.c struct image; // defined in image.c
struct io_context; struct io_context;
struct realtime_sem_context; // defined in realtime_sem.cpp struct realtime_sem_context; // defined in realtime_sem.cpp
struct scheduler_thread_data;
struct select_info; struct select_info;
struct user_thread; // defined in libroot/user_thread.h struct user_thread; // defined in libroot/user_thread.h
struct xsi_sem_context; // defined in xsi_semaphore.cpp struct xsi_sem_context; // defined in xsi_semaphore.cpp
@ -154,9 +158,48 @@ struct free_user_thread {
struct user_thread* thread; struct user_thread* thread;
}; };
struct scheduler_thread_data;
struct team { class AssociatedDataOwner;
class AssociatedData : public Referenceable,
public DoublyLinkedListLinkImpl<AssociatedData> {
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<AssociatedData> DataList;
private:
mutex fLock;
DataList fList;
};
struct team : AssociatedDataOwner {
struct team *next; // next in hash struct team *next; // next in hash
struct team *siblings_next; struct team *siblings_next;
struct team *parent; struct team *parent;

View File

@ -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<TeamHashDefinition> TeamHashTable;
static TeamHashTable sTeamHash;
static hash_table* sGroupHash = NULL; static hash_table* sGroupHash = NULL;
static struct team* sKernelTeam = NULL; static struct team* sKernelTeam = NULL;
@ -368,8 +396,6 @@ _dump_team_info(struct team* team)
static int static int
dump_team_info(int argc, char** argv) dump_team_info(int argc, char** argv)
{ {
struct hash_iterator iterator;
struct team* team;
team_id id = -1; team_id id = -1;
bool found = false; 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 // walk through the thread list, trying to match name or id
hash_open(sTeamHash, &iterator); for (TeamHashTable::Iterator it = sTeamHash.GetIterator();
while ((team = (struct team*)hash_next(sTeamHash, &iterator)) != NULL) { struct team* team = it.Next();) {
if ((team->name && strcmp(argv[1], team->name) == 0) if ((team->name && strcmp(argv[1], team->name) == 0)
|| team->id == id) { || team->id == id) {
_dump_team_info(team); _dump_team_info(team);
@ -399,7 +425,6 @@ dump_team_info(int argc, char** argv)
break; break;
} }
} }
hash_close(sTeamHash, &iterator, false);
if (!found) if (!found)
kprintf("team \"%s\" (%ld) doesn't exist!\n", argv[1], id); kprintf("team \"%s\" (%ld) doesn't exist!\n", argv[1], id);
@ -410,47 +435,17 @@ dump_team_info(int argc, char** argv)
static int static int
dump_teams(int argc, char** argv) dump_teams(int argc, char** argv)
{ {
struct hash_iterator iterator;
struct team* team;
kprintf("team id parent name\n"); 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); kprintf("%p%7ld %p %s\n", team, team->id, team->parent, team->name);
} }
hash_close(sTeamHash, &iterator, false);
return 0; 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 static int
process_group_compare(void* _group, const void* _key) process_group_compare(void* _group, const void* _key)
{ {
@ -742,10 +737,10 @@ set_team_name(struct team* team, const char* name)
static struct team* static struct team*
create_team_struct(const char* name, bool kernel) 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) if (team == NULL)
return NULL; return NULL;
MemoryDeleter teamDeleter(team); ObjectDeleter<struct team> teamDeleter(team);
team->next = team->siblings_next = team->children = team->parent = NULL; team->next = team->siblings_next = team->children = team->parent = NULL;
team->id = allocate_thread_id(); team->id = allocate_thread_id();
@ -840,6 +835,9 @@ create_team_struct(const char* name, bool kernel)
static void static void
delete_team_struct(struct team* team) delete_team_struct(struct team* team)
{ {
// get rid of all associated data
team->PrepareForDeletion();
while (death_entry* threadDeathEntry = (death_entry*)list_remove_head_item( while (death_entry* threadDeathEntry = (death_entry*)list_remove_head_item(
&team->dead_threads)) { &team->dead_threads)) {
free(threadDeathEntry); free(threadDeathEntry);
@ -860,7 +858,7 @@ delete_team_struct(struct team* team)
delete team->continued_children; delete team->continued_children;
delete team->stopped_children; delete team->stopped_children;
delete team->dead_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 the parent's user/group
inherit_parent_user_and_group_locked(team, parent); inherit_parent_user_and_group_locked(team, parent);
hash_insert(sTeamHash, team); sTeamHash.InsertUnchecked(team);
insert_team_into_parent(parent, team); insert_team_into_parent(parent, team);
insert_team_into_group(parent->group, team); insert_team_into_group(parent->group, team);
sUsedTeams++; sUsedTeams++;
@ -1331,7 +1329,7 @@ err1:
remove_team_from_group(team); remove_team_from_group(team);
remove_team_from_parent(team->parent, team); remove_team_from_parent(team->parent, team);
hash_remove(sTeamHash, team); sTeamHash.RemoveUnchecked(team);
RELEASE_TEAM_LOCK(); RELEASE_TEAM_LOCK();
restore_interrupts(state); restore_interrupts(state);
@ -1546,7 +1544,7 @@ fork_team(void)
// Inherit the parent's user/group. // Inherit the parent's user/group.
inherit_parent_user_and_group_locked(team, parentTeam); inherit_parent_user_and_group_locked(team, parentTeam);
hash_insert(sTeamHash, team); sTeamHash.InsertUnchecked(team);
insert_team_into_parent(parentTeam, team); insert_team_into_parent(parentTeam, team);
insert_team_into_group(parentTeam->group, team); insert_team_into_group(parentTeam->group, team);
sUsedTeams++; sUsedTeams++;
@ -1687,7 +1685,7 @@ err1:
remove_team_from_group(team); remove_team_from_group(team);
remove_team_from_parent(parentTeam, team); remove_team_from_parent(parentTeam, team);
hash_remove(sTeamHash, team); sTeamHash.RemoveUnchecked(team);
teamLocker.Unlock(); teamLocker.Unlock();
@ -2058,8 +2056,9 @@ team_init(kernel_args* args)
struct process_group* group; struct process_group* group;
// create the team hash table // create the team hash table
sTeamHash = hash_init(16, offsetof(struct team, next), new(&sTeamHash) TeamHashTable;
&team_struct_compare, &team_struct_hash); if (sTeamHash.Init(32) != B_OK)
panic("Failed to init team hash table!");
sGroupHash = hash_init(16, offsetof(struct process_group, next), sGroupHash = hash_init(16, offsetof(struct process_group, next),
&process_group_compare, &process_group_hash); &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"); panic("could not create io_context for kernel team!\n");
// stick it in the team hash // stick it in the team hash
hash_insert(sTeamHash, sKernelTeam); sTeamHash.InsertUnchecked(sKernelTeam);
add_debugger_command_etc("team", &dump_team_info, add_debugger_command_etc("team", &dump_team_info,
"Dump info about a particular team", "Dump info about a particular team",
@ -2138,18 +2137,13 @@ team_used_teams(void)
struct team* struct team*
team_iterate_through_teams(team_iterator_callback callback, void* cookie) team_iterate_through_teams(team_iterator_callback callback, void* cookie)
{ {
struct hash_iterator iterator; for (TeamHashTable::Iterator it = sTeamHash.GetIterator();
hash_open(sTeamHash, &iterator); struct team* team = it.Next();) {
struct team* team;
while ((team = (struct team*)hash_next(sTeamHash, &iterator)) != NULL) {
if (callback(team, cookie)) if (callback(team, cookie))
break; return team;
} }
hash_close(sTeamHash, &iterator, false); return NULL;
return team;
} }
@ -2204,10 +2198,7 @@ team_is_valid(team_id id)
struct team* struct team*
team_get_team_struct_locked(team_id id) team_get_team_struct_locked(team_id id)
{ {
struct team_key key; return sTeamHash.Lookup(id);
key.id = id;
return (struct team*)hash_lookup(sTeamHash, &key);
} }
@ -2331,7 +2322,7 @@ team_remove_team(struct team* team)
// mutex_lock_threads_lock(<team related lock>), as used in the VFS code to // mutex_lock_threads_lock(<team related lock>), as used in the VFS code to
// lock another team's IO context. // lock another team's IO context.
GRAB_THREAD_LOCK(); GRAB_THREAD_LOCK();
hash_remove(sTeamHash, team); sTeamHash.RemoveUnchecked(team);
RELEASE_THREAD_LOCK(); RELEASE_THREAD_LOCK();
sUsedTeams--; 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 // #pragma mark - Public kernel API