parlib: Prevent running ctors twice
[akaros.git] / user / parlib / panic.c
index 07f1c74..dc796f5 100644 (file)
@@ -1,40 +1,53 @@
 #include <parlib/arch/arch.h>
-#include <stdio.h>
+#include <parlib/stdio.h>
+#include <parlib/assert.h>
+#include <parlib/ros_debug.h>
 #include <stdarg.h>
-#include <parlib/rassert.h>
 #include <stdlib.h>
-#include <parlib/ros_debug.h>
 
-char *argv0;
+static void __attribute__((constructor)) parlib_stdio_init(void)
+{
+       if (__in_fake_parlib())
+               return;
+       /* This isn't ideal, since it might affect some stdout streams where our
+        * parent tried to do something else.  Note that isatty() always returns
+        * TRUE, due to how we fake tcgetattr(), and that doesn't affect whatever
+        * our shells are doing to set us up. */
+       setlinebuf(stdout);
+}
 
-/*
- * Panic is called on unresolvable fatal errors.
- * It prints "panic: <message>", then causes a breakpoint exception,
- * which causes ROS to enter the ROS kernel monitor.
- */
-void
-_panic(const char *file, int line, const char *fmt,...)
+static void __attribute__((noreturn)) fatal_backtrace(void)
 {
+       /* This will cause the kernel to print out a backtrace to the console.
+        * Short of reading /proc/self/maps or other stuff, userspace would have a
+        * hard time backtracing itself. */
+       breakpoint();
+       abort();
+}
+
+void _panic(const char *file, int line, const char *fmt, ...)
+{
+       char buf[128];
+       int ret = 0;
        va_list ap;
 
        va_start(ap, fmt);
-
-       // Print the panic message
-       if (argv0)
-               printf("%s: ", argv0);
-       printf("user panic at %s:%d: ", file, line);
-       vprintf(fmt, ap);
-       printf("\n");
-
-       // Cause a breakpoint exception
-       while (1)
-               breakpoint();
+       ret += snprintf(buf + ret, sizeof(buf) - ret,
+                       "[user] panic: PID %d, vcore %d, %s:%d: ",
+                       getpid(), vcore_id(), __FILE__, __LINE__);
+       /* ignore errors (ret < 0) by setting ret to be at least 0 */
+       ret = MAX(ret, 0);
+       ret += vsnprintf(buf + ret, sizeof(buf) - ret, fmt, ap);
+       ret = MAX(ret, 0);
+       ret += snprintf(buf + ret, sizeof(buf) - ret, "\n");
+       ret = MAX(ret, 0);
+       write(2, buf, ret);
+       fatal_backtrace();
 }
 
 void _assert_failed(const char *file, int line, const char *msg)
 {
-       ros_debug("[user] %s:%d, vcore %d, Assertion failed: %s\n",
-                 file, line, vcore_id(), msg);
-       breakpoint();
-       abort();
+       fprintf(stderr, "[user] %s:%d, vcore %d, Assertion failed: %s\n", file,
+               line, vcore_id(), msg);
+       fatal_backtrace();
 }