diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 22cbcc2c13480d5d1e085bcfa48327360109b1ae..312a1da5bf85a8fcf24dfc052a76378e9442555f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -59,7 +59,7 @@ set (core_sources
      diag.c
      say.c
      memory.c
-     fiber.cc
+     fiber.c
      cbus.c
      exception.cc
      coro.c
diff --git a/src/cbus.c b/src/cbus.c
index 5cb62944e40ea7a08c14c1434a35affb5cc4dfd4..04c0e33049b42ca6da5855176e417c5b18a072e7 100644
--- a/src/cbus.c
+++ b/src/cbus.c
@@ -308,7 +308,11 @@ cpipe_fiber_pool_cb(ev_loop *loop, struct ev_async *watcher,
 					      struct fiber, state);
 			fiber_call(f);
 		} else if (! cpipe_fiber_pool_needs_throttling(pool)) {
-			f = fiber_new(pool->name, cpipe_fiber_pool_f);
+			f = fiber_new_nothrow(pool->name, cpipe_fiber_pool_f);
+			if (f == NULL) {
+				error_log(diag_last_error(&fiber()->diag));
+				break;
+			}
 			fiber_start(f, pool);
 		} else {
 			/**
diff --git a/src/coio.cc b/src/coio.cc
index 7406d3f43c6419b450d9252c71480e67b1233b87..ac480a63a8e36916d2af138a6dd7c93b2b50ab90 100644
--- a/src/coio.cc
+++ b/src/coio.cc
@@ -631,7 +631,7 @@ coio_service_on_accept(struct evio_service *evio_service,
 
 void
 coio_service_init(struct coio_service *service, const char *name,
-		  void (*handler)(va_list ap), void *handler_param)
+		  fiber_func handler, void *handler_param)
 {
 	evio_service_init(loop(), &service->evio_service, name,
 			  coio_service_on_accept, service);
diff --git a/src/coio.h b/src/coio.h
index f43811c9e143256efe9a3272524b5b91c71e8351..c27bcf09be1fcf6a00047d21b930f5f509997674 100644
--- a/src/coio.h
+++ b/src/coio.h
@@ -42,7 +42,7 @@ struct coio_service
 {
 	struct evio_service evio_service;
 	/* Fiber function. */
-	void (*handler)(va_list ap);
+	fiber_func handler;
 	/** Passed to the created fiber. */
 	void *handler_param;
 };
@@ -160,7 +160,7 @@ coio_recvfrom_timeout(struct ev_io *coio, void *buf, size_t sz, int flags,
 
 void
 coio_service_init(struct coio_service *service, const char *name,
-		  void (*handler)(va_list ap), void *handler_param);
+		  fiber_func handler, void *handler_param);
 
 /** Wait until the service binds to the port. */
 void
diff --git a/src/exception.cc b/src/exception.cc
index 0c739b6037e4034c3582a5590da4698da96338f6..8d242458b644923855cc4ce0d1a6be43b7319083 100644
--- a/src/exception.cc
+++ b/src/exception.cc
@@ -34,6 +34,8 @@
 #include <string.h>
 #include <errno.h>
 
+#include "fiber.h"
+
 extern "C" {
 
 static void
@@ -176,6 +178,17 @@ TimedOut::TimedOut(const char *file, unsigned line)
 	m_errno = ETIMEDOUT;
 }
 
+const struct type type_FiberCancelException =
+	make_type("FiberCancelException", &type_Exception);
+
+void
+FiberCancelException::log()
+{
+	say_info("fiber `%s' has been cancelled",
+		 fiber_name(fiber()));
+	say_info("fiber `%s': exiting", fiber_name(fiber()));
+}
+
 void
 exception_init()
 {
@@ -188,3 +201,4 @@ exception_init()
 	/* A special workaround for out_of_memory static init */
 	out_of_memory.refs = 1;
 }
+
diff --git a/src/exception.h b/src/exception.h
index 810ecf2f66e0b663734c80fb887d8887505cfa43..04c8a53c893af1cd21cf65044dda8cae57ff0958 100644
--- a/src/exception.h
+++ b/src/exception.h
@@ -92,6 +92,22 @@ class TimedOut: public SystemError {
 	virtual void raise() { throw this; }
 };
 
