unlock the list before calling reschedule
[AROS.git] / rom / exec / signal.c
blob895cbe6068106a880f49d22ba4fc1e1d8751f8f2
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Send some signal to a given task
6 Lang: english
7 */
9 #include <exec/execbase.h>
10 #include <aros/libcall.h>
11 #include <proto/exec.h>
12 #include <aros/debug.h>
14 #include "exec_intern.h"
16 /*****************************************************************************
18 NAME */
20 AROS_LH2(void, Signal,
22 /* SYNOPSIS */
23 AROS_LHA(struct Task *, task, A1),
24 AROS_LHA(ULONG, signalSet, D0),
26 /* LOCATION */
27 struct ExecBase *, SysBase, 54, Exec)
29 /* FUNCTION
30 Send some signals to a given task. If the task is currently waiting
31 on these signals, has a higher priority as the current one and if
32 taskswitches are allowed the new task begins to run immediately.
34 INPUTS
35 task - Pointer to task structure.
36 signalSet - The set of signals to send to the task.
38 RESULT
40 NOTES
41 This function may be used from interrupts.
43 EXAMPLE
45 BUGS
47 SEE ALSO
48 AllocSignal(), FreeSignal(), Wait(), SetSignal(), SetExcept()
50 INTERNALS
52 HISTORY
54 ******************************************************************************/
56 AROS_LIBFUNC_INIT
58 #if defined(__AROSEXEC_SMP__)
59 spinlock_t *task_listlock = NULL;
60 #endif
62 /* Protect the task lists against other tasks that may use Signal(). */
63 #if defined(__AROSEXEC_SMP__)
64 switch (task->tc_State)
66 case TS_RUN:
67 task_listlock =&PrivExecBase(SysBase)->TaskRunningSpinLock;
68 break;
69 case TS_WAIT:
70 task_listlock = &PrivExecBase(SysBase)->TaskWaitSpinLock;
71 break;
72 default:
73 task_listlock = &PrivExecBase(SysBase)->TaskReadySpinLock;
74 break;
76 EXEC_SPINLOCK_LOCK(task_listlock, SPINLOCK_MODE_WRITE);
77 #endif
78 Disable();
80 /* Set the signals in the task structure. */
81 task->tc_SigRecvd |= signalSet;
83 /* Do those bits raise exceptions? */
84 if (task->tc_SigExcept & task->tc_SigRecvd)
86 /* Yes. Set the exception flag. */
87 task->tc_Flags |= TF_EXCEPT;
89 /* task is running (Signal() called from within interrupt)? Raise the exception or defer it for later. */
90 if (task->tc_State == TS_RUN)
92 #if defined(__AROSEXEC_SMP__)
93 EXEC_SPINLOCK_UNLOCK(task_listlock);
94 #endif
95 /* Order a reschedule */
96 Reschedule();
98 /* All done. */
99 Enable();
101 return;
106 Is the task receiving the signals waiting on them
107 (or on a exception) ?
109 if ((task->tc_State == TS_WAIT) &&
110 (task->tc_SigRecvd&(task->tc_SigWait | task->tc_SigExcept)))
112 /* Yes. Move him to the ready list. */
113 task->tc_State = TS_READY;
114 Remove(&task->tc_Node);
115 #if defined(__AROSEXEC_SMP__)
116 EXEC_SPINLOCK_UNLOCK(task_listlock);
117 Enable();
118 task_listlock = EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase)->TaskReadySpinLock, SPINLOCK_MODE_WRITE);
119 Disable();
120 #endif
121 Enqueue(&SysBase->TaskReady, &task->tc_Node);
123 /* Has it a higher priority as the current one? */
124 if (task->tc_Node.ln_Pri > GET_THIS_TASK->tc_Node.ln_Pri)
127 Yes. A taskswitch is necessary. Prepare one if possible.
128 (If the current task is not running it is already moved)
130 if (GET_THIS_TASK->tc_State == TS_RUN)
132 #if defined(__AROSEXEC_SMP__)
133 EXEC_SPINLOCK_UNLOCK(task_listlock);
134 task_listlock = NULL;
135 #endif
136 Reschedule();
141 #if defined(__AROSEXEC_SMP__)
142 if (task_listlock)
144 EXEC_SPINLOCK_UNLOCK(task_listlock);
146 #endif
147 Enable();
149 AROS_LIBFUNC_EXIT