Rename umtxq_check_susp() to thread_check_susp()
and make it usable outside of kern_umtx.c. To be used in several future changes. Discussed with: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
8f4d74eb1e
commit
478ca4b004
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356293
@ -1074,6 +1074,49 @@ thread_suspend_check(int return_instead)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for possible stops and suspensions while executing a
|
||||||
|
* casueword or similar transiently failing operation.
|
||||||
|
*
|
||||||
|
* The sleep argument controls whether the function can handle a stop
|
||||||
|
* request itself or it should return ERESTART and the request is
|
||||||
|
* proceed at the kernel/user boundary in ast.
|
||||||
|
*
|
||||||
|
* Typically, when retrying due to casueword(9) failure (rv == 1), we
|
||||||
|
* should handle the stop requests there, with exception of cases when
|
||||||
|
* the thread owns a kernel resource, for instance busied the umtx
|
||||||
|
* key, or when functions return immediately if casueword_check_susp()
|
||||||
|
* returned non-zero. On the other hand, retrying the whole lock
|
||||||
|
* operation, we better not stop there but delegate the handling to
|
||||||
|
* ast.
|
||||||
|
*
|
||||||
|
* If the request is for thread termination P_SINGLE_EXIT, we cannot
|
||||||
|
* handle it at all, and simply return EINTR.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
thread_check_susp(struct thread *td, bool sleep)
|
||||||
|
{
|
||||||
|
struct proc *p;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The check for TDF_NEEDSUSPCHK is racy, but it is enough to
|
||||||
|
* eventually break the lockstep loop.
|
||||||
|
*/
|
||||||
|
if ((td->td_flags & TDF_NEEDSUSPCHK) == 0)
|
||||||
|
return (0);
|
||||||
|
error = 0;
|
||||||
|
p = td->td_proc;
|
||||||
|
PROC_LOCK(p);
|
||||||
|
if (p->p_flag & P_SINGLE_EXIT)
|
||||||
|
error = EINTR;
|
||||||
|
else if (P_SHOULDSTOP(p) ||
|
||||||
|
((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_SUSPEND)))
|
||||||
|
error = sleep ? thread_suspend_check(0) : ERESTART;
|
||||||
|
PROC_UNLOCK(p);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
thread_suspend_switch(struct thread *td, struct proc *p)
|
thread_suspend_switch(struct thread *td, struct proc *p)
|
||||||
{
|
{
|
||||||
|
@ -690,48 +690,6 @@ umtxq_count_pi(struct umtx_key *key, struct umtx_q **first)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for possible stops and suspensions while executing a umtx
|
|
||||||
* locking operation.
|
|
||||||
*
|
|
||||||
* The sleep argument controls whether the function can handle a stop
|
|
||||||
* request itself or it should return ERESTART and the request is
|
|
||||||
* proceed at the kernel/user boundary in ast.
|
|
||||||
*
|
|
||||||
* Typically, when retrying due to casueword(9) failure (rv == 1), we
|
|
||||||
* should handle the stop requests there, with exception of cases when
|
|
||||||
* the thread busied the umtx key, or when functions return
|
|
||||||
* immediately if umtxq_check_susp() returned non-zero. On the other
|
|
||||||
* hand, retrying the whole lock operation, we better not stop there
|
|
||||||
* but delegate the handling to ast.
|
|
||||||
*
|
|
||||||
* If the request is for thread termination P_SINGLE_EXIT, we cannot
|
|
||||||
* handle it at all, and simply return EINTR.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
umtxq_check_susp(struct thread *td, bool sleep)
|
|
||||||
{
|
|
||||||
struct proc *p;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The check for TDF_NEEDSUSPCHK is racy, but it is enough to
|
|
||||||
* eventually break the lockstep loop.
|
|
||||||
*/
|
|
||||||
if ((td->td_flags & TDF_NEEDSUSPCHK) == 0)
|
|
||||||
return (0);
|
|
||||||
error = 0;
|
|
||||||
p = td->td_proc;
|
|
||||||
PROC_LOCK(p);
|
|
||||||
if (p->p_flag & P_SINGLE_EXIT)
|
|
||||||
error = EINTR;
|
|
||||||
else if (P_SHOULDSTOP(p) ||
|
|
||||||
((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_SUSPEND)))
|
|
||||||
error = sleep ? thread_suspend_check(0) : ERESTART;
|
|
||||||
PROC_UNLOCK(p);
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wake up threads waiting on an userland object.
|
* Wake up threads waiting on an userland object.
|
||||||
*/
|
*/
|
||||||
@ -1070,7 +1028,7 @@ do_lock_normal(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
return (EOWNERDEAD); /* success */
|
return (EOWNERDEAD); /* success */
|
||||||
}
|
}
|
||||||
MPASS(rv == 1);
|
MPASS(rv == 1);
|
||||||
rv = umtxq_check_susp(td, false);
|
rv = thread_check_susp(td, false);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
return (rv);
|
return (rv);
|
||||||
continue;
|
continue;
|
||||||
@ -1111,7 +1069,7 @@ do_lock_normal(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
rv = umtxq_check_susp(td, false);
|
rv = thread_check_susp(td, false);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
@ -1124,7 +1082,7 @@ do_lock_normal(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* rv == 1 but not contested, likely store failure */
|
/* rv == 1 but not contested, likely store failure */
|
||||||
rv = umtxq_check_susp(td, false);
|
rv = thread_check_susp(td, false);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
@ -1167,7 +1125,7 @@ do_lock_normal(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
if (rv == -1)
|
if (rv == -1)
|
||||||
return (EFAULT);
|
return (EFAULT);
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
rv = umtxq_check_susp(td, false);
|
rv = thread_check_susp(td, false);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
@ -1189,7 +1147,7 @@ do_lock_normal(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
umtx_key_release(&uq->uq_key);
|
umtx_key_release(&uq->uq_key);
|
||||||
|
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@ -1224,7 +1182,7 @@ do_unlock_normal(struct thread *td, struct umutex *m, uint32_t flags, bool rb)
|
|||||||
if (error == -1)
|
if (error == -1)
|
||||||
return (EFAULT);
|
return (EFAULT);
|
||||||
if (error == 1) {
|
if (error == 1) {
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
goto again;
|
goto again;
|
||||||
@ -1261,7 +1219,7 @@ do_unlock_normal(struct thread *td, struct umutex *m, uint32_t flags, bool rb)
|
|||||||
if (error == 1) {
|
if (error == 1) {
|
||||||
if (old != owner)
|
if (old != owner)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
goto again;
|
goto again;
|
||||||
@ -1316,7 +1274,7 @@ do_wake_umutex(struct thread *td, struct umutex *m)
|
|||||||
umtxq_unbusy(&key);
|
umtxq_unbusy(&key);
|
||||||
umtxq_unlock(&key);
|
umtxq_unlock(&key);
|
||||||
umtx_key_release(&key);
|
umtx_key_release(&key);
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
goto again;
|
goto again;
|
||||||
@ -1400,7 +1358,7 @@ do_wake2_umutex(struct thread *td, struct umutex *m, uint32_t flags)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
owner = old;
|
owner = old;
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
umtxq_lock(&key);
|
umtxq_lock(&key);
|
||||||
@ -1905,7 +1863,7 @@ do_lock_pi(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
* to the pending signal with suspension check result.
|
* to the pending signal with suspension check result.
|
||||||
*/
|
*/
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1922,7 +1880,7 @@ do_lock_pi(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
}
|
}
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1994,7 +1952,7 @@ do_lock_pi(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
}
|
}
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
umtxq_unbusy_unlocked(&uq->uq_key);
|
umtxq_unbusy_unlocked(&uq->uq_key);
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2017,7 +1975,7 @@ do_lock_pi(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
if (error != 0)
|
if (error != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2063,7 +2021,7 @@ do_unlock_pi(struct thread *td, struct umutex *m, uint32_t flags, bool rb)
|
|||||||
if (error == -1)
|
if (error == -1)
|
||||||
return (EFAULT);
|
return (EFAULT);
|
||||||
if (error == 1) {
|
if (error == 1) {
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
goto usrloop;
|
goto usrloop;
|
||||||
@ -2150,7 +2108,7 @@ do_unlock_pi(struct thread *td, struct umutex *m, uint32_t flags, bool rb)
|
|||||||
again:
|
again:
|
||||||
error = casueword32(&m->m_owner, owner, &old, new_owner);
|
error = casueword32(&m->m_owner, owner, &old, new_owner);
|
||||||
if (error == 1) {
|
if (error == 1) {
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
@ -2255,7 +2213,7 @@ do_lock_pp(struct thread *td, struct umutex *m, uint32_t flags,
|
|||||||
* error to not skip the last loop iteration.
|
* error to not skip the last loop iteration.
|
||||||
*/
|
*/
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
if (try != 0)
|
if (try != 0)
|
||||||
error = EBUSY;
|
error = EBUSY;
|
||||||
@ -2770,7 +2728,7 @@ do_rw_rdlock(struct thread *td, struct urwlock *rwlock, long fflag,
|
|||||||
umtx_key_release(&uq->uq_key);
|
umtx_key_release(&uq->uq_key);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
@ -2806,7 +2764,7 @@ do_rw_rdlock(struct thread *td, struct urwlock *rwlock, long fflag,
|
|||||||
goto sleep;
|
goto sleep;
|
||||||
}
|
}
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2818,7 +2776,7 @@ do_rw_rdlock(struct thread *td, struct urwlock *rwlock, long fflag,
|
|||||||
/* state is changed while setting flags, restart */
|
/* state is changed while setting flags, restart */
|
||||||
if (!(state & wrflags)) {
|
if (!(state & wrflags)) {
|
||||||
umtxq_unbusy_unlocked(&uq->uq_key);
|
umtxq_unbusy_unlocked(&uq->uq_key);
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
continue;
|
continue;
|
||||||
@ -2886,7 +2844,7 @@ do_rw_rdlock(struct thread *td, struct urwlock *rwlock, long fflag,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
error1 = umtxq_check_susp(td, false);
|
error1 = thread_check_susp(td, false);
|
||||||
if (error1 != 0) {
|
if (error1 != 0) {
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
error = error1;
|
error = error1;
|
||||||
@ -2948,7 +2906,7 @@ do_rw_wrlock(struct thread *td, struct urwlock *rwlock, struct _umtx_time *timeo
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2995,7 +2953,7 @@ do_rw_wrlock(struct thread *td, struct urwlock *rwlock, struct _umtx_time *timeo
|
|||||||
goto sleep;
|
goto sleep;
|
||||||
}
|
}
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3007,7 +2965,7 @@ do_rw_wrlock(struct thread *td, struct urwlock *rwlock, struct _umtx_time *timeo
|
|||||||
if ((state & URWLOCK_WRITE_OWNER) == 0 &&
|
if ((state & URWLOCK_WRITE_OWNER) == 0 &&
|
||||||
URWLOCK_READER_COUNT(state) == 0) {
|
URWLOCK_READER_COUNT(state) == 0) {
|
||||||
umtxq_unbusy_unlocked(&uq->uq_key);
|
umtxq_unbusy_unlocked(&uq->uq_key);
|
||||||
error = umtxq_check_susp(td, false);
|
error = thread_check_susp(td, false);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
break;
|
break;
|
||||||
continue;
|
continue;
|
||||||
@ -3070,7 +3028,7 @@ do_rw_wrlock(struct thread *td, struct urwlock *rwlock, struct _umtx_time *timeo
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state = oldstate;
|
state = oldstate;
|
||||||
error1 = umtxq_check_susp(td, false);
|
error1 = thread_check_susp(td, false);
|
||||||
/*
|
/*
|
||||||
* We are leaving the URWLOCK_WRITE_WAITERS
|
* We are leaving the URWLOCK_WRITE_WAITERS
|
||||||
* behind, but this should not harm the
|
* behind, but this should not harm the
|
||||||
@ -3136,7 +3094,7 @@ do_rw_unlock(struct thread *td, struct urwlock *rwlock)
|
|||||||
error = EPERM;
|
error = EPERM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto out;
|
goto out;
|
||||||
} else
|
} else
|
||||||
@ -3156,7 +3114,7 @@ do_rw_unlock(struct thread *td, struct urwlock *rwlock)
|
|||||||
error = EPERM;
|
error = EPERM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
error = umtxq_check_susp(td, true);
|
error = thread_check_susp(td, true);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto out;
|
goto out;
|
||||||
} else
|
} else
|
||||||
@ -3234,7 +3192,7 @@ do_sem_wait(struct thread *td, struct _usem *sem, struct _umtx_time *timeout)
|
|||||||
umtxq_remove(uq);
|
umtxq_remove(uq);
|
||||||
umtxq_unlock(&uq->uq_key);
|
umtxq_unlock(&uq->uq_key);
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
rv = umtxq_check_susp(td, true);
|
rv = thread_check_susp(td, true);
|
||||||
if (rv == 0)
|
if (rv == 0)
|
||||||
goto again;
|
goto again;
|
||||||
error = rv;
|
error = rv;
|
||||||
@ -3356,7 +3314,7 @@ do_sem2_wait(struct thread *td, struct _usem2 *sem, struct _umtx_time *timeout)
|
|||||||
umtx_key_release(&uq->uq_key);
|
umtx_key_release(&uq->uq_key);
|
||||||
if (rv == -1)
|
if (rv == -1)
|
||||||
return (EFAULT);
|
return (EFAULT);
|
||||||
rv = umtxq_check_susp(td, true);
|
rv = thread_check_susp(td, true);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
return (rv);
|
return (rv);
|
||||||
goto again;
|
goto again;
|
||||||
@ -3416,7 +3374,7 @@ do_sem2_wake(struct thread *td, struct _usem2 *sem)
|
|||||||
rv = casueword32(&sem->_count, count, &count,
|
rv = casueword32(&sem->_count, count, &count,
|
||||||
count & ~USEM_HAS_WAITERS);
|
count & ~USEM_HAS_WAITERS);
|
||||||
if (rv == 1) {
|
if (rv == 1) {
|
||||||
rv = umtxq_check_susp(td, true);
|
rv = thread_check_susp(td, true);
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1144,6 +1144,7 @@ void cpu_thread_swapin(struct thread *);
|
|||||||
void cpu_thread_swapout(struct thread *);
|
void cpu_thread_swapout(struct thread *);
|
||||||
struct thread *thread_alloc(int pages);
|
struct thread *thread_alloc(int pages);
|
||||||
int thread_alloc_stack(struct thread *, int pages);
|
int thread_alloc_stack(struct thread *, int pages);
|
||||||
|
int thread_check_susp(struct thread *td, bool sleep);
|
||||||
void thread_cow_get_proc(struct thread *newtd, struct proc *p);
|
void thread_cow_get_proc(struct thread *newtd, struct proc *p);
|
||||||
void thread_cow_get(struct thread *newtd, struct thread *td);
|
void thread_cow_get(struct thread *newtd, struct thread *td);
|
||||||
void thread_cow_free(struct thread *td);
|
void thread_cow_free(struct thread *td);
|
||||||
|
Loading…
Reference in New Issue
Block a user