2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
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>
17 #include "exec_util.h"
18 #include "exec_debug.h"
19 #include "taskstorage.h"
21 /*****************************************************************************
25 AROS_LH4(APTR
, NewAddTask
,
28 AROS_LHA(struct Task
*, task
, A1
),
29 AROS_LHA(APTR
, initialPC
, A2
),
30 AROS_LHA(APTR
, finalPC
, A3
),
31 AROS_LHA(struct TagItem
*, tagList
, A4
),
34 struct ExecBase
*, SysBase
, 176, Exec
)
37 Add a new task to the system. If the new task has the highest
38 priority of all and task switches are allowed it will be started
40 Certain task fields should be intitialized and a stack must be
41 allocated before calling this function. tc_SPReg will be used as the
42 starting location for the stack pointer, i.e. a part of the stack can
43 be reserved to pass the task some initial arguments.
44 Memory can be added to the tc_MemEntry list and will be freed when the
45 task dies. The new task's registers are set to 0.
48 task - Pointer to task structure.
49 initialPC - Entry point for the new task.
50 finalPC - Routine that is called if the initialPC() function returns.
51 A NULL pointer installs the default finalizer.
54 The address of the new task or NULL if the operation failed (can only
55 happen with TF_ETASK set - currenty not implemented).
58 This function is private. Use MorphOS-compatible NewCreateTaskA()
72 ******************************************************************************/
76 ASSERT_VALID_PTR(task
);
78 /* Sigh - you should provide a name for your task. */
79 if(task
->tc_Node
.ln_Name
==NULL
)
80 task
->tc_Node
.ln_Name
="unknown task";
82 DADDTASK("NewAddTask (0x%p (\"%s\"), 0x%p, 0x%p)", task
, task
->tc_Node
.ln_Name
, initialPC
, finalPC
);
84 /* Initialize the memory entry list if the caller forgot */
85 if (!task
->tc_MemEntry
.lh_Head
)
86 NEWLIST(&task
->tc_MemEntry
);
88 DADDTASK("NewAddTask MemEntry head: 0x%p", GetHead(&task
->tc_MemEntry
.lh_Head
));
90 /* Set node type to NT_TASK if not set to something else. */
91 if(!task
->tc_Node
.ln_Type
)
92 task
->tc_Node
.ln_Type
=NT_TASK
;
94 /* This is moved into SysBase at the tasks's startup */
95 task
->tc_IDNestCnt
=-1;
96 task
->tc_TDNestCnt
=-1;
98 task
->tc_State
= TS_ADDED
;
101 task
->tc_SigWait
= 0;
102 task
->tc_SigRecvd
= 0;
103 task
->tc_SigExcept
= 0;
105 /* Signals default to all system signals allocated. */
106 if(task
->tc_SigAlloc
==0)
107 task
->tc_SigAlloc
=SysBase
->TaskSigAlloc
;
109 /* Currently only used for segmentation violation */
110 if(task
->tc_TrapCode
==NULL
)
111 task
->tc_TrapCode
=SysBase
->TaskTrapCode
;
113 if(task
->tc_ExceptCode
==NULL
)
114 task
->tc_ExceptCode
=SysBase
->TaskExceptCode
;
117 * EXECF_StackSnoop can be set or reset at runtime.
118 * However task's stack is either snooped or not, it's problematic
119 * to turn it on at runtime. So we initialize it when the task starts up.
121 if (PrivExecBase(SysBase
)->IntFlags
& EXECF_StackSnoop
)
122 task
->tc_Flags
|= TF_STACKCHK
;
124 /* Initialize ETask */
126 if (!task
->tc_UnionETask
.tc_ETask
)
129 /* Get new stackpointer. */
130 if (task
->tc_SPReg
==NULL
)
131 task
->tc_SPReg
= (UBYTE
*)(task
->tc_SPUpper
) - SP_OFFSET
;
133 #ifdef AROS_STACKALIGN
134 if ((IPTR
)task
->tc_SPReg
& (AROS_STACKALIGN
- 1))
136 DADDTASK("NewAddTask with unaligned stack pointer (0x%p)! Fixing...", task
->tc_SPReg
);
137 task
->tc_SPReg
= (APTR
)((IPTR
)task
->tc_SPReg
& ~(AROS_STACKALIGN
- 1));
140 DADDTASK("NewAddTask: SPLower: 0x%p SPUpper: 0x%p SP: 0x%p", task
->tc_SPLower
, task
->tc_SPUpper
, task
->tc_SPReg
);
142 if (task
->tc_Flags
& TF_STACKCHK
)
144 UBYTE
*startfill
, *endfill
;
146 startfill
= (UBYTE
*)task
->tc_SPLower
;
147 endfill
= ((UBYTE
*)task
->tc_SPReg
) - 16;
149 while(startfill
<= endfill
)
155 /* Default finalizer? */
157 finalPC
=SysBase
->TaskExitCode
;
159 /* Init new context. */
160 if (!PrepareContext(task
, initialPC
, finalPC
, tagList
, SysBase
))
166 /* Set the task flags for switch and launch. */
168 task
->tc_Flags
|=TF_SWITCH
;
171 task
->tc_Flags
|=TF_LAUNCH
;
174 Protect the task lists. This must be done with Disable() because
175 of Signal() which is usable from interrupts and may change those
180 /* Add the new task to the ready list. */
181 task
->tc_State
=TS_READY
;
182 Enqueue(&SysBase
->TaskReady
,&task
->tc_Node
);
185 Determine if a task switch is necessary. (If the new task has a
186 higher priority than the current one and the current one
187 is still active.) If the current task isn't of type TS_RUN it
191 if (task
->tc_Node
.ln_Pri
> SysBase
->ThisTask
->tc_Node
.ln_Pri
&&
192 SysBase
->ThisTask
->tc_State
== TS_RUN
)
194 D(bug("[AddTask] Rescheduling...\n"));
196 /* Reschedule() will take care about disabled task switching automatically */
202 DADDTASK("Added task 0x%p", task
);