- Wait for mouse acks properly.
[cake.git] / rom / exec / newaddtask.c
blob2aa6c729e54ac71e4af2aae947a36967f34ffa58
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)
139 * We don't add this to the task memory, it isn't free'd by
140 * RemTask(), rather by somebody else calling ChildFree().
141 * Alternatively, an orphaned task will free its own ETask.
143 task->tc_UnionETask.tc_ETask = AllocVec
145 sizeof (struct IntETask),
146 MEMF_ANY|MEMF_CLEAR
149 if (!task->tc_UnionETask.tc_ETask)
150 return NULL;
152 InitETask(task, task->tc_UnionETask.tc_ETask);
154 else
156 task->tc_UnionETask.tc_ETrap.tc_ETrapAlloc = SysBase->TaskTrapAlloc;
157 task->tc_UnionETask.tc_ETrap.tc_ETrapAble = 0;
160 /* Get new stackpointer. Note, the doc says this MUST be initialised. */
161 if (task->tc_SPReg==NULL)
162 #if AROS_STACK_GROWS_DOWNWARDS
163 task->tc_SPReg = (UBYTE *)(task->tc_SPUpper) - SP_OFFSET;
164 #else
165 task->tc_SPReg = (UBYTE *)(task->tc_SPLower) - SP_OFFSET;
166 #endif
168 #if AROS_STACK_DEBUG
170 UBYTE *startfill, *endfill;
172 #if AROS_STACK_GROWS_DOWNWARDS
173 startfill = (UBYTE *)task->tc_SPLower;
174 endfill = ((UBYTE *)task->tc_SPReg) - 16;
175 #else
176 startfill = ((UBYTE *)task->tc_SPReg) + 16;
177 endfill = ((UBYTE *)task->tc_SPUpper) - 1; /* FIXME: -1 correct ?? */
178 #endif
180 while(startfill <= endfill)
182 *startfill++ = 0xE1;
186 #endif
188 /* Default finalizer? */
189 if(finalPC == NULL)
190 finalPC = SysBase->TaskExitCode;
192 /* Init new context. */
193 if (!PrepareContext (task, initialPC, finalPC, tagList))
195 FreeVec(task->tc_UnionETask.tc_ETask);
196 return NULL;
199 /* Set the task flags for switch and launch. */
200 if(task->tc_Switch)
201 task->tc_Flags|=TF_SWITCH;
203 if(task->tc_Launch)
204 task->tc_Flags|=TF_LAUNCH;
206 /* tc_MemEntry _must_ already be set. */
209 Protect the task lists. This must be done with Disable() because
210 of Signal() which is usable from interrupts and may change those
211 lists.
213 Disable();
215 /* Add the new task to the ready list. */
216 task->tc_State=TS_READY;
217 Enqueue(&SysBase->TaskReady,&task->tc_Node);
220 Determine if a task switch is necessary. (If the new task has a
221 higher priority than the current one and the current one
222 is still active.) If the current task isn't of type TS_RUN it
223 is already gone.
225 if(task->tc_Node.ln_Pri>SysBase->ThisTask->tc_Node.ln_Pri&&
226 SysBase->ThisTask->tc_State==TS_RUN)
228 /* Are taskswitches allowed? (Don't count own Disable() here) */
229 if(SysBase->TDNestCnt>=0||SysBase->IDNestCnt>0) {
230 /* No. Store it for later. */
231 SysBase->AttnResched|=0x80;
232 } else {
233 /* Switches are allowed. Move the current task away. */
234 SysBase->ThisTask->tc_State=TS_READY;
235 Enqueue(&SysBase->TaskReady,&SysBase->ThisTask->tc_Node);
237 /* And force a rescedule. */
238 Switch();
242 Enable();
244 ReturnPtr ("NewAddTask", struct Task *, task);
245 AROS_LIBFUNC_EXIT
246 } /* NewAddTask */
248 /* Default finaliser. */
249 void Exec_TaskFinaliser(void)
251 /* Get rid of current task. */
252 RemTask(SysBase->ThisTask);