PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/tekui/src/exec/exec_doexec.c

http://github.com/luaforge/tekui
C | 1100 lines | 794 code | 186 blank | 120 comment | 117 complexity | 22f92d716af8b1370ff718b5747c761c MD5 | raw file
  1. /*
  2. ** $Id: exec_doexec.c,v 1.1 2008-06-30 12:34:17 tmueller Exp $
  3. ** teklib/src/exec/exec_doexec.c - Exec task contexts
  4. **
  5. ** Written by Timm S. Mueller <tmueller at neoscientists.org>
  6. ** See copyright notice in teklib/COPYRIGHT
  7. */
  8. #include <tek/debug.h>
  9. #include <tek/teklib.h>
  10. #include <tek/proto/io.h>
  11. #include "exec_mod.h"
  12. static void exec_requestmod(TEXECBASE *exec, struct TTask *taskmsg);
  13. static void exec_closemod(TEXECBASE *exec, struct TTask *taskmsg);
  14. static void exec_replymod(TEXECBASE *exec, struct TTask *taskmsg);
  15. static void exec_main(TEXECBASE *exec, struct TTask *task,
  16. struct TTagItem *tags);
  17. static void exec_ramlib(TEXECBASE *exec, struct TTask *task,
  18. struct TTagItem *tags);
  19. static void exec_loadmod(TEXECBASE *exec, struct TTask *task,
  20. struct TTask *taskmsg);
  21. static void exec_unloadmod(TEXECBASE *exec, struct TTask *task,
  22. struct TTask *taskmsg);
  23. static void exec_newtask(TEXECBASE *exec, struct TTask *taskmsg);
  24. static struct TTask *exec_createtask(TEXECBASE *exec, TTASKFUNC func,
  25. TINITFUNC initfunc, struct TTagItem *tags);
  26. static TTASKENTRY void exec_taskentryfunc(struct TTask *task);
  27. static void exec_childinit(TEXECBASE *exec);
  28. static void exec_childexit(TEXECBASE *exec);
  29. static void exec_lockatom(TEXECBASE *exec, struct TTask *msg);
  30. static void exec_unlockatom(TEXECBASE *exec, struct TTask *msg);
  31. /*****************************************************************************/
  32. /*
  33. ** success = TDoExec(exec, tags)
  34. ** entrypoint to exec internal services and initializations
  35. */
  36. EXPORT TBOOL
  37. exec_DoExec(TEXECBASE *exec, struct TTagItem *tags)
  38. {
  39. struct TTask *task = exec_FindTask(exec, TNULL);
  40. if (task == exec_FindTask(exec, (TSTRPTR) TTASKNAME_EXEC))
  41. {
  42. /* perform execbase context */
  43. exec_main(exec, task, tags);
  44. return TTRUE;
  45. }
  46. else if (task == exec_FindTask(exec, (TSTRPTR) TTASKNAME_RAMLIB))
  47. {
  48. /* perform ramlib context */
  49. exec_ramlib(exec, task, tags);
  50. return TTRUE;
  51. }
  52. else if (task == exec_FindTask(exec, (TSTRPTR) TTASKNAME_ENTRY))
  53. {
  54. /* place for initializations in entry context */
  55. return TTRUE;
  56. }
  57. return TFALSE;
  58. }
  59. /*****************************************************************************/
  60. /*
  61. ** Ramlib task - Module loading
  62. */
  63. static void
  64. exec_ramlib(TEXECBASE *exec, struct TTask *task, struct TTagItem *tags)
  65. {
  66. struct TMsgPort *port = &task->tsk_UserPort;
  67. TUINT waitsig = TTASK_SIG_ABORT | port->tmp_Signal;
  68. TUINT sig;
  69. struct TTask *taskmsg;
  70. TINT n = 0;
  71. for (;;)
  72. {
  73. sig = THALWait(exec->texb_HALBase, waitsig);
  74. if (sig & TTASK_SIG_ABORT) break;
  75. while ((taskmsg = exec_getmsg(exec, port)))
  76. {
  77. switch (taskmsg->tsk_ReqCode)
  78. {
  79. case TTREQ_LOADMOD:
  80. exec_loadmod(exec, task, taskmsg);
  81. break;
  82. case TTREQ_UNLOADMOD:
  83. exec_unloadmod(exec, task, taskmsg);
  84. break;
  85. case TTREQ_ADDMOD:
  86. TAddHead(&exec->texb_IntModList, (struct TNode *)
  87. taskmsg->tsk_Request.trq_AddRemMod.trm_ModInitNode);
  88. taskmsg->tsk_Request.trq_AddRemMod.trm_Result = TTRUE;
  89. exec_ReplyMsg(exec, taskmsg);
  90. break;
  91. case TTREQ_REMMOD:
  92. /* TODO: removal should only succeed if flags == 0 or
  93. flags == TMODF_INITIALIZED and nestcount == 0 */
  94. TRemove((struct TNode *)
  95. taskmsg->tsk_Request.trq_AddRemMod.trm_ModInitNode);
  96. taskmsg->tsk_Request.trq_AddRemMod.trm_Result = TTRUE;
  97. exec_ReplyMsg(exec, taskmsg);
  98. break;
  99. }
  100. }
  101. }
  102. while ((taskmsg = exec_getmsg(exec, port)))
  103. n++;
  104. if (n > 0)
  105. {
  106. TDBPRINTF(TDB_FAIL,("Module requests pending: %d\n", n));
  107. TDBFATAL();
  108. }
  109. }
  110. /*****************************************************************************/
  111. static void
  112. exec_loadmod(TEXECBASE *exec, struct TTask *task, struct TTask *taskmsg)
  113. {
  114. TAPTR halmod = TNULL;
  115. TAPTR hal = exec->texb_HALBase;
  116. union TTaskRequest *req = &taskmsg->tsk_Request;
  117. TSTRPTR modname = req->trq_Mod.trm_InitMod.tmd_Handle.thn_Name;
  118. TUINT nsize = 0, psize = 0;
  119. struct TInitModule *imod = TNULL;
  120. struct TNode *nnode, *node;
  121. /* try to open from list of internal modules: */
  122. node = exec->texb_IntModList.tlh_Head;
  123. for (; (nnode = node->tln_Succ); node = nnode)
  124. {
  125. struct TInitModule *im =
  126. ((struct TModInitNode *) node)->tmin_Modules;
  127. TSTRPTR tempn;
  128. for (; (tempn = im->tinm_Name); im++)
  129. {
  130. if (exec_StrEqual(exec, tempn, modname))
  131. {
  132. psize = (*im->tinm_InitFunc)(TNULL, TNULL,
  133. req->trq_Mod.trm_InitMod.tmd_Version, TNULL);
  134. if (psize)
  135. nsize = (*im->tinm_InitFunc)(TNULL, TNULL, 0xffff,
  136. TNULL);
  137. imod = im;
  138. break;
  139. }
  140. }
  141. }
  142. if (psize == 0)
  143. {
  144. /* try to load module via HAL interface: */
  145. halmod = THALLoadModule(hal, modname,
  146. req->trq_Mod.trm_InitMod.tmd_Version, &psize, &nsize);
  147. }
  148. if (psize)
  149. {
  150. TINT nlen;
  151. TSTRPTR s = modname;
  152. TINT8 *mmem;
  153. while (*s++);
  154. nlen = s - modname;
  155. mmem = exec_AllocMMU(exec, TNULL, psize + nsize + nlen);
  156. if (mmem)
  157. {
  158. TBOOL success = TFALSE;
  159. struct TModule *mod = (struct TModule *) (mmem + nsize);
  160. TSTRPTR d = (TSTRPTR) mmem + nsize + psize;
  161. exec_FillMem(exec, mmem, psize + nsize, 0);
  162. s = modname;
  163. /* insert and copy name: */
  164. mod->tmd_Handle.thn_Name = d;
  165. while ((*d++ = *s++));
  166. /* modsuper: */
  167. mod->tmd_Handle.thn_Hook.thk_Data = mod;
  168. mod->tmd_Handle.thn_Owner = (struct TModule *) exec;
  169. mod->tmd_ModSuper = mod;
  170. mod->tmd_InitTask = task;
  171. mod->tmd_HALMod = halmod;
  172. mod->tmd_PosSize = psize;
  173. mod->tmd_NegSize = nsize;
  174. mod->tmd_RefCount = 1;
  175. if (halmod)
  176. success = THALCallModule(hal, halmod, task, mod);
  177. else
  178. success = (*imod->tinm_InitFunc)(task, mod,
  179. req->trq_Mod.trm_InitMod.tmd_Version, TNULL);
  180. if (success)
  181. {
  182. if ((mod->tmd_Flags & TMODF_VECTORTABLE) &&
  183. nsize < sizeof(TMFPTR) * TMODV_NUMRESERVED)
  184. {
  185. TDBPRINTF(TDB_FAIL,
  186. ("Module %s hasn't reserved enough vectors\n",
  187. mod->tmd_Handle.thn_Name));
  188. TDBFATAL();
  189. }
  190. req->trq_Mod.trm_Module = mod;
  191. exec_ReplyMsg(exec, taskmsg);
  192. return;
  193. }
  194. exec_Free(exec, mmem);
  195. }
  196. if (halmod)
  197. THALUnloadModule(hal, halmod);
  198. }
  199. /* failed */
  200. exec_DropMsg(exec, taskmsg);
  201. }
  202. /*****************************************************************************/
  203. static void
  204. exec_unloadmod(TEXECBASE *exec, struct TTask *task, struct TTask *taskmsg)
  205. {
  206. TAPTR hal = exec->texb_HALBase;
  207. union TTaskRequest *req = &taskmsg->tsk_Request;
  208. struct TModule *mod = req->trq_Mod.trm_Module;
  209. TDBPRINTF(TDB_TRACE,("unload mod: %s\n", mod->tmd_Handle.thn_Name));
  210. /* invoke module destructor */
  211. TDESTROY(mod);
  212. /* unload */
  213. if (mod->tmd_HALMod)
  214. THALUnloadModule(hal, mod->tmd_HALMod);
  215. /* free */
  216. exec_Free(exec, (TINT8 *) mod - mod->tmd_NegSize);
  217. /* restore original replyport */
  218. TGETMSGPTR(taskmsg)->tmsg_RPort = req->trq_Mod.trm_RPort;
  219. /* return to caller */
  220. exec_returnmsg(exec, taskmsg, TMSG_STATUS_ACKD | TMSGF_QUEUED);
  221. }
  222. /*****************************************************************************/
  223. /*
  224. ** Exec task
  225. */
  226. static void
  227. exec_checkmodules(TEXECBASE *exec)
  228. {
  229. TINT n = 0;
  230. struct TNode *nnode, *node = exec->texb_ModList.tlh_Head;
  231. for (; (nnode = node->tln_Succ); node = nnode)
  232. {
  233. struct TModule *mod = (struct TModule *) node;
  234. if (mod == (TAPTR) exec || mod == exec->texb_HALBase)
  235. continue;
  236. TDBPRINTF(TDB_FAIL,
  237. ("Module not closed: %s\n", mod->tmd_Handle.thn_Name));
  238. n++;
  239. }
  240. if (n > 0)
  241. {
  242. TDBPRINTF(TDB_FAIL,("Applications must close all modules"));
  243. TDBFATAL();
  244. }
  245. }
  246. static void
  247. exec_main(TEXECBASE *exec, struct TTask *exectask, struct TTagItem *tags)
  248. {
  249. struct TMsgPort *execport = exec->texb_ExecPort;
  250. struct TMsgPort *modreply = exec->texb_ModReply;
  251. TUINT waitsig = TTASK_SIG_ABORT | execport->tmp_Signal |
  252. modreply->tmp_Signal | TTASK_SIG_CHILDINIT | TTASK_SIG_CHILDEXIT;
  253. TUINT sig;
  254. struct TTask *taskmsg;
  255. for (;;)
  256. {
  257. sig = THALWait(exec->texb_HALBase, waitsig);
  258. if (sig & TTASK_SIG_ABORT)
  259. break;
  260. if (sig & modreply->tmp_Signal)
  261. while ((taskmsg = exec_getmsg(exec, modreply)))
  262. exec_replymod(exec, taskmsg);
  263. if (sig & execport->tmp_Signal)
  264. {
  265. while ((taskmsg = exec_getmsg(exec, execport)))
  266. {
  267. switch (taskmsg->tsk_ReqCode)
  268. {
  269. case TTREQ_OPENMOD:
  270. exec_requestmod(exec, taskmsg);
  271. break;
  272. case TTREQ_CLOSEMOD:
  273. exec_closemod(exec, taskmsg);
  274. break;
  275. case TTREQ_CREATETASK:
  276. exec_newtask(exec, taskmsg);
  277. break;
  278. case TTREQ_DESTROYTASK:
  279. {
  280. /* insert backptr to self */
  281. taskmsg->tsk_Request.trq_Task.trt_Parent = taskmsg;
  282. /* add request to taskexitlist */
  283. TAddTail(&exec->texb_TaskExitList,
  284. (struct TNode *) &taskmsg->tsk_Request);
  285. /* force list processing */
  286. sig |= TTASK_SIG_CHILDEXIT;
  287. break;
  288. }
  289. case TTREQ_LOCKATOM:
  290. exec_lockatom(exec, taskmsg);
  291. break;
  292. case TTREQ_UNLOCKATOM:
  293. exec_unlockatom(exec, taskmsg);
  294. break;
  295. }
  296. }
  297. }
  298. if (sig & TTASK_SIG_CHILDINIT)
  299. exec_childinit(exec);
  300. if (sig & TTASK_SIG_CHILDEXIT)
  301. exec_childexit(exec);
  302. }
  303. if (exec->texb_NumTasks || exec->texb_NumInitTasks)
  304. {
  305. TDBPRINTF(TDB_FAIL,("Number of tasks running: %d - initializing: %d\n",
  306. exec->texb_NumTasks, exec->texb_NumInitTasks));
  307. TDBFATAL();
  308. }
  309. exec_checkmodules(exec);
  310. }
  311. /*****************************************************************************/
  312. static void
  313. exec_requestmod(TEXECBASE *exec, struct TTask *taskmsg)
  314. {
  315. struct TModule *mod;
  316. union TTaskRequest *req;
  317. req = &taskmsg->tsk_Request;
  318. mod = (struct TModule *) TFindHandle(&exec->texb_ModList,
  319. req->trq_Mod.trm_InitMod.tmd_Handle.thn_Name);
  320. if (mod == TNULL)
  321. {
  322. /* prepare load request */
  323. taskmsg->tsk_ReqCode = TTREQ_LOADMOD;
  324. /* backup msg original replyport */
  325. req->trq_Mod.trm_RPort = TGETMSGREPLYPORT(taskmsg);
  326. /* init list of waiters */
  327. TINITLIST(&req->trq_Mod.trm_Waiters);
  328. /* mark module as uninitialized */
  329. req->trq_Mod.trm_InitMod.tmd_Flags = 0;
  330. /* insert request as fake/uninitialized module to modlist */
  331. TAddTail(&exec->texb_ModList, (struct TNode *) req);
  332. /* forward this request to I/O task */
  333. exec_PutMsg(exec, &exec->texb_IOTask->tsk_UserPort,
  334. exec->texb_ModReply, taskmsg);
  335. return;
  336. }
  337. if (mod->tmd_Version < req->trq_Mod.trm_InitMod.tmd_Version)
  338. {
  339. /* mod version insufficient */
  340. exec_returnmsg(exec, taskmsg, TMSG_STATUS_FAILED | TMSGF_QUEUED);
  341. return;
  342. }
  343. if (mod->tmd_Flags & TMODF_INITIALIZED)
  344. {
  345. /* request succeeded, reply */
  346. mod->tmd_RefCount++;
  347. req->trq_Mod.trm_Module = mod;
  348. exec_returnmsg(exec, taskmsg, TMSG_STATUS_REPLIED | TMSGF_QUEUED);
  349. return;
  350. }
  351. /* this mod is an initializing request.
  352. add new request to list of its waiters */
  353. req->trq_Mod.trm_ReqTask = taskmsg;
  354. TAddTail(&((union TTaskRequest *) mod)->trq_Mod.trm_Waiters,
  355. (struct TNode *) req);
  356. }
  357. /*****************************************************************************/
  358. static void
  359. exec_replymod(TEXECBASE *exec, struct TTask *taskmsg)
  360. {
  361. struct TModule *mod;
  362. union TTaskRequest *req;
  363. struct TNode *node, *tnode;
  364. req = &taskmsg->tsk_Request;
  365. node = req->trq_Mod.trm_Waiters.tlh_Head;
  366. mod = req->trq_Mod.trm_Module;
  367. /* unlink fake/initializing module request from modlist */
  368. TREMOVE((struct TNode *) req);
  369. /* restore original replyport */
  370. TGETMSGPTR(taskmsg)->tmsg_RPort = req->trq_Mod.trm_RPort;
  371. if (TGETMSGSTATUS(taskmsg) == TMSG_STATUS_FAILED)
  372. {
  373. /* fail-reply to all waiters */
  374. while ((tnode = node->tln_Succ))
  375. {
  376. TREMOVE(node);
  377. /* reply to opener */
  378. exec_returnmsg(exec,
  379. ((union TTaskRequest *) node)->trq_Mod.trm_ReqTask,
  380. TMSG_STATUS_FAILED | TMSGF_QUEUED);
  381. node = tnode;
  382. }
  383. /* forward failure to opener */
  384. exec_returnmsg(exec, taskmsg, TMSG_STATUS_FAILED | TMSGF_QUEUED);
  385. return;
  386. }
  387. /* mark as ready */
  388. mod->tmd_Flags |= TMODF_INITIALIZED;
  389. /* link real module to modlist */
  390. TAddTail(&exec->texb_ModList, (struct TNode *) mod);
  391. /* send replies to all waiters */
  392. while ((tnode = node->tln_Succ))
  393. {
  394. TREMOVE(node);
  395. /* insert module */
  396. ((union TTaskRequest *) node)->trq_Mod.trm_Module = mod;
  397. /* reply to opener */
  398. exec_returnmsg(exec,
  399. ((union TTaskRequest *) node)->trq_Mod.trm_ReqTask,
  400. TMSG_STATUS_REPLIED | TMSGF_QUEUED);
  401. mod->tmd_RefCount++;
  402. node = tnode;
  403. }
  404. /* forward success to opener */
  405. exec_returnmsg(exec, taskmsg, TMSG_STATUS_REPLIED | TMSGF_QUEUED);
  406. }
  407. /*****************************************************************************/
  408. static void
  409. exec_closemod(TEXECBASE *exec, struct TTask *taskmsg)
  410. {
  411. struct TModule *mod;
  412. union TTaskRequest *req;
  413. req = &taskmsg->tsk_Request;
  414. mod = req->trq_Mod.trm_Module;
  415. if (--mod->tmd_RefCount == 0)
  416. {
  417. /* remove from modlist */
  418. TREMOVE((struct TNode *) mod);
  419. /* prepare unload request */
  420. taskmsg->tsk_ReqCode = TTREQ_UNLOADMOD;
  421. /* backup msg original replyport */
  422. req->trq_Mod.trm_RPort = TGETMSGREPLYPORT(taskmsg);
  423. /* forward this request to I/O task */
  424. exec_PutMsg(exec, &exec->texb_IOTask->tsk_UserPort, TNULL, taskmsg);
  425. return;
  426. }
  427. /* confirm */
  428. exec_returnmsg(exec, taskmsg, TMSG_STATUS_ACKD | TMSGF_QUEUED);
  429. }
  430. /*****************************************************************************/
  431. static void
  432. exec_newtask(TEXECBASE *exec, struct TTask *taskmsg)
  433. {
  434. union TTaskRequest *req;
  435. struct TTask *newtask;
  436. req = &taskmsg->tsk_Request;
  437. req->trq_Task.trt_Task = newtask =
  438. exec_createtask(exec, req->trq_Task.trt_Func,
  439. req->trq_Task.trt_InitFunc, req->trq_Task.trt_Tags);
  440. if (newtask)
  441. {
  442. /* insert ptr to self, i.e. the requesting parent */
  443. req->trq_Task.trt_Parent = taskmsg;
  444. /* add request (not taskmsg) to list of initializing tasks */
  445. TAddTail(&exec->texb_TaskInitList, (struct TNode *) req);
  446. exec->texb_NumInitTasks++;
  447. }
  448. else
  449. {
  450. /* failed */
  451. exec_returnmsg(exec, taskmsg, TMSG_STATUS_FAILED | TMSGF_QUEUED);
  452. }
  453. }
  454. /*****************************************************************************/
  455. /*
  456. ** create task
  457. */
  458. static THOOKENTRY TTAG
  459. exec_usertaskdestroy(struct THook *h, TAPTR obj, TTAG msg)
  460. {
  461. if (msg == TMSG_DESTROY)
  462. {
  463. struct TTask *task = obj;
  464. TEXECBASE *exec = (TEXECBASE *) TGetExecBase(task);
  465. struct TTask *self = THALFindSelf(exec->texb_HALBase);
  466. union TTaskRequest *req = &self->tsk_Request;
  467. self->tsk_ReqCode = TTREQ_DESTROYTASK;
  468. req->trq_Task.trt_Task = task;
  469. exec_sendmsg(exec, self, exec->texb_ExecPort, self);
  470. }
  471. return 0;
  472. }
  473. static struct TTask *
  474. exec_createtask(TEXECBASE *exec, TTASKFUNC func, TINITFUNC initfunc,
  475. struct TTagItem *tags)
  476. {
  477. TAPTR hal = exec->texb_HALBase;
  478. TUINT tnlen = 0;
  479. struct TTask *newtask;
  480. TSTRPTR tname;
  481. tname = (TSTRPTR) TGetTag(tags, TTask_Name, TNULL);
  482. if (tname)
  483. {
  484. TSTRPTR t = tname;
  485. while (*t++);
  486. tnlen = t - tname;
  487. }
  488. /* note that tasks are message allocations */
  489. newtask = exec_AllocMMU(exec, &exec->texb_MsgMMU,
  490. sizeof(struct TTask) + tnlen);
  491. if (newtask == TNULL)
  492. return TNULL;
  493. exec_FillMem(exec, newtask, sizeof(struct TTask), 0);
  494. if (THALInitLock(hal, &newtask->tsk_TaskLock))
  495. {
  496. if (exec_initmmu(exec, &newtask->tsk_HeapMMU, TNULL,
  497. TMMUT_TaskSafe | TMMUT_Tracking, TNULL))
  498. {
  499. if (exec_initport(exec, &newtask->tsk_UserPort, newtask,
  500. TTASK_SIG_USER))
  501. {
  502. if (exec_initport(exec, &newtask->tsk_SyncPort, newtask,
  503. TTASK_SIG_SINGLE))
  504. {
  505. if (tname)
  506. {
  507. TSTRPTR t = (TSTRPTR) (newtask + 1);
  508. newtask->tsk_Handle.thn_Name = t;
  509. while ((*t++ = *tname++));
  510. }
  511. newtask->tsk_Handle.thn_Hook.thk_Entry =
  512. exec_usertaskdestroy;
  513. newtask->tsk_Handle.thn_Owner = (struct TModule *) exec;
  514. newtask->tsk_UserData =
  515. (TAPTR) TGetTag(tags, TTask_UserData, TNULL);
  516. newtask->tsk_SigFree = ~((TUINT) TTASK_SIG_RESERVED);
  517. newtask->tsk_SigUsed = TTASK_SIG_RESERVED;
  518. newtask->tsk_Status = TTASK_INITIALIZING;
  519. newtask->tsk_Request.trq_Task.trt_Func = func;
  520. newtask->tsk_Request.trq_Task.trt_InitFunc = initfunc;
  521. newtask->tsk_Request.trq_Task.trt_Tags = tags;
  522. if (THALInitThread(hal, &newtask->tsk_Thread,
  523. (TTASKENTRY void (*)(TAPTR data)) exec_taskentryfunc,
  524. newtask))
  525. {
  526. /* kick it to life */
  527. THALSignal(hal, &newtask->tsk_Thread,
  528. TTASK_SIG_SINGLE);
  529. return newtask;
  530. }
  531. TDESTROY(&newtask->tsk_SyncPort);
  532. }
  533. TDESTROY(&newtask->tsk_UserPort);
  534. }
  535. TDESTROY(&newtask->tsk_HeapMMU);
  536. }
  537. THALDestroyLock(hal, &newtask->tsk_TaskLock);
  538. }
  539. return TNULL;
  540. }
  541. /*****************************************************************************/
  542. /*
  543. ** Task entry
  544. */
  545. static void
  546. exec_closetaskfh(struct TTask *task, TAPTR fh, TUINT flag)
  547. {
  548. if (task->tsk_Flags & flag)
  549. {
  550. TREMOVE((struct TNode *) fh);
  551. TIOCloseFile(task->tsk_IOBase, fh);
  552. }
  553. }
  554. static TTASKENTRY void
  555. exec_taskentryfunc(struct TTask *task)
  556. {
  557. TEXECBASE *exec = (TEXECBASE *) TGetExecBase(task);
  558. union TTaskRequest *req = &task->tsk_Request;
  559. TTASKFUNC func = req->trq_Task.trt_Func;
  560. TINITFUNC initfunc = req->trq_Task.trt_InitFunc;
  561. TTAGITEM *tags = req->trq_Task.trt_Tags;
  562. TAPTR currentdir = (TAPTR) TGetTag(tags, TTask_CurrentDir, TNULL);
  563. TUINT status = 0;
  564. if (currentdir)
  565. {
  566. task->tsk_IOBase = exec_OpenModule(exec, (TSTRPTR) "io", 0, TNULL);
  567. if (task->tsk_IOBase)
  568. {
  569. TAPTR newcd = TIODupLock(task->tsk_IOBase, currentdir);
  570. if (newcd)
  571. {
  572. /* new lock on currentdir duplicated from parent */
  573. TIOChangeDir(task->tsk_IOBase, newcd);
  574. }
  575. else
  576. goto closedown;
  577. }
  578. else
  579. goto closedown;
  580. }
  581. task->tsk_FHIn = (TAPTR) TGetTag(tags, TTask_InputFH, TNULL);
  582. task->tsk_FHOut = (TAPTR) TGetTag(tags, TTask_OutputFH, TNULL);
  583. task->tsk_FHErr = (TAPTR) TGetTag(tags, TTask_ErrorFH, TNULL);
  584. if (initfunc)
  585. status = (*initfunc)(task);
  586. else
  587. status = 1;
  588. if (status)
  589. {
  590. /* change from initializing to running state */
  591. task->tsk_Status = TTASK_RUNNING;
  592. THALSignal(exec->texb_HALBase, &exec->texb_ExecTask->tsk_Thread,
  593. TTASK_SIG_CHILDINIT);
  594. if (func)
  595. (*func)(task);
  596. }
  597. if (task->tsk_Flags & (TTASKF_CLOSEOUTPUT | TTASKF_CLOSEINPUT |
  598. TTASKF_CLOSEERROR))
  599. {
  600. if (task->tsk_IOBase == TNULL)
  601. {
  602. /* Someone passed a filehandle to this task, but we don't
  603. even have the I/O module open. It should be investigated if
  604. this can fail: */
  605. task->tsk_IOBase = exec_OpenModule(exec, (TSTRPTR) "io", 0, TNULL);
  606. if (task->tsk_IOBase == TNULL)
  607. TDBFATAL();
  608. }
  609. exec_closetaskfh(task, task->tsk_FHOut, TTASKF_CLOSEOUTPUT);
  610. exec_closetaskfh(task, task->tsk_FHIn, TTASKF_CLOSEINPUT);
  611. exec_closetaskfh(task, task->tsk_FHErr, TTASKF_CLOSEERROR);
  612. }
  613. closedown:
  614. if (task->tsk_IOBase)
  615. {
  616. /* if we are responsible for a currentdir lock, close it */
  617. TAPTR cd = TIOChangeDir(task->tsk_IOBase, TNULL);
  618. if (cd)
  619. TIOUnlockFile(task->tsk_IOBase, cd);
  620. exec_CloseModule(exec, task->tsk_IOBase);
  621. }
  622. if (status)
  623. {
  624. /* succeeded */
  625. task->tsk_Status = TTASK_FINISHED;
  626. THALSignal(exec->texb_HALBase, &exec->texb_ExecTask->tsk_Thread,
  627. TTASK_SIG_CHILDEXIT);
  628. }
  629. else
  630. {
  631. /* system initialization failed */
  632. task->tsk_Status = TTASK_FAILED;
  633. THALSignal(exec->texb_HALBase, &exec->texb_ExecTask->tsk_Thread,
  634. TTASK_SIG_CHILDINIT);
  635. }
  636. }
  637. /*****************************************************************************/
  638. static void
  639. exec_destroytask(TEXECBASE *exec, struct TTask *task)
  640. {
  641. TAPTR hal = exec->texb_HALBase;
  642. THALDestroyThread(hal, &task->tsk_Thread);
  643. TDESTROY(&task->tsk_SyncPort);
  644. TDESTROY(&task->tsk_UserPort);
  645. TDESTROY(&task->tsk_HeapMMU);
  646. THALDestroyLock(hal, &task->tsk_TaskLock);
  647. exec_Free(exec, task);
  648. }
  649. /*****************************************************************************/
  650. /*
  651. ** handle tasks that change from initializing to running state
  652. */
  653. static void
  654. exec_childinit(TEXECBASE *exec)
  655. {
  656. TAPTR hal = exec->texb_HALBase;
  657. struct TNode *nnode, *node;
  658. node = exec->texb_TaskInitList.tlh_Head;
  659. while ((nnode = node->tln_Succ))
  660. {
  661. union TTaskRequest *req = (union TTaskRequest *) node;
  662. struct TTask *task = req->trq_Task.trt_Task;
  663. struct TTask *taskmsg = req->trq_Task.trt_Parent;
  664. if (task->tsk_Status == TTASK_FAILED)
  665. {
  666. /* remove request from taskinitlist */
  667. TREMOVE((struct TNode *) req);
  668. exec->texb_NumInitTasks--;
  669. /* destroy task corpse */
  670. exec_destroytask(exec, task);
  671. /* fail-reply taskmsg to sender */
  672. exec_returnmsg(exec, taskmsg, TMSG_STATUS_FAILED | TMSGF_QUEUED);
  673. }
  674. else if (task->tsk_Status != TTASK_INITIALIZING)
  675. {
  676. /* remove taskmsg from taskinitlist */
  677. TREMOVE((struct TNode *) req);
  678. exec->texb_NumInitTasks--;
  679. /* link task to list of running tasks */
  680. THALLock(hal, &exec->texb_Lock);
  681. /* note: using node as tempnode argument here */
  682. TAddTail(&exec->texb_TaskList, (struct TNode *) task);
  683. THALUnlock(hal, &exec->texb_Lock);
  684. exec->texb_NumTasks++;
  685. /* reply taskmsg */
  686. exec_returnmsg(exec, taskmsg, TMSG_STATUS_REPLIED | TMSGF_QUEUED);
  687. }
  688. node = nnode;
  689. }
  690. }
  691. /*****************************************************************************/
  692. /*
  693. ** handle exiting tasks
  694. */
  695. static void
  696. exec_childexit(TEXECBASE *exec)
  697. {
  698. TAPTR hal = exec->texb_HALBase;
  699. struct TNode *nnode, *node;
  700. node = exec->texb_TaskExitList.tlh_Head;
  701. while ((nnode = node->tln_Succ))
  702. {
  703. union TTaskRequest *req = (union TTaskRequest *) node;
  704. struct TTask *task = req->trq_Task.trt_Task;
  705. struct TTask *taskmsg = req->trq_Task.trt_Parent;
  706. if (task->tsk_Status == TTASK_FINISHED)
  707. {
  708. /* unlink task from list of running tasks */
  709. THALLock(hal, &exec->texb_Lock);
  710. TREMOVE((struct TNode *) task);
  711. THALUnlock(hal, &exec->texb_Lock);
  712. /* destroy task */
  713. exec_destroytask(exec, task);
  714. /* unlink taskmsg from list of exiting tasks */
  715. TREMOVE((struct TNode *) req);
  716. exec->texb_NumTasks--;
  717. /* reply to caller */
  718. exec_returnmsg(exec, taskmsg, TMSG_STATUS_REPLIED | TMSGF_QUEUED);
  719. }
  720. node = nnode;
  721. }
  722. }
  723. /*****************************************************************************/
  724. /*
  725. ** Atoms
  726. */
  727. static void
  728. exec_replyatom(TEXECBASE *exec, struct TTask *msg, struct TAtom *atom)
  729. {
  730. msg->tsk_Request.trq_Atom.tra_Atom = atom;
  731. exec_returnmsg(exec, msg, TMSG_STATUS_REPLIED | TMSGF_QUEUED);
  732. }
  733. static TAPTR
  734. exec_lookupatom(TEXECBASE *exec, TSTRPTR name)
  735. {
  736. return TFindHandle(&exec->texb_AtomList, name);
  737. }
  738. static struct TAtom *
  739. exec_newatom(TEXECBASE *exec, TSTRPTR name)
  740. {
  741. struct TAtom *atom;
  742. TSTRPTR s, d;
  743. s = d = name;
  744. while (*s++);
  745. atom = exec_AllocMMU0(exec, TNULL, sizeof(struct TAtom) + (s - d));
  746. if (atom)
  747. {
  748. atom->tatm_Handle.thn_Owner = (struct TModule *) exec;
  749. s = d;
  750. d = (TSTRPTR) (atom + 1);
  751. atom->tatm_Handle.thn_Name = d;
  752. while ((*d++ = *s++));
  753. TINITLIST(&atom->tatm_Waiters);
  754. atom->tatm_State = TATOMF_LOCKED;
  755. atom->tatm_Nest = 1;
  756. TAddHead(&exec->texb_AtomList, (struct TNode *) atom);
  757. TDBPRINTF(TDB_TRACE,("atom %s created - nest: 1\n", name));
  758. }
  759. return atom;
  760. }
  761. /*****************************************************************************/
  762. static void
  763. exec_lockatom(TEXECBASE *exec, struct TTask *msg)
  764. {
  765. TUINT mode = msg->tsk_Request.trq_Atom.tra_Mode;
  766. struct TAtom *atom = msg->tsk_Request.trq_Atom.tra_Atom;
  767. struct TTask *task = msg->tsk_Request.trq_Atom.tra_Task;
  768. switch (mode & (TATOMF_CREATE|TATOMF_SHARED|TATOMF_NAME|TATOMF_TRY))
  769. {
  770. case TATOMF_CREATE | TATOMF_SHARED | TATOMF_NAME:
  771. case TATOMF_CREATE | TATOMF_NAME:
  772. atom = exec_lookupatom(exec, (TSTRPTR) atom);
  773. if (atom)
  774. goto obtain;
  775. goto create;
  776. case TATOMF_CREATE | TATOMF_SHARED | TATOMF_TRY | TATOMF_NAME:
  777. case TATOMF_CREATE | TATOMF_TRY | TATOMF_NAME:
  778. atom = exec_lookupatom(exec, (TSTRPTR) atom);
  779. if (atom)
  780. {
  781. atom = TNULL; /* already exists - deny */
  782. goto reply;
  783. }
  784. create:
  785. atom = exec_newatom(exec, msg->tsk_Request.trq_Atom.tra_Atom);
  786. reply:
  787. exec_replyatom(exec, msg, atom);
  788. return;
  789. case TATOMF_NAME | TATOMF_SHARED | TATOMF_TRY:
  790. case TATOMF_NAME | TATOMF_SHARED:
  791. case TATOMF_NAME | TATOMF_TRY:
  792. case TATOMF_NAME:
  793. atom = exec_lookupatom(exec, (TSTRPTR) atom);
  794. case TATOMF_SHARED | TATOMF_TRY:
  795. case TATOMF_SHARED:
  796. case TATOMF_TRY:
  797. case 0:
  798. if (atom)
  799. goto obtain;
  800. fail:
  801. default:
  802. atom = TNULL;
  803. goto reply;
  804. obtain:
  805. if (atom->tatm_State & TATOMF_LOCKED)
  806. {
  807. if (atom->tatm_State & TATOMF_SHARED)
  808. {
  809. if (mode & TATOMF_SHARED)
  810. {
  811. nest: atom->tatm_Nest++;
  812. TDBPRINTF(TDB_TRACE,("nest: %d\n", atom->tatm_Nest));
  813. goto reply;
  814. }
  815. }
  816. else
  817. if (atom->tatm_Owner == task)
  818. goto nest;
  819. if (mode & TATOMF_TRY)
  820. goto fail;
  821. }
  822. else
  823. {
  824. if (atom->tatm_Nest)
  825. TDBPRINTF(TDB_FAIL,
  826. ("atom->nestcount %d!\n", atom->tatm_Nest));
  827. atom->tatm_State = TATOMF_LOCKED;
  828. if (mode & TATOMF_SHARED)
  829. {
  830. atom->tatm_State |= TATOMF_SHARED;
  831. atom->tatm_Owner = TNULL;
  832. }
  833. else
  834. atom->tatm_Owner = task;
  835. atom->tatm_Nest = 1;
  836. TDBPRINTF(TDB_TRACE,
  837. ("atom taken. nest: %d\n", atom->tatm_Nest));
  838. goto reply;
  839. }
  840. /* put this request into atom's list of waiters */
  841. msg->tsk_Request.trq_Atom.tra_Mode = mode & TATOMF_SHARED;
  842. TAddTail(&atom->tatm_Waiters, &msg->tsk_Request.trq_Atom.tra_Node);
  843. TDBPRINTF(TDB_TRACE,("must wait\n"));
  844. }
  845. }
  846. /*****************************************************************************/
  847. static void
  848. exec_unlockatom(TEXECBASE *exec, struct TTask *msg)
  849. {
  850. TUINT mode = msg->tsk_Request.trq_Atom.tra_Mode;
  851. struct TAtom *atom = msg->tsk_Request.trq_Atom.tra_Atom;
  852. atom->tatm_Nest--;
  853. TDBPRINTF(TDB_TRACE,("unlock. nest: %d\n", atom->tatm_Nest));
  854. if (atom->tatm_Nest == 0)
  855. {
  856. union TTaskRequest *waiter;
  857. atom->tatm_State = 0;
  858. atom->tatm_Owner = TNULL;
  859. if (mode & TATOMF_DESTROY)
  860. {
  861. struct TNode *nextnode, *node = atom->tatm_Waiters.tlh_Head;
  862. while ((nextnode = node->tln_Succ))
  863. {
  864. waiter = (union TTaskRequest *) node;
  865. TREMOVE(node);
  866. exec_replyatom(exec, waiter->trq_Atom.tra_Task, TNULL);
  867. node = nextnode;
  868. }
  869. TDBPRINTF(TDB_TRACE,
  870. ("atom free: %s\n", atom->tatm_Handle.thn_Name));
  871. TREMOVE((struct TNode *) atom);
  872. exec_Free(exec, atom);
  873. }
  874. else
  875. {
  876. waiter = (union TTaskRequest *) TRemHead(&atom->tatm_Waiters);
  877. if (waiter)
  878. {
  879. TUINT waitmode = waiter->trq_Atom.tra_Mode;
  880. atom->tatm_Nest++;
  881. atom->tatm_State = TATOMF_LOCKED;
  882. TDBPRINTF(TDB_TRACE,
  883. ("restarted waiter. nest: %d\n", atom->tatm_Nest));
  884. exec_replyatom(exec, waiter->trq_Atom.tra_Task, atom);
  885. /* just restarted a shared waiter?
  886. then restart ALL shared waiters */
  887. if (waitmode & TATOMF_SHARED)
  888. {
  889. struct TNode *nextnode, *node =
  890. atom->tatm_Waiters.tlh_Head;
  891. atom->tatm_State |= TATOMF_SHARED;
  892. while ((nextnode = node->tln_Succ))
  893. {
  894. waiter = (union TTaskRequest *) node;
  895. if (waiter->trq_Atom.tra_Mode & TATOMF_SHARED)
  896. {
  897. TREMOVE(node);
  898. atom->tatm_Nest++;
  899. TDBPRINTF(TDB_TRACE,
  900. ("restarted waiter. nest: %d\n",
  901. atom->tatm_Nest));
  902. exec_replyatom(exec, waiter->trq_Atom.tra_Task,
  903. atom);
  904. }
  905. node = nextnode;
  906. }
  907. }
  908. else
  909. atom->tatm_Owner = waiter->trq_Atom.tra_Task;
  910. }
  911. }
  912. }
  913. exec_returnmsg(exec, msg, TMSG_STATUS_ACKD | TMSGF_QUEUED);
  914. }