2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
9 #include <exec/execbase.h>
10 #include <exec/memory.h>
11 #include <utility/tagitem.h>
12 #include <aros/libcall.h>
13 #include <proto/exec.h>
14 #include <exec/rawfmt.h>
17 #include "exec_util.h"
18 #include "exec_debug.h"
19 #include "taskstorage.h"
21 #if defined(__AROSEXEC_SMP__)
22 #define __KERNEL_NOLIBBASE__
23 #include <proto/kernel.h>
26 /*****************************************************************************
30 AROS_LH4(APTR
, NewAddTask
,
33 AROS_LHA(struct Task
*, task
, A1
),
34 AROS_LHA(APTR
, initialPC
, A2
),
35 AROS_LHA(APTR
, finalPC
, A3
),
36 AROS_LHA(struct TagItem
*, tagList
, A4
),
39 struct ExecBase
*, SysBase
, 176, Exec
)
42 Add a new task to the system. If the new task has the highest
43 priority of all and task switches are allowed it will be started
45 Certain task fields should be intitialized and a stack must be
46 allocated before calling this function. tc_SPReg will be used as the
47 starting location for the stack pointer, i.e. a part of the stack can
48 be reserved to pass the task some initial arguments.
49 Memory can be added to the tc_MemEntry list and will be freed when the
50 task dies. The new task's registers are set to 0.
53 task - Pointer to task structure.
54 initialPC - Entry point for the new task.
55 finalPC - Routine that is called if the initialPC() function returns.
56 A NULL pointer installs the default finalizer.
59 The address of the new task or NULL if the operation failed (can only
60 happen with TF_ETASK set - currenty not implemented).
63 This function is private. Use MorphOS-compatible NewCreateTaskA()
77 ******************************************************************************/
82 struct MemList
*mlExtra
= NULL
;
84 ASSERT_VALID_PTR(task
);
86 #if defined(__AROSEXEC_SMP__)
87 int cpunum
= KrnGetCPUNumber();
90 parent
= GET_THIS_TASK
;
92 /* Sigh - you should provide a name for your task. */
93 if ((task
->tc_Node
.ln_Name
== NULL
) && (parent
) && (parent
->tc_Node
.ln_Name
))
97 (IPTR
)parent
->tc_Node
.ln_Name
100 if ((mlExtra
= AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
102 mlExtra
->ml_NumEntries
= 1;
103 mlExtra
->ml_ME
[0].me_Length
= strlen(parent
->tc_Node
.ln_Name
) + 10;
104 if ((mlExtra
->ml_ME
[0].me_Addr
= AllocMem(mlExtra
->ml_ME
[0].me_Length
, MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
106 task
->tc_Node
.ln_Name
= mlExtra
->ml_ME
[0].me_Addr
;
107 RawDoFmt("%s.subtask", (RAWARG
)&fmtname
, RAWFMTFUNC_STRING
, task
->tc_Node
.ln_Name
);
111 FreeMem(mlExtra
, sizeof(struct MemList
));
117 if (task
->tc_Node
.ln_Name
== NULL
)
118 task
->tc_Node
.ln_Name
= "bad task";
120 DADDTASK("NewAddTask (0x%p (\"%s\"), 0x%p, 0x%p)", task
, task
->tc_Node
.ln_Name
, initialPC
, finalPC
);
122 /* Initialize the memory entry list if the caller forgot */
123 if (!task
->tc_MemEntry
.lh_Head
)
124 NEWLIST(&task
->tc_MemEntry
);
127 AddTail(&task
->tc_MemEntry
, &mlExtra
->ml_Node
);
129 DADDTASK("NewAddTask MemEntry head: 0x%p", GetHead(&task
->tc_MemEntry
.lh_Head
));
131 /* Set node type to NT_TASK if not set to something else. */
132 if (!task
->tc_Node
.ln_Type
)
133 task
->tc_Node
.ln_Type
= NT_TASK
;
135 /* This is moved into SysBase at the tasks's startup */
136 task
->tc_IDNestCnt
= -1;
137 task
->tc_TDNestCnt
= -1;
139 task
->tc_State
= TS_ADDED
;
142 task
->tc_SigWait
= 0;
143 task
->tc_SigRecvd
= 0;
144 task
->tc_SigExcept
= 0;
146 /* Signals default to all system signals allocated. */
147 if (task
->tc_SigAlloc
== 0)
148 task
->tc_SigAlloc
= SysBase
->TaskSigAlloc
;
150 /* Currently only used for segmentation violation */
151 if (task
->tc_TrapCode
== NULL
)
152 task
->tc_TrapCode
= SysBase
->TaskTrapCode
;
154 if (task
->tc_ExceptCode
== NULL
)
155 task
->tc_ExceptCode
= SysBase
->TaskExceptCode
;
158 * EXECF_StackSnoop can be set or reset at runtime.
159 * However task's stack is either snooped or not, it's problematic
160 * to turn it on at runtime. So we initialize it when the task starts up.
162 if (PrivExecBase(SysBase
)->IntFlags
& EXECF_StackSnoop
)
163 task
->tc_Flags
|= TF_STACKCHK
;
165 /* Initialize ETask */
166 if (!InitETask(task
, parent
))
169 /* Get new stackpointer. */
170 if (task
->tc_SPReg
== NULL
)
171 task
->tc_SPReg
= (UBYTE
*)(task
->tc_SPUpper
) - SP_OFFSET
;
173 #ifdef AROS_STACKALIGN
174 if ((IPTR
)task
->tc_SPReg
& (AROS_STACKALIGN
- 1))
176 DADDTASK("NewAddTask with unaligned stack pointer (0x%p)! Fixing...", task
->tc_SPReg
);
177 task
->tc_SPReg
= (APTR
)((IPTR
)task
->tc_SPReg
& ~(AROS_STACKALIGN
- 1));
180 DADDTASK("NewAddTask: SPLower: 0x%p SPUpper: 0x%p SP: 0x%p", task
->tc_SPLower
, task
->tc_SPUpper
, task
->tc_SPReg
);
182 if (task
->tc_Flags
& TF_STACKCHK
)
184 UBYTE
*startfill
, *endfill
;
186 startfill
= (UBYTE
*)task
->tc_SPLower
;
187 endfill
= ((UBYTE
*)task
->tc_SPReg
) - 16;
189 while (startfill
<= endfill
)
195 /* Default finalizer? */
197 finalPC
= SysBase
->TaskExitCode
;
199 /* Init new context. */
200 if (!PrepareContext(task
, initialPC
, finalPC
, tagList
, SysBase
))
206 /* Set the task flags for switch and launch. */
208 task
->tc_Flags
|=TF_SWITCH
;
211 task
->tc_Flags
|=TF_LAUNCH
;
214 Protect the task lists. This must be done with Disable() because
215 of Signal() which is usable from interrupts and may change those
219 #if !defined(__AROSEXEC_SMP__)
223 /* Add the new task to the ready list. */
224 #if !defined(__AROSEXEC_SMP__)
225 task
->tc_State
= TS_READY
;
226 Enqueue(&SysBase
->TaskReady
, &task
->tc_Node
);
228 task
->tc_State
= TS_INVALID
;
229 krnSysCallReschedTask(task
, TS_READY
);
233 Determine if a task switch is necessary. (If the new task has a
234 higher priority than the current one and the current one
235 is still active.) If the current task isn't of type TS_RUN it
239 #if defined(__AROSEXEC_SMP__)
240 (!(PrivExecBase(SysBase
)->IntFlags
& EXECF_CPUAffinity
) || (IntETask(task
->tc_UnionETask
.tc_ETask
) && KrnCPUInMask(cpunum
, IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
))))
242 parent
= GET_THIS_TASK
;
245 parent
&& task
->tc_Node
.ln_Pri
> parent
->tc_Node
.ln_Pri
&&
246 parent
->tc_State
== TS_RUN
)
248 DADDTASK("NewAddTask: Rescheduling...\n");
250 /* Reschedule() will take care about disabled task switching automatically */
253 #if defined(__AROSEXEC_SMP__)
255 else if (PrivExecBase(SysBase
)->IntFlags
& EXECF_CPUAffinity
)
257 //bug("[Exec] AddTask: CPU #%d not in mask [%08x:%08x]\n", cpunum, KrnGetCPUMask(cpunum), IntETask(task->tc_UnionETask.tc_ETask)->iet_CpuAffinity);
258 DADDTASK("NewAddTask: CPU #%d not in mask\n", cpunum
);
259 if (IntETask(task
->tc_UnionETask
.tc_ETask
))
260 KrnScheduleCPU(IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
);
264 bug("[Exec] NewAddTask: Unable to Launch on the selected CPU\n");
265 // TODO: Free up all the task data ..
266 krnSysCallReschedTask(task
, TS_REMOVED
);
268 KrnDeleteContext(GetETask(task
)->et_RegFrame
);
276 DADDTASK("NewAddTask: Added task 0x%p", task
);