Port the SB128 code to AROS.
[AROS.git] / rom / exec / newaddtask.c
blob8cc5fd493a028bdfa898929b9de8cbcf16f0ec79
1 /*
2 Copyright © 1995-2011, 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"
20 /*****************************************************************************
22 NAME */
24 AROS_LH4(APTR, NewAddTask,
26 /* SYNOPSIS */
27 AROS_LHA(struct Task *, task, A1),
28 AROS_LHA(APTR, initialPC, A2),
29 AROS_LHA(APTR, finalPC, A3),
30 AROS_LHA(struct TagItem *, tagList, A4),
32 /* LOCATION */
33 struct ExecBase *, SysBase, 176, Exec)
35 /* FUNCTION
36 Add a new task to the system. If the new task has the highest
37 priority of all and task switches are allowed it will be started
38 immediately.
39 Certain task fields should be intitialized and a stack must be
40 allocated before calling this function. tc_SPReg will be used as the
41 starting location for the stack pointer, i.e. a part of the stack can
42 be reserved to pass the task some initial arguments.
43 Memory can be added to the tc_MemEntry list and will be freed when the
44 task dies. The new task's registers are set to 0.
46 INPUTS
47 task - Pointer to task structure.
48 initialPC - Entry point for the new task.
49 finalPC - Routine that is called if the initialPC() function returns.
50 A NULL pointer installs the default finalizer.
52 RESULT
53 The address of the new task or NULL if the operation failed (can only
54 happen with TF_ETASK set - currenty not implemented).
56 NOTES
57 This function is private. Use MorphOS-compatible NewCreateTaskA()
58 in your applications.
60 EXAMPLE
62 BUGS
64 SEE ALSO
65 RemTask()
67 INTERNALS
69 HISTORY
71 ******************************************************************************/
73 AROS_LIBFUNC_INIT
75 ASSERT_VALID_PTR(task);
77 /* Sigh - you should provide a name for your task. */
78 if(task->tc_Node.ln_Name==NULL)
79 task->tc_Node.ln_Name="unknown task";
81 DADDTASK("NewAddTask (0x%p (\"%s\"), 0x%p, 0x%p)", task, task->tc_Node.ln_Name, initialPC, finalPC);
83 /* Initialize the memory entry list if the caller forgot */
84 if (!task->tc_MemEntry.lh_Head)
85 NEWLIST(&task->tc_MemEntry);
87 DADDTASK("NewAddTask MemEntry head: 0x%p", GetHead(&task->tc_MemEntry.lh_Head));
89 /* Set node type to NT_TASK if not set to something else. */
90 if(!task->tc_Node.ln_Type)
91 task->tc_Node.ln_Type=NT_TASK;
93 /* This is moved into SysBase at the tasks's startup */
94 task->tc_IDNestCnt=-1;
95 task->tc_TDNestCnt=-1;
97 task->tc_State = TS_ADDED;
98 task->tc_Flags = 0;
100 task->tc_SigWait = 0;
101 task->tc_SigRecvd = 0;
102 task->tc_SigExcept = 0;
104 /* Signals default to all system signals allocated. */
105 if(task->tc_SigAlloc==0)
106 task->tc_SigAlloc=SysBase->TaskSigAlloc;
108 /* Currently only used for segmentation violation */
109 if(task->tc_TrapCode==NULL)
110 task->tc_TrapCode=SysBase->TaskTrapCode;
112 if(task->tc_ExceptCode==NULL)
113 task->tc_ExceptCode=SysBase->TaskExceptCode;
115 task->tc_Flags |= TF_ETASK;
118 * EXECF_StackSnoop can be set or reset at runtime.
119 * However task's stack is either snooped or not, it's problematic
120 * to turn it on at runtime. So we initialize it when the task starts up.
122 if (PrivExecBase(SysBase)->IntFlags & EXECF_StackSnoop)
123 task->tc_Flags |= TF_STACKCHK;
126 * We don't add this to the task memory, it isn't free'd by
127 * RemTask(), rather by somebody else calling ChildFree().
128 * Alternatively, an orphaned task will free its own ETask.
130 task->tc_UnionETask.tc_ETask = AllocVec
132 sizeof (struct IntETask),
133 MEMF_ANY|MEMF_CLEAR
136 if (!task->tc_UnionETask.tc_ETask)
137 return NULL;
139 InitETask(task, task->tc_UnionETask.tc_ETask);
141 /* Get new stackpointer. */
142 if (task->tc_SPReg==NULL)
143 #if AROS_STACK_GROWS_DOWNWARDS
144 task->tc_SPReg = (UBYTE *)(task->tc_SPUpper) - SP_OFFSET;
145 #else
146 task->tc_SPReg = (UBYTE *)(task->tc_SPLower) - SP_OFFSET;
147 #endif
149 #ifdef AROS_STACKALIGN
150 if ((IPTR)task->tc_SPReg & (AROS_STACKALIGN - 1))
152 DADDTASK("NewAddTask with unaligned stack pointer (0x%p)! Fixing...", task->tc_SPReg);
153 task->tc_SPReg = (APTR)((IPTR)task->tc_SPReg & ~(AROS_STACKALIGN - 1));
155 #endif
156 DADDTASK("NewAddTask: SPLower: 0x%p SPUpper: 0x%p SP: 0x%p", task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
158 if (task->tc_Flags & TF_STACKCHK)
160 UBYTE *startfill, *endfill;
162 #if AROS_STACK_GROWS_DOWNWARDS
163 startfill = (UBYTE *)task->tc_SPLower;
164 endfill = ((UBYTE *)task->tc_SPReg) - 16;
165 #else
166 startfill = ((UBYTE *)task->tc_SPReg) + 16;
167 endfill = ((UBYTE *)task->tc_SPUpper) - 1; /* FIXME: -1 correct ?? */
168 #endif
170 while(startfill <= endfill)
172 *startfill++ = 0xE1;
176 /* Default finalizer? */
177 if(finalPC==NULL)
178 finalPC=SysBase->TaskExitCode;
180 /* Init new context. */
181 if (!PrepareContext (task, initialPC, finalPC, tagList))
183 FreeTaskMem (task, task->tc_UnionETask.tc_ETask);
184 return NULL;
187 /* Set the task flags for switch and launch. */
188 if(task->tc_Switch)
189 task->tc_Flags|=TF_SWITCH;
191 if(task->tc_Launch)
192 task->tc_Flags|=TF_LAUNCH;
195 Protect the task lists. This must be done with Disable() because
196 of Signal() which is usable from interrupts and may change those
197 lists.
199 Disable();
201 /* Add the new task to the ready list. */
202 task->tc_State=TS_READY;
203 Enqueue(&SysBase->TaskReady,&task->tc_Node);
206 Determine if a task switch is necessary. (If the new task has a
207 higher priority than the current one and the current one
208 is still active.) If the current task isn't of type TS_RUN it
209 is already gone.
212 if (task->tc_Node.ln_Pri > SysBase->ThisTask->tc_Node.ln_Pri &&
213 SysBase->ThisTask->tc_State == TS_RUN)
215 D(bug("[AddTask] Rescheduling...\n"));
217 /* Reschedule() will take care about disabled task switching automatically */
218 Reschedule(task);
221 Enable();
223 DADDTASK("Added task 0x%p", task);
224 return task;
226 AROS_LIBFUNC_EXIT
227 } /* NewAddTask */