Index: uspace/app/vlaunch/vlaunch.c
===================================================================
--- uspace/app/vlaunch/vlaunch.c	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/app/vlaunch/vlaunch.c	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -200,5 +200,5 @@
 	}
 	
-	timer = fibril_timer_create();
+	timer = fibril_timer_create(NULL);
 	if (!timer) {
 		printf("Unable to create timer.\n");
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/lib/c/generic/fibril_synch.c	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -448,5 +448,5 @@
 	int rc;
 
-	fibril_mutex_lock(&timer->lock);
+	fibril_mutex_lock(timer->lockp);
 
 	while (timer->state != fts_cleanup) {
@@ -454,14 +454,16 @@
 		case fts_not_set:
 		case fts_fired:
-			fibril_condvar_wait(&timer->cv, &timer->lock);
+			fibril_condvar_wait(&timer->cv, timer->lockp);
 			break;
 		case fts_active:
 			rc = fibril_condvar_wait_timeout(&timer->cv,
-			    &timer->lock, timer->delay);
+			    timer->lockp, timer->delay);
 			if (rc == ETIMEOUT && timer->state == fts_active) {
 				timer->state = fts_fired;
-				fibril_mutex_unlock(&timer->lock);
+				timer->handler_running = true;
+				fibril_mutex_unlock(timer->lockp);
 				timer->fun(timer->arg);
-				fibril_mutex_lock(&timer->lock);
+				fibril_mutex_lock(timer->lockp);
+				timer->handler_running = false;
 			}
 			break;
@@ -475,6 +477,6 @@
 	/* Acknowledge timer fibril has finished cleanup. */
 	timer->state = fts_clean;
-	fibril_condvar_broadcast(&timer->cv);
-	fibril_mutex_unlock(&timer->lock);
+	fibril_mutex_unlock(timer->lockp);
+	free(timer);
 
 	return 0;
@@ -485,5 +487,5 @@
  * @return		New timer on success, @c NULL if out of memory.
  */
-fibril_timer_t *fibril_timer_create(void)
+fibril_timer_t *fibril_timer_create(fibril_mutex_t *lock)
 {
 	fid_t fid;
@@ -505,7 +507,7 @@
 	timer->fibril = fid;
 	timer->state = fts_not_set;
+	timer->lockp = (lock != NULL) ? lock : &timer->lock;
 
 	fibril_add_ready(fid);
-
 	return timer;
 }
@@ -517,5 +519,5 @@
 void fibril_timer_destroy(fibril_timer_t *timer)
 {
-	fibril_mutex_lock(&timer->lock);
+	fibril_mutex_lock(timer->lockp);
 	assert(timer->state == fts_not_set || timer->state == fts_fired);
 
@@ -523,10 +525,5 @@
 	timer->state = fts_cleanup;
 	fibril_condvar_broadcast(&timer->cv);
-
-	/* Wait for timer fibril to acknowledge. */
-	while (timer->state != fts_clean)
-		fibril_condvar_wait(&timer->cv, &timer->lock);
-
-	fibril_mutex_unlock(&timer->lock);
+	fibril_mutex_unlock(timer->lockp);
 }
 
@@ -544,5 +541,23 @@
     fibril_timer_fun_t fun, void *arg)
 {
-	fibril_mutex_lock(&timer->lock);
+	fibril_mutex_lock(timer->lockp);
+	fibril_timer_set_locked(timer, delay, fun, arg);
+	fibril_mutex_unlock(timer->lockp);
+}
+
+/** Set locked timer.
+ *
+ * Set timer to execute a callback function after the specified
+ * interval. Must be called when the timer is locked.
+ *
+ * @param timer		Timer
+ * @param delay		Delay in microseconds
+ * @param fun		Callback function
+ * @param arg		Argument for @a fun
+ */
+void fibril_timer_set_locked(fibril_timer_t *timer, suseconds_t delay,
+    fibril_timer_fun_t fun, void *arg)
+{
+	assert(fibril_mutex_is_locked(timer->lockp));
 	assert(timer->state == fts_not_set || timer->state == fts_fired);
 	timer->state = fts_active;
@@ -551,5 +566,4 @@
 	timer->arg = arg;
 	fibril_condvar_broadcast(&timer->cv);
-	fibril_mutex_unlock(&timer->lock);
 }
 
@@ -569,5 +583,32 @@
 	fibril_timer_state_t old_state;
 
