Bug 1400563 - timer deadlock fix r=drno,dminor
authorNico Grunbaum <na-g@nostrum.com>
Tue, 23 Apr 2019 05:32:57 +0000
changeset 530177 34d3173eb662ec893d94f1a0f45d1b98ea0068cd
parent 530176 537eef35789de0383a14029e44b3f7eec5fe993a
child 530178 e980a61a57d13ac9d17bf3de66fcd69bf21765ea
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdrno, dminor
bugs1400563
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1400563 - timer deadlock fix r=drno,dminor timer deadlock fix Differential Revision: https://phabricator.services.mozilla.com/D28087
netwerk/sctp/src/netinet/sctp_callout.c
netwerk/sctp/src/netinet/sctp_callout.h
netwerk/sctp/src/netinet/sctp_indata.c
netwerk/sctp/src/netinet/sctp_os_userspace.h
netwerk/sctp/src/netinet/sctp_pcb.c
netwerk/sctp/src/netinet/sctp_ss_functions.c
netwerk/sctp/src/netinet/sctp_userspace.c
netwerk/sctp/src/netinet/sctp_usrreq.c
--- a/netwerk/sctp/src/netinet/sctp_callout.c
+++ b/netwerk/sctp/src/netinet/sctp_callout.c
@@ -71,18 +71,37 @@ int sctp_get_tick_count(void) {
 	SCTP_TIMERQ_UNLOCK();
 	return ret;
 }
 
 /*
  * SCTP_TIMERQ_LOCK protects:
  * - SCTP_BASE_INFO(callqueue)
  * - sctp_os_timer_next: next timer to check
+ * - sctp_os_timer_current: current callout callback in progress
+ * - sctp_os_timer_current_tid: current callout thread id in progress
+ * - sctp_os_timer_waiting: some thread is waiting for callout to complete
+ * - sctp_os_timer_wait_ctr: incremented every time a thread wants to wait
+ *                           for a callout to complete.
  */
 static sctp_os_timer_t *sctp_os_timer_next = NULL;
+static sctp_os_timer_t *sctp_os_timer_current = NULL;
+static int sctp_os_timer_waiting = 0;
+static int sctp_os_timer_wait_ctr = 0;
+static userland_thread_id_t sctp_os_timer_current_tid;
+
+/*
+ * SCTP_TIMERWAIT_LOCK (sctp_os_timerwait_mtx) protects:
+ * - sctp_os_timer_wait_cond: waiting for callout to complete
+ * - sctp_os_timer_done_ctr: value of "wait_ctr" after triggering "waiting"
+ */
+userland_mutex_t sctp_os_timerwait_mtx;
+static userland_cond_t sctp_os_timer_wait_cond;
+static int sctp_os_timer_done_ctr = 0;
+
 
 void
 sctp_os_timer_init(sctp_os_timer_t *c)
 {
 	memset(c, 0, sizeof(*c));
 }
 
 void
