play nicer with tsan
diff --git a/aos/linux_code/logging/linux_interface.cc b/aos/linux_code/logging/linux_interface.cc
index cbc114e..f3ea9e0 100644
--- a/aos/linux_code/logging/linux_interface.cc
+++ b/aos/linux_code/logging/linux_interface.cc
@@ -37,12 +37,22 @@
   return process_name + '.' + thread_name;
 }
 
-AOS_THREAD_LOCAL Context *my_context(NULL);
+AOS_THREAD_LOCAL Context *my_context(nullptr);
+
+// A temporary stash for Context objects that we're going to delete ASAP. The
+// reason for doing this instead of just deleting them is that tsan (at least)
+// doesn't like it when pthread_atfork handlers do complicated stuff and it's
+// not a great idea anyways.
+AOS_THREAD_LOCAL Context *old_context(nullptr);
 
 }  // namespace
 
 Context *Context::Get() {
-  if (__builtin_expect(my_context == NULL, 0)) {
+  if (__builtin_expect(my_context == nullptr, 0)) {
+    if (old_context != nullptr) {
+      delete old_context;
+      old_context = nullptr;
+    }
     my_context = new Context();
     my_context->name = GetMyName();
     if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
@@ -55,8 +65,13 @@
 }
 
 void Context::Delete() {
-  delete my_context;
-  my_context = NULL;
+  if (my_context != nullptr) {
+    if (old_context != nullptr) {
+      delete old_context;
+    }
+    old_context = my_context;
+    my_context = nullptr;
+  }
 }
 
 }  // namespace internal