* Some cleanup in _user_setpgid() (use of autolocking, don't use

shadowing variables).
* Resolved TODO: We wake up the parent if waiting in wait_for_child()
  now, if the process group changes.
* Added another TODO: setpgid() is supposed to fail on a child after
  it has executed exec*().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22185 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-09-05 19:36:38 +00:00
parent 96b421b83d
commit 35e78b5674
+36 -36
View File
@@ -2411,14 +2411,8 @@ _user_setpgid(pid_t processID, pid_t groupID)
{ {
struct thread *thread = thread_get_current_thread(); struct thread *thread = thread_get_current_thread();
struct team *currentTeam = thread->team; struct team *currentTeam = thread->team;
struct process_group *group = NULL, *freeGroup = NULL;
struct team *team; struct team *team;
cpu_status state;
team_id teamID = -1; team_id teamID = -1;
status_t status = B_OK;
// TODO: we might want to notify waiting wait_for_child() threads in case
// they wait for children of the former process group ID (see wait_test_4.cpp)
if (groupID < 0) if (groupID < 0)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -2439,39 +2433,35 @@ _user_setpgid(pid_t processID, pid_t groupID)
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
} }
status = B_OK;
} else { } else {
state = disable_interrupts(); InterruptsSpinLocker _(thread_spinlock);
GRAB_THREAD_LOCK();
thread = thread_get_thread_struct_locked(processID); thread = thread_get_thread_struct_locked(processID);
// the thread must be the team's main thread, as that // the thread must be the team's main thread, as that
// determines its process ID // determines its process ID
if (thread != NULL && thread == thread->team->main_thread) { if (thread == NULL && thread != thread->team->main_thread)
// check if the thread is in a child team of the calling team and return B_BAD_THREAD_ID;
// if it's already a process group leader and in the same session
if (thread->team->parent != currentTeam
|| is_process_group_leader(thread->team)
|| thread->team->session_id != currentTeam->session_id)
status = B_NOT_ALLOWED;
else
teamID = thread->team->id;
} else
status = B_BAD_THREAD_ID;
RELEASE_THREAD_LOCK(); // check if the thread is in a child team of the calling team and
restore_interrupts(state); // if it's already a process group leader and in the same session
if (thread->team->parent != currentTeam
|| is_process_group_leader(thread->team)
|| thread->team->session_id != currentTeam->session_id) {
return B_NOT_ALLOWED;
}
// TODO: According to the standard, the call is also supposed to fail
// on a child, when the child already has executed exec*().
teamID = thread->team->id;
} }
if (status != B_OK)
return status;
// if the group ID is not specified, a new group should be created // if the group ID is not specified, a new group should be created
if (groupID == 0) if (groupID == 0)
groupID = processID; groupID = processID;
struct process_group *group = NULL;
if (groupID == processID) { if (groupID == processID) {
// We need to create a new process group for this team // We need to create a new process group for this team
group = create_process_group(groupID); group = create_process_group(groupID);
@@ -2479,34 +2469,44 @@ _user_setpgid(pid_t processID, pid_t groupID)
return B_NO_MEMORY; return B_NO_MEMORY;
} }
state = disable_interrupts(); status_t status = B_OK;
GRAB_TEAM_LOCK(); struct process_group *freeGroup = NULL;
InterruptsSpinLocker locker(team_spinlock);
team = team_get_team_struct_locked(teamID); team = team_get_team_struct_locked(teamID);
if (team != NULL) { if (team != NULL) {
if (processID == groupID) { if (processID == groupID) {
// we created a new process group, let us insert it into the team's session // we created a new process group, let us insert it into the team's
// session
insert_group_into_session(team->group->session, group); insert_group_into_session(team->group->session, group);
remove_team_from_group(team, &freeGroup); remove_team_from_group(team, &freeGroup);
insert_team_into_group(group, team); insert_team_into_group(group, team);
} else { } else {
// check if this team can have the group ID; there must be one matching // check if this team can have the group ID; there must be one
// process ID in the team's session // matching process ID in the team's session
struct process_group *group = struct process_group *targetGroup =
team_get_process_group_locked(team->group->session, groupID); team_get_process_group_locked(team->group->session, groupID);
if (group) { if (targetGroup != NULL) {
// we got a group, let's move the team there // we got a group, let's move the team there
remove_team_from_group(team, &freeGroup); remove_team_from_group(team, &freeGroup);
insert_team_into_group(group, team); insert_team_into_group(targetGroup, team);
} else } else
status = B_NOT_ALLOWED; status = B_NOT_ALLOWED;
} }
} else } else
status = B_NOT_ALLOWED; status = B_NOT_ALLOWED;
RELEASE_TEAM_LOCK(); // Changing the process group might have changed the situation for a parent
restore_interrupts(state); // waiting in wait_for_child(). Hence we notify it.
if (status == B_OK) {
team->parent->dead_children->condition_variable.NotifyAll(false);
team->parent->stopped_children->condition_variable.NotifyAll(false);
team->parent->continued_children->condition_variable.NotifyAll(false);
}
locker.Unlock();
if (status != B_OK && group != NULL) { if (status != B_OK && group != NULL) {
// in case of error, the group hasn't been added into the hash // in case of error, the group hasn't been added into the hash