2 Copyright © 1995-2015, 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 #if defined(__AROSEXEC_SMP__)
22 #include <proto/kernel.h>
25 /*****************************************************************************
29 AROS_LH4(APTR
, NewAddTask
,
32 AROS_LHA(struct Task
*, task
, A1
),
33 AROS_LHA(APTR
, initialPC
, A2
),
34 AROS_LHA(APTR
, finalPC
, A3
),
35 AROS_LHA(struct TagItem
*, tagList
, A4
),
38 struct ExecBase
*, SysBase
, 176, Exec
)
41 Add a new task to the system. If the new task has the highest
42 priority of all and task switches are allowed it will be started
44 Certain task fields should be intitialized and a stack must be
45 allocated before calling this function. tc_SPReg will be used as the
46 starting location for the stack pointer, i.e. a part of the stack can
47 be reserved to pass the task some initial arguments.
48 Memory can be added to the tc_MemEntry list and will be freed when the
49 task dies. The new task's registers are set to 0.
52 task - Pointer to task structure.
53 initialPC - Entry point for the new task.
54 finalPC - Routine that is called if the initialPC() function returns.
55 A NULL pointer installs the default finalizer.
58 The address of the new task or NULL if the operation failed (can only
59 happen with TF_ETASK set - currenty not implemented).
62 This function is private. Use MorphOS-compatible NewCreateTaskA()
76 ******************************************************************************/
80 ASSERT_VALID_PTR(task
);
82 #if defined(__AROSEXEC_SMP__)
83 int cpunum
= KrnGetCPUNumber();
86 /* Sigh - you should provide a name for your task. */
87 if (task
->tc_Node
.ln_Name
== NULL
)
88 task
->tc_Node
.ln_Name
= "unknown task";
90 DADDTASK("NewAddTask (0x%p (\"%s\"), 0x%p, 0x%p)", task
, task
->tc_Node
.ln_Name
, initialPC
, finalPC
);
92 /* Initialize the memory entry list if the caller forgot */
93 if (!task
->tc_MemEntry
.lh_Head
)
94 NEWLIST(&task
->tc_MemEntry
);
96 DADDTASK("NewAddTask MemEntry head: 0x%p", GetHead(&task
->tc_MemEntry
.lh_Head
));
98 /* Set node type to NT_TASK if not set to something else. */
99 if (!task
->tc_Node
.ln_Type
)
100 task
->tc_Node
.ln_Type
= NT_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
;
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
;
117 /* Currently only used for segmentation violation */
118 if (task
->tc_TrapCode
== NULL
)
119 task
->tc_TrapCode
= SysBase
->TaskTrapCode
;
121 if (task
->tc_ExceptCode
== NULL
)
122 task
->tc_ExceptCode
= SysBase
->TaskExceptCode
;
125 * EXECF_StackSnoop can be set or reset at runtime.
126 * However task's stack is either snooped or not, it's problematic
127 * to turn it on at runtime. So we initialize it when the task starts up.
129 if (PrivExecBase(SysBase
)->IntFlags
& EXECF_StackSnoop
)
130 task
->tc_Flags
|= TF_STACKCHK
;
132 /* Initialize ETask */
133 if (!InitETask(task
))
136 /* Get new stackpointer. */
137 if (task
->tc_SPReg
== NULL
)
138 task
->tc_SPReg
= (UBYTE
*)(task
->tc_SPUpper
) - SP_OFFSET
;
140 #ifdef AROS_STACKALIGN
141 if ((IPTR
)task
->tc_SPReg
& (AROS_STACKALIGN
- 1))
143 DADDTASK("NewAddTask with unaligned stack pointer (0x%p)! Fixing...", task
->tc_SPReg
);
144 task
->tc_SPReg
= (APTR
)((IPTR
)task
->tc_SPReg
& ~(AROS_STACKALIGN
- 1));
147 DADDTASK("NewAddTask: SPLower: 0x%p SPUpper: 0x%p SP: 0x%p", task
->tc_SPLower
, task
->tc_SPUpper
, task
->tc_SPReg
);
149 if (task
->tc_Flags
& TF_STACKCHK
)
151 UBYTE
*startfill
, *endfill
;
153 startfill
= (UBYTE
*)task
->tc_SPLower
;
154 endfill
= ((UBYTE
*)task
->tc_SPReg
) - 16;
156 while (startfill
<= endfill
)
162 /* Default finalizer? */
164 finalPC
= SysBase
->TaskExitCode
;
166 /* Init new context. */
167 if (!PrepareContext(task
, initialPC
, finalPC
, tagList
, SysBase
))
173 /* Set the task flags for switch and launch. */
175 task
->tc_Flags
|=TF_SWITCH
;
178 task
->tc_Flags
|=TF_LAUNCH
;
181 Protect the task lists. This must be done with Disable() because
182 of Signal() which is usable from interrupts and may change those
186 #if defined(__AROSEXEC_SMP__)
187 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase
)->TaskReadySpinLock
, SPINLOCK_MODE_WRITE
);
191 /* Add the new task to the ready list. */
192 task
->tc_State
= TS_READY
;
193 Enqueue(&SysBase
->TaskReady
, &task
->tc_Node
);
194 #if defined(__AROSEXEC_SMP__)
195 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase
)->TaskReadySpinLock
);
199 Determine if a task switch is necessary. (If the new task has a
200 higher priority than the current one and the current one
201 is still active.) If the current task isn't of type TS_RUN it
206 #if defined(__AROSEXEC_SMP__)
207 ((IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
& KrnGetCPUMask(cpunum
)) == KrnGetCPUMask(cpunum
)) &&
209 task
->tc_Node
.ln_Pri
> GET_THIS_TASK
->tc_Node
.ln_Pri
&&
210 GET_THIS_TASK
->tc_State
== TS_RUN
)
212 D(bug("[AddTask] Rescheduling...\n");)
214 /* Reschedule() will take care about disabled task switching automatically */
217 #if defined(__AROSEXEC_SMP__)
220 bug("[Exec] AddTask:\n");
226 DADDTASK("Added task 0x%p", task
);