@@ -90,16 +109,31 @@ sctp_os_timer_start(sctp_os_timer_t *c, 
                     void *arg)
 {
 	/* paranoia */
 	if ((c == NULL) || (ftn == NULL))
 	    return;
 
 	SCTP_TIMERQ_LOCK();
 	/* check to see if we're rescheduling a timer */
+	if (c == sctp_os_timer_current) {
+		/*
+		 * We're being asked to reschedule a callout which is
+		 * currently in progress.
+		 */
+		if (sctp_os_timer_waiting) {
+			/*
+			 * This callout is already being stopped.
+			 * callout.  Don't reschedule.
+			 */
+			SCTP_TIMERQ_UNLOCK();
+			return;
+		}
+	}
+
 	if (c->c_flags & SCTP_CALLOUT_PENDING) {
 		if (c == sctp_os_timer_next) {
 			sctp_os_timer_next = TAILQ_NEXT(c, tqe);
 		}
 		TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
 		/*
 		 * part of the normal "stop a pending callout" process
 		 * is to clear the CALLOUT_ACTIVE and CALLOUT_PENDING
@@ -121,23 +155,61 @@ sctp_os_timer_start(sctp_os_timer_t *c, 
 	c->c_time = ticks + to_ticks;
 	TAILQ_INSERT_TAIL(&SCTP_BASE_INFO(callqueue), c, tqe);
 	SCTP_TIMERQ_UNLOCK();
 }
 
 int
 sctp_os_timer_stop(sctp_os_timer_t *c)
 {
+	int wakeup_cookie;
+
 	SCTP_TIMERQ_LOCK();
 	/*
 	 * Don't attempt to delete a callout that's not on the queue.
 	 */
 	if (!(c->c_flags & SCTP_CALLOUT_PENDING)) {
 		c->c_flags &= ~SCTP_CALLOUT_ACTIVE;
-		SCTP_TIMERQ_UNLOCK();
+		if (sctp_os_timer_current != c) {
+			SCTP_TIMERQ_UNLOCK();
+			return (0);
+		} else {
+			/*
+			 * Deleting the callout from the currently running
+			 * callout from the same thread, so just return
+			 */
+			userland_thread_id_t tid;
+			sctp_userspace_thread_id(&tid);
+			if (sctp_userspace_thread_equal(tid,
+						sctp_os_timer_current_tid)) {
+				SCTP_TIMERQ_UNLOCK();
+				return (0);
+			}
+
+			/* need to wait until the callout is finished */
+			sctp_os_timer_waiting = 1;
+			wakeup_cookie = ++sctp_os_timer_wait_ctr;
+			SCTP_TIMERQ_UNLOCK();
+			SCTP_TIMERWAIT_LOCK();
+			/*
+			 * wait only if sctp_handle_tick didn't do a wakeup
+			 * in between the lock dance
+			 */
+			if (wakeup_cookie - sctp_os_timer_done_ctr > 0) {
+#if defined (__Userspace_os_Windows)
+				SleepConditionVariableCS(&sctp_os_timer_wait_cond,
+							 &sctp_os_timerwait_mtx,
+							 INFINITE);
+#else
+				pthread_cond_wait(&sctp_os_timer_wait_cond,
+						  &sctp_os_timerwait_mtx);
+#endif
+			}
+			SCTP_TIMERWAIT_UNLOCK();
+		}
 		return (0);
 	}
 	c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
 	if (c == sctp_os_timer_next) {
 		sctp_os_timer_next = TAILQ_NEXT(c, tqe);
 	}
 	TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
 	SCTP_TIMERQ_UNLOCK();
@@ -145,31 +217,49 @@ sctp_os_timer_stop(sctp_os_timer_t *c)
 }
 
 static void
 sctp_handle_tick(int delta)
 {
 	sctp_os_timer_t *c;
 	void (*c_func)(void *);
 	void *c_arg;
+	int wakeup_cookie;
 
 	SCTP_TIMERQ_LOCK();
 	/* update our tick count */
 	ticks += delta;
 	c = TAILQ_FIRST(&SCTP_BASE_INFO(callqueue));
 	while (c) {
 		if (c->c_time <= ticks) {
 			sctp_os_timer_next = TAILQ_NEXT(c, tqe);
 			TAILQ_REMOVE(&SCTP_BASE_INFO(callqueue), c, tqe);
 			c_func = c->c_func;
 			c_arg = c->c_arg;
 			c->c_flags &= ~SCTP_CALLOUT_PENDING;
+			sctp_os_timer_current = c;
+			sctp_userspace_thread_id(&sctp_os_timer_current_tid);
 			SCTP_TIMERQ_UNLOCK();
 			c_func(c_arg);
 			SCTP_TIMERQ_LOCK();
+			sctp_os_timer_current = NULL;
+			if (sctp_os_timer_waiting) {
+				wakeup_cookie = sctp_os_timer_wait_ctr;
+				SCTP_TIMERQ_UNLOCK();
+				SCTP_TIMERWAIT_LOCK();
+#if defined (__Userspace_os_Windows)
+				WakeAllConditionVariable(&sctp_os_timer_wait_cond);
+#else
+				pthread_cond_broadcast(&sctp_os_timer_wait_cond);
+#endif
+				sctp_os_timer_done_ctr = wakeup_cookie;
+				SCTP_TIMERWAIT_UNLOCK();
+				SCTP_TIMERQ_LOCK();
+				sctp_os_timer_waiting = 0;
+			}
 			c = sctp_os_timer_next;
 		} else {
 			c = TAILQ_NEXT(c, tqe);
 		}
 	}
 	sctp_os_timer_next = NULL;
 	SCTP_TIMERQ_UNLOCK();
 }
@@ -212,15 +302,23 @@ void
 sctp_start_timer(void)
 {
 	/*
 	 * No need to do SCTP_TIMERQ_LOCK_INIT();
 	 * here, it is being done in sctp_pcb_init()
 	 */
 	int rc;
 
+#if defined(__Userspace_os_Windows)
+        InitializeConditionVariable(&sctp_os_timer_wait_cond);
+#else
+	rc = pthread_cond_init(&sctp_os_timer_wait_cond, NULL);
+	if (rc)
+		SCTP_PRINTF("ERROR; return code from pthread_cond_init is %d\n", rc);
+#endif
+
 	rc = sctp_userspace_thread_create(&SCTP_BASE_VAR(timer_thread), user_sctp_timer_iterate);
 	if (rc) {
 		SCTP_PRINTF("ERROR; return code from sctp_thread_create() is %d\n", rc);
 	}
 }
 
 #endif
--- a/netwerk/sctp/src/netinet/sctp_callout.h
+++ b/netwerk/sctp/src/netinet/sctp_callout.h
@@ -47,32 +47,45 @@
  * - SCTP_TIMERQ_LOCK_INIT()
  * - SCTP_TIMERQ_LOCK_DESTROY()
  */
 
 #define _SCTP_NEEDS_CALLOUT_ 1
 
 #define SCTP_TICKS_PER_FASTTIMO 20	/* called about every 20ms */
 
+extern userland_mutex_t sctp_os_timerwait_mtx;
+
 #if defined(__Userspace__)
 #if defined(__Userspace_os_Windows)
 #define SCTP_TIMERQ_LOCK()          EnterCriticalSection(&SCTP_BASE_VAR(timer_mtx))
 #define SCTP_TIMERQ_UNLOCK()        LeaveCriticalSection(&SCTP_BASE_VAR(timer_mtx))
 #define SCTP_TIMERQ_LOCK_INIT()     InitializeCriticalSection(&SCTP_BASE_VAR(timer_mtx))
 #define SCTP_TIMERQ_LOCK_DESTROY()  DeleteCriticalSection(&SCTP_BASE_VAR(timer_mtx))
+
+#define SCTP_TIMERWAIT_LOCK()          EnterCriticalSection(&sctp_os_timerwait_mtx)
+#define SCTP_TIMERWAIT_UNLOCK()        LeaveCriticalSection(&sctp_os_timerwait_mtx)
+#define SCTP_TIMERWAIT_LOCK_INIT()     InitializeCriticalSection(&sctp_os_timerwait_mtx)
+#define SCTP_TIMERWAIT_LOCK_DESTROY()  DeleteCriticalSection(&sctp_os_timerwait_mtx)
 #else
 #ifdef INVARIANTS
 #define SCTP_TIMERQ_LOCK()          KASSERT(pthread_mutex_lock(&SCTP_BASE_VAR(timer_mtx)) == 0, ("%s: timer_mtx already locked", __func__))
 #define SCTP_TIMERQ_UNLOCK()        KASSERT(pthread_mutex_unlock(&SCTP_BASE_VAR(timer_mtx)) == 0, ("%s: timer_mtx not locked", __func__))
+#define SCTP_TIMERWAIT_LOCK()       KASSERT(pthread_mutex_lock(&sctp_os_timerwait_mtx) == 0, ("%s: sctp_os_timerwait_mtx already locked", __func__))
+#define SCTP_TIMERWAIT_UNLOCK()	    KASSERT(pthread_mutex_unlock(&sctp_os_timerwait_mtx) == 0, ("%s: sctp_os_timerwait_mtx not locked", __func__))
 #else
 #define SCTP_TIMERQ_LOCK()          (void)pthread_mutex_lock(&SCTP_BASE_VAR(timer_mtx))
 #define SCTP_TIMERQ_UNLOCK()        (void)pthread_mutex_unlock(&SCTP_BASE_VAR(timer_mtx))
+#define SCTP_TIMERWAIT_LOCK()       (void)pthread_mutex_lock(&sctp_os_timerwait_mtx)
+#define SCTP_TIMERWAIT_UNLOCK()     (void)pthread_mutex_unlock(&sctp_os_timerwait_mtx)
 #endif
 #define SCTP_TIMERQ_LOCK_INIT()     (void)pthread_mutex_init(&SCTP_BASE_VAR(timer_mtx), &SCTP_BASE_VAR(mtx_attr))
 #define SCTP_TIMERQ_LOCK_DESTROY()  (void)pthread_mutex_destroy(&SCTP_BASE_VAR(timer_mtx))
+#define SCTP_TIMERWAIT_LOCK_INIT()     (void)pthread_mutex_init(&sctp_os_timerwait_mtx, &SCTP_BASE_VAR(mtx_attr))
+#define SCTP_TIMERWAIT_LOCK_DESTROY()  (void)pthread_mutex_destroy(&sctp_os_timerwait_mtx)
 #endif
 #endif
 
 int sctp_get_tick_count(void);
 
 TAILQ_HEAD(calloutlist, sctp_callout);
 
 struct sctp_callout {
--- a/netwerk/sctp/src/netinet/sctp_indata.c
+++ b/netwerk/sctp/src/netinet/sctp_indata.c
@@ -29,17 +29,17 @@
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 325434 2017-11-05 11:59:33Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_indata.c 345494 2019-03-25 09:47:22Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
 #ifdef __FreeBSD__
 #include <sys/proc.h>
 #endif
 #include <netinet/sctp_var.h>
 #include <netinet/sctp_sysctl.h>
--- a/netwerk/sctp/src/netinet/sctp_os_userspace.h
+++ b/netwerk/sctp/src/netinet/sctp_os_userspace.h
@@ -71,16 +71,17 @@ void WakeAllXPConditionVariable(userland
 #define DeleteConditionVariable(cond) DeleteXPConditionVariable(cond)
 #define SleepConditionVariableCS(cond, mtx, time) SleepXPConditionVariable(cond, mtx)
 #define WakeAllConditionVariable(cond) WakeAllXPConditionVariable(cond)
 #else
 #define DeleteConditionVariable(cond)
 typedef CONDITION_VARIABLE userland_cond_t;
 #endif
 typedef HANDLE userland_thread_t;
+typedef DWORD userland_thread_id_t;
 #define ADDRESS_FAMILY	unsigned __int8
 #define IPVERSION  4
 #define MAXTTL     255
 /* VS2010 comes with stdint.h */
 #if _MSC_VER >= 1600
 #include <stdint.h>
 #else
 #define uint64_t   unsigned __int64
@@ -277,16 +278,17 @@ typedef char* caddr_t;
 #else /* !defined(Userspace_os_Windows) */
 #include <sys/socket.h>
 #if defined(__Userspace_os_DragonFly) || defined(__Userspace_os_FreeBSD) || defined(__Userspace_os_Linux) || defined(__Userspace_os_NetBSD) || defined(__Userspace_os_OpenBSD) || defined(__Userspace_os_NaCl) || defined(__Userspace_os_Fuchsia)
 #include <pthread.h>
 #endif
 typedef pthread_mutex_t userland_mutex_t;
 typedef pthread_cond_t userland_cond_t;
 typedef pthread_t userland_thread_t;
+typedef pthread_t userland_thread_id_t;
 #endif
 
 #if defined(__Userspace_os_Windows) || defined(__Userspace_os_NaCl)
 
 #define IFNAMSIZ 64
 
 #define random() rand()
 #define srandom(s) srand(s)
@@ -1034,16 +1036,19 @@ struct sockaddr_conn {
 typedef void *(*start_routine_t)(void *);
 
 extern int
 sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine);
 
 void
 sctp_userspace_set_threadname(const char *name);
 
+int sctp_userspace_thread_id(userland_thread_id_t *thread);
+int sctp_userspace_thread_equal(userland_thread_id_t t1, userland_thread_id_t t2);
+
 /*
  * SCTP protocol specific mbuf flags.
  */
 #define	M_NOTIFICATION		M_PROTO5	/* SCTP notification */
 
 /*
  * IP output routines
  */
--- a/netwerk/sctp/src/netinet/sctp_pcb.c
+++ b/netwerk/sctp/src/netinet/sctp_pcb.c
@@ -29,17 +29,17 @@
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 334532 2018-06-02 16:28:10Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.c 345504 2019-03-25 15:23:20Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
 #ifdef __FreeBSD__
 #include <sys/proc.h>
 #endif
 #include <netinet/sctp_var.h>
 #include <netinet/sctp_sysctl.h>
@@ -5755,25 +5755,26 @@ sctp_free_assoc(struct sctp_inpcb *inp, 
 	}
 
 	asoc->strreset_timer.type = SCTP_TIMER_TYPE_NONE;
 	/*
 	 * The chunk lists and such SHOULD be empty but we check them just
 	 * in case.
 	 */
 	/* anything on the wheel needs to be removed */
+	SCTP_TCB_SEND_LOCK(stcb);
 	for (i = 0; i < asoc->streamoutcnt; i++) {
 		struct sctp_stream_out *outs;
 
 		outs = &asoc->strmout[i];
 		/* now clean up any chunks here */
 		TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
 			atomic_subtract_int(&asoc->stream_queue_cnt, 1);
 			TAILQ_REMOVE(&outs->outqueue, sp, next);
-			stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 0);
+			stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1);
 			sctp_free_spbufspace(stcb, asoc, sp);
 			if (sp->data) {
 				if (so) {
 					/* Still an open socket - report */
 					sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
 					                0, (void *)sp, SCTP_SO_LOCKED);
 				}
 				if (sp->data) {
@@ -5785,16 +5786,17 @@ sctp_free_assoc(struct sctp_inpcb *inp, 
 			}
 			if (sp->net) {
 				sctp_free_remote_addr(sp->net);
 				sp->net = NULL;
 			}
 			sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED);
 		}
 	}