+extern const struct type type_FiberCancelException;
+/**
+ * This is thrown by fiber_* API calls when the fiber is
+ * cancelled.
+ */
+class FiberCancelException: public Exception {
+public:
+	FiberCancelException(const char *file, unsigned line)
+		: Exception(&type_FiberCancelException, file, line) {
+		/* Nothing */
+	}
+
+	virtual void log();
+	virtual void raise() { throw this; }
+};
+
 /**
  * Initialize the exception subsystem.
  */
diff --git a/src/fiber.cc b/src/fiber.c
similarity index 94%
rename from src/fiber.cc
rename to src/fiber.c
index cc1891181e3075fc5b787d9a40a200eb4f5d02a3..89d3e31d560f591f3114bfe0bb04b9b55c5bf1a2 100644
--- a/src/fiber.cc
+++ b/src/fiber.c
@@ -40,6 +40,8 @@
 #include "trigger.h"
 #include "third_party/pmatomic.h"
 
+static void (*fiber_invoke)(fiber_func f, va_list ap);
+
 /*
  * Defines a handler to be executed on exit from cord's thread func,
  * accessible via cord()->on_exit (normally NULL). It is used to
@@ -62,9 +64,6 @@ static struct cord main_cord;
 __thread struct cord *cord_ptr = NULL;
 pthread_t main_thread_id;
 
-const struct type type_FiberCancelException =
-	make_type("FiberCancelException", &type_Exception);
-
 static void
 update_last_stack_frame(struct fiber *fiber)
 {
@@ -210,14 +209,14 @@ fiber_join(struct fiber *fiber)
 		fiber_yield();
 	}
 	assert(fiber_is_dead(fiber));
+	bool fiber_was_cancelled = fiber->flags & FIBER_IS_CANCELLED;
 	/* The fiber is already dead. */
 	fiber_recycle(fiber);
 
 	/* Move exception to the caller */
 	diag_move(&fiber->diag, &fiber()->diag);
-	struct error *e = diag_last_error(&fiber()->diag);
 	/** Don't bother with propagation of FiberCancelException */
-	if (e != NULL && type_cast(FiberCancelException, e) != NULL)
+	if (fiber_was_cancelled)
 		diag_clear(&fiber()->diag);
 }
 
@@ -252,9 +251,10 @@ struct fiber_watcher_data {
 };
 
 static void
-fiber_schedule_timeout(ev_loop * /* loop */,
+fiber_schedule_timeout(ev_loop *loop,
 		       ev_timer *watcher, int revents)
 {
+	(void) loop;
 	(void) revents;
 
 	assert(fiber() == &cord()->sched);
@@ -309,8 +309,10 @@ fiber_sleep(ev_tstamp delay)
 }
 
 void
-fiber_schedule_cb(ev_loop * /* loop */, ev_watcher *watcher, int /* revents */)
+fiber_schedule_cb(ev_loop *loop, ev_watcher *watcher, int revents)
 {
+	(void) loop;
+	(void) revents;
 	assert(fiber() == &cord()->sched);
 	fiber_call((struct fiber *) watcher->data);
 }
@@ -330,8 +332,9 @@ fiber_schedule_list(struct rlist *list)
 }
 
 static void
-fiber_schedule_wakeup(ev_loop * /* loop */, ev_async *watcher, int revents)
+fiber_schedule_wakeup(ev_loop *loop, ev_async *watcher, int revents)
 {
+	(void) loop;
 	(void) watcher;
 	(void) revents;
 	struct cord *cord = cord();
@@ -339,9 +342,13 @@ fiber_schedule_wakeup(ev_loop * /* loop */, ev_async *watcher, int revents)
 }
 
 static void
-fiber_schedule_idle(ev_loop * /* loop */, ev_idle * /* watcher */,
-		    int /* revents */)
-{}
+fiber_schedule_idle(ev_loop *loop, ev_idle *watcher,
+		    int revents)
+{
+	(void) loop;
+	(void) watcher;
+	(void) revents;
+}
 
 
 struct fiber *
@@ -411,20 +418,14 @@ fiber_loop(void *data __attribute__((unused)))
 		struct fiber *fiber = fiber();
 
 		assert(fiber != NULL && fiber->f != NULL && fiber->fid != 0);
