Include CPU number in debug output
[aros:aros.git] / AROS / rom / exec / newaddtask.c
1 /*
2     Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3     $Id$
4
5     Desc: Add a task.
6     Lang: english
7 */
8
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>
15
16 #include "etask.h"
17 #include "exec_util.h"
18 #include "exec_debug.h"
19 #include "taskstorage.h"
20
21 /*****************************************************************************
22
23     NAME */
24
25         AROS_LH4(APTR, NewAddTask,
26
27 /*  SYNOPSIS */
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),
32
33 /*  LOCATION */
34         struct ExecBase *, SysBase, 176, Exec)
35
36 /*  FUNCTION
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
39         immediately.
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.
46
47     INPUTS
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.
52
53     RESULT
54         The address of the new task or NULL if the operation failed (can only
55         happen with TF_ETASK set - currenty not implemented).
56
57     NOTES
58         This function is private. Use MorphOS-compatible NewCreateTaskA()
59         in your applications.
60
61     EXAMPLE
62
63     BUGS
64
65     SEE ALSO
66         RemTask()
67
68     INTERNALS
69
70     HISTORY
71
72 ******************************************************************************/
73 {
74     AROS_LIBFUNC_INIT
75
76     ASSERT_VALID_PTR(task);
77
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";
81
82     DADDTASK("NewAddTask (0x%p (\"%s\"), 0x%p, 0x%p)", task, task->tc_Node.ln_Name, initialPC, finalPC);
83
84     /* Initialize the memory entry list if the caller forgot */
85     if (!task->tc_MemEntry.lh_Head)
86         NEWLIST(&task->tc_MemEntry);
87
88     DADDTASK("NewAddTask MemEntry head: 0x%p", GetHead(&task->tc_MemEntry.lh_Head));
89
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;
93
94     /* This is moved into SysBase at the tasks's startup */
95     task->tc_IDNestCnt=-1;
96     task->tc_TDNestCnt=-1;
97
98     task->tc_State = TS_ADDED;
99     task->tc_Flags = 0;
100     
101     task->tc_SigWait = 0;
102     task->tc_SigRecvd = 0;
103     task->tc_SigExcept = 0;
104         
105     /* Signals default to all system signals allocated. */
106     if(task->tc_SigAlloc==0)
107         task->tc_SigAlloc=SysBase->TaskSigAlloc;
108
109     /* Currently only used for segmentation violation */
110     if(task->tc_TrapCode==NULL)
111         task->tc_TrapCode=SysBase->TaskTrapCode;
112
113     if(task->tc_ExceptCode==NULL)
114         task->tc_ExceptCode=SysBase->TaskExceptCode;
115         
116     /*
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.
120      */
121     if (PrivExecBase(SysBase)->IntFlags & EXECF_StackSnoop)
122         task->tc_Flags |= TF_STACKCHK;
123
124     /* Initialize ETask */
125     if (!InitETask(task))
126         return NULL;
127
128     /* Get new stackpointer. */
129     if (task->tc_SPReg==NULL)
130         task->tc_SPReg = (UBYTE *)(task->tc_SPUpper) - SP_OFFSET;
131
132 #ifdef AROS_STACKALIGN
133     if ((IPTR)task->tc_SPReg & (AROS_STACKALIGN - 1))
134     {
135         DADDTASK("NewAddTask with unaligned stack pointer (0x%p)! Fixing...", task->tc_SPReg);
136         task->tc_SPReg = (APTR)((IPTR)task->tc_SPReg & ~(AROS_STACKALIGN - 1));
137     }
138 #endif
139     DADDTASK("NewAddTask: SPLower: 0x%p SPUpper: 0x%p SP: 0x%p", task->tc_SPLower, task->tc_SPUpper, task->tc_SPReg);
140
141     if (task->tc_Flags & TF_STACKCHK)
142     {
143         UBYTE *startfill, *endfill;
144
145         startfill = (UBYTE *)task->tc_SPLower;
146         endfill   = ((UBYTE *)task->tc_SPReg) - 16;
147
148         while(startfill <= endfill)
149         {
150             *startfill++ = 0xE1;
151         }
152     }
153
154     /* Default finalizer? */
155     if(finalPC==NULL)
156         finalPC=SysBase->TaskExitCode;
157
158     /* Init new context. */
159     if (!PrepareContext(task, initialPC, finalPC, tagList, SysBase))
160     {
161         CleanupETask(task);
162         return NULL;
163     }
164
165     /* Set the task flags for switch and launch. */
166     if(task->tc_Switch)
167         task->tc_Flags|=TF_SWITCH;
168
169     if(task->tc_Launch)
170         task->tc_Flags|=TF_LAUNCH;
171
172     /*
173         Protect the task lists. This must be done with Disable() because
174         of Signal() which is usable from interrupts and may change those
175         lists.
176      */
177     Disable();
178
179     /* Add the new task to the ready list. */
180     task->tc_State=TS_READY;
181     Enqueue(&GetESysCPU(task)->TaskReady,&task->tc_Node);
182
183     /*
184         Determine if a task switch is necessary. (If the new task has a
185         higher priority than the current one and the current one
186         is still active.) If the current task isn't of type TS_RUN it
187         is already gone.
188     */
189
190     if (task->tc_Node.ln_Pri > GetESysCPU(task)->ThisTask->tc_Node.ln_Pri &&
191        GetESysCPU(task)->ThisTask->tc_State == TS_RUN)
192     {
193         D(bug("[AddTask] Rescheduling...\n"));
194
195         /* Reschedule() will take care about disabled task switching automatically */
196         Reschedule();
197     }
198
199     Enable();
200
201     DADDTASK("Added task 0x%p on CPU%d", task, GetESysCPU(task)->ec_CPUNumber);
202     return task;
203
204     AROS_LIBFUNC_EXIT
205 } /* NewAddTask */