-	fibril_mutex_lock(&timer->lock);
+	fibril_mutex_lock(timer->lockp);
+	old_state = fibril_timer_clear_locked(timer);
+	fibril_mutex_unlock(timer->lockp);
+
+	return old_state;
+}
+
+/** Clear locked timer.
+ *
+ * Clears (cancels) timer and returns last state of the timer.
+ * This can be one of:
+ *    - fts_not_set	If the timer has not been set or has been cleared
+ *    - fts_active	Timer was set but did not fire
+ *    - fts_fired	Timer fired
+ * Must be called when the timer is locked.
+ *
+ * @param timer		Timer
+ * @return		Last timer state
+ */
+fibril_timer_state_t fibril_timer_clear_locked(fibril_timer_t *timer)
+{
+	fibril_timer_state_t old_state;
+
+	assert(fibril_mutex_is_locked(timer->lockp));
+
+	while (timer->handler_running)
+		fibril_condvar_wait(&timer->cv, timer->lockp);
+
 	old_state = timer->state;
 	timer->state = fts_not_set;
@@ -577,5 +618,4 @@
 	timer->arg = NULL;
 	fibril_condvar_broadcast(&timer->cv);
-	fibril_mutex_unlock(&timer->lock);
 
 	return old_state;
Index: uspace/lib/c/include/fibril_synch.h
===================================================================
--- uspace/lib/c/include/fibril_synch.h	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/lib/c/include/fibril_synch.h	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -131,7 +131,9 @@
 typedef struct {
 	fibril_mutex_t lock;
+	fibril_mutex_t *lockp;
 	fibril_condvar_t cv;
 	fid_t fibril;
 	fibril_timer_state_t state;
+	bool handler_running;
 
 	suseconds_t delay;
@@ -162,9 +164,12 @@
 extern void fibril_condvar_broadcast(fibril_condvar_t *);
 
-extern fibril_timer_t *fibril_timer_create(void);
+extern fibril_timer_t *fibril_timer_create(fibril_mutex_t *);
 extern void fibril_timer_destroy(fibril_timer_t *);
 extern void fibril_timer_set(fibril_timer_t *, suseconds_t, fibril_timer_fun_t,
     void *);
+extern void fibril_timer_set_locked(fibril_timer_t *, suseconds_t,
+    fibril_timer_fun_t, void *);
 extern fibril_timer_state_t fibril_timer_clear(fibril_timer_t *);
+extern fibril_timer_state_t fibril_timer_clear_locked(fibril_timer_t *);
 
 #endif
Index: uspace/srv/net/dhcp/dhcp.c
===================================================================
--- uspace/srv/net/dhcp/dhcp.c	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/srv/net/dhcp/dhcp.c	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -436,5 +436,5 @@
 
 	dlink->link_id = link_id;
-	dlink->timeout = fibril_timer_create();
+	dlink->timeout = fibril_timer_create(NULL);
 	if (dlink->timeout == NULL) {
 		rc = ENOMEM;
Index: uspace/srv/net/tcp/conn.c
===================================================================
--- uspace/srv/net/tcp/conn.c	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/srv/net/tcp/conn.c	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -78,9 +78,9 @@
 		goto error;
 
-	conn->tw_timer = fibril_timer_create();
+	fibril_mutex_initialize(&conn->lock);
+
+	conn->tw_timer = fibril_timer_create(&conn->lock);
 	if (conn->tw_timer == NULL)
 		goto error;
-
-	fibril_mutex_initialize(&conn->lock);
 
 	/* One for the user, one for not being in closed state */
@@ -200,4 +200,27 @@
 	if (atomic_predec(&conn->refcnt) == 0)
 		tcp_conn_free(conn);
+}
+
+/** Lock connection.
+ *
+ * Must be called before any other connection-manipulating function,
+ * except tcp_conn_{add|del}ref(). Locks the connection including
+ * its timers. Must not be called inside any of the connection
+ * timer handlers.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_lock(tcp_conn_t *conn)
+{
+	fibril_mutex_lock(&conn->lock);
+}
+
+/** Unlock connection.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_unlock(tcp_conn_t *conn)
+{
+	fibril_mutex_unlock(&conn->lock);
 }
 
@@ -1183,9 +1206,9 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p)", conn);
 
-	fibril_mutex_lock(&conn->lock);
+	tcp_conn_lock(conn);
 
 	if (conn->cstate == st_closed) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		tcp_conn_delref(conn);
 		return;
@@ -1196,6 +1219,8 @@
 	tcp_conn_state_set(conn, st_closed);
 
-	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_unlock(conn);
 	tcp_conn_delref(conn);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p) end", conn);
 }
 
@@ -1206,7 +1231,9 @@
 void tcp_conn_tw_timer_set(tcp_conn_t *conn)
 {
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_set() begin");
 	tcp_conn_addref(conn);
-	fibril_timer_set(conn->tw_timer, TIME_WAIT_TIMEOUT, tw_timeout_func,
-	    (void *)conn);
+	fibril_timer_set_locked(conn->tw_timer, TIME_WAIT_TIMEOUT,
+	    tw_timeout_func, (void *)conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_set() end");
 }
 
@@ -1217,6 +1244,8 @@
 void tcp_conn_tw_timer_clear(tcp_conn_t *conn)
 {
-	if (fibril_timer_clear(conn->tw_timer) == fts_active)
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_clear() begin");
+	if (fibril_timer_clear_locked(conn->tw_timer) == fts_active)
 		tcp_conn_delref(conn);
+	log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_clear() end");
 }
 
Index: uspace/srv/net/tcp/conn.h
===================================================================
--- uspace/srv/net/tcp/conn.h	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/srv/net/tcp/conn.h	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -50,4 +50,6 @@
 extern void tcp_conn_addref(tcp_conn_t *);
 extern void tcp_conn_delref(tcp_conn_t *);
+extern void tcp_conn_lock(tcp_conn_t *);
+extern void tcp_conn_unlock(tcp_conn_t *);
 extern bool tcp_conn_got_syn(tcp_conn_t *);
 extern void tcp_conn_segment_arrived(tcp_conn_t *, tcp_segment_t *);
Index: uspace/srv/net/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tcp/tqueue.c	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/srv/net/tcp/tqueue.c	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -59,8 +59,10 @@
 static void tcp_tqueue_timer_clear(tcp_conn_t *conn);
 
+#include <stdio.h>
 int tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
 {
+	printf("tcp_tqueue_init\n");
 	tqueue->conn = conn;
-	tqueue->timer = fibril_timer_create();
+	tqueue->timer = fibril_timer_create(&conn->lock);
 	if (tqueue->timer == NULL)
 		return ENOMEM;
@@ -78,4 +80,5 @@
 void tcp_tqueue_fini(tcp_tqueue_t *tqueue)
 {
+	printf("tcp_tqueue_fini\n");
 	if (tqueue->timer != NULL) {
 		fibril_timer_destroy(tqueue->timer);
@@ -319,9 +322,9 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
 
-	fibril_mutex_lock(&conn->lock);
+	tcp_conn_lock(conn);
 
 	if (conn->cstate == st_closed) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		tcp_conn_delref(conn);
 		return;
@@ -331,5 +334,5 @@
 	if (link == NULL) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "Nothing to retransmit");
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		tcp_conn_delref(conn);
 		return;
@@ -341,5 +344,5 @@
 	if (rt_seg == NULL) {
 		log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed.");
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		tcp_conn_delref(conn);
 		/* XXX Handle properly */
@@ -353,6 +356,8 @@
 	tcp_tqueue_timer_set(tqe->conn);
 
-	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_unlock(conn);
 	tcp_conn_delref(conn);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: retransmit_timeout_func(%p) end", conn->name, conn);
 }
 
@@ -360,5 +365,5 @@
 static void tcp_tqueue_timer_set(tcp_conn_t *conn)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_set() begin", conn->name);
 
 	/* Clear first to make sure we update refcnt correctly */
@@ -366,6 +371,8 @@
 
 	tcp_conn_addref(conn);
-	fibril_timer_set(conn->retransmit.timer, RETRANSMIT_TIMEOUT,
+	fibril_timer_set_locked(conn->retransmit.timer, RETRANSMIT_TIMEOUT,
 	    retransmit_timeout_func, (void *) conn);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_set() end", conn->name);
 }
 
@@ -373,8 +380,10 @@
 static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
 {
-	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
-
-	if (fibril_timer_clear(conn->retransmit.timer) == fts_active)
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_clear() begin", conn->name);
+
+	if (fibril_timer_clear_locked(conn->retransmit.timer) == fts_active)
 		tcp_conn_delref(conn);
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "### %s: tcp_tqueue_timer_clear() end", conn->name);
 }
 
