summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_thread.c')
-rw-r--r--sys/kern/kern_thread.c87
1 files changed, 36 insertions, 51 deletions
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index 9d834b5..18c097f 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -424,14 +424,8 @@ kse_exit(struct thread *td, struct kse_exit_args *uap)
struct kse *ke;
p = td->td_proc;
- /*
- * Only UTS can call the syscall and current group
- * should be a threaded group.
- */
- if ((td->td_mailbox != NULL) || (td->td_ksegrp->kg_numupcalls == 0))
+ if (td->td_upcall == NULL || TD_CAN_UNBIND(td))
return (EINVAL);
- KASSERT((td->td_upcall != NULL), ("%s: not own an upcall", __func__));
-
kg = td->td_ksegrp;
/* Serialize removing upcall */
PROC_LOCK(p);
@@ -480,13 +474,8 @@ kse_release(struct thread *td, struct kse_release_args *uap)
p = td->td_proc;
kg = td->td_ksegrp;
- /*
- * Only UTS can call the syscall and current group
- * should be a threaded group.
- */
- if ((td->td_mailbox != NULL) || (td->td_ksegrp->kg_numupcalls == 0))
+ if (td->td_upcall == NULL || TD_CAN_UNBIND(td))
return (EINVAL);
- KASSERT((td->td_upcall != NULL), ("%s: not own an upcall", __func__));
if (uap->timeout != NULL) {
if ((error = copyin(uap->timeout, &timeout, sizeof(timeout))))
return (error);
@@ -1539,8 +1528,10 @@ thread_user_enter(struct proc *p, struct thread *td)
{
struct ksegrp *kg;
struct kse_upcall *ku;
+ struct kse_thr_mailbox *tmbx;
kg = td->td_ksegrp;
+
/*
* First check that we shouldn't just abort.
* But check if we are the single thread first!
@@ -1565,20 +1556,20 @@ thread_user_enter(struct proc *p, struct thread *td)
ku = td->td_upcall;
KASSERT(ku, ("%s: no upcall owned", __func__));
KASSERT((ku->ku_owner == td), ("%s: wrong owner", __func__));
- td->td_mailbox =
- (void *)fuword((void *)&ku->ku_mailbox->km_curthread);
- if ((td->td_mailbox == NULL) ||
- (td->td_mailbox == (void *)-1)) {
- /* Don't schedule upcall when blocked */
+ KASSERT(!TD_CAN_UNBIND(td), ("%s: can unbind", __func__));
+ ku->ku_mflags = fuword((void *)&ku->ku_mailbox->km_flags);
+ tmbx = (void *)fuword((void *)&ku->ku_mailbox->km_curthread);
+ if ((tmbx == NULL) || (tmbx == (void *)-1)) {
td->td_mailbox = NULL;
- mtx_lock_spin(&sched_lock);
- td->td_flags &= ~TDF_CAN_UNBIND;
- mtx_unlock_spin(&sched_lock);
} else {
+ td->td_mailbox = tmbx;
if (td->td_standin == NULL)
thread_alloc_spare(td, NULL);
mtx_lock_spin(&sched_lock);
- td->td_flags |= TDF_CAN_UNBIND;
+ if (ku->ku_mflags & KMF_NOUPCALL)
+ td->td_flags &= ~TDF_CAN_UNBIND;
+ else
+ td->td_flags |= TDF_CAN_UNBIND;
mtx_unlock_spin(&sched_lock);
}
}
@@ -1599,7 +1590,7 @@ thread_user_enter(struct proc *p, struct thread *td)
int
thread_userret(struct thread *td, struct trapframe *frame)
{
- int error = 0, upcalls;
+ int error = 0, upcalls, uts_crit;
struct kse_upcall *ku;
struct ksegrp *kg, *kg2;
struct proc *p;
@@ -1608,7 +1599,6 @@ thread_userret(struct thread *td, struct trapframe *frame)
p = td->td_proc;
kg = td->td_ksegrp;
-
/* Nothing to do with non-threaded group/process */
if (td->td_ksegrp->kg_numupcalls == 0)
return (0);
@@ -1628,6 +1618,8 @@ thread_userret(struct thread *td, struct trapframe *frame)
thread_user_enter(p, td);
}
+ uts_crit = (td->td_mailbox == NULL);
+ ku = td->td_upcall;
/*
* Optimisation:
* This thread has not started any upcall.
@@ -1637,7 +1629,6 @@ thread_userret(struct thread *td, struct trapframe *frame)
if (TD_CAN_UNBIND(td)) {
mtx_lock_spin(&sched_lock);
td->td_flags &= ~TDF_CAN_UNBIND;
- ku = td->td_upcall;
if ((td->td_flags & TDF_NEEDSIGCHK) == 0 &&
(kg->kg_completed == NULL) &&
(ku->ku_flags & KUF_DOUPCALL) == 0 &&
@@ -1649,6 +1640,7 @@ thread_userret(struct thread *td, struct trapframe *frame)
(caddr_t)&ku->ku_mailbox->km_timeofday,
sizeof(ts));
td->td_mailbox = 0;
+ ku->ku_mflags = 0;
if (error)
goto out;
return (0);
@@ -1661,7 +1653,7 @@ thread_userret(struct thread *td, struct trapframe *frame)
* back to synchonous operation, so just return from
* the syscall.
*/
- return (0);
+ goto out;
}
/*
* There is something to report, and we own an upcall
@@ -1671,7 +1663,7 @@ thread_userret(struct thread *td, struct trapframe *frame)
mtx_lock_spin(&sched_lock);
td->td_flags |= TDF_UPCALLING;
mtx_unlock_spin(&sched_lock);
- } else if (td->td_mailbox) {
+ } else if (td->td_mailbox && (ku == NULL)) {
error = thread_export_context(td);
/* possibly upcall with error? */
PROC_LOCK(p);
@@ -1716,8 +1708,8 @@ thread_userret(struct thread *td, struct trapframe *frame)
}
if (td->td_flags & TDF_UPCALLING) {
+ uts_crit = 0;
kg->kg_nextupcall = ticks+kg->kg_upquantum;
- ku = td->td_upcall;
/*
* There is no more work to do and we are going to ride
* this thread up to userland as an upcall.
@@ -1726,12 +1718,6 @@ thread_userret(struct thread *td, struct trapframe *frame)
CTR3(KTR_PROC, "userret: upcall thread %p (pid %d, %s)",
td, td->td_proc->p_pid, td->td_proc->p_comm);
- /*
- * Set user context to the UTS.
- * Will use Giant in cpu_thread_clean() because it uses
- * kmem_free(kernel_map, ...)
- */
- cpu_set_upcall_kse(td, ku);
mtx_lock_spin(&sched_lock);
td->td_flags &= ~TDF_UPCALLING;
if (ku->ku_flags & KUF_DOUPCALL)
@@ -1739,31 +1725,29 @@ thread_userret(struct thread *td, struct trapframe *frame)
mtx_unlock_spin(&sched_lock);
/*
+ * Set user context to the UTS
+ */
+ if (!(ku->ku_mflags & KMF_NOUPCALL)) {
+ cpu_set_upcall_kse(td, ku);
+ error = suword(&ku->ku_mailbox->km_curthread, 0);
+ if (error)
+ goto out;
+ }
+
+ /*
* Unhook the list of completed threads.
* anything that completes after this gets to
* come in next time.
* Put the list of completed thread mailboxes on
* this KSE's mailbox.
*/
- error = thread_link_mboxes(kg, ku);
- if (error)
+ if (!(ku->ku_mflags & KMF_NOCOMPLETED) &&
+ (error = thread_link_mboxes(kg, ku)) != 0)
goto out;
-
- /*
- * Set state and clear the thread mailbox pointer.
- * From now on we are just a bound outgoing process.
- * **Problem** userret is often called several times.
- * it would be nice if this all happenned only on the first
- * time through. (the scan for extra work etc.)
- */
- error = suword((caddr_t)&ku->ku_mailbox->km_curthread, 0);
- if (error)
- goto out;
-
- /* Export current system time */
+ }
+ if (!uts_crit) {
nanotime(&ts);
- error = copyout(&ts, (caddr_t)&ku->ku_mailbox->km_timeofday,
- sizeof(ts));
+ error = copyout(&ts, &ku->ku_mailbox->km_timeofday, sizeof(ts));
}
out:
@@ -1786,6 +1770,7 @@ out:
thread_alloc_spare(td, NULL);
}
+ ku->ku_mflags = 0;
/*
* Clear thread mailbox first, then clear system tick count.
* The order is important because thread_statclock() use
OpenPOWER on IntegriCloud