+
+static void
+mptcp_urgency_timer_locked(struct mptses *mpte)
+{
+ uint64_t time_now = mach_continuous_time();
+ struct socket *mp_so = mptetoso(mpte);
+
+ VERIFY(mp_so->so_usecount >= 0);
+
+ os_log(mptcp_log_handle, "%s - %lx: timer at %llu now %llu usecount %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mpte->mpte_time_target, time_now, mp_so->so_usecount);
+
+ mptcp_check_subflows_and_add(mpte);
+
+ mp_so->so_usecount--;
+}
+
+static void
+mptcp_urgency_timer(void *param0, __unused void *param1)
+{
+ struct mptses *mpte = (struct mptses *)param0;
+ struct socket *mp_so = mptetoso(mpte);
+
+ socket_lock(mp_so, 1);
+
+ mptcp_urgency_timer_locked(mpte);
+
+ socket_unlock(mp_so, 1);
+}
+
+void
+mptcp_init_urgency_timer(struct mptses *mpte)
+{
+ /* thread_call_allocate never fails */
+ mpte->mpte_time_thread = thread_call_allocate(mptcp_urgency_timer, mpte);
+}
+
+void
+mptcp_set_urgency_timer(struct mptses *mpte)
+{
+ struct socket *mp_so = mptetoso(mpte);
+ uint64_t time_now = 0;
+ boolean_t ret = FALSE;
+
+ socket_lock_assert_owned(mp_so);
+
+ VERIFY(mp_so->so_usecount >= 0);
+ if (mp_so->so_usecount == 0) {
+ goto exit_log;
+ }
+
+ if (mpte->mpte_time_target == 0) {
+ mptcp_cancel_urgency_timer(mpte);
+
+ goto exit_log;
+ }
+
+ time_now = mach_continuous_time();
+
+ if ((int64_t)(mpte->mpte_time_target - time_now) > 0) {
+ mptcp_check_subflows_and_remove(mpte);
+
+ ret = thread_call_enter_delayed_with_leeway(mpte->mpte_time_thread, NULL,
+ mpte->mpte_time_target, 0, THREAD_CALL_CONTINUOUS);
+
+ if (!ret) {
+ mp_so->so_usecount++;
+ }
+ } else if ((int64_t)(mpte->mpte_time_target - time_now) <= 0) {
+ mp_so->so_usecount++;
+
+ /* Already passed the deadline, trigger subflows now */
+ mptcp_urgency_timer_locked(mpte);
+ }
+
+exit_log:
+ os_log(mptcp_log_handle, "%s - %lx: timer at %llu now %llu usecount %u ret %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mpte->mpte_time_target, time_now,
+ mp_so->so_usecount, ret);
+}
+
+static int
+mptcp_cancel_urgency_timer(struct mptses *mpte)
+{
+ struct socket *mp_so = mptetoso(mpte);
+ boolean_t ret;
+
+ ret = thread_call_cancel(mpte->mpte_time_thread);
+
+ os_log(mptcp_log_handle, "%s - %lx: Canceled timer thread usecount %u ret %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mp_so->so_usecount, ret);
+
+ mptcp_check_subflows_and_remove(mpte);
+
+ if (ret) {
+ mp_so->so_usecount--;
+ }
+
+ return 0;
+}