* Introduced new job_control_entry structure which, among other things,

is used instead of death_entry for team::dead_children.
* Added team::{stopped,continued}_children, which, analoguously to
  dead_children, are used to track the state of stopped/continued
  children.
* A team does have a job_control_entry, which is allocated at team
  creation time. It will be inserted into the parent's
  {stopped,continued}_children lists as the team's main thread is
  stopped/continued and removed when waitpid() retrieves the child
  state. When the team dies the entry is detached from the team and goes
  into the parent's dead_children list.
* Removed the wait_for_any field from team_dead_children. It was solely
  used to avoid deletion of the contained entries in certain situations.
  wait_for_child() (the waitpid() backend) always deletes an entry now,
  regardless of whether other threads are waiting; that's in
  accordance with the waidpid() specification. wait_for_thread() removes
  the entry only, if the caller is the parent of the respective team.
* Introduced team_set_job_control_state() which performes the job
  control entry transitions between the respective lists and wakes up
  threads waiting in wait_for_child(). It is invoked on team death and
  when the team's main thread receives job control signals.
* Reorganized wait_for_child(). It handles WCONTINUED and WUNTRACED now,
  too. Removed a block that interpreted the supplied ID as thread ID.
* Added missing parts in waitpid().

Job control starts to work, though it seems to have some glitches.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22088 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-08-28 03:29:14 +00:00
parent c9e5503e5e
commit 24bcf55926
5 changed files with 348 additions and 156 deletions
+39 -33
View File
@@ -1094,7 +1094,6 @@ thread_exit(void)
struct thread *thread = thread_get_current_thread();
struct process_group *freeGroup = NULL;
struct team *team = thread->team;
struct death_entry *death = NULL;
thread_id parentID = -1;
bool deleteTeam = false;
sem_id cachedDeathSem = -1;
@@ -1122,20 +1121,11 @@ thread_exit(void)
delete_area_etc(team, area);
}
struct job_control_entry *death = NULL;
if (team != team_get_kernel_team()) {
if (team->main_thread == thread) {
// this was the main thread in this team, so we will delete that as well
deleteTeam = true;
// put a death entry into the dead children list of our parent
death = (struct death_entry *)malloc(sizeof(struct death_entry));
if (death != NULL) {
death->group_id = team->group_id;
death->thread = thread->id;
death->status = thread->exit.status;
death->reason = thread->exit.reason;
death->signal = thread->exit.signal;
}
}
// remove this thread from the current team and add it to the kernel
@@ -1161,22 +1151,30 @@ thread_exit(void)
// remember who our parent was so we can send a signal
parentID = parent->id;
if (death != NULL) {
// insert death entry into the parent's list
// Set the team job control state to "dead" and detach the job
// control entry from our team struct.
team_set_job_control_state(team, JOB_CONTROL_STATE_DEAD, 0, true);
death = team->job_control_entry;
team->job_control_entry = NULL;
list_add_link_to_tail(&parent->dead_children->list, death);
if (++parent->dead_children->count > MAX_DEAD_CHILDREN) {
death = (struct death_entry*)list_remove_head_item(
&parent->dead_children->list);
if (death != NULL) {
death->team = NULL;
death->group_id = team->group_id;
death->thread = thread->id;
death->status = thread->exit.status;
death->reason = thread->exit.reason;
death->signal = thread->exit.signal;
// team_set_job_control_state() already moved our entry
// into the parent's list. We just check the soft limit of
// death entries.
if (parent->dead_children->count > MAX_DEAD_CHILDREN) {
death = parent->dead_children->entries.RemoveHead();
parent->dead_children->count--;
} else
death = NULL;
RELEASE_THREAD_LOCK();
// notify listeners that a new death entry is available
// TODO: should that be moved to handle_signal() (for SIGCHLD)?
parent->dead_children->condition_variable.NotifyOne();
} else
RELEASE_THREAD_LOCK();
@@ -1198,9 +1196,9 @@ thread_exit(void)
team_delete_process_group(freeGroup);
team_delete_team(team);
// we need to remove any death entry that made it to here
// we need to delete any death entry that made it to here
if (death != NULL)
free(death);
delete death;
send_signal_etc(parentID, SIGCHLD, B_DO_NOT_RESCHEDULE);
cachedDeathSem = -1;
@@ -1251,12 +1249,12 @@ thread_exit(void)
thread->exit.sem = -1;
// fill all death entries
death = NULL;
while ((death = (struct death_entry*)list_get_next_item(
&thread->exit.waiters, death)) != NULL) {
death->status = thread->exit.status;
death->reason = thread->exit.reason;
death->signal = thread->exit.signal;
death_entry* entry = NULL;
while ((entry = (struct death_entry*)list_get_next_item(
&thread->exit.waiters, entry)) != NULL) {
entry->status = thread->exit.status;
entry->reason = thread->exit.reason;
entry->signal = thread->exit.signal;
}
RELEASE_THREAD_LOCK();
@@ -1513,7 +1511,8 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
status_t *_returnCode)
{
sem_id exitSem = B_BAD_THREAD_ID;
struct death_entry death, *freeDeath = NULL;
struct death_entry death;
job_control_entry* freeDeath = NULL;
struct thread *thread;
cpu_status state;
status_t status = B_OK;
@@ -1540,8 +1539,15 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
// find its death entry in our team
GRAB_TEAM_LOCK();
status = team_get_death_entry(thread_get_current_thread()->team,
id, &death, &freeDeath);
bool deleteEntry;
freeDeath = team_get_death_entry(thread_get_current_thread()->team, id,
&deleteEntry);
if (freeDeath != NULL) {
death.status = freeDeath->status;
if (!deleteEntry)
freeDeath = NULL;
} else
status = B_BAD_THREAD_ID;
RELEASE_TEAM_LOCK();
}
@@ -1553,7 +1559,7 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
if (_returnCode)
*_returnCode = death.status;
free(freeDeath);
delete freeDeath;
return B_OK;
}