aboutsummaryrefslogtreecommitdiff
path: root/sys/rt
diff options
context:
space:
mode:
authorNicholas <nbnoll@eml.cc>2021-11-20 17:07:23 -0800
committerNicholas <nbnoll@eml.cc>2021-11-20 17:07:23 -0800
commitc9a32c1a43d2bdded07eaa45732c3a6e195a5442 (patch)
treecb7e9cb8c34cbe6551b801eff4201afcf71dd0fd /sys/rt
parente97c8c469db0aa27985dab2879dc1f14905c7387 (diff)
Chore: cleaned up the exit code to cleanly interface with libc
We use weak linking to ensure we clean up at exit time correctly. If libc is linked, then we call our cleanup function by registering an atexit callback with the library. If libc is not linked, we have a weak symbol that results in a noop. Similarly, if we call rt·exit while linked with libc, this immediately calls libc's exit (which will call our cleanup as we registered it). If we are not linked to libc, exit() is given as a weak link to a noop function.
Diffstat (limited to 'sys/rt')
-rw-r--r--sys/rt/atexit.c49
-rw-r--r--sys/rt/boot.c4
-rw-r--r--sys/rt/dummy.c3
-rw-r--r--sys/rt/exit.c19
4 files changed, 69 insertions, 6 deletions
diff --git a/sys/rt/atexit.c b/sys/rt/atexit.c
new file mode 100644
index 0000000..208cc6e
--- /dev/null
+++ b/sys/rt/atexit.c
@@ -0,0 +1,49 @@
+#include <u.h>
+#include <rt.h>
+
+#define COUNT 32
+
+static struct cleaner
+{
+ struct cleaner *next;
+ void (*clean[COUNT])(void *);
+ void *arg[COUNT];
+} arena, *head;
+static int slot;
+
+void weaklink exit(int code){};
+
+void
+rt·clean(void)
+{
+ void (*clean)(void *), *arg;
+ /*LOCK*/
+ for(; head; head=head->next, slot=COUNT) {
+ while(slot-- > 0){
+ arg = head->arg[slot];
+ clean = head->clean[slot];
+ /* UNLOCK */
+ clean(arg);
+ /* LOCK */
+ }
+ }
+}
+
+int
+rt·atexit(void (*clean)(void *), void *arg)
+{
+ /* LOCK */
+ if(!head)
+ head = &arena;
+
+ /* we need malloc... */
+ if(slot==COUNT)
+ return -1;
+
+ head->arg[slot] = arg;
+ head->clean[slot] = clean;
+ slot++;
+
+ /* UNLOCK */
+ return 0;
+}
diff --git a/sys/rt/boot.c b/sys/rt/boot.c
index 320a596..8c6616d 100644
--- a/sys/rt/boot.c
+++ b/sys/rt/boot.c
@@ -3,7 +3,10 @@
#include <elf.h>
/* tell linker to go find */
+int atexit(void (*)(void));
int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv);
+
+void rt·clean(void);
void rt·guardstack(void);
#define NAUX 38
@@ -30,6 +33,7 @@ rt·boot(int (*main)(), int argc, char **argv, void (*init)(), void (*fini)(), v
rt·init(env, argv[0]);
/* ring libc, anyone home? */
+ atexit(rt·clean);
__libc_start_main(main, argc, argv);
/* no? ok we continue on if there is no libc linked */
diff --git a/sys/rt/dummy.c b/sys/rt/dummy.c
index f123d16..0cef224 100644
--- a/sys/rt/dummy.c
+++ b/sys/rt/dummy.c
@@ -4,3 +4,6 @@
/* provide a dummy implementation if libc is not linked */
static int noop(int (*main)(), int argc, char **argv) { return 0; }
weakalias(noop, __libc_start_main);
+
+static int noop2(void (*func)(void)) { return 0; }
+weakalias(noop, atexit);
diff --git a/sys/rt/exit.c b/sys/rt/exit.c
index e6027b7..386a1bf 100644
--- a/sys/rt/exit.c
+++ b/sys/rt/exit.c
@@ -2,10 +2,13 @@
#include <rt.h>
#include <syscall.h>
-/* XXX:
- * if we are here, we are in charge, call exit syscalls
- * think of better way to encapsulate these syscalls?
- */
+/* tell linker to go find */
+void noreturn exit(int code);
+
+/* if did not call rt·atexit, then don't pull it in */
+static void noop(void){}
+weakalias(noop, rt·clean);
+
static noreturn void
rt·shutdown(int code)
{
@@ -14,14 +17,18 @@ rt·shutdown(int code)
if(rt·context.exit)
rt·context.exit();
+ /* XXX: better way to encapsulate these calls? */
_syscall1(·ExitGroup, code);
for(;;)
_syscall1(·Exit, code);
}
-weakalias(rt·shutdown, exit);
noreturn void
rt·exit(int code)
{
- rt·shutdown(code);
+ /* ring libc, anyone home? */
+ exit(code);
+ /* if we are here, we are in charge, shut it down */
+ rt·clean();
+ rt·shutdown(code);
}