diff --git a/blacklist.txt b/blacklist.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7a73a2772bdab80711cb3425c355cb531f9f8695
--- /dev/null
+++ b/blacklist.txt
@@ -0,0 +1,6 @@
+# false positives from thread::spawn (?)
+race:<alloc::arc::Arc<T>>::drop_slow
+race:__GI___call_tls_dtors
+race:alloc::heap::{{impl}}::dealloc
+race:core::ptr::drop_in_place<core::option::Option<core::result::Result<(), alloc::boxed::Box<Any>>>>
+race:core::ptr::drop_in_place<core::result::Result<(), alloc::boxed::Box<Any>>>
diff --git a/ci/install.sh b/ci/install.sh
index 4d5d56a45bb9563ed35d06665575322b4c392172..8724552da22f53a78bf4aed3b94a545f0c0ee0ad 100644
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -11,7 +11,11 @@ main() {
             rustup component list | grep 'rust-src.*installed' || \
                 rustup component add rust-src
             ;;
+        x86_64-unknown-linux-gnu)
+            ;;
         *)
+            # unhandled case
+            exit 1
             ;;
     esac
 }
diff --git a/ci/script.sh b/ci/script.sh
index e9ff7e38b9f350574d31a079eeb684e88a3f6d6c..5bf4a8b07bd7d6ed509ba8af7f6e97236ef3372d 100644
--- a/ci/script.sh
+++ b/ci/script.sh
@@ -5,8 +5,19 @@ main() {
         thumb*m-none-eabi)
             xargo check --target $TARGET
             ;;
-        *)
+        x86_64-unknown-linux-gnu)
             cargo check --target $TARGET
+            cargo test --target $TARGET
+
+            export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt"
+            export RUSTFLAGS="-Z sanitizer=thread"
+
+            cargo test --test tsan --target $TARGET
+            cargo test --test tsan --target $TARGET --release
+            ;;
+        *)
+            # unhandled case
+            exit 1
             ;;
     esac
 }
diff --git a/tests/tsan.rs b/tests/tsan.rs
new file mode 100644
index 0000000000000000000000000000000000000000..edee90111872fb6593d58d27a106ed09f00ed50f
--- /dev/null
+++ b/tests/tsan.rs
@@ -0,0 +1,20 @@
+extern crate heapless;
+
+use std::thread;
+
+use heapless::RingBuffer;
+
+#[test]
+fn tsan() {
+    static mut RB: RingBuffer<i32, [i32; 4]> = RingBuffer::new();
+
+    unsafe { RB.split() }.0.enqueue(0).unwrap();
+
+    thread::spawn(|| {
+        unsafe { RB.split() }.0.enqueue(1).unwrap();
+    });
+
+    thread::spawn(|| {
+        unsafe { RB.split() }.1.dequeue().unwrap();
+    });
+}