send_signal_etc() is now capable of broadcasting a signal to all teams in
the specified process group (by passing in a negative pid, as in BeOS). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9351 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+127
-63
@@ -123,25 +123,12 @@ handle_signals(struct thread *thread, int state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static status_t
|
||||||
send_signal_etc(pid_t threadID, uint signal, uint32 flags)
|
deliver_signal(struct thread *thread, uint signal, uint32 flags)
|
||||||
{
|
{
|
||||||
struct thread *thread;
|
if (flags & B_CHECK_PERMISSION) {
|
||||||
cpu_status state;
|
// ToDo: introduce euid & uid fields to the team and check permission
|
||||||
|
|
||||||
if (signal < 1 || signal > MAX_SIGNO)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
state = disable_interrupts();
|
|
||||||
GRAB_THREAD_LOCK();
|
|
||||||
|
|
||||||
thread = thread_get_thread_struct_locked(threadID);
|
|
||||||
if (!thread) {
|
|
||||||
RELEASE_THREAD_LOCK();
|
|
||||||
restore_interrupts(state);
|
|
||||||
return B_BAD_THREAD_ID;
|
|
||||||
}
|
}
|
||||||
// XXX check permission
|
|
||||||
|
|
||||||
if (thread->team == team_get_kernel_team()) {
|
if (thread->team == team_get_kernel_team()) {
|
||||||
// Signals to kernel threads will only wake them up
|
// Signals to kernel threads will only wake them up
|
||||||
@@ -149,57 +136,134 @@ send_signal_etc(pid_t threadID, uint signal, uint32 flags)
|
|||||||
thread->state = thread->next_state = B_THREAD_READY;
|
thread->state = thread->next_state = B_THREAD_READY;
|
||||||
scheduler_enqueue_in_run_queue(thread);
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
}
|
}
|
||||||
} else {
|
return B_OK;
|
||||||
thread->sig_pending |= SIGNAL_TO_MASK(signal);
|
|
||||||
|
|
||||||
switch (signal) {
|
|
||||||
case SIGKILL:
|
|
||||||
{
|
|
||||||
struct thread *mainThread = thread->team->main_thread;
|
|
||||||
// Forward KILLTHR to the main thread of the team
|
|
||||||
|
|
||||||
mainThread->sig_pending |= SIGNAL_TO_MASK(SIGKILLTHR);
|
|
||||||
// Wake up main thread
|
|
||||||
if (mainThread->state == B_THREAD_SUSPENDED) {
|
|
||||||
mainThread->state = mainThread->next_state = B_THREAD_READY;
|
|
||||||
scheduler_enqueue_in_run_queue(mainThread);
|
|
||||||
} else if (mainThread->state == B_THREAD_WAITING)
|
|
||||||
sem_interrupt_thread(mainThread);
|
|
||||||
|
|
||||||
// Supposed to fall through
|
|
||||||
}
|
|
||||||
case SIGKILLTHR:
|
|
||||||
// Wake up suspended threads and interrupt waiting ones
|
|
||||||
if (thread->state == B_THREAD_SUSPENDED) {
|
|
||||||
thread->state = thread->next_state = B_THREAD_READY;
|
|
||||||
scheduler_enqueue_in_run_queue(thread);
|
|
||||||
} else if (thread->state == B_THREAD_WAITING)
|
|
||||||
sem_interrupt_thread(thread);
|
|
||||||
break;
|
|
||||||
case SIGCONT:
|
|
||||||
// Wake up thread if it was suspended
|
|
||||||
if (thread->state == B_THREAD_SUSPENDED) {
|
|
||||||
thread->state = thread->next_state = B_THREAD_READY;
|
|
||||||
scheduler_enqueue_in_run_queue(thread);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (thread->sig_pending & (~thread->sig_block_mask | SIGNAL_TO_MASK(SIGCHLD))) {
|
|
||||||
// Interrupt thread if it was waiting
|
|
||||||
if (thread->state == B_THREAD_WAITING)
|
|
||||||
sem_interrupt_thread(thread);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & B_DO_NOT_RESCHEDULE))
|
thread->sig_pending |= SIGNAL_TO_MASK(signal);
|
||||||
|
|
||||||
|
switch (signal) {
|
||||||
|
case SIGKILL:
|
||||||
|
{
|
||||||
|
struct thread *mainThread = thread->team->main_thread;
|
||||||
|
// Forward KILLTHR to the main thread of the team
|
||||||
|
|
||||||
|
mainThread->sig_pending |= SIGNAL_TO_MASK(SIGKILLTHR);
|
||||||
|
// Wake up main thread
|
||||||
|
if (mainThread->state == B_THREAD_SUSPENDED) {
|
||||||
|
mainThread->state = mainThread->next_state = B_THREAD_READY;
|
||||||
|
scheduler_enqueue_in_run_queue(mainThread);
|
||||||
|
} else if (mainThread->state == B_THREAD_WAITING)
|
||||||
|
sem_interrupt_thread(mainThread);
|
||||||
|
|
||||||
|
// Supposed to fall through
|
||||||
|
}
|
||||||
|
case SIGKILLTHR:
|
||||||
|
// Wake up suspended threads and interrupt waiting ones
|
||||||
|
if (thread->state == B_THREAD_SUSPENDED) {
|
||||||
|
thread->state = thread->next_state = B_THREAD_READY;
|
||||||
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
|
} else if (thread->state == B_THREAD_WAITING)
|
||||||
|
sem_interrupt_thread(thread);
|
||||||
|
break;
|
||||||
|
case SIGCONT:
|
||||||
|
// Wake up thread if it was suspended
|
||||||
|
if (thread->state == B_THREAD_SUSPENDED) {
|
||||||
|
thread->state = thread->next_state = B_THREAD_READY;
|
||||||
|
scheduler_enqueue_in_run_queue(thread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (thread->sig_pending & (~thread->sig_block_mask | SIGNAL_TO_MASK(SIGCHLD))) {
|
||||||
|
// Interrupt thread if it was waiting
|
||||||
|
if (thread->state == B_THREAD_WAITING)
|
||||||
|
sem_interrupt_thread(thread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
send_signal_etc(pid_t id, uint signal, uint32 flags)
|
||||||
|
{
|
||||||
|
status_t status = B_BAD_THREAD_ID;
|
||||||
|
struct thread *thread;
|
||||||
|
cpu_status state;
|
||||||
|
|
||||||
|
if (signal < 1 || signal > MAX_SIGNO)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (id == 0) {
|
||||||
|
// send a signal to the current team
|
||||||
|
id = thread_get_current_thread()->team->main_thread->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = disable_interrupts();
|
||||||
|
|
||||||
|
if (id > 0) {
|
||||||
|
// send a signal to the specified thread
|
||||||
|
|
||||||
|
GRAB_THREAD_LOCK();
|
||||||
|
|
||||||
|
thread = thread_get_thread_struct_locked(id);
|
||||||
|
if (thread != NULL)
|
||||||
|
status = deliver_signal(thread, signal, flags);
|
||||||
|
} else {
|
||||||
|
// send a signal to the specified process group
|
||||||
|
// (the absolute value of the id)
|
||||||
|
|
||||||
|
GRAB_THREAD_LOCK();
|
||||||
|
|
||||||
|
thread = thread_get_thread_struct_locked(id);
|
||||||
|
if (thread != NULL) {
|
||||||
|
struct process_group *group;
|
||||||
|
struct team *team, *next;
|
||||||
|
|
||||||
|
// we need a safe way to get from the thread to the process group
|
||||||
|
id = thread->team->id;
|
||||||
|
|
||||||
|
RELEASE_THREAD_LOCK();
|
||||||
|
GRAB_TEAM_LOCK();
|
||||||
|
|
||||||
|
// get a pointer to the process group
|
||||||
|
team = team_get_team_struct_locked(id);
|
||||||
|
group = team->group;
|
||||||
|
|
||||||
|
for (team = group->teams; team != NULL; team = next) {
|
||||||
|
// ToDo: there is a *big* race condition here on SMP machines;
|
||||||
|
// the team pointer will probably have gone bad in the mean time
|
||||||
|
next = team->group_next;
|
||||||
|
id = team->main_thread->id;
|
||||||
|
|
||||||
|
RELEASE_TEAM_LOCK();
|
||||||
|
GRAB_THREAD_LOCK();
|
||||||
|
|
||||||
|
thread = thread_get_thread_struct_locked(id);
|
||||||
|
if (thread != NULL) {
|
||||||
|
// we don't stop because of an error sending the signal; we
|
||||||
|
// rather want to send as much signals as possible
|
||||||
|
status = deliver_signal(thread, signal, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
RELEASE_THREAD_LOCK();
|
||||||
|
GRAB_TEAM_LOCK();
|
||||||
|
}
|
||||||
|
|
||||||
|
RELEASE_TEAM_LOCK();
|
||||||
|
GRAB_THREAD_LOCK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: maybe the scheduler should only be invoked is there is reason to do it?
|
||||||
|
// (ie. deliver_signal() moved some threads in the running queue?)
|
||||||
|
if ((flags & B_DO_NOT_RESCHEDULE) == 0)
|
||||||
scheduler_reschedule();
|
scheduler_reschedule();
|
||||||
|
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
return B_OK;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -345,7 +409,7 @@ _user_set_alarm(bigtime_t time, uint32 mode)
|
|||||||
int
|
int
|
||||||
_user_send_signal(pid_t team, uint signal)
|
_user_send_signal(pid_t team, uint signal)
|
||||||
{
|
{
|
||||||
return send_signal(team, signal);
|
return send_signal_etc(team, signal, B_CHECK_PERMISSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user