-		try {
-			fiber->f(fiber->f_data);
-			/*
-			 * Make sure a leftover exception does not
-			 * propagate up to the joiner.
-			 */
-			diag_clear(&fiber->diag);
-		} catch (struct error *e) {
+		fiber_invoke(fiber->f, fiber->f_data);
+		struct error *e = diag_last_error(&fiber->diag);
+		if (e != NULL && !(fiber->flags & FIBER_IS_JOINABLE)) {
 			/*
 			 * For joinable fibers, it's the business
 			 * of the caller to deal with the error.
 			 */
-			if (! (fiber->flags & FIBER_IS_JOINABLE))
-				error_log(e);
+			error_log(e);
 		}
 		fiber->flags |= FIBER_IS_DEAD;
 		while (! rlist_empty(&fiber->wake)) {
@@ -472,7 +473,7 @@ fiber_get_key(struct fiber *fiber, enum fiber_key key);
  * completes.
  */
 struct fiber *
-fiber_new(const char *name, void (*f) (va_list))
+fiber_new_nothrow(const char *name, fiber_func f)
 {
 	struct cord *cord = cord();
 	struct fiber *fiber = NULL;
@@ -482,11 +483,19 @@ fiber_new(const char *name, void (*f) (va_list))
 					  struct fiber, link);
 		rlist_move_entry(&cord->alive, fiber, link);
 	} else {
-		fiber = (struct fiber *) mempool_alloc0(&cord->fiber_pool);
+		fiber = (struct fiber *)
+			mempool_alloc_nothrow(&cord->fiber_pool);
+		if (fiber == NULL) {
+			diag_set(OutOfMemory, sizeof(struct fiber),
+				 "fiber pool", "fiber");
+			return NULL;
+		}
+		memset(fiber, 0, sizeof(struct fiber));
 
 		if (tarantool_coro_create(&fiber->coro, &cord->slabc,
 					  fiber_loop, NULL)) {
-			diag_raise();
+			mempool_free(&cord->fiber_pool, fiber);
+			return NULL;
 		}
 
 		region_create(&fiber->gc, &cord->slabc);
@@ -774,8 +783,10 @@ cord_cojoin(struct cord *cord)
 }
 
 void
-break_ev_loop_f(struct trigger * /* trigger */, void * /* event */)
+break_ev_loop_f(struct trigger *trigger, void *event)
 {
+	(void) trigger;
+	(void) event;
 	ev_break(loop(), EVBREAK_ALL);
 }
 
@@ -791,13 +802,10 @@ cord_costart_thread_func(void *arg)
 {
 	struct costart_ctx ctx = *(struct costart_ctx *) arg;
 	free(arg);
-	struct fiber *f;
 
-	try {
-		f = fiber_new("main", ctx.run);
-	} catch (...) {
+	struct fiber *f = fiber_new_nothrow("main", ctx.run);
+	if (f == NULL)
 		return NULL;
-	}
 
 	struct trigger break_ev_loop = {
 		RLIST_LINK_INITIALIZER, break_ev_loop_f, NULL, NULL
@@ -854,8 +862,9 @@ cord_is_main()
 }
 
 void
-fiber_init(void)
+fiber_init(void (*invoke)(fiber_func f, va_list ap))
 {
+	fiber_invoke = invoke;
 	main_thread_id = pthread_self();
 	cord() = &main_cord;
 	cord_init("main");
diff --git a/src/fiber.h b/src/fiber.h
index 5b9655748dcc57dadf87470891b9549362e22ac9..a209e5a4790bdf23ea02f56ae2df2f84ed929268 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -96,7 +96,7 @@ enum fiber_key {
 	FIBER_KEY_MAX = 5
 };
 
-typedef void(*fiber_func)(va_list);
+typedef void (*fiber_func)(va_list);
 
 struct fiber {
 	struct tarantool_coro coro;
@@ -136,7 +136,7 @@ struct fiber {
 	 * You can safely ignore all offset_of-related warnings.
 	 * See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31488
 	 */
-	void (*f) (va_list);
+	fiber_func f;
 	va_list f_data;
 	/** Fiber local storage */
 	void *fls[FIBER_KEY_MAX];
@@ -266,11 +266,14 @@ cord_set_name(const char *name);
 bool
 cord_is_main();
 
-void fiber_init(void);
-void fiber_free(void);
+void
+fiber_init(void (*fiber_invoke)(fiber_func f, va_list ap));
+
+void
+fiber_free(void);
 
 struct fiber *
-fiber_new(const char *name, fiber_func f);
+fiber_new_nothrow(const char *name, fiber_func f);
 
 void
 fiber_set_name(struct fiber *fiber, const char *name);
@@ -414,29 +417,15 @@ fiber_time64(void)
 	return (uint64_t) ( ev_now(loop()) * 1000000 + 0.5 );
 }
 
+inline void
+fiber_c_invoke(fiber_func f, va_list ap)
+{
+	return f(ap);
+}
+
 #if defined(__cplusplus)
 } /* extern "C" */
 
-/**
- * This is thrown by fiber_* API calls when the fiber is
- * cancelled.
- */
-extern const struct type type_FiberCancelException;
-class FiberCancelException: public Exception {
-public:
-	FiberCancelException(const char *file, unsigned line)
-		: Exception(&type_FiberCancelException, file, line) {
-		/* Nothing */
-	}
-
-	virtual void log() const {
-			say_info("fiber `%s' has been cancelled",
-				 fiber_name(fiber()));
-			say_info("fiber `%s': exiting", fiber_name(fiber()));
-	}
-	virtual void raise() { throw this; }
-};
-
 /*
  * Test if this fiber is in a cancellable state and was indeed
  * cancelled, and raise an exception (FiberCancelException) if
@@ -456,7 +445,6 @@ fiber_testcancel(void)
 		tnt_raise(FiberCancelException);
 }
 
-
 static inline void
 diag_raise(void)
 {
@@ -465,6 +453,31 @@ diag_raise(void)
 		error_raise(e);
 }
 
+static inline struct fiber *
+fiber_new(const char *name, fiber_func func)
+{
+	struct fiber *f = fiber_new_nothrow(name, func);
+	if (f == NULL) {
+		diag_raise();
+		assert(false);
+	}
+	return f;
+}
+
+inline void
+fiber_cxx_invoke(fiber_func f, va_list ap)
+{
+	try {
+		f(ap);
+		/*
+		 * Make sure a leftover exception does not
+		 * propagate up to the joiner.
+		 */
+		diag_clear(&fiber()->diag);
+	} catch (struct error *e) {
+	}
+}
+
 #endif /* defined(__cplusplus) */
 
 #endif /* TARANTOOL_FIBER_H_INCLUDED */
diff --git a/src/main.cc b/src/main.cc
index f2007b4af56192e729a68e2e8ca4344d9c78be1f..ccce27a44da4f0424d4beb6472b8ebf1d87ee9b3 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -631,7 +631,7 @@ main(int argc, char **argv)
 
 	exception_init();
 
-	fiber_init();
+	fiber_init(fiber_cxx_invoke);
 	/* Init iobuf library with default readahead */
 	iobuf_init();
 	coeio_init();
diff --git a/src/trigger.h b/src/trigger.h
index bd67f604d0c67b6f6e408b3e45859f4c3caea528..51b2506a658089c90fda328e3ca44531de033bcb 100644
--- a/src/trigger.h
+++ b/src/trigger.h
@@ -31,10 +31,15 @@
  * SUCH DAMAGE.
  */
 #include "salad/rlist.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
 /**
  * Type of the callback which may be invoked
  * on an event.
  */
+struct trigger;
 typedef void (*trigger_f)(struct trigger *trigger, void *event);
 typedef void (*trigger_f0)(struct trigger *trigger);
 
@@ -105,5 +110,8 @@ trigger_destroy(struct rlist *list)
 			trigger->destroy(trigger);
 	}
 }
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
 
 #endif /* INCLUDES_TARANTOOL_TRIGGER_H */
