* 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);
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,

View File

@ -10,8 +10,11 @@
#ifndef _ASSEMBLER
#include <Referenceable.h>
#include <arch/thread_types.h>
#include <condition_variable.h>
#include <lock.h>
#include <signal.h>
#include <smp.h>
#include <thread_defs.h>
@ -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<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 *siblings_next;
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 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<struct team> 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(<team related 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