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.
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;
31 static int GM_UNIQUENAME(Close
)(struct ThreadBase
*ThreadBase
) {
32 int nthreads
, nattached
;
33 struct _Thread
*thread
, *next
;
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
41 * 2. wait for them to finish
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
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
) {
70 if (!thread
->detached
) nattached
++;
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");
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 */
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
);
106 ADD2OPENLIB(GM_UNIQUENAME(Open
), 0)
107 ADD2CLOSELIB(GM_UNIQUENAME(Close
), 0)