diff --git a/test/unit/coio.cc b/test/unit/coio.cc
index aeb1154692154efc4727cac6d7e792384d9dcb0e..e1f2a6a0ab711fe88ccf2933c31cdd0512a32a3c 100644
--- a/test/unit/coio.cc
+++ b/test/unit/coio.cc
@@ -15,7 +15,8 @@ touch_f(va_list ap)
 		fail_unless(rc == 1);
 		fflush(f);
 		fiber_sleep(0.01);
-		fiber_testcancel();
+		if (fiber_is_cancelled())
+			return;
 	}
 }
 
@@ -63,7 +64,7 @@ main_f(va_list ap)
 int main()
 {
 	memory_init();
-	fiber_init();
+	fiber_init(fiber_cxx_invoke);
 	struct fiber *test = fiber_new("coio_stat", main_f);
 	fiber_wakeup(test);
 	ev_run(loop(), 0);
diff --git a/test/unit/coio.result b/test/unit/coio.result
index 392e2807f98b8f824464930690808e9d76aba1a7..b8391a50c65b5f8b692ae3949fbd11c91b9e8521 100644
--- a/test/unit/coio.result
+++ b/test/unit/coio.result
@@ -1,5 +1,3 @@
-(null): fiber `touch' has been cancelled
-(null): fiber `touch': exiting
 	*** stat_timeout_test ***
 	*** stat_timeout_test: done ***
 	*** stat_notify_test ***
diff --git a/test/unit/fiber.cc b/test/unit/fiber.cc
index dc87e311bf5478cb0f959626cf29470d78d09079..99918c32cc90a6d0eb4b0960416390d543128667 100644
--- a/test/unit/fiber.cc
+++ b/test/unit/fiber.cc
@@ -105,7 +105,7 @@ main_f(va_list ap)
 int main()
 {
 	memory_init();
-	fiber_init();
+	fiber_init(fiber_cxx_invoke);
 	struct fiber *main = fiber_new("main", main_f);
 	fiber_wakeup(main);
 	ev_run(loop(), 0);
diff --git a/test/unit/fiber_stress.cc b/test/unit/fiber_stress.cc
index 2afcb382f30a1e0b2a7f145605784dd909c8a7ff..ed7e4dcd5f408d0b6ee7c0b2cf1e8ce55a9aa8f0 100644
--- a/test/unit/fiber_stress.cc
+++ b/test/unit/fiber_stress.cc
@@ -32,7 +32,7 @@ void benchmark_f(va_list ap)
 int main()
 {
 	memory_init();
-	fiber_init();
+	fiber_init(fiber_cxx_invoke);
 	struct fiber *benchmark = fiber_new("benchmark", benchmark_f);
 	fiber_wakeup(benchmark);
 	ev_run(loop(), 0);
diff --git a/test/unit/ipc.cc b/test/unit/ipc.cc
index c475e84cad8feae43c5db5c149bc126cc3a1b7cd..8d69de03c065d0059d808622ff5630542b3acbf9 100644
--- a/test/unit/ipc.cc
+++ b/test/unit/ipc.cc
@@ -8,7 +8,6 @@ int status;
 void
 ipc_basic()
 {
-
 	header();
 	plan(10);
 
@@ -83,7 +82,7 @@ void main_f(va_list /* ap */)
 int main()
 {
 	memory_init();
-	fiber_init();
+	fiber_init(fiber_c_invoke);
 	struct fiber *main= fiber_new("main", main_f);
 	fiber_wakeup(main);
 	ev_run(loop(), 0);
diff --git a/test/unit/ipc_stress.cc b/test/unit/ipc_stress.cc
index c5812bbf90744b73442b3bea481480c995dea721..78d44fa3fb7ab31186d08dcbe8898af7fd302eb3 100644
--- a/test/unit/ipc_stress.cc
+++ b/test/unit/ipc_stress.cc
@@ -45,7 +45,7 @@ void main_f(va_list ap)
 int main()
 {
 	memory_init();
-	fiber_init();
+	fiber_init(fiber_c_invoke);
 	struct fiber *main= fiber_new("main", main_f);
 	fiber_wakeup(main);
 	ev_run(loop(), 0);
diff --git a/test/unit/rmean.cc b/test/unit/rmean.cc
index 797d12dda10aef4d266869499a747f8a37090605..a2fbb65c1f23678291e23bf69bab075bdcb24a33 100644
--- a/test/unit/rmean.cc
+++ b/test/unit/rmean.cc
@@ -46,7 +46,7 @@ int main()
 	printf("Stat. 2 names, timer simulation\n");
 
 	memory_init();
-	fiber_init();
+	fiber_init(fiber_c_invoke);
 
 	struct rmean *st;
 	const char *name[] = {"EV1", "EV2"};