From b2d0c991b3fb4274b56a2f688c5f9ace0d8a201f Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Wed, 21 Oct 2015 23:31:08 +0300
Subject: [PATCH] arm: fiber.cc -> fiber.c

---
 src/CMakeLists.txt        |  2 +-
 src/cbus.c                |  6 +++-
 src/coio.cc               |  2 +-
 src/coio.h                |  4 +--
 src/exception.cc          | 14 ++++++++
 src/exception.h           | 16 +++++++++
 src/{fiber.cc => fiber.c} | 71 ++++++++++++++++++++++-----------------
 src/fiber.h               | 65 +++++++++++++++++++++--------------
 src/main.cc               |  2 +-
 src/trigger.h             |  8 +++++
 test/unit/coio.cc         |  5 +--
 test/unit/coio.result     |  2 --
 test/unit/fiber.cc        |  2 +-
 test/unit/fiber_stress.cc |  2 +-
 test/unit/ipc.cc          |  3 +-
 test/unit/ipc_stress.cc   |  2 +-
 test/unit/rmean.cc        |  2 +-
 17 files changed, 135 insertions(+), 73 deletions(-)
 rename src/{fiber.cc => fiber.c} (94%)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 22cbcc2c13..312a1da5bf 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 5cb62944e4..04c0e33049 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 7406d3f43c..ac480a63a8 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 f43811c9e1..c27bcf09be 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 0c739b6037..8d242458b6 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 810ecf2f66..04c8a53c89 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 cc1891181e..89d3e31d56 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 5b9655748d..a209e5a479 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 f2007b4af5..ccce27a44d 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 bd67f604d0..51b2506a65 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 aeb1154692..e1f2a6a0ab 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 392e2807f9..b8391a50c6 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 dc87e311bf..99918c32cc 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 2afcb382f3..ed7e4dcd5f 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 c475e84cad..8d69de03c0 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 c5812bbf90..78d44fa3fb 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 797d12dda1..a2fbb65c1f 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"};
-- 
GitLab