try to make sure compiler/include/mmakefile is always refreshed correctly.
[AROS.git] / rom / exec / newaddtask.c
blob01f983fe12ff59529dbbbbd1cfa546c6a51af27a
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Add a task.
6 Lang: english
7 */
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>
16 #include "etask.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>
24 #endif
26 /*****************************************************************************
28 NAME */
30 AROS_LH4(APTR, NewAddTask,
32 /* SYNOPSIS */
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),
38 /* LOCATION */
39 struct ExecBase *, SysBase, 176, Exec)
41 /* FUNCTION
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
44 immediately.
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.
52 INPUTS
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.
58 RESULT
59 The address of the new task or NULL if the operation failed (can only
60 happen with TF_ETASK set - currenty not implemented).
62 NOTES
63 This function is private. Use MorphOS-compatible NewCreateTaskA()
64 in your applications.
66 EXAMPLE
68 BUGS
70 SEE ALSO
71 RemTask()
73 INTERNALS
75 HISTORY
77 ******************************************************************************/
79 AROS_LIBFUNC_INIT
81 struct Task *parent;
82 struct MemList *mlExtra = NULL;
84 ASSERT_VALID_PTR(task);
86 #if defined(__AROSEXEC_SMP__)
87 int cpunum = KrnGetCPUNumber();
88 #endif
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))
95 IPTR fmtname[] =
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);
109 else
111 FreeMem(mlExtra, sizeof(struct MemList));
112 mlExtra = NULL;
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);
126 if (mlExtra)
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;
140 task->tc_Flags = 0;
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))
167 return NULL;
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));
179 #endif
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)
191 *startfill++ = 0xE1;
195 /* Default finalizer? */
196 if (finalPC == NULL)
197 finalPC = SysBase->TaskExitCode;
199 /* Init new context. */
200 if (!PrepareContext(task, initialPC, finalPC, tagList, SysBase))
202 CleanupETask(task);
203 return NULL;
206 /* Set the task flags for switch and launch. */
207 if(task->tc_Switch)
208 task->tc_Flags|=TF_SWITCH;
210 if(task->tc_Launch)
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
216 lists.
219 #if !defined(__AROSEXEC_SMP__)
220 Disable();
221 #endif
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);
227 #else
228 task->tc_State = TS_INVALID;
229 krnSysCallReschedTask(task, TS_READY);
230 #endif
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
236 is already gone.
238 if (
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;
243 if (
244 #endif
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 */
251 Reschedule();
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);
262 else
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);
267 if (GetETask(task))
268 KrnDeleteContext(GetETask(task)->et_RegFrame);
269 CleanupETask(task);
270 task = NULL;
272 #else
273 Enable();
274 #endif
276 DADDTASK("NewAddTask: Added task 0x%p", task);
277 return task;
279 AROS_LIBFUNC_EXIT
280 } /* NewAddTask */