diff --git a/headers/private/kernel/team.h b/headers/private/kernel/team.h index ddee7605f8..9f51e9f673 100644 --- a/headers/private/kernel/team.h +++ b/headers/private/kernel/team.h @@ -32,6 +32,9 @@ struct team *team_get_team_struct_locked(team_id id); int32 team_max_teams(void); int32 team_used_teams(void); +status_t start_watching_team(team_id team, void (*hook)(team_id, void *), void *data); +status_t stop_watching_team(team_id team, void (*hook)(team_id, void *), void *data); + // used in syscalls.c thread_id _user_load_image(int32 argCount, const char **args, int32 envCount, const char **envp, int32 priority, uint32 flags); diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 95ca23d526..a34afbfce4 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -78,6 +78,12 @@ struct team_loading_info { bool done; // set when loading is done/aborted }; +struct team_watcher { + struct list_link link; + void (*hook)(team_id team, void *data); + void *data; +}; + #define MAX_DEAD_CHILDREN 32 // this is a soft limit for the number of dead entries in a team @@ -111,6 +117,7 @@ struct team { struct thread *thread_list; struct team_loading_info *loading_info; struct list image_list; + struct list watcher_list; struct arch_team arch_info; struct team_debug_info debug_info; diff --git a/src/system/kernel/team.c b/src/system/kernel/team.c index cb550abd00..1bde3c1985 100644 --- a/src/system/kernel/team.c +++ b/src/system/kernel/team.c @@ -689,6 +689,7 @@ create_team_struct(const char *name, bool kernel) goto error1; list_init(&team->image_list); + list_init(&team->watcher_list); clear_team_debug_info(&team->debug_info, true); @@ -761,10 +762,10 @@ team_delete_team(struct team *team) sem_id deathSem; int32 threadCount; - sprintf(death_sem_name, "team %ld death sem", team->id); + sprintf(death_sem_name, "team %ld death sem", teamID); deathSem = create_sem(0, death_sem_name); if (deathSem < 0) - panic("thread_exit: cannot init death sem for team %ld\n", team->id); + panic("thread_exit: cannot init death sem for team %ld\n", teamID); state = disable_interrupts(); GRAB_TEAM_LOCK(); @@ -828,11 +829,24 @@ team_delete_team(struct team *team) // free team resources vm_delete_aspace(team->aspace); - delete_owned_ports(team->id); - sem_delete_owned_sems(team->id); + delete_owned_ports(teamID); + sem_delete_owned_sems(teamID); remove_images(team); vfs_free_io_context(team->io_context); + // notify team watchers + + { + // we're not reachable from anyone anymore at this point, so we + // can safely access the list without any locking + struct team_watcher *watcher; + while ((watcher = list_remove_head_item(&team->watcher_list)) != NULL) { + watcher->hook(teamID, watcher->data); + free(watcher); + } + } + + // ToDo: what about the dead_children.sem? shouldn't we call delete_team_struct() here? free(team); // notify the debugger, that the team is gone @@ -1634,6 +1648,84 @@ err: } +/** Adds a hook to the team that is called as soon as this + * team goes away. + * This call might get public in the future. + */ + +status_t +start_watching_team(team_id teamID, void (*hook)(team_id, void *), void *data) +{ + struct team_watcher *watcher; + struct team *team; + cpu_status state; + + if (hook == NULL || teamID < B_OK) + return B_BAD_VALUE; + + watcher = malloc(sizeof(struct team_watcher)); + if (watcher == NULL) + return B_NO_MEMORY; + + // find team and add watcher + + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = team_get_team_struct_locked(teamID); + if (team != NULL) + list_add_item(&team->watcher_list, watcher); + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + if (team == NULL) { + free(watcher); + return B_BAD_TEAM_ID; + } + + return B_OK; +} + + +status_t +stop_watching_team(team_id teamID, void (*hook)(team_id, void *), void *data) +{ + struct team_watcher *watcher = NULL; + struct team *team; + cpu_status state; + + if (hook == NULL || teamID < B_OK) + return B_BAD_VALUE; + + // find team and remove watcher (if present) + + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = team_get_team_struct_locked(teamID); + if (team != NULL) { + // search for watcher + while ((watcher = list_get_next_item(&team->watcher_list, watcher)) != NULL) { + if (watcher->hook == hook && watcher->data == data) { + // got it! + list_remove_item(&team->watcher_list, watcher); + break; + } + } + } + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + if (watcher == NULL) + return B_ENTRY_NOT_FOUND; + + free(watcher); + return B_OK; +} + + // #pragma mark - // public team API