+	SCTP_TCB_SEND_UNLOCK(stcb);
 	/*sa_ignore FREED_MEMORY*/
 	TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) {
 		TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp);
 		SCTP_FREE(strrst, SCTP_M_STRESET);
 	}
 	TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) {
 		TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next);
 		if (sq->data) {
@@ -6843,16 +6845,17 @@ sctp_pcb_init()
 #if defined(__FreeBSD__) && __FreeBSD_cc_version >= 1300000
 	if (ip_register_flow_handler(sctp_netisr_hdlr, IPPROTO_SCTP)) {
 		SCTP_PRINTF("***SCTP- Error can't register netisr handler***\n");
 	}
 #endif
 #if defined(_SCTP_NEEDS_CALLOUT_) || defined(_USER_SCTP_NEEDS_CALLOUT_)
 	/* allocate the lock for the callout/timer queue */
 	SCTP_TIMERQ_LOCK_INIT();
+	SCTP_TIMERWAIT_LOCK_INIT();
 	TAILQ_INIT(&SCTP_BASE_INFO(callqueue));
 #endif
 #if defined(__Userspace__)
 	mbuf_initialize(NULL);
 	atomic_init();
 #if defined(INET) || defined(INET6)
 	recv_thread_init();
 #endif
@@ -7037,16 +7040,17 @@ retry:
 			}
 			SCTP_FREE(prev_twait_block, SCTP_M_TIMW);
 		}
 	}
 
 	/* free the locks and mutexes */
 #if defined(__APPLE__)
 	SCTP_TIMERQ_LOCK_DESTROY();
