revert between 56095 -> 55830 in arch
[AROS.git] / rom / exec / signal.c
blobd0d011dd2f1b80de096fe86d2430f3df0d276b4a
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Send some signal to a given task
6 Lang: english
7 */
9 #define DEBUG 0
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)
30 AROS_USERFUNC_INIT
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);
44 return 0;
46 AROS_USERFUNC_EXIT
48 #endif
50 /*****************************************************************************
52 NAME */
54 AROS_LH2(void, Signal,
56 /* SYNOPSIS */
57 AROS_LHA(struct Task *, task, A1),
58 AROS_LHA(ULONG, signalSet, D0),
60 /* LOCATION */
61 struct ExecBase *, SysBase, 54, Exec)
63 /* FUNCTION
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.
68 INPUTS
69 task - Pointer to task structure.
70 signalSet - The set of signals to send to the task.
72 RESULT
74 NOTES
75 This function may be used from interrupts.
77 EXAMPLE
79 BUGS
81 SEE ALSO
82 AllocSignal(), FreeSignal(), Wait(), SetSignal(), SetExcept()
84 INTERNALS
86 HISTORY
88 ******************************************************************************/
90 AROS_LIBFUNC_INIT
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)))
108 struct Hook h;
109 IPTR args[3];
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);
124 else
126 int i;
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);
135 break;
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"));
148 else
151 if (cpunum != 0)
153 D(bug("[Exec] Signal(0x%p, %08lX) on CPU%03d\n", task, signalSet, cpunum));
155 #else
156 D(bug("[Exec] Signal(0x%p, %08lX)\n", task, signalSet);)
157 #endif
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");
163 else
164 bug("[Exec] Signal: (Called from '%s')\n", thisTask->tc_Node.ln_Name);
167 Disable();
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);
172 #else
173 task->tc_SigRecvd |= signalSet;
174 #endif
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);
183 #else
184 task->tc_Flags |= TF_EXCEPT;
185 #endif
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))
198 #endif
199 D(bug("[Exec] Signal: Raising Exception for 'running' Task\n");)
200 /* Order a reschedule */
201 Reschedule();
202 #if defined(__AROSEXEC_SMP__)
204 else
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);
209 #endif
210 Enable();
212 /* All done. */
213 return;
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);
228 #else
229 Remove(&task->tc_Node);
230 task->tc_State = TS_READY;
231 Enqueue(&SysBase->TaskReady, &task->tc_Node);
232 #endif
233 /* Has it a higher priority as the current one? */
234 if (
235 #if defined(__AROSEXEC_SMP__)
236 (!(PrivExecBase(SysBase)->IntFlags & EXECF_CPUAffinity) ||
237 (KrnCPUInMask(cpunum, IntETask(task->tc_UnionETask.tc_ETask)->iet_CpuAffinity))) &&
238 #endif
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"));
248 Reschedule();
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);
259 #endif
260 else
262 D(bug("[Exec] Signal: Letting Task process signal when next scheduled to run...\n"););
266 Enable();
268 D(bug("[Exec] Signal: 0x%p finished signal processing\n", task);)
269 #if defined(__AROSEXEC_SMP__)
271 #endif
273 AROS_LIBFUNC_EXIT