Pull in missing guard for the currently executing callout (v2)

The code to guard the currently executing callout while being in
process was not ported in for some reason. This leaves open the
possibility for the currently executing callout's function to free
the callout from another thread while running.
diff --git a/usrsctplib/netinet/sctp_callout.c b/usrsctplib/netinet/sctp_callout.c
index 16526d2..64b2da4 100755
--- a/usrsctplib/netinet/sctp_callout.c
+++ b/usrsctplib/netinet/sctp_callout.c
@@ -78,17 +78,24 @@
  * - SCTP_BASE_INFO(callqueue)
  * - sctp_os_timer_next: next timer to check
  * - sctp_os_timer_current: current callout callback in progress
- * - sctp_os_timer_waiting: waiting for callout to complete
+ * - 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;
 
-#if defined (__Userspace_os_Windows)
-static CONDITION_VARIABLE sctp_os_timer_wait_cond;
-#else
-static pthread_cond_t sctp_os_timer_wait_cond;
-#endif
+/*
+ * 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)
@@ -137,6 +144,8 @@
 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.
@@ -149,15 +158,26 @@
 		} else {
 			/* 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_BASE_VAR(timer_mtx),
-						 INFINITE);
+				SleepConditionVariableCS(&sctp_os_timer_wait_cond,
+							 &sctp_os_timerwait_mtx,
+							 INFINITE);
 #else
-			pthread_cond_wait(&sctp_os_timer_wait_cond,
-					  &SCTP_BASE_VAR(timer_mtx));
+				pthread_cond_wait(&sctp_os_timer_wait_cond,
+						  &SCTP_BASE_VAR(timer_mtx));
 #endif
+			}
+			SCTP_TIMERWAIT_UNLOCK();
 		}
+		return (0);
 	}
 	c->c_flags &= ~(SCTP_CALLOUT_ACTIVE | SCTP_CALLOUT_PENDING);
 	if (c == sctp_os_timer_next) {
@@ -174,6 +194,7 @@
 	sctp_os_timer_t *c;
 	void (*c_func)(void *);
 	void *c_arg;
+	int wakeup_cookie;
 
 	SCTP_TIMERQ_LOCK();
 	/* update our tick count */
@@ -192,11 +213,17 @@
 			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;
diff --git a/usrsctplib/netinet/sctp_callout.h b/usrsctplib/netinet/sctp_callout.h
index 765f966..ab68313 100755
--- a/usrsctplib/netinet/sctp_callout.h
+++ b/usrsctplib/netinet/sctp_callout.h
@@ -52,22 +52,35 @@
 
 #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_TIMERWIT_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
 
diff --git a/usrsctplib/netinet/sctp_pcb.c b/usrsctplib/netinet/sctp_pcb.c
index 86cccf9..55390bc 100755
--- a/usrsctplib/netinet/sctp_pcb.c
+++ b/usrsctplib/netinet/sctp_pcb.c
@@ -6844,6 +6844,7 @@
 #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__)
@@ -7038,6 +7039,7 @@
 	/* 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();
@@ -7064,6 +7066,7 @@
 #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);