Index: uspace/srv/net/tcp/ucall.c
===================================================================
--- uspace/srv/net/tcp/ucall.c	(revision c1b979a5a2332e971f29013cd230bf1a1c6f35d4)
+++ uspace/srv/net/tcp/ucall.c	(revision 78192cc76cb5a03ba9516217419bd93b085f9b93)
@@ -90,5 +90,5 @@
 	/* Wait for connection to be established or reset */
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Wait for connection.");
-	fibril_mutex_lock(&nconn->lock);
+	tcp_conn_lock(nconn);
 	while (nconn->cstate == st_listen ||
 	    nconn->cstate == st_syn_sent ||
@@ -100,9 +100,9 @@
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was reset.");
 		assert(nconn->cstate == st_closed);
-		fibril_mutex_unlock(&nconn->lock);
+		tcp_conn_unlock(nconn);
 		return TCP_ERESET;
 	}
 
-	fibril_mutex_unlock(&nconn->lock);
+	tcp_conn_unlock(nconn);
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_open: Connection was established.");
 
@@ -121,8 +121,8 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
 
-	fibril_mutex_lock(&conn->lock);
+	tcp_conn_lock(conn);
 
 	if (conn->cstate == st_closed) {
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		return TCP_ENOTEXIST;
 	}
@@ -135,5 +135,5 @@
 
 	if (conn->snd_buf_fin) {
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		return TCP_ECLOSING;
 	}