+	SCTP_TIMERWAIT_LOCK_DESTROY();
 #endif
 #ifdef SCTP_PACKET_LOGGING
 	SCTP_IP_PKTLOG_DESTROY();
 #endif
 	SCTP_IPI_ADDR_DESTROY();
 #if defined(__APPLE__)
 	SCTP_IPI_COUNT_DESTROY();
 #endif
@@ -7063,16 +7067,17 @@ retry:
 #else
 	lck_grp_attr_free(SCTP_BASE_INFO(sctbinfo).ipi_lock_grp_attr);
 	lck_grp_free(SCTP_BASE_INFO(sctbinfo).ipi_lock_grp);
 	lck_attr_free(SCTP_BASE_INFO(sctbinfo).ipi_lock_attr);
 #endif
 #endif
 #if defined(__Userspace__)
 	SCTP_TIMERQ_LOCK_DESTROY();
+	SCTP_TIMERWAIT_LOCK_DESTROY();
 	SCTP_ZONE_DESTROY(zone_mbuf);
 	SCTP_ZONE_DESTROY(zone_clust);
 	SCTP_ZONE_DESTROY(zone_ext_refcnt);
 #endif
 	/* Get rid of other stuff too. */
 	if (SCTP_BASE_INFO(sctp_asochash) != NULL)
 		SCTP_HASH_FREE(SCTP_BASE_INFO(sctp_asochash), SCTP_BASE_INFO(hashasocmark));
 	if (SCTP_BASE_INFO(sctp_ephash) != NULL)
