diff --git a/lib/core/context.c b/lib/core/context.c
index 1a39b10ab5d4b903634452d2641c2f33c090bbbb..fad0b7d4e24395070f5d4726fe1fc52691cebb26 100644
--- a/lib/core/context.c
+++ b/lib/core/context.c
@@ -1369,7 +1369,7 @@ __lws_vhost_destroy2(struct lws_vhost *vh)
 	 */
 
 	while (vh->timed_vh_protocol_list)
-		lws_timed_callback_remove(vh, vh->timed_vh_protocol_list);
+		__lws_timed_callback_remove(vh, vh->timed_vh_protocol_list);
 
 	/*
 	 * let the protocols destroy the per-vhost protocol objects
diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c
index 0b2a0b5acb0390efec5fc624c91a282b97982358..28323fd58566fa09175fd652f2bc63d9ea78353d 100644
--- a/lib/core/libwebsockets.c
+++ b/lib/core/libwebsockets.c
@@ -120,8 +120,10 @@ lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
 {
 	if (wsi->vhost == vh)
 		return;
+	lws_context_lock(vh->context, __func__); /* ---------- context { */
 	wsi->vhost = vh;
 	vh->count_bound_wsi++;
+	lws_context_unlock(vh->context); /* } context ---------- */
 	lwsl_info("%s: vh %s: count_bound_wsi %d\n",
 		    __func__, vh->name, vh->count_bound_wsi);
 	assert(wsi->vhost->count_bound_wsi > 0);
@@ -487,8 +489,10 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
 	lws_pt_unlock(pt);
 }
 
+/* requires context + vh lock */
+
 int
-lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p)
+__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p)
 {
 	lws_start_foreach_llp(struct lws_timed_vh_protocol **, pt,
 			      vh->timed_vh_protocol_list) {
@@ -503,9 +507,30 @@ lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p)
 	return 1;
 }
 
+int
+lws_pthread_self_to_tsi(struct lws_context *context)
+{
+#if LWS_MAX_SMP > 1
+	pthread_t ps = pthread_self();
+	struct lws_context_per_thread *pt = &context->pt[0];
+	int n;
+
+	for (n = 0; n < context->count_threads; n++) {
+		if (pthread_equal(ps, pt->self))
+			return n;
+		pt++;
+	}
+
+	return -1;
+#else
+	return 0;
+#endif
+}
+
 LWS_VISIBLE LWS_EXTERN int
-lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols *prot,
-			       int reason, int secs)
+lws_timed_callback_vh_protocol(struct lws_vhost *vh,
+			       const struct lws_protocols *prot, int reason,
+			       int secs)
 {
 	struct lws_timed_vh_protocol *p = (struct lws_timed_vh_protocol *)
 			lws_malloc(sizeof(*p), "timed_vh");
@@ -513,12 +538,22 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh, const struct lws_protocols
 	if (!p)
 		return 1;
 
+	p->tsi_req = lws_pthread_self_to_tsi(vh->context);
+	if (p->tsi_req < 0) /* not called from a service thread --> tsi 0 */
+		p->tsi_req = 0;
+
+	lws_context_lock(vh->context, __func__); /* context ----------------- */
+
 	p->protocol = prot;
 	p->reason = reason;
 	p->time = lws_now_secs() + secs;
-	p->next = vh->timed_vh_protocol_list;
 
+	lws_vhost_lock(vh); /* vhost ---------------------------------------- */
+	p->next = vh->timed_vh_protocol_list;
 	vh->timed_vh_protocol_list = p;
+	lws_vhost_unlock(vh); /* -------------------------------------- vhost */
+
+	lws_context_unlock(vh->context); /* ------------------------- context */
 
 	return 0;
 }