@@ -149,5 +149,5 @@
 
 		if (conn->reset) {
-			fibril_mutex_unlock(&conn->lock);
+			tcp_conn_unlock(conn);
 			return TCP_ERESET;
 		}
@@ -165,5 +165,5 @@
 
 	tcp_tqueue_new_data(conn);
-	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_unlock(conn);
 
 	return TCP_EOK;
@@ -178,8 +178,8 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
 
-	fibril_mutex_lock(&conn->lock);
+	tcp_conn_lock(conn);
 
 	if (conn->cstate == st_closed) {
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		return TCP_ENOTEXIST;
 	}
@@ -197,10 +197,10 @@
 		if (conn->rcv_buf_fin) {
 			/* End of data, peer closed connection */
-			fibril_mutex_unlock(&conn->lock);
+			tcp_conn_unlock(conn);
 			return TCP_ECLOSING;
 		} else {
 			/* Connection was reset */
 			assert(conn->reset);
-			fibril_mutex_unlock(&conn->lock);
+			tcp_conn_unlock(conn);
 			return TCP_ERESET;
 		}
@@ -227,5 +227,5 @@
 	    conn->name, xfer_size);
 
-	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_unlock(conn);
 
 	return TCP_EOK;
@@ -238,9 +238,9 @@
 	    conn);
 
-	fibril_mutex_lock(&conn->lock);
+	tcp_conn_lock(conn);
 
 	if (conn->cstate == st_closed) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_close - ENOTEXIST");
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		return TCP_ENOTEXIST;
 	}
@@ -250,4 +250,5 @@
 		tcp_conn_reset(conn);
 		tcp_conn_remove(conn);
+		tcp_conn_unlock(conn);
 		return TCP_EOK;
 	}
@@ -255,5 +256,5 @@
 	if (conn->snd_buf_fin) {
 		log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_uc_close - ECLOSING");
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		return TCP_ECLOSING;
 	}
@@ -263,5 +264,5 @@
 	tcp_tqueue_new_data(conn);
 
-	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_unlock(conn);
 	return TCP_EOK;
 }
@@ -321,10 +322,10 @@
 	}
 
-	fibril_mutex_lock(&conn->lock);
+	tcp_conn_lock(conn);
 
 	if (conn->cstate == st_closed) {
 		log_msg(LOG_DEFAULT, LVL_WARN, "Connection is closed.");
 		tcp_unexpected_segment(sp, seg);
-		fibril_mutex_unlock(&conn->lock);
+		tcp_conn_unlock(conn);
 		tcp_conn_delref(conn);
 		return;
@@ -342,5 +343,5 @@
 	tcp_conn_segment_arrived(conn, seg);
 
-	fibril_mutex_unlock(&conn->lock);
+	tcp_conn_unlock(conn);
 	tcp_conn_delref(conn);
 }
