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"
20 /*****************************************************************************
24 AROS_LH4(APTR
, NewAddTask
,
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
),
33 struct ExecBase
*, SysBase
, 176, Exec
)
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
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.
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.
53 The address of the new task or NULL if the operation failed (can only
54 happen with TF_ETASK set - currenty not implemented).
57 This function is private. Use MorphOS-compatible NewCreateTaskA()
71 ******************************************************************************/
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
;
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
),
136 if (!task
->tc_UnionETask
.tc_ETask
)
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
;
146 task
->tc_SPReg
= (UBYTE
*)(task
->tc_SPLower
) - SP_OFFSET
;
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));
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;
166 startfill
= ((UBYTE
*)task
->tc_SPReg
) + 16;
167 endfill
= ((UBYTE
*)task
->tc_SPUpper
) - 1; /* FIXME: -1 correct ?? */
170 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
);
187 /* Set the task flags for switch and launch. */
189 task
->tc_Flags
|=TF_SWITCH
;
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
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
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 */
223 DADDTASK("Added task 0x%p", task
);