rom/exec: Added some debug output.
[AROS.git] / rom / exec / exec_util.c
blob08422c301ceaa72bf2950e4c921b7b1a646f58a0
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Exec utility functions.
6 Lang: english
7 */
9 #define DEBUG 0
10 #include <aros/debug.h>
11 #include <exec/lists.h>
12 #include <exec/tasks.h>
13 #include <exec/memory.h>
14 #include <exec/execbase.h>
15 #include <dos/dosextens.h>
17 #include <proto/exec.h>
19 #include "etask.h"
20 #include "exec_intern.h"
21 #include "exec_util.h"
22 #include "taskstorage.h"
24 /*****************************************************************************
26 NAME */
27 #include "exec_util.h"
29 struct ETask * Exec_FindChild(
31 /* SYNOPSIS */
32 ULONG id,
33 struct ExecBase *SysBase)
35 /* FUNCTION
36 Scan through the current tasks children list searching for the task
37 whose et_UniqueID field matches.
39 INPUTS
40 id - The task ID to match.
42 RESULT
43 Address of the ETask structure that matches, or
44 NULL otherwise.
46 NOTES
48 EXAMPLE
50 BUGS
52 SEE ALSO
54 INTERNALS
56 ******************************************************************************/
58 struct ETask *et;
59 struct ETask *thisET;
61 thisET = GetETask(FindTask(NULL));
62 if (thisET != NULL)
64 ForeachNode (&thisET->et_Children, et)
66 if (et->et_UniqueID == id)
67 return et;
69 ForeachNode(&thisET->et_TaskMsgPort.mp_MsgList, et)
71 if (et->et_UniqueID == id)
72 return et;
75 return NULL;
78 void
79 Exec_InitETask(struct Task *task, struct ExecBase *SysBase)
81 struct Task *thistask = FindTask(NULL);
83 * We don't add this to the task memory, it isn't free'd by
84 * RemTask(), rather by somebody else calling ChildFree().
85 * Alternatively, an orphaned task will free its own ETask.
87 IPTR *ts = AllocMem(PrivExecBase(SysBase)->TaskStorageSize, MEMF_PUBLIC|MEMF_CLEAR);
88 D(bug("[TSS] Create new TS=%x for task=%x with size %d\n",
89 ts, task, PrivExecBase(SysBase)->TaskStorageSize
90 ));
92 /* IntETask is embedded in TaskStorage */
93 struct ETask *et = (struct ETask *)ts;
94 task->tc_UnionETask.tc_TaskStorage = ts;
95 if (!ts)
96 return;
97 task->tc_Flags |= TF_ETASK;
99 ts[__TS_FIRSTSLOT] = (IPTR)PrivExecBase(SysBase)->TaskStorageSize;
100 if (thistask != NULL)
102 /* Clone TaskStorage */
103 CopyMem(&thistask->tc_UnionETask.tc_TaskStorage[__TS_FIRSTSLOT+1],
104 &task->tc_UnionETask.tc_TaskStorage[__TS_FIRSTSLOT+1],
105 ((ULONG)thistask->tc_UnionETask.tc_TaskStorage[__TS_FIRSTSLOT])-(__TS_FIRSTSLOT+1)*sizeof(IPTR)
108 et->et_Parent = thistask;
109 NEWLIST(&et->et_Children);
111 /* Initialise the message list */
112 InitMsgPort(&et->et_TaskMsgPort);
113 et->et_TaskMsgPort.mp_SigTask = task;
114 et->et_TaskMsgPort.mp_SigBit = SIGB_CHILD;
116 /* Initialise the trap fields */
117 et->et_TrapAlloc = SysBase->TaskTrapAlloc;
118 et->et_TrapAble = 0;
120 #ifdef DEBUG_ETASK
122 int len = strlen(task->tc_Node.ln_Name) + 1;
123 IntETask(et)->iet_Me = AllocVec(len, MEMF_CLEAR|MEMF_PUBLIC);
124 if (IntETask(et)->iet_Me != NULL)
125 CopyMem(task->tc_Node.ln_Name, IntETask(et)->iet_Me, len);
127 #endif
129 /* Get an unique identifier for this task */
130 Forbid();
131 while(et->et_UniqueID == 0)
134 * Add some fuzz on wrapping. Its likely that the early numbers
135 * where taken by somebody else.
137 if(++SysBase->ex_TaskID == 0)
138 SysBase->ex_TaskID = 1024;
140 Disable();
141 if (FindTaskByPID(SysBase->ex_TaskID) == NULL)
142 et->et_UniqueID = SysBase->ex_TaskID;
143 Enable();
145 Permit();
147 /* Finally if the parent task is an ETask, add myself as its child */
148 if(et->et_Parent && ((struct Task*) et->et_Parent)->tc_Flags & TF_ETASK)
150 Forbid();
151 ADDHEAD(&GetETask(et->et_Parent)->et_Children, et);
152 Permit();
156 void
157 Exec_CleanupETask(struct Task *task, struct ExecBase *SysBase)
159 struct ETask *et = NULL, *child, *nextchild, *parent;
160 struct Node *tmpNode;
161 BOOL expunge = TRUE;
163 if(task->tc_Flags & TF_ETASK)
164 et = task->tc_UnionETask.tc_ETask;
165 if(!et)
166 return;
168 D(bug("CleanupETask: task=%x, et=%x\n", task, et));
170 Forbid();
172 /* Clean up after all the children that the task didn't do itself. */
173 ForeachNodeSafe(&et->et_TaskMsgPort.mp_MsgList, child, tmpNode)
175 ExpungeETask(child);
178 /* If we have an ETask parent, tell it we have exited. */
179 if(et->et_Parent != NULL)
181 parent = GetETask(et->et_Parent);
183 /* Link children to our parent. */
184 ForeachNodeSafe(&et->et_Children, child, nextchild)
186 child->et_Parent = et->et_Parent;
187 //Forbid();
188 ADDTAIL(&parent->et_Children, child);
189 //Permit();
192 /* Notify parent only if child was created with NP_NotifyOnDeath set
193 to TRUE */
194 if(parent != NULL)
196 REMOVE(et);
199 (((struct Task *)task)->tc_Node.ln_Type == NT_PROCESS) &&
200 (((struct Process*) task)->pr_Flags & PRF_NOTIFYONDEATH)
203 PutMsg(&parent->et_TaskMsgPort, (struct Message *)et);
204 expunge = FALSE;
208 else
210 /* Orphan all our remaining children. */
211 ForeachNode(&et->et_Children, child)
212 child->et_Parent = NULL;
215 if(expunge)
216 ExpungeETask(et);
218 Permit();
221 void
222 Exec_ExpungeETask(struct ETask *et, struct ExecBase *SysBase)
224 IPTR *ts = (IPTR *)et;
226 if(et->et_Result2)
227 FreeVec(et->et_Result2);
229 #ifdef DEBUG_ETASK
230 FreeVec(IntETask(et)->iet_Me);
231 #endif
232 D(bug("Exec_ExpungeETask: Freeing ts=%x, size=%d\n",
233 ts, (ULONG)ts[__TS_FIRSTSLOT]
235 FreeMem(ts, (ULONG)ts[__TS_FIRSTSLOT]);
238 static inline void FixList(struct List *from, struct List *to)
241 * This sequence is incomplete. It is valid only after the whole structure has been copied.
242 * !!! DO NOT remove the second line !!!
243 * If the list is empty, the first line actually modifies from->lh_TailPred, so that
244 * to->lh_TailPred gets correct value !
246 to->lh_Head->ln_Pred = (struct Node *)&to->lh_Head;
247 to->lh_TailPred = from->lh_TailPred;
248 to->lh_TailPred->ln_Succ = (struct Node *)&to->lh_Tail;
251 BOOL Exec_ExpandTS(struct Task *task, struct ExecBase *SysBase)
253 struct Task *me = FindTask(NULL);
254 ULONG oldsize = task->tc_UnionETask.tc_TaskStorage[__TS_FIRSTSLOT];
255 struct ETask *et_old = task->tc_UnionETask.tc_ETask;
256 struct ETask *et_new;
258 D(bug("[TSS] Increasing storage (%d to %d) for task 0x%p (%s)\n", oldsize, PrivExecBase(SysBase)->TaskStorageSize, task, task->tc_Node.ln_Name));
260 /* Allocate new storage */
261 et_new = AllocMem(PrivExecBase(SysBase)->TaskStorageSize, MEMF_PUBLIC|MEMF_CLEAR);
262 if (!et_new)
263 return FALSE;
265 if (task == me)
268 * If we are updating ourselves, we need to disable task switching.
269 * Otherwise our ETask can become inconsistent (data in old ETask will
270 * be modified in the middle of copying).
272 Forbid();
275 /* This copies most of data. */
276 CopyMemQuick(et_old, et_new, oldsize);
278 /* ETask includes lists, and we need to fix up pointers in them now */
279 FixList((struct List *)&et_old->et_Children, (struct List *)&et_new->et_Children);
280 FixList(&et_old->et_TaskMsgPort.mp_MsgList, &et_new->et_TaskMsgPort.mp_MsgList);
282 /* Set new TSS size, and install new ETask */
283 ((IPTR *)et_new)[__TS_FIRSTSLOT] = PrivExecBase(SysBase)->TaskStorageSize;
284 task->tc_UnionETask.tc_ETask = et_new;
286 if (task == me)
288 /* All done, enable multitask again */
289 Permit();
292 FreeMem(et_old, oldsize);
293 return TRUE;
296 BOOL Exec_CheckTask(struct Task *task, struct ExecBase *SysBase)
298 struct Task *t;
300 if (!task)
301 return FALSE;
303 Forbid();
305 if (task == SysBase->ThisTask)
307 Permit();
308 return TRUE;
311 ForeachNode(&SysBase->TaskReady, t)
313 if (task == t)
315 Permit();
316 return TRUE;
320 ForeachNode(&SysBase->TaskWait, t)
322 if (task == t)
324 Permit();
325 return TRUE;
329 Permit();
330 return FALSE;