diff --git a/CMakeLists.txt b/CMakeLists.txt
index e0ecf4fdef18764118882f8d5f344d2d1ce11a6c..2428e35b126914879eef294e6367974fe4ed23cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,6 +55,7 @@ include(cmake/FindReadline.cmake)
 include(cmake/FindSphinx.cmake)
 include(cmake/systemd.cmake)
 include(cmake/module.cmake)
+include(cmake/thread.cmake)
 
 if (NOT READLINE_FOUND)
     message(FATAL_ERROR "readline library not found.")
diff --git a/cmake/BuildLibEIO.cmake b/cmake/BuildLibEIO.cmake
index 3f4c59a924f242d9e8f7920e53ee3a7efa4ba5aa..48e7582e5a994bcb55232ace7f1d2a573450b520 100644
--- a/cmake/BuildLibEIO.cmake
+++ b/cmake/BuildLibEIO.cmake
@@ -8,6 +8,10 @@ macro(libeio_build)
     set(eio_compile_flags "${eio_compile_flags} -Wno-unused-value")
     set(eio_compile_flags "${eio_compile_flags} -DENABLE_BUNDLED_LIBEIO=1")
     set(eio_compile_flags "${eio_compile_flags} -DEIO_STACKSIZE=0")
+    if (TARGET_OS_LINUX)
+        set(eio_compile_flags
+            "${eio_compile_flags} -DHAVE_SYS_PRCTL_H -DHAVE_PRCTL_SET_NAME")
+    endif ()
 
     set(eio_src
         ${PROJECT_SOURCE_DIR}/third_party/tarantool_eio.c
diff --git a/cmake/BuildLibEV.cmake b/cmake/BuildLibEV.cmake
index c9e3a90bdce956dabcd346e6e233f4b70e2d4d34..f8216991c0f20af65989f3dac38d894fb9024546 100644
--- a/cmake/BuildLibEV.cmake
+++ b/cmake/BuildLibEV.cmake
@@ -29,6 +29,8 @@ macro(libev_build)
         #
         # Enable Linux-specific event notification API (man inotify)
         set(ev_compile_flags "${ev_compile_flags} -DEV_USE_INOTIFY")
+        set(ev_compile_flags "${ev_compile_flags} -DEV_USE_EVENTFD")
+        set(ev_compile_flags "${ev_compile_flags} -DEV_USE_SIGNALFD")
     elseif (TARGET_OS_FREEBSD OR TARGET_OS_DARWIN)
         #
         # On FreeBSD build libev loop on top of
diff --git a/cmake/thread.cmake b/cmake/thread.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..9febca8fae90c35b2cea72c4cce1fd21feb42e25
--- /dev/null
+++ b/cmake/thread.cmake
@@ -0,0 +1,36 @@
+#
+# Doing it in a function to avoid polluting the toplevel namespace
+function (do_pthread_checks)
+    check_include_file(pthread_np.h HAVE_PTHREAD_NP_H)
+    if (HAVE_PTHREAD_NP_H)
+        set(INCLUDE_MISC_PTHREAD_HEADERS "#include <pthread_np.h>")
+    endif ()
+    set(CMAKE_REQUIRED_FLAGS -pedantic-errors)
+    set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE -D_DARWIN_C_SOURCE)
+    set(CMAKE_REQUIRED_LIBRARIES pthread)
+    # pthread_setname_np(<thread_id>, <name>) - Linux
+    check_c_source_compiles("
+        #include <pthread.h>
+        ${INCLUDE_MISC_PTHREAD_HEADERS}
+        int main() { pthread_setname_np(pthread_self(), \"\"); }
+        " HAVE_PTHREAD_SETNAME_NP)
+    # pthread_setname_np(<name>) - OSX
+    check_c_source_compiles("
+        #include <pthread.h>
+        ${INCLUDE_MISC_PTHREAD_HEADERS}
+        int main() { pthread_setname_np(\"\"); }
+        " HAVE_PTHREAD_SETNAME_NP_1)
+    # pthread_set_name_np(<thread_id>, <name>) - *BSD
+    check_c_source_compiles("
+        #include <pthread.h>
+        ${INCLUDE_MISC_PTHREAD_HEADERS}
+        int main() { pthread_set_name_np(pthread_self(), \"\"); }
+        " HAVE_PTHREAD_SET_NAME_NP)
+    if (NOT (HAVE_PTHREAD_SETNAME_NP OR
+             HAVE_PTHREAD_SETNAME_NP_1 OR
+             HAVE_PTHREAD_SET_NAME_NP))
+        message(FATAL_ERROR "No suitable function for setting thread names found")
+    endif ()
+endfunction (do_pthread_checks)
+do_pthread_checks()
+
diff --git a/src/fiber.cc b/src/fiber.cc
index ea0fccaeb5ec2dd650adc1572bf6cbd31c0a689c..2d8a8a6f56b49c8a808387783a781269f1ad7314 100644
--- a/src/fiber.cc
+++ b/src/fiber.cc
@@ -583,9 +583,11 @@ fiber_destroy_all(struct cord *cord)
 		fiber_destroy(cord, f);
 }
 
-void
-cord_create(struct cord *cord, const char *name)
+static void
+cord_init(const char *name)
 {
+	struct cord *cord = cord();
+
 	cord->id = pthread_self();
 	cord->on_exit = NULL;
 	cord->loop = cord->id == main_thread_id ?
@@ -613,10 +615,10 @@ cord_create(struct cord *cord, const char *name)
 	ev_async_start(cord->loop, &cord->wakeup_event);
 
 	ev_idle_init(&cord->idle_event, fiber_schedule_idle);
-	snprintf(cord->name, sizeof(cord->name), "%s", name);
+	cord_set_name(name);
 }
 
-void
+static void
 cord_destroy(struct cord *cord)
 {
 	slab_cache_set_thread(&cord->slabc);
@@ -649,7 +651,7 @@ void *cord_thread_func(void *p)
 	cord() = ct_arg->cord;
 	slab_cache_set_thread(&cord()->slabc);
 	struct cord *cord = cord();
-	cord_create(cord, ct_arg->name);
+	cord_init(ct_arg->name);
 	/** Can't possibly be the main thread */
 	assert(cord->id != main_thread_id);
 	tt_pthread_mutex_lock(&ct_arg->start_mutex);
@@ -879,6 +881,16 @@ cord_costart(struct cord *cord, const char *name, fiber_func f, void *arg)
 	return 0;
 }
 
+void
+cord_set_name(const char *name)
+{
+	snprintf(cord()->name, sizeof cord()->name, "%s", name);
+	/* Main thread's name will replace process title in ps, skip it */
+	if (cord_is_main())
+		return;
+	tt_pthread_setname(name);
+}
+
 bool
 cord_is_main()
 {
@@ -890,13 +902,13 @@ fiber_init(void)
 {
 	main_thread_id = pthread_self();
 	cord() = &main_cord;
-	cord_create(cord(), "main");
+	cord_init("main");
 }
 
 void
 fiber_free(void)
 {
-	cord_destroy(cord());
+	cord_destroy(&main_cord);
 }
 
 int fiber_stat(fiber_stat_cb cb, void *cb_ctx)
diff --git a/src/fiber.h b/src/fiber.h
index d8f26fb6fd669df799fec833b02077f29109b046..0d51e9088743708c8b3df6174d50dc3ee3ec3ffa 100644
--- a/src/fiber.h
+++ b/src/fiber.h
@@ -263,14 +263,8 @@ cord_costart(struct cord *cord, const char *name, fiber_func f, void *arg);
 int
 cord_join(struct cord *cord);
 
-static inline void
-cord_set_name(const char *name)
-{
-	snprintf(cord()->name, FIBER_NAME_MAX, "%s", name);
-}
-
 void
-cord_destroy(struct cord *cord);
+cord_set_name(const char *name);
 
 /** True if this cord represents the process main thread. */
 bool
diff --git a/src/trivia/config.h.cmake b/src/trivia/config.h.cmake
index b8faa6f4bbcb184e341e24741038eb3bdc19443d..a2f27c96822683a1c9a75543a9e7478800adc629 100644
--- a/src/trivia/config.h.cmake
+++ b/src/trivia/config.h.cmake
@@ -183,6 +183,15 @@
 #cmakedefine HAVE_UUIDGEN 1
 #cmakedefine HAVE_CLOCK_GETTIME 1
 
+/** pthread_np.h - non-portable stuff */
+#cmakedefine HAVE_PTHREAD_NP_H 1
+/** pthread_setname_np(pthread_self(), "") - Linux */
+#cmakedefine HAVE_PTHREAD_SETNAME_NP 1
+/** pthread_setname_np("") - OSX */
+#cmakedefine HAVE_PTHREAD_SETNAME_NP_1 1
+/** pthread_set_name_np(pthread_self(), "") - *BSD */
+#cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
+
 /** \cond public */
 
 /** System configuration dir (e.g /etc) */
diff --git a/src/tt_pthread.h b/src/tt_pthread.h
index e37a6e6e9f1bda106ad6e05ccd0d531161ef4466..f5d7b571676e5d57834cb5c0b084da4ddbc464da 100644
--- a/src/tt_pthread.h
+++ b/src/tt_pthread.h
@@ -34,7 +34,11 @@
 #include "trivia/config.h"
 #include "trivia/util.h"
 
+#include <stdio.h>
 #include <pthread.h>
+#if HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
 #include "say.h"
 
 /**
@@ -177,4 +181,25 @@
 	tt_pthread_error(e);				\
 })
 
+/** Set the current thread's name
+ */
+static inline void
+tt_pthread_setname(const char *name)
+{
+	/* Setting the name fails if the name was too long. Linux limits a
+	 * name to 16 bytes (including the trailing NUL), other OS don't
+	 * even bother to document the limit.
+	 */
+	char short_name[16];
+	snprintf(short_name, sizeof name, "%s", name);
+
+#if HAVE_PTHREAD_SETNAME_NP
+	pthread_setname_np(pthread_self(), short_name);
+#elif HAVE_PTHREAD_SETNAME_NP_1
+	pthread_setname_np(short_name);
+#elif HAVE_PTHREAD_SET_NAME_NP
+	pthread_set_name_np(pthread_self(), short_name);
+#endif
+}
+
 #endif /* TARANTOOL_PTHREAD_H_INCLUDED */
diff --git a/third_party/tarantool_ev.h b/third_party/tarantool_ev.h
index 0b1556efcf5df3ce12ee1f49cabfbd639e6f3ec0..639dd0eca1f3654f9125dc8f32862400b08d2b9b 100644
--- a/third_party/tarantool_ev.h
+++ b/third_party/tarantool_ev.h
@@ -43,11 +43,13 @@
 #define EV_USE_POLL 1
 #define EV_USE_NANOSLEEP 1
 #define EV_USE_REALTIME 1
+#define EV_USE_MONOTONIC 1
 #define EV_PERIODIC_ENABLE 1
 #define EV_IDLE_ENABLE 1
 #define EV_STAT_ENABLE 1
 #define EV_FORK_ENABLE 1
 #define EV_CONFIG_H 0
+#define EV_USE_FLOOR 1
 #include "third_party/libev/ev.h"
 #else /* !defined(ENABLE_BUNDLED_LIBEV) */
 #include <ev.h>