2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
8 #include <exec/execbase.h>
9 #include <exec/memory.h>
10 #include <utility/tagitem.h>
11 #include <aros/libcall.h>
12 #include <proto/exec.h>
14 #include "exec_util.h"
16 #include "exec_debug.h"
19 # define DEBUG_AddTask 0
25 #include <aros/debug.h>
27 void AROS_SLIB_ENTRY(TrapHandler
,Exec
)(void);
29 /*****************************************************************************
33 AROS_LH4(APTR
, NewAddTask
,
36 AROS_LHA(struct Task
*, task
, A1
),
37 AROS_LHA(APTR
, initialPC
, A2
),
38 AROS_LHA(APTR
, finalPC
, A3
),
39 AROS_LHA(struct TagItem
*, tagList
, A4
),
42 struct ExecBase
*, SysBase
, 152, Exec
)
45 Add a new task to the system. If the new task has the highest
46 priority of all and task switches are allowed it will be started
48 Certain task fields should be intitialized and a stack must be
49 allocated before calling this function. tc_SPReg will be used as the
50 starting location for the stack pointer, i.e. a part of the stack can
51 be reserved to pass the task some initial arguments.
52 Memory can be added to the tc_MemEntry list and will be freed when the
53 task dies. The new task's registers are set to 0.
56 task - Pointer to task structure.
57 initialPC - Entry point for the new task.
58 finalPC - Routine that is called if the initialPC() function returns.
59 A NULL pointer installs the default finalizer.
62 The address of the new task or NULL if the operation failed (can only
63 happen with TF_ETASK set - currenty not implemented).
78 ******************************************************************************/
83 D(bug("[exec] Call NewAddTask (%012lx (\"%s\"), %012lx, %012lx)\n"
85 , task
->tc_Node
.ln_Name
89 ASSERT_VALID_PTR(task
);
91 /* Set node type to NT_TASK if not set to something else. */
92 if(!task
->tc_Node
.ln_Type
)
93 task
->tc_Node
.ln_Type
=NT_TASK
;
95 /* Sigh - you should provide a name for your task. */
96 if(task
->tc_Node
.ln_Name
==NULL
)
97 task
->tc_Node
.ln_Name
="unknown task";
99 /* This is moved into SysBase at the tasks's startup */
100 task
->tc_IDNestCnt
=-1;
101 task
->tc_TDNestCnt
=-1;
103 task
->tc_State
= TS_ADDED
;
106 task
->tc_SigWait
= 0;
107 task
->tc_SigRecvd
= 0;
108 task
->tc_SigExcept
= 0;
110 /* Signals default to all system signals allocated. */
111 if(task
->tc_SigAlloc
==0)
112 task
->tc_SigAlloc
=SysBase
->TaskSigAlloc
;
114 /* Currently only used for segmentation violation */
115 if(task
->tc_TrapCode
==NULL
)
116 task
->tc_TrapCode
=SysBase
->TaskTrapCode
;
118 if(task
->tc_ExceptCode
==NULL
)
119 task
->tc_ExceptCode
=SysBase
->TaskExceptCode
;
121 task
->tc_Flags
|= TF_ETASK
;
124 * We don't add this to the task memory, it isn't free'd by
125 * RemTask(), rather by somebody else calling ChildFree().
126 * Alternatively, an orphaned task will free its own ETask.
128 task
->tc_UnionETask
.tc_ETask
= AllocVec
130 sizeof (struct IntETask
),
134 if (!task
->tc_UnionETask
.tc_ETask
)
137 InitETask(task
, task
->tc_UnionETask
.tc_ETask
);
139 /* Get new stackpointer. */
140 /* sp=task->tc_SPReg; */
141 if (task
->tc_SPReg
==NULL
)
142 #if AROS_STACK_GROWS_DOWNWARDS
143 task
->tc_SPReg
= (UBYTE
*)(task
->tc_SPUpper
) - SP_OFFSET
;
145 task
->tc_SPReg
= (UBYTE
*)(task
->tc_SPLower
) - SP_OFFSET
;
148 if ((IPTR
)task
->tc_SPReg
& 0xf)
150 bug("[exec] NewAddTask with unaligned stack pointer! fixing %08x->%08x\n",
151 task
->tc_SPReg
, (IPTR
)task
->tc_SPReg
& 0xfffffff0);
153 task
->tc_SPReg
= (APTR
)((IPTR
)task
->tc_SPReg
& 0xfffffff0);
158 UBYTE
*startfill
, *endfill
;
160 #if AROS_STACK_GROWS_DOWNWARDS
161 startfill
= (UBYTE
*)task
->tc_SPLower
;
162 endfill
= ((UBYTE
*)task
->tc_SPReg
) - 16;
164 startfill
= ((UBYTE
*)task
->tc_SPReg
) + 16;
165 endfill
= ((UBYTE
*)task
->tc_SPUpper
) - 1; /* FIXME: -1 correct ?? */
168 while(startfill
<= endfill
)
176 /* Default finalizer? */
178 finalPC
=SysBase
->TaskExitCode
;
180 /* Init new context. */
181 if (!PrepareContext (task
, initialPC
, finalPC
, tagList
))
183 FreeTaskMem (task
, task
->tc_UnionETask
.tc_ETask
);
188 /* task->tc_SPReg=sp; */
190 /* Set the task flags for switch and launch. */
192 task
->tc_Flags
|=TF_SWITCH
;
195 task
->tc_Flags
|=TF_LAUNCH
;
197 /* tc_MemEntry _must_ already be set. */
200 Protect the task lists. This must be done with Disable() because
201 of Signal() which is usable from interrupts and may change those
206 /* Add the new task to the ready list. */
207 task
->tc_State
=TS_READY
;
208 Enqueue(&SysBase
->TaskReady
,&task
->tc_Node
);
211 Determine if a task switch is necessary. (If the new task has a
212 higher priority than the current one and the current one
213 is still active.) If the current task isn't of type TS_RUN it
217 if(task
->tc_Node
.ln_Pri
>SysBase
->ThisTask
->tc_Node
.ln_Pri
&&
218 SysBase
->ThisTask
->tc_State
==TS_RUN
)
220 /* Are taskswitches allowed? (Don't count own Disable() here) */
221 if(SysBase
->TDNestCnt
>=0||SysBase
->IDNestCnt
>0)
222 /* No. Store it for later. */
223 SysBase
->AttnResched
|=0x80;
226 /* Force a reschedule. */
233 ReturnPtr ("NewAddTask", struct Task
*, task
);