diff --git a/src/fiber.cc b/src/fiber.cc
index ff02fb3132cd68813f52c43e722e95b4ce9d872b..111aaca7da0c9b4f106119fa603df2b6810263cd 100644
--- a/src/fiber.cc
+++ b/src/fiber.cc
@@ -105,12 +105,12 @@ fiber_wakeup(struct fiber *f)
 	if (rlist_empty(&cord->ready)) {
 		/*
 		 * ev_feed_event() is possibly faster,
-		 * but custom event gets scheduled in the
+		 * but EV_CUSTOM event gets scheduled in the
 		 * same event loop iteration, which can
-		 * produce unfair scheduling (see the case of
+		 * produce unfair scheduling, (see the case of
 		 * fiber_sleep(0))
 		 */
-		ev_async_send(cord->loop, &cord->wakeup_event);
+		ev_feed_event(cord->loop, &cord->wakeup_event, EV_CUSTOM);
 	}
 	rlist_move_tail_entry(&cord->ready, f, state);
 }
@@ -293,13 +293,11 @@ fiber_yield_timeout(ev_tstamp delay)
 void
 fiber_sleep(ev_tstamp delay)
 {
-	if (delay == 0) {
-		/* Faster than starting and stopping a timer. */
-		fiber_wakeup(fiber());
-		fiber_yield();
-	} else {
-		fiber_yield_timeout(delay);
-	}
+	/*
+	 * We don't use fiber_wakeup() here to ensure there is
+	 * no infinite wakeup loop in case of fiber_sleep(0).
+	 */
+	fiber_yield_timeout(delay);
 	fiber_testcancel();
 }
 
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 1b8d8c0088382ebae013631316a7096d65211fc8..4833461371e482ad674f8222e01a20de7945ca46 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -65,6 +65,9 @@ target_link_libraries(fiber.test core)
 add_executable(fiber_stress.test fiber_stress.cc)
 target_link_libraries(fiber_stress.test core)
 
+add_executable(ipc.test ipc.cc ${CMAKE_SOURCE_DIR}/src/ipc.cc)
+target_link_libraries(ipc.test core)
+
 add_executable(coio.test coio.cc unit.c
         ${CMAKE_SOURCE_DIR}/src/sio.cc
         ${CMAKE_SOURCE_DIR}/src/evio.cc
diff --git a/test/unit/ipc.cc b/test/unit/ipc.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c5812bbf90744b73442b3bea481480c995dea721
--- /dev/null
+++ b/test/unit/ipc.cc
@@ -0,0 +1,55 @@
+#include "memory.h"
+#include "fiber.h"
+#include "ipc.h"
+#include "unit.h"
+
+enum {
+	ITERATIONS = 100000,
+};
+
+void
+push_f(va_list ap)
+{
+	struct ipc_channel *channel = va_arg(ap, struct ipc_channel *);
+
+	for (int i = 0; i < ITERATIONS; i++)
+		ipc_channel_put(channel, NULL);
+}
+
+void
+pop_f(va_list ap)
+{
+	struct ipc_channel *channel = va_arg(ap, struct ipc_channel *);
+
+	for (int i = 0; i < ITERATIONS; i++)
+		(void) ipc_channel_get(channel);
+}
+
+void main_f(va_list ap)
+{
+	header();
+	struct fiber *push = fiber_new("push_f", push_f);
+	fiber_set_joinable(push, true);
+	struct fiber *pop = fiber_new("pop_f", pop_f);
+	fiber_set_joinable(pop, true);
+	struct ipc_channel *channel = ipc_channel_new(1);
+	fiber_start(push, channel);
+	fiber_start(pop, channel);
+	fiber_join(push);
+	fiber_join(pop);
+	ipc_channel_delete(channel);
+	ev_break(loop(), EVBREAK_ALL);
+	footer();
+}
+
+int main()
+{
+	memory_init();
+	fiber_init();
+	struct fiber *main= fiber_new("main", main_f);
+	fiber_wakeup(main);
+	ev_run(loop(), 0);
+	fiber_free();
+	memory_free();
+	return 0;
+}
diff --git a/test/unit/ipc.result b/test/unit/ipc.result
new file mode 100644
index 0000000000000000000000000000000000000000..f3398fb9c7731397e2535321288bd427198fba1e
--- /dev/null
+++ b/test/unit/ipc.result
@@ -0,0 +1,3 @@
+	*** main_f ***
+	*** main_f: done ***
+ 
\ No newline at end of file