diff --git a/lib/core/private.h b/lib/core/private.h
index 857366a6a453926497abbb6f688614b8090ecbde..a5722b890c216216001f853cd4736c6075ab4520 100644
--- a/lib/core/private.h
+++ b/lib/core/private.h
@@ -351,6 +351,7 @@ struct lws_context_per_thread {
 #if LWS_MAX_SMP > 1
 	pthread_mutex_t lock_stats;
 	struct lws_mutex_refcount mr;
+	pthread_t self;
 #endif
 
 	struct lws_context *context;
@@ -445,6 +446,7 @@ struct lws_timed_vh_protocol {
 	struct lws_vhost *vhost; /* only used for pending processing */
 	time_t time;
 	int reason;
+	int tsi_req;
 };
 
 /*
@@ -1097,7 +1099,7 @@ LWS_EXTERN int
 lws_service_flag_pending(struct lws_context *context, int tsi);
 
 LWS_EXTERN int
-lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p);
+__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p);
 
 LWS_EXTERN int LWS_WARN_UNUSED_RESULT
 __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi);
@@ -1437,6 +1439,10 @@ LWS_EXTERN int
 lws_plat_service(struct lws_context *context, int timeout_ms);
 LWS_EXTERN LWS_VISIBLE int
 _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi);
+
+LWS_EXTERN int
+lws_pthread_self_to_tsi(struct lws_context *context);
+
 LWS_EXTERN int
 lws_plat_init(struct lws_context *context,
 	      const struct lws_context_creation_info *info);
diff --git a/lib/core/service.c b/lib/core/service.c
index 00258fa211b392e62a832f9ca0afb1fc4b54a379..065756b15f834ea1349f876ce97a2226a7222461 100644
--- a/lib/core/service.c
+++ b/lib/core/service.c
@@ -658,7 +658,7 @@ lws_service_periodic_checks(struct lws_context *context,
 		our_fd = pollfd->fd;
 
 	/*
-	 * Phase 1: check every wsi on the timeout check list
+	 * Phase 1: check every wsi on our pt's timeout check list
 	 */
 
 	lws_pt_lock(pt, __func__);
@@ -792,7 +792,7 @@ lws_service_periodic_checks(struct lws_context *context,
 
 			lws_start_foreach_ll_safe(struct lws_timed_vh_protocol *,
 					q, v->timed_vh_protocol_list, next) {
-				if (now >= q->time)
+				if (now >= q->time && q->tsi_req == tsi)
 					n++;
 			} lws_end_foreach_ll_safe(q);
 		}
@@ -839,6 +839,8 @@ lws_service_periodic_checks(struct lws_context *context,
 
 		if (v->timed_vh_protocol_list) {
 
+			lws_vhost_lock(v); /* vhost ------------------------- */
+
 			lws_start_foreach_ll_safe(struct lws_timed_vh_protocol *,
 					q, v->timed_vh_protocol_list, next) {
 
@@ -846,7 +848,7 @@ lws_service_periodic_checks(struct lws_context *context,
 				if (m == n)
 					break;
 
-				if (now >= q->time) {
+				if (now >= q->time && q->tsi_req == tsi) {
 
 					/*
 					 * tmr is an allocated array.
@@ -858,10 +860,12 @@ lws_service_periodic_checks(struct lws_context *context,
 
 					/* take the timer out now we took
 					 * responsibility */
-					lws_timed_callback_remove(v, q);
+					__lws_timed_callback_remove(v, q);
 				}
 
 			} lws_end_foreach_ll_safe(q);
+
+			lws_vhost_unlock(v); /* ----------------------- vhost */
 		}
 
 	} lws_end_foreach_ll(v, vhost_next);
@@ -1085,6 +1089,9 @@ lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
 	int n;
 
 	pt->inside_service = 1;
+#if LWS_MAX_SMP > 1
+	pt->self = pthread_self();
+#endif
 
 	if (context->event_loop_ops->run_pt) {
 		/* we are configured for an event loop */
diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c
index 2bd9ab1b21810dfef25590a79c61e23838a324a0..0daf9c6b9079e7873258cff188cf40c3893b98ec 100644
--- a/lib/roles/http/server/server.c
+++ b/lib/roles/http/server/server.c
@@ -697,6 +697,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
 		p = (unsigned char *)args.p;
 	}
 
+	*p = '\0';
 	n = lws_serve_http_file(wsi, path, mimetype, (char *)start,
 				lws_ptr_diff(p, start));
 
@@ -2299,8 +2300,8 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
 
 	/* Only add cache control if its not specified by any other_headers. */
 	if (!other_headers ||
-			(!strstr(other_headers, "cache-control") &&
-			 !strstr(other_headers, "Cache-Control"))) {
+	    (!strstr(other_headers, "cache-control") &&
+	     !strstr(other_headers, "Cache-Control"))) {
 		if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CACHE_CONTROL,
 				(unsigned char *)cc, cclen, &p, end))
 			return -1;
diff --git a/lib/roles/listen/ops-listen.c b/lib/roles/listen/ops-listen.c
index 92f8cd856e374405964012ffadd62bc02d280f89..977c4b0377b41b7e9305caad4805cffefd207970 100644
--- a/lib/roles/listen/ops-listen.c
+++ b/lib/roles/listen/ops-listen.c
@@ -79,8 +79,8 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
 		 * block the connect queue for other legit peers.
 		 */
 
-		accept_fd  = accept((int)pollfd->fd,
-				    (struct sockaddr *)&cli_addr, &clilen);
+		accept_fd = accept((int)pollfd->fd,
+				   (struct sockaddr *)&cli_addr, &clilen);
 		lws_latency(context, wsi, "listener accept",
 			    (int)accept_fd, accept_fd != LWS_SOCK_INVALID);
 		if (accept_fd == LWS_SOCK_INVALID) {
@@ -88,9 +88,8 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
 			    LWS_ERRNO == LWS_EWOULDBLOCK) {
 				break;
 			}
-			lwsl_err("ERROR on accept: %s\n",
-				 strerror(LWS_ERRNO));
-			break;
+			lwsl_err("accept: %s\n", strerror(LWS_ERRNO));
+			return LWS_HPI_RET_HANDLED;
 		}
 
 		lws_plat_set_socket_options(wsi->vhost, accept_fd, 0);
@@ -130,9 +129,12 @@ rops_handle_POLLIN_listen(struct lws_context_per_thread *pt, struct lws *wsi,
 		fd.sockfd = accept_fd;
 		cwsi = lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
 						  NULL, NULL);
-		if (!cwsi)
+		if (!cwsi) {
+			lwsl_err("%s: lws_adopt_descriptor_vhost failed\n",
+					__func__);
 			/* already closed cleanly as necessary */
 			return LWS_HPI_RET_WSI_ALREADY_DIED;
+		}
 
 		if (lws_server_socket_service_ssl(cwsi, accept_fd)) {
 			lws_close_free_wsi(cwsi, LWS_CLOSE_STATUS_NOSTATUS,