diff --git a/src/lib/core/coio_task.c b/src/lib/core/coio_task.c
index bae6acc9e4e6411b59b0a8919733035d79760250..4dba16bc60bce7c351af649fd2853a0004491c6d 100644
--- a/src/lib/core/coio_task.c
+++ b/src/lib/core/coio_task.c
@@ -122,6 +122,7 @@ static int
 coio_on_stop(void *data)
 {
 	(void) data;
+	cord_exit(cord());
 	cord_destroy(cord());
 	free(cord());
 	return 0;
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index 37fda82c5895e0317d6116f56ce9b2e9d63ba1b0..ca415678ac8c637fa08a9ef6ad59aa46edb3828d 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -1560,6 +1560,13 @@ cord_add_garbage(struct cord *cord, struct fiber *f)
 		cord->garbage = f;
 }
 
+void
+cord_exit(struct cord *cord)
+{
+	assert(cord == cord());
+	(void)cord;
+}
+
 void
 cord_destroy(struct cord *cord)
 {
@@ -1625,6 +1632,9 @@ void *cord_thread_func(void *p)
 	                                            CORD_ON_EXIT_WONT_RUN);
 	if (!changed)
 		handler->callback(handler->argument);
+
+	cord_exit(cord());
+
 	return res;
 }
 
@@ -1874,6 +1884,7 @@ fiber_init(int (*invoke)(fiber_func f, va_list ap))
 void
 fiber_free(void)
 {
+	cord_exit(&main_cord);
 	cord_destroy(&main_cord);
 }
 
diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h
index 821376edf0515a788542139b7a7bced553c3b25c..d9b2fb6ae0471ca432db0ea20329f30417b3c609 100644
--- a/src/lib/core/fiber.h
+++ b/src/lib/core/fiber.h
@@ -771,6 +771,13 @@ extern __thread struct cord *cord_ptr;
 void
 cord_create(struct cord *cord, const char *name);
 
+/**
+ * Perform all the thread-specific deinitialization. Must be called in the
+ * exiting thread.
+ */
+void
+cord_exit(struct cord *cord);
+
 void
 cord_destroy(struct cord *cord);