revert between 56095 -> 55830 in arch
[AROS.git] / rom / exec / exec_util.c
blobe643f58033ae230221ba9c7bbc8b1768b65888d8
1 /*
2 Copyright © 1995-2017, 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>
12 #include <exec/lists.h>
13 #include <exec/tasks.h>
14 #include <exec/memory.h>
15 #include <exec/execbase.h>
16 #include <dos/dosextens.h>
18 #include <proto/exec.h>
20 #include "etask.h"
21 #include "exec_intern.h"
22 #include "exec_util.h"
23 #include "taskstorage.h"
25 /****************************************************************************
27 NAME */
28 #include "exec_util.h"
30 struct ETask * Exec_FindChild(
32 /* SYNOPSIS */
33 ULONG id,
34 struct ExecBase *SysBase)
36 /* FUNCTION
37 Scan through the current tasks children list searching for the task
38 whose et_UniqueID field matches.
40 INPUTS
41 id - The task ID to match.
43 RESULT
44 Address of the ETask structure that matches, or
45 NULL otherwise.
47 NOTES
48 This is an internal exec.library function not exported from the
49 library.
51 EXAMPLE
53 BUGS
55 SEE ALSO
57 INTERNALS
59 ******************************************************************************/
61 struct Task *ThisTask = GET_THIS_TASK;
62 struct ETask *et, *retVal = NULL;
63 struct ETask *thisET;
65 thisET = GetETask(ThisTask);
66 if (thisET != NULL)
68 #if defined(__AROSEXEC_SMP__)
69 EXEC_SPINLOCK_LOCK(&IntETask(thisET)->iet_TaskLock, NULL, SPINLOCK_MODE_READ);
70 #endif
71 ForeachNode (&thisET->et_Children, et)
73 if (et->et_UniqueID == id)
75 retVal = et;
76 break;
79 #if defined(__AROSEXEC_SMP__)
80 EXEC_SPINLOCK_UNLOCK(&IntETask(thisET)->iet_TaskLock);
81 #endif
82 if (!retVal)
84 #if defined(__AROSEXEC_SMP__)
85 EXEC_SPINLOCK_LOCK(&thisET->et_TaskMsgPort.mp_SpinLock, NULL, SPINLOCK_MODE_READ);
86 #endif
87 ForeachNode(&thisET->et_TaskMsgPort.mp_MsgList, et)
89 if (et->et_UniqueID == id)
91 retVal = et;
92 break;
95 #if defined(__AROSEXEC_SMP__)
96 EXEC_SPINLOCK_UNLOCK(&thisET->et_TaskMsgPort.mp_SpinLock);
97 #endif
100 return retVal;
103 BOOL
104 Exec_InitETask(struct Task *task, struct Task *parent, struct ExecBase *SysBase)
107 * We don't add this to the task memory, it isn't free'd by
108 * RemTask(), rather by somebody else calling ChildFree().
109 * Alternatively, an orphaned task will free its own ETask.
111 #if defined(__AROSEXEC_SMP__)
112 int cpunum;
113 #endif
114 struct ETask *et =
115 AllocMem(sizeof(struct IntETask), MEMF_PUBLIC | MEMF_CLEAR);
118 bug("[EXEC:ETask] Init: Allocated ETask for Task '%s' @ %p\n",
119 task->tc_Node.ln_Name, task);
120 bug("[EXEC:ETask] Init: ETask @ 0x%p, %d bytes\n",
121 et, sizeof(struct IntETask));
124 task->tc_UnionETask.tc_ETask = et;
125 if (!et)
126 return FALSE;
127 task->tc_Flags |= TF_ETASK;
129 #if defined(__AROSEXEC_SMP__)
130 cpunum = KrnGetCPUNumber();
131 EXEC_SPINLOCK_INIT(&IntETask(et)->iet_TaskLock);
132 if (PrivExecBase(SysBase)->IntFlags & EXECF_CPUAffinity)
134 IntETask(et)->iet_CpuAffinity = KrnAllocCPUMask();
135 KrnGetCPUMask(cpunum, IntETask(et)->iet_CpuAffinity);
137 D(bug("[EXEC:ETask] Init: CPU #%d, mask %08x\n", cpunum, IntETask(et)->iet_CpuAffinity);)
139 #endif
141 et->et_Parent = parent;
142 NEWLIST(&et->et_Children);
144 D(bug("[EXEC:ETask] Init: Parent @ 0x%p\n", et->et_Parent);)
146 /* Initialise the message list */
147 InitMsgPort(&et->et_TaskMsgPort);
148 et->et_TaskMsgPort.mp_SigTask = task;
149 et->et_TaskMsgPort.mp_SigBit = SIGB_CHILD;
151 /* Initialise the trap fields */
152 et->et_TrapAlloc = SysBase->TaskTrapAlloc;
153 et->et_TrapAble = 0;
155 #ifdef DEBUG_ETASK
157 int len = strlen(task->tc_Node.ln_Name) + 1;
158 IntETask(et)->iet_Me = AllocVec(len, MEMF_CLEAR|MEMF_PUBLIC);
159 if (IntETask(et)->iet_Me != NULL)
160 CopyMem(task->tc_Node.ln_Name, IntETask(et)->iet_Me, len);
162 #endif
164 D(bug("[EXEC:ETask] Init: Generating Unique ID...\n");)
166 /* Get a unique identifier for this task */
167 Forbid();
168 while(et->et_UniqueID == 0)
170 //TODO: Replace with UUID!
173 * Add some fuzz on wrapping. It's likely that the early numbers
174 * where taken by somebody else.
176 if(++SysBase->ex_TaskID == 0)
177 SysBase->ex_TaskID = 1024;
179 Disable();
180 D(bug("[EXEC:ETask] Init: Checking for existing ID...\n");)
181 if (FindTaskByPID(SysBase->ex_TaskID) == NULL)
182 et->et_UniqueID = SysBase->ex_TaskID;
183 D(bug("[EXEC:ETask] Init: done\n");)
184 Enable();
187 D(bug("[EXEC:ETask] Init: Task ID : %08x\n", et->et_UniqueID);)
189 /* Finally if the parent task is an ETask, add myself as its child */
190 if(et->et_Parent && ((struct Task*) et->et_Parent)->tc_Flags & TF_ETASK)
192 struct ETask * parentEtask = GetETask(et->et_Parent);
193 D(bug("[EXEC:ETask] Init: Registering with Parent ETask\n");)
194 #if defined(__AROSEXEC_SMP__)
195 EXEC_SPINLOCK_LOCK(&IntETask(parentEtask)->iet_TaskLock, NULL, SPINLOCK_MODE_WRITE);
196 #endif
197 ADDHEAD(&parentEtask->et_Children, et);
198 #if defined(__AROSEXEC_SMP__)
199 EXEC_SPINLOCK_UNLOCK(&IntETask(parentEtask)->iet_TaskLock);
200 #endif
202 Permit();
204 D(bug("[EXEC:ETask] Init: Initialized\n");)
206 return TRUE;
209 void
210 Exec_CleanupETask(struct Task *task, struct ExecBase *SysBase)
212 struct ETask *et, *child, *nextchild, *parent;
213 struct Node *tmpNode;
214 BOOL expunge = TRUE;
216 if(!(task->tc_Flags & TF_ETASK) ||
217 ((et = task->tc_UnionETask.tc_ETask) == NULL))
218 return;
220 D(bug("[EXEC:ETask] Cleanup: Task @ 0x%p, ETask @ 0x%p\n", task, et);)
222 Forbid();
224 #if defined(__AROSEXEC_SMP__)
225 if ((PrivExecBase(SysBase)->IntFlags & EXECF_CPUAffinity) && (IntETask(et)->iet_CpuAffinity))
227 if ((IPTR)IntETask(et)->iet_CpuAffinity != TASKAFFINITY_ANY)
228 KrnFreeCPUMask(IntETask(et)->iet_CpuAffinity);
230 #endif
232 #if defined(__AROSEXEC_SMP__)
233 EXEC_SPINLOCK_LOCK(&et->et_TaskMsgPort.mp_SpinLock, NULL, SPINLOCK_MODE_WRITE);
234 #endif
235 /* Clean up after all the children that the task didn't do itself. */
236 ForeachNodeSafe(&et->et_TaskMsgPort.mp_MsgList, child, tmpNode)
238 ExpungeETask(child);
240 #if defined(__AROSEXEC_SMP__)
241 EXEC_SPINLOCK_UNLOCK(&et->et_TaskMsgPort.mp_SpinLock);
242 #endif
243 /* If we have an ETask parent, tell it we have exited. */
244 if(et->et_Parent != NULL)
246 parent = GetETask(et->et_Parent);
248 #if defined(__AROSEXEC_SMP__)
249 EXEC_SPINLOCK_LOCK(&IntETask(et)->iet_TaskLock, NULL, SPINLOCK_MODE_WRITE);
250 #endif
251 /* Link children to our parent. */
252 ForeachNodeSafe(&et->et_Children, child, nextchild)
254 child->et_Parent = et->et_Parent;
255 //Forbid();
256 if (parent)
258 #if defined(__AROSEXEC_SMP__)
259 EXEC_SPINLOCK_LOCK(&IntETask(parent)->iet_TaskLock, NULL, SPINLOCK_MODE_WRITE);
260 #endif
261 ADDTAIL(&parent->et_Children, child);
262 #if defined(__AROSEXEC_SMP__)
263 EXEC_SPINLOCK_UNLOCK(&IntETask(parent)->iet_TaskLock);
264 #endif
266 //Permit();
268 #if defined(__AROSEXEC_SMP__)
269 EXEC_SPINLOCK_UNLOCK(&IntETask(et)->iet_TaskLock);
270 #endif
272 /* Notify parent only if child was created with NP_NotifyOnDeath set
273 to TRUE */
274 if(parent != NULL)
276 #if defined(__AROSEXEC_SMP__)
277 EXEC_SPINLOCK_LOCK(&IntETask(parent)->iet_TaskLock, NULL, SPINLOCK_MODE_WRITE);
278 #endif
279 REMOVE(et);
280 #if defined(__AROSEXEC_SMP__)
281 EXEC_SPINLOCK_UNLOCK(&IntETask(parent)->iet_TaskLock);
282 #endif
284 (((struct Task *)task)->tc_Node.ln_Type == NT_PROCESS) &&
285 (((struct Process*) task)->pr_Flags & PRF_NOTIFYONDEATH)
288 PutMsg(&parent->et_TaskMsgPort, (struct Message *)et);
289 expunge = FALSE;
293 else
295 #if defined(__AROSEXEC_SMP__)
296 EXEC_SPINLOCK_LOCK(&IntETask(et)->iet_TaskLock, NULL, SPINLOCK_MODE_WRITE);
297 #endif
298 /* Orphan all our remaining children. */
299 ForeachNode(&et->et_Children, child)
300 child->et_Parent = NULL;
301 #if defined(__AROSEXEC_SMP__)
302 EXEC_SPINLOCK_UNLOCK(&IntETask(et)->iet_TaskLock);
303 #endif
306 if(expunge)
307 ExpungeETask(et);
309 Permit();
312 void
313 Exec_ExpungeETask(struct ETask *et, struct ExecBase *SysBase)
315 IPTR *ts = et->et_TaskStorage;
317 FreeVec(et->et_Result2);
319 #ifdef DEBUG_ETASK
320 FreeVec(IntETask(et)->iet_Me);
321 #endif
322 D(bug("[EXEC:ETask] Expunge: Freeing ETask @ 0x%p, TS @ 0x%p, size=%d\n",
323 et, ts, ts ? (ULONG)ts[__TS_FIRSTSLOT] : 0
325 FreeMem(et, sizeof(struct IntETask));
326 if (ts)
327 FreeMem(ts, ts[__TS_FIRSTSLOT] * sizeof(ts[0]));
330 BOOL Exec_CheckTask(struct Task *task, struct ExecBase *SysBase)
332 struct Task *t;
334 if (!task)
335 return FALSE;
337 Forbid();
338 #if defined(__AROSEXEC_SMP__)
339 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase)->TaskRunningSpinLock, NULL, SPINLOCK_MODE_READ);
340 ForeachNode(&PrivExecBase(SysBase)->TaskRunning, t)
342 if (task == t)
344 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskRunningSpinLock);
345 Permit();
346 return TRUE;
349 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskRunningSpinLock);
350 Permit();
351 Forbid();
352 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase)->TaskSpinningLock, NULL, SPINLOCK_MODE_READ);
353 ForeachNode(&PrivExecBase(SysBase)->TaskSpinning, t)
355 if (task == t)
357 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskSpinningLock);
358 Permit();
359 return TRUE;
362 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskSpinningLock);
363 Permit();
364 Forbid();
365 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase)->TaskReadySpinLock, NULL, SPINLOCK_MODE_READ);
366 #else
367 if (task == GET_THIS_TASK)
369 Permit();
370 return TRUE;
372 #endif
374 ForeachNode(&SysBase->TaskReady, t)
376 if (task == t)
378 #if defined(__AROSEXEC_SMP__)
379 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskReadySpinLock);
380 #endif
381 Permit();
382 return TRUE;
385 #if defined(__AROSEXEC_SMP__)
386 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskReadySpinLock);
387 Permit();
388 Forbid();
389 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase)->TaskWaitSpinLock, NULL, SPINLOCK_MODE_READ);
390 #endif
391 ForeachNode(&SysBase->TaskWait, t)
393 if (task == t)
395 #if defined(__AROSEXEC_SMP__)
396 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskWaitSpinLock);
397 #endif
398 Permit();
399 return TRUE;
402 #if defined(__AROSEXEC_SMP__)
403 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase)->TaskWaitSpinLock);
404 #endif
405 Permit();
407 return FALSE;