2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
5 Desc: Send some signal to a given task
10 #include <aros/debug.h>
12 #include <exec/execbase.h>
13 #include <aros/libcall.h>
14 #include <proto/exec.h>
16 #define __AROS_KERNEL__
17 #include "exec_intern.h"
19 #if defined(__AROSEXEC_SMP__)
20 #include <utility/hooks.h>
22 #include "kernel_ipi.h"
24 AROS_UFH3(IPTR
, signal_hook
,
25 AROS_UFHA(struct IPIHook
*, hook
, A0
),
26 AROS_UFHA(APTR
, object
, A2
),
27 AROS_UFHA(APTR
, message
, A1
)
32 struct ExecBase
*SysBase
= (struct ExecBase
*)hook
->ih_Args
[0];
33 struct Task
*target
= (struct Task
*)hook
->ih_Args
[1];
34 ULONG sigset
= (ULONG
)hook
->ih_Args
[2];
37 struct KernelBase
*KernelBase
= __kernelBase
;
38 int cpunum
= KrnGetCPUNumber();
39 bug("[Exec] CPU%03d: Using IPI to do Signal(%p, %08x), SysBase=%p\n", cpunum
, msg
->target
, msg
->sigset
, SysBase
);
42 Signal(target
, sigset
);
50 /*****************************************************************************
54 AROS_LH2(void, Signal
,
57 AROS_LHA(struct Task
*, task
, A1
),
58 AROS_LHA(ULONG
, signalSet
, D0
),
61 struct ExecBase
*, SysBase
, 54, Exec
)
64 Send some signals to a given task. If the task is currently waiting
65 on these signals, has a higher priority as the current one and if
66 taskswitches are allowed the new task begins to run immediately.
69 task - Pointer to task structure.
70 signalSet - The set of signals to send to the task.
75 This function may be used from interrupts.
82 AllocSignal(), FreeSignal(), Wait(), SetSignal(), SetExcept()
88 ******************************************************************************/
92 struct Task
*thisTask
= GET_THIS_TASK
;
94 #if defined(__AROSEXEC_SMP__)
95 struct KernelBase
*KernelBase
= __kernelBase
;
96 int cpunum
= KrnGetCPUNumber();
99 * # If current CPU number is not the task's CPU and the task is running now, send signal to that task
100 * from CPU which the task is running on.
101 * # If task is not running and the current CPU is not in the Affinitymask, send signal to CPU form Affinity mask
102 * # If task is not running and the current CPU is in the Affinity mask, just proceed with regular signal
104 if ((PrivExecBase(SysBase
)->IntFlags
& EXECF_CPUAffinity
) &&
105 ((IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
!= cpunum
&& task
->tc_State
== TS_RUN
) ||
106 !KrnCPUInMask(cpunum
, IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
)))
110 // We cannot use KrnAllocCPUMask() since this function uses AllocMem
111 // And we cannot use AllocMem from interrupts (where Signal() is allowed)...
112 ULONG mask
[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // CPU mask large enough for 256 CPUs...
113 void *cpu_mask
= &mask
;
115 args
[0] = (IPTR
)SysBase
;
116 args
[1] = (IPTR
)task
;
117 args
[2] = (IPTR
)signalSet
;
119 /* Task is running *now* on another CPU, send signal there */
120 if (task
->tc_State
== TS_RUN
)
122 KrnGetCPUMask(IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
, cpu_mask
);
127 int cpumax
= KrnGetCPUCount();
129 /* Task is not running now, find first cpu suitable to run this task. Use CPU balancing some day... */
130 for (i
=0; i
< cpumax
; i
++)
132 if (KrnCPUInMask(i
, IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
))
134 KrnGetCPUMask(i
, cpu_mask
);
140 D(bug("[Exec] Signal: Signaling from CPU%03d -> CPU%03d using IPI...\n", cpunum
, IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
));
142 h
.h_Entry
= signal_hook
;
144 D(bug("[Exec] Sending IPI...\n"));
145 core_DoCallIPI(&h
, cpu_mask
, 1, 3, args
, (void *)KernelBase
);
146 D(bug("[Exec] IPI Sent\n"));
153 D(bug("[Exec] Signal(0x%p, %08lX) on CPU%03d\n", task
, signalSet
, cpunum
));
156 D(bug("[Exec] Signal(0x%p, %08lX)\n", task
, signalSet
);)
160 bug("[Exec] Signal: Signaling '%s', state = %08x\n", task
->tc_Node
.ln_Name
, task
->tc_State
);
161 if (((struct KernelBase
*)KernelBase
)->kb_ICFlags
& KERNBASEF_IRQPROCESSING
)
162 bug("[Exec] Signal: (Called from Interrupt)\n");
164 bug("[Exec] Signal: (Called from '%s')\n", thisTask
->tc_Node
.ln_Name
);
168 D(bug("[Exec] Signal: Target signal flags : %08x ->", task
->tc_SigRecvd
);)
169 /* Set the signals in the task structure. */
170 #if defined(__AROSEXEC_SMP__)
171 __AROS_ATOMIC_OR_L(task
->tc_SigRecvd
, signalSet
);
173 task
->tc_SigRecvd
|= signalSet
;
175 D(bug(" %08x\n", task
->tc_SigRecvd
);)
177 /* Do those bits raise exceptions? */
178 if (task
->tc_SigRecvd
& task
->tc_SigExcept
)
180 /* Yes. Set the exception flag. */
181 #if defined(__AROSEXEC_SMP__)
182 __AROS_ATOMIC_OR_B(task
->tc_Flags
, TF_EXCEPT
);
184 task
->tc_Flags
|= TF_EXCEPT
;
186 D(bug("[Exec] Signal: TF_EXCEPT set\n");)
189 if the target task is running (called from within interrupt handler, or from another processor),
190 raise the exception or defer it for later.
192 if (task
->tc_State
== TS_RUN
)
194 #if defined(__AROSEXEC_SMP__)
195 if (!(PrivExecBase(SysBase
)->IntFlags
& EXECF_CPUAffinity
) ||
196 (IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
== cpunum
))
199 D(bug("[Exec] Signal: Raising Exception for 'running' Task\n");)
200 /* Order a reschedule */
202 #if defined(__AROSEXEC_SMP__)
206 (bug("[Exec] Signal: Raising Exception for 'running' Task on CPU %03u\n", IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
));
207 KrnScheduleCPU(IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
);
217 Is the task receiving the signals waiting on them
218 (or on a exception) ?
220 if ((task
->tc_State
== TS_WAIT
) &&
221 (task
->tc_SigRecvd
& (task
->tc_SigWait
| task
->tc_SigExcept
)))
223 D(bug("[Exec] Signal: Signaling 'waiting' Task\n");)
225 /* Yes. Move it to the ready list. */
226 #if defined(__AROSEXEC_SMP__)
227 krnSysCallReschedTask(task
, TS_READY
);
229 Remove(&task
->tc_Node
);
230 task
->tc_State
= TS_READY
;
231 Enqueue(&SysBase
->TaskReady
, &task
->tc_Node
);
233 /* Has it a higher priority as the current one? */
235 #if defined(__AROSEXEC_SMP__)
236 (!(PrivExecBase(SysBase
)->IntFlags
& EXECF_CPUAffinity
) ||
237 (KrnCPUInMask(cpunum
, IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
))) &&
239 (task
->tc_Node
.ln_Pri
>= thisTask
->tc_Node
.ln_Pri
))
242 Yes. A taskswitch is necessary. Prepare one if possible.
243 (If the current task is not running it is already moved)
245 if (thisTask
->tc_State
== TS_RUN
)
247 D(bug("[Exec] Signal: Rescheduling 'running' Task to let it process the signal...\n"));
251 #if defined(__AROSEXEC_SMP__)
252 else if ((PrivExecBase(SysBase
)->IntFlags
& EXECF_CPUAffinity
) &&
253 !(KrnCPUInMask(cpunum
, IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
)))
255 D(bug("[Exec] Signal: Signaling task on another CPU\n"));
256 krnSysCallReschedTask(task
, TS_READY
);
257 KrnScheduleCPU(IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
);
262 D(bug("[Exec] Signal: Letting Task process signal when next scheduled to run...\n"););
268 D(bug("[Exec] Signal: 0x%p finished signal processing\n", task
);)
269 #if defined(__AROSEXEC_SMP__)