* 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:
parent
eeecbf6fb8
commit
2d8d1cdbaa
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user