Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / thread / thread_init.c
blobe59af7a546cab2cd73f1771138f0578b85d80d15
1 /*
2 * thread.library - threading and synchronisation primitives
4 * Copyright © 2007 Robert Norris
6 * This program is free software; you can redistribute it and/or modify it
7 * under the same terms as AROS itself.
8 */
10 #include "thread_intern.h"
12 #include <exec/semaphores.h>
13 #include <exec/lists.h>
14 #include <exec/tasks.h>
15 #include <proto/exec.h>
16 #include <proto/thread.h>
17 #include <aros/symbolsets.h>
19 #include LC_LIBDEFS_FILE
21 static int GM_UNIQUENAME(Open)(struct ThreadBase *ThreadBase) {
22 InitSemaphore(&ThreadBase->lock);
24 NEWLIST(&ThreadBase->threads);
26 ThreadBase->nextid = 1;
28 return TRUE;
31 static int GM_UNIQUENAME(Close)(struct ThreadBase *ThreadBase) {
32 int nthreads, nattached;
33 struct _Thread *thread, *next;
34 struct Task *task;
36 /* we're most likely here because main() exited. if there are remaining
37 * threads, we need to do something with them. we have the following
38 * options:
40 * 1. leave them alone
41 * 2. wait for them to finish
42 * 3. kill them
44 * [1] is close to impossible. the main task exiting will cause all the
45 * resources that DOS has open for the task, including the program code
46 * itself, to be deallocated.
48 * [2] is fine, but there's no guarantee that they ever will finish;
49 * furthermore this Close function is inside Forbid() right now, which
50 * means we'd have to re-enable task switches. that's safe because this is
51 * a per-opener base, but its just a little bit tricky.
53 * [3] ensures that the threads are gone and the main task can exit right
54 * now, but AROS really doesn't provide a way to safely kill a process.
55 * RemTask() will make sure it never gets scheduled again and will free
56 * the memory it allocated, but it may have open libraries, filehandles,
57 * etc which will get leaked. This can't be fixed without proper task
58 * resource tracking.
60 * I've chosen [2] for now, because its really the only option that
61 * doesn't cause either a system crash (executing code that no longer
62 * exists) or at least instability (leaked files, libraries, etc). They
63 * all suck though. The main task should arrange (or wait) for the threads
64 * to exit before it exits itself.
67 nthreads = nattached = 0;
68 ForeachNode(&ThreadBase->threads, thread) {
69 nthreads++;
70 if (!thread->detached) nattached++;
73 if (nthreads > 0) {
74 task = FindTask(NULL);
76 kprintf("[thread] %d thread%s still running, waiting for %s to finish.\n", nthreads,
77 nthreads > 1 ? "s" : "",
78 nthreads > 1 ? "them" : "it");
80 if (nattached > 0) {
81 kprintf(" %d thread%s still attached at main task exit!\n", nthreads,
82 nthreads > 1 ? "s" : "");
83 kprintf(" This probably means a bug in the main task '%s'.\n", task->tc_Node.ln_Name);
84 kprintf(" Please report this to the author of that program.\n");
87 /* re-enable task switches. we can do this safely because this is a
88 * per-opener library base */
89 Permit();
91 ForeachNodeSafe(&ThreadBase->threads, thread, next) {
92 /* re-attach the thread so that WaitThread() can work */
93 ObtainSemaphore(&thread->lock);
94 thread->detached = FALSE;
95 ReleaseSemaphore(&thread->lock);
97 WaitThread(thread->id, NULL);
100 Forbid();
103 return TRUE;
106 ADD2OPENLIB(GM_UNIQUENAME(Open), 0)
107 ADD2CLOSELIB(GM_UNIQUENAME(Close), 0)