Commit of the code which was suggested by Georg as a fix for:
[cake.git] / rom / exec / newaddtask.c
blobf2ee3737bcfab3a7572d4efb6c1d2188b82661d5
1 /*
2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Add a task.
6 Lang: english
7 */
8 #include <exec/execbase.h>
9 #include <exec/memory.h>
10 #include <utility/tagitem.h>
11 #include <aros/libcall.h>
12 #include <aros/config.h>
13 #include <proto/exec.h>
14 #include "etask.h"
15 #include "exec_util.h"
17 #include "exec_debug.h"
18 #ifndef DEBUG_NewAddTask
19 # define DEBUG_NewAddTask 0
20 #endif
21 #undef DEBUG
22 #if DEBUG_NewAddTask
23 # define DEBUG 1
24 #endif
25 #include <aros/debug.h>
27 /*****************************************************************************
29 NAME */
31 AROS_LH4(APTR, NewAddTask,
33 /* SYNOPSIS */
34 AROS_LHA(struct Task *, task, A1),
35 AROS_LHA(APTR, initialPC, A2),
36 AROS_LHA(APTR, finalPC, A3),
37 AROS_LHA(struct TagItem *, tagList, A4),
39 /* LOCATION */
40 struct ExecBase *, SysBase, 152, Exec)
42 /* FUNCTION
43 Add a new task to the system. If the new task has the highest
44 priority of all and task switches are allowed it will be started
45 immediately.
47 You must initialise certain fields, and allocate a stack before
48 calling this function. The fields that must be initialised are:
49 tc_SPLower, tc_SPUpper, tc_SPReg, and the tc_Node structure.
51 If any other fields are initialised to zero, then they will be
52 filled in with the system defaults.
54 The value of tc_SPReg will be used as the location for the stack
55 pointer. You can place any arguments you wish to pass to the Task
56 onto the stack before calling AddTask(). However note that you may
57 need to consider the stack direction on your processor.
59 Memory can be added to the tc_MemEntry list and will be freed when
60 the task dies. The new task's registers are set to 0.
62 INPUTS
63 task - Pointer to task structure.
64 initialPC - Entry point for the new task.
65 finalPC - Routine that is called if the initialPC() function
66 returns. A NULL pointer installs the default finalizer.
68 RESULT
69 The address of the new task or NULL if the operation failed.
71 NOTES
73 EXAMPLE
75 BUGS
77 SEE ALSO
78 RemTask()
80 INTERNALS
82 ******************************************************************************/
84 AROS_LIBFUNC_INIT
86 D(bug("Call NewAddTask (%08lx (\"%s\"), %08lx, %08lx)\n"
87 , task
88 , task->tc_Node.ln_Name
89 , initialPC
90 , finalPC
91 ));
92 ASSERT_VALID_PTR(task);
94 /* Set node type to NT_TASK if not set to something else. */
95 if(task->tc_Node.ln_Type == 0)
96 task->tc_Node.ln_Type = NT_TASK;
98 /* Sigh - you should provide a name for your task. */
99 if(task->tc_Node.ln_Name == NULL)
100 task->tc_Node.ln_Name = "unknown 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;
118 * tc_SigWait, tc_SigRecvd, tc_SigExcept are default 0
119 * tc_ExceptCode, tc_ExceptData default to NULL.
122 /* Currently only used for segmentation violation */
123 if(task->tc_TrapCode == NULL)
124 task->tc_TrapCode = SysBase->TaskTrapCode;
126 if (task->tc_ExceptCode == NULL)
127 task->tc_ExceptCode=SysBase->TaskExceptCode;
130 If you can't to store the registers on the signal stack, you
131 must set this flag.
133 task->tc_Flags |= TF_ETASK;
135 /* Allocate the ETask structure if requested */
136 if (task->tc_Flags & TF_ETASK)
138 struct ETask *et;
141 * We don't add this to the task memory, it isn't free'd by
142 * RemTask(), rather by somebody else calling ChildFree().
143 * Alternatively, an orphaned task will free its own ETask.
145 task->tc_UnionETask.tc_ETask = AllocVec
147 sizeof (struct IntETask),
148 MEMF_ANY|MEMF_CLEAR
151 if (!task->tc_UnionETask.tc_ETask)
152 return NULL;
154 et = (struct ETask *)task->tc_UnionETask.tc_ETask;
155 NEWLIST(&et->et_Children);
156 /* Add the newly created task to the parent's children
157 list. */
158 et->et_Parent = FindTask(NULL);
159 Forbid();
160 ADDHEAD(&GetETask(et->et_Parent)->et_Children, et);
161 Permit();
163 /* Initialise the message list */
164 NEWLIST(&et->et_TaskMsgPort.mp_MsgList);
165 et->et_TaskMsgPort.mp_Flags = PA_SIGNAL;
166 et->et_TaskMsgPort.mp_Node.ln_Type = NT_MSGPORT;
167 et->et_TaskMsgPort.mp_SigTask = task;
168 et->et_TaskMsgPort.mp_SigBit = SIGB_CHILD;
170 /* Initialise the trap fields */
171 et->et_TrapAlloc = SysBase->TaskTrapAlloc;
172 et->et_TrapAble = 0;
174 #if 0
175 Forbid();
176 while(et->et_UniqueID == 0)
179 * Add some fuzz on wrapping. Its likely that the early numbers
180 * where taken by somebody else.
182 if(++SysBase->ex_TaskID == 0)
183 SysBase->exTaskID = 1024;
185 Disable();
186 if(FindTaskByID(SysBase->ex_TaskID, SysBase) == NULL)
187 et->et_UniqueID = SysBase->ex_TaskID;
188 Enable();
190 Permit();
191 #endif
193 else
195 task->tc_UnionETask.tc_ETrap.tc_ETrapAlloc = SysBase->TaskTrapAlloc;
196 task->tc_UnionETask.tc_ETrap.tc_ETrapAble = 0;
199 /* Get new stackpointer. Note, the doc says this MUST be initialised. */
200 if (task->tc_SPReg==NULL)
201 #if AROS_STACK_GROWS_DOWNWARDS
202 task->tc_SPReg = (UBYTE *)(task->tc_SPUpper) - SP_OFFSET;
203 #else
204 task->tc_SPReg = (UBYTE *)(task->tc_SPLower) - SP_OFFSET;
205 #endif
207 #if AROS_STACK_DEBUG
209 UBYTE *startfill, *endfill;
211 #if AROS_STACK_GROWS_DOWNWARDS
212 startfill = (UBYTE *)task->tc_SPLower;
213 endfill = ((UBYTE *)task->tc_SPReg) - 16;
214 #else
215 startfill = ((UBYTE *)task->tc_SPReg) + 16;
216 endfill = ((UBYTE *)task->tc_SPUpper) - 1; /* FIXME: -1 correct ?? */
217 #endif
219 while(startfill <= endfill)
221 *startfill++ = 0xE1;
225 #endif
227 /* Default finalizer? */
228 if(finalPC == NULL)
229 finalPC = SysBase->TaskExitCode;
231 /* Init new context. */
232 if (!PrepareContext (task, initialPC, finalPC, tagList))
234 FreeVec(task->tc_UnionETask.tc_ETask);
235 return NULL;
238 /* Set the task flags for switch and launch. */
239 if(task->tc_Switch)
240 task->tc_Flags|=TF_SWITCH;
242 if(task->tc_Launch)
243 task->tc_Flags|=TF_LAUNCH;
245 /* tc_MemEntry _must_ already be set. */
248 Protect the task lists. This must be done with Disable() because
249 of Signal() which is usable from interrupts and may change those
250 lists.
252 Disable();
254 /* Add the new task to the ready list. */
255 task->tc_State=TS_READY;
256 Enqueue(&SysBase->TaskReady,&task->tc_Node);
259 Determine if a task switch is necessary. (If the new task has a
260 higher priority than the current one and the current one
261 is still active.) If the current task isn't of type TS_RUN it
262 is already gone.
264 if(task->tc_Node.ln_Pri>SysBase->ThisTask->tc_Node.ln_Pri&&
265 SysBase->ThisTask->tc_State==TS_RUN)
267 /* Are taskswitches allowed? (Don't count own Disable() here) */
268 if(SysBase->TDNestCnt>=0||SysBase->IDNestCnt>0) {
269 /* No. Store it for later. */
270 SysBase->AttnResched|=0x80;
271 } else {
272 /* Switches are allowed. Move the current task away. */
273 SysBase->ThisTask->tc_State=TS_READY;
274 Enqueue(&SysBase->TaskReady,&SysBase->ThisTask->tc_Node);
276 /* And force a rescedule. */
277 Switch();
281 Enable();
283 ReturnPtr ("NewAddTask", struct Task *, task);
284 AROS_LIBFUNC_EXIT
285 } /* NewAddTask */
287 /* Default finaliser. */
288 void Exec_TaskFinaliser(void)
290 /* Get rid of current task. */
291 RemTask(SysBase->ThisTask);