--- a/netwerk/sctp/src/netinet/sctp_ss_functions.c
+++ b/netwerk/sctp/src/netinet/sctp_ss_functions.c
@@ -25,17 +25,17 @@
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 326180 2017-11-24 19:38:59Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 345505 2019-03-25 16:40:54Z tuexen $");
 #endif
 
 #include <netinet/sctp_pcb.h>
 #if defined(__Userspace__)
 #include <netinet/sctp_os_userspace.h>
 #endif
 
 /*
@@ -815,16 +815,18 @@ sctp_ss_fcfs_init_stream(struct sctp_tcb
 	if (with_strq != NULL) {
 		if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
 			stcb->asoc.ss_data.locked_on_sending = strq;
 		}
 		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
 			stcb->asoc.ss_data.last_out_stream = strq;
 		}
 	}
+	strq->ss_params.fb.next_spoke.tqe_next = NULL;
+	strq->ss_params.fb.next_spoke.tqe_prev = NULL;
 	return;
 }
 
 static void
 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
                  struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
                  int holds_lock)
 {
--- a/netwerk/sctp/src/netinet/sctp_userspace.c
+++ b/netwerk/sctp/src/netinet/sctp_userspace.c
@@ -56,22 +56,49 @@ int
 sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine)
 {
 	*thread = CreateThread(NULL, 0, sctp_create_thread_adapter,
 			       (void *)start_routine, 0, NULL);
 	if (*thread == NULL)
 		return GetLastError();
 	return 0;
 }
+
+int
+sctp_userspace_thread_id(userland_thread_id_t *thread)
+{
+	*thread = GetCurrentThreadId();
+	return 0;
+}
+
+int
+sctp_userspace_thread_equal(userland_thread_id_t t1, userland_thread_id_t t2)
+{
+	return (t1 == t2);
+}
+
 #else
 int
 sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_routine)
 {
 	return pthread_create(thread, NULL, start_routine, NULL);
 }
+
+int
+sctp_userspace_thread_id(userland_thread_id_t *thread)
+{
+	*thread = pthread_self();
+	return 0;
+}
+
+int
+sctp_userspace_thread_equal(userland_thread_id_t t1, userland_thread_id_t t2)
+{
+	return pthread_equal(t1, t2);
+}
 #endif
 
 void
 sctp_userspace_set_threadname(const char *name)
 {
 #if defined(__Userspace_os_Darwin)
 	pthread_setname_np(name);
 #endif
--- a/netwerk/sctp/src/netinet/sctp_usrreq.c
+++ b/netwerk/sctp/src/netinet/sctp_usrreq.c
@@ -29,17 +29,17 @@
  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 325370 2017-11-03 20:46:12Z tuexen $");
+__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 345525 2019-03-26 08:27:00Z tuexen $");
 #endif
 
 #include <netinet/sctp_os.h>
 #ifdef __FreeBSD__
 #include <sys/proc.h>
 #endif
 #include <netinet/sctp_pcb.h>
 #include <netinet/sctp_header.h>
@@ -2076,18 +2076,16 @@ sctp_do_connect_x(struct socket *so, str
 	default:
 		break;
 	}
 
 	error = 0;
 	sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error);
 	/* Fill in the return id */
 	if (error) {
-		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE,
-		                      SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
 		goto out_now;
 	}
 	a_id = (sctp_assoc_t *)optval;
 	*a_id = sctp_get_associd(stcb);
 
 	/* initialize authentication parameters for the assoc */
 	sctp_initialize_auth_params(inp, stcb);