зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1400563
- timer deadlock fix r=drno,dminor
timer deadlock fix Differential Revision: https://phabricator.services.mozilla.com/D28087 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
e14e511763
Коммит
8a57537454
|
@ -76,8 +76,27 @@ int sctp_get_tick_count(void) {
|
|||
* 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)
|
||||
|
@ -95,6 +114,21 @@ sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
|
|||
|
||||
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);
|
||||
|
@ -126,13 +160,51 @@ sctp_os_timer_start(sctp_os_timer_t *c, int to_ticks, void (*ftn) (void *),
|
|||
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);
|
||||
|
@ -150,6 +222,7 @@ 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 */
|
||||
|
@ -162,9 +235,26 @@ sctp_handle_tick(int delta)
|
|||
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);
|
||||
|
@ -217,6 +307,14 @@ sctp_start_timer(void)
|
|||
*/
|
||||
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);
|
||||
|
|
|
@ -52,22 +52,35 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
#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
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#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>
|
||||
|
|
|
@ -76,6 +76,7 @@ void WakeAllXPConditionVariable(userland_cond_t *);
|
|||
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
|
||||
|
@ -282,6 +283,7 @@ typedef char* caddr_t;
|
|||
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)
|
||||
|
@ -1039,6 +1041,9 @@ sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_ro
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#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>
|
||||
|
@ -5760,6 +5760,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
|||
* 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;
|
||||
|
||||
|
@ -5768,7 +5769,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
|||
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) {
|
||||
|
@ -5790,6 +5791,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
|||
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);
|
||||
|
@ -6848,6 +6850,7 @@ sctp_pcb_init()
|
|||
#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__)
|
||||
|
@ -7042,6 +7045,7 @@ retry:
|
|||
/* 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();
|
||||
|
@ -7068,6 +7072,7 @@ retry:
|
|||
#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);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#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>
|
||||
|
@ -820,6 +820,8 @@ sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, st
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,12 +61,39 @@ sctp_userspace_thread_create(userland_thread_t *thread, start_routine_t start_ro
|
|||
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
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#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>
|
||||
|
@ -2081,8 +2081,6 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
|||
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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче