Test current SDI headers.
[AROS.git] / rom / exec / newaddtask.c
blobf6752e1214e361b6a309b1d2e24025ad678f2c07
1 /*
2 Copyright © 1995-2015, 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/debug.h>
13 #include <aros/libcall.h>
14 #include <proto/exec.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 #include <proto/kernel.h>
23 #endif
25 /*****************************************************************************
27 NAME */
29 AROS_LH4(APTR, NewAddTask,
31 /* SYNOPSIS */
32 AROS_LHA(struct Task *, task, A1),
33 AROS_LHA(APTR, initialPC, A2),
34 AROS_LHA(APTR, finalPC, A3),
35 AROS_LHA(struct TagItem *, tagList, A4),
37 /* LOCATION */
38 struct ExecBase *, SysBase, 176, Exec)
40 /* FUNCTION
41 Add a new task to the system. If the new task has the highest
42 priority of all and task switches are allowed it will be started
43 immediately.
44 Certain task fields should be intitialized and a stack must be
45 allocated before calling this function. tc_SPReg will be used as the
46 starting location for the stack pointer, i.e. a part of the stack can
47 be reserved to pass the task some initial arguments.
48 Memory can be added to the tc_MemEntry list and will be freed when the
49 task dies. The new task's registers are set to 0.
51 INPUTS
52 task - Pointer to task structure.
53 initialPC - Entry point for the new task.
54 finalPC - Routine that is called if the initialPC() function returns.
55 A NULL pointer installs the default finalizer.
57 RESULT
58 The address of the new task or NULL if the operation failed (can only
59 happen with TF_ETASK set - currenty not implemented).
61 NOTES
62 This function is private. Use MorphOS-compatible NewCreateTaskA()
63 in your applications.
65 EXAMPLE
67 BUGS
69 SEE ALSO
70 RemTask()
72 INTERNALS
74 HISTORY
76 ******************************************************************************/
78 AROS_LIBFUNC_INIT
80 ASSERT_VALID_PTR(task);
82 #if defined(__AROSEXEC_SMP__)
83 int cpunum = KrnGetCPUNumber();
84 #endif
86 /* Sigh - you should provide a name for your task. */
87 if (task->tc_Node.ln_Name == NULL)
88 task->tc_Node.ln_Name = "unknown task";
90 DADDTASK("NewAddTask (0x%p (\"%s\"), 0x%p, 0x%p)", task, task->tc_Node.ln_Name, initialPC, finalPC);
92 /* Initialize the memory entry list if the caller forgot */
93 if (!task->tc_MemEntry.lh_Head)
94 NEWLIST(&task->tc_MemEntry);
96 DADDTASK("NewAddTask MemEntry head: 0x%p", GetHead(&task->tc_MemEntry.lh_Head));
98 /* Set node type to NT_TASK if not set to something else. */
99 if (!task->tc_Node.ln_Type)
100 task->tc_Node.ln_Type = NT_TASK;
102 /* This is moved into SysBase at the tasks's startup */
103 task->tc_IDNestCnt = -1;
104 task->tc_TDNestCnt = -1;
106 task->tc_State = TS_ADDED;
107 task->tc_Flags = 0;
109 task->tc_SigWait = 0;
110 task->tc_SigRecvd = 0;
111 task->tc_SigExcept = 0;
113 /* Signals default to all system signals allocated. */
114 if (task->tc_SigAlloc == 0)
115 task->tc_SigAlloc = SysBase->TaskSigAlloc;
117 /* Currently only used for segmentation violation */
118 if (task->tc_TrapCode == NULL)
119 task->tc_TrapCode = SysBase->TaskTrapCode;
121 if (task->tc_ExceptCode == NULL)
122 task->tc_ExceptCode = SysBase->TaskExceptCode;
125 * EXECF_StackSnoop can be set or reset at runtime.
126 * However task's stack is either snooped or not, it's problematic
127 * to turn it on at runtime. So we initialize it when the task starts up.
129 if (PrivExecBase(SysBase)->IntFlags & EXECF_StackSnoop)
130 task->tc_Flags |= TF_STACKCHK;
132 /* Initialize ETask */
133 if (!InitETask(task))
134 return NULL;
136 /* Get new stackpointer. */
137 if (task->tc_SPReg == NULL)
138 task->tc_SPReg = (UBYTE *)(task->tc_SPUpper) - SP_OFFSET;
140 #ifdef AROS_STACKALIGN
141 if ((IPTR)task->tc_SPReg & (AROS_STACKALIGN - 1))
143 DADDTASK("NewAddTask with unaligned stack pointer (0x%p)! Fixing...", task->tc_SPReg);
144 task->tc_SPReg = (APTR)((IPTR)task->tc_SPReg & ~(AROS_STACKALIGN - 1));
146 #endif
147 DADDTASK("NewAddTask: SPLower: 0x%p SPUpper: 0x%p SP: 0x%p", task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
149 if (task->tc_Flags & TF_STACKCHK)
151 UBYTE *startfill, *endfill;
153 startfill = (UBYTE *)task->tc_SPLower;
154 endfill = ((UBYTE *)task->tc_SPReg) - 16;
156 while (startfill <= endfill)
158 *startfill++ = 0xE1;
162 /* Default finalizer? */
163 if (finalPC == NULL)
164 finalPC = SysBase->TaskExitCode;
166 /* Init new context. */
167 if (!PrepareContext(task, initialPC, finalPC, tagList, SysBase))
169 CleanupETask(task);
170 return NULL;
173 /* Set the task flags for switch and launch. */
174 if(task->tc_Switch)
175 task->tc_Flags|=TF_SWITCH;
177 if(task->tc_Launch)
178 task->tc_Flags|=TF_LAUNCH;
181 Protect the task lists. This must be done with Disable() because
182 of Signal() which is usable from interrupts and may change those
183 lists.
186 #if defined(__AROSEXEC_SMP__)
187 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase)->TaskReadySpinLock, SPINLOCK_MODE_WRITE);
188 #endif
189 Disable();
191 /* Add the new task to the ready list. */
192 task->tc_State = TS_READY;
193 Enqueue(&SysBase->TaskReady, &task->tc_Node);
194 #if defined(__AROSEXEC_SMP__)
195 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskReadySpinLock);
196 #endif
199 Determine if a task switch is necessary. (If the new task has a
200 higher priority than the current one and the current one
201 is still active.) If the current task isn't of type TS_RUN it
202 is already gone.
205 if (
206 #if defined(__AROSEXEC_SMP__)
207 ((IntETask(task->tc_UnionETask.tc_ETask)->iet_CpuAffinity & KrnGetCPUMask(cpunum)) == KrnGetCPUMask(cpunum)) &&
208 #endif
209 task->tc_Node.ln_Pri > GET_THIS_TASK->tc_Node.ln_Pri &&
210 GET_THIS_TASK->tc_State == TS_RUN)
212 D(bug("[AddTask] Rescheduling...\n");)
214 /* Reschedule() will take care about disabled task switching automatically */
215 Reschedule();
217 #if defined(__AROSEXEC_SMP__)
218 else
220 bug("[Exec] AddTask:\n");
222 #endif
224 Enable();
226 DADDTASK("Added task 0x%p", task);
227 return task;
229 AROS_LIBFUNC_EXIT
230 } /* NewAddTask */