Index: sys/proc.h =================================================================== RCS file: /home/ncvs/src/sys/sys/proc.h,v retrieving revision 1.327 diff -u -r1.327 proc.h --- sys/proc.h 2 May 2003 00:33:12 -0000 1.327 +++ sys/proc.h 2 May 2003 15:16:53 -0000 @@ -373,7 +373,7 @@ #define TD_CAN_UNBIND(td) \ (((td)->td_flags & TDF_CAN_UNBIND) == TDF_CAN_UNBIND && \ ((td)->td_upcall != NULL)) - +#define TD_IS_OWNER(td) ((td) == (td)->td_upcall->ku_owner) #define TD_IS_SLEEPING(td) ((td)->td_inhibitors & TDI_SLEEPING) #define TD_ON_SLEEPQ(td) ((td)->td_wchan != NULL) #define TD_IS_SUSPENDED(td) ((td)->td_inhibitors & TDI_SUSPENDED) @@ -468,6 +468,9 @@ stack_t ku_stack; /* userland upcall stack. */ void *ku_func; /* userland upcall function. */ unsigned int ku_mflags; /* cached upcall mailbox flags */ + struct kse_thr_mailbox *ku_completed; /* (c) Completed thread mboxes. */ + int ku_upsleep; + int ku_refcount; }; #define KUF_DOUPCALL 0x00001 /* Do upcall now, don't wait */ @@ -494,8 +497,6 @@ int kg_runq_kses; /* (j) Num KSEs on runq. */ int kg_idle_kses; /* (j) Num KSEs on iq */ int kg_numupcalls; /* (j) Num upcalls */ - int kg_upsleeps; /* (c) Num threads in kse_release() */ - struct kse_thr_mailbox *kg_completed; /* (c) Completed thread mboxes. */ int kg_nextupcall; /* (*) Next upcall time */ int kg_upquantum; /* (*) Quantum to schedule an upcall */ #define kg_endzero kg_pri_class Index: kern/kern_thread.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_thread.c,v retrieving revision 1.129 diff -u -r1.129 kern_thread.c --- kern/kern_thread.c 1 May 2003 12:16:06 -0000 1.129 +++ kern/kern_thread.c 2 May 2003 15:16:53 -0000 @@ -139,7 +139,7 @@ td = (struct thread *)mem; td->td_state = TDS_INACTIVE; - td->td_oncpu = NOCPU; + td->td_oncpu = NOCPU; } /* @@ -343,6 +343,7 @@ mtx_assert(&sched_lock, MA_OWNED); KASSERT(ku->ku_owner == NULL, ("%s: have owner", __func__)); + KASSERT(ku->ku_refcount == 0, ("%s: have user ", __func__)); TAILQ_REMOVE(&kg->kg_upcalls, ku, ku_link); kg->kg_numupcalls--; upcall_stash(ku); @@ -351,10 +352,15 @@ void upcall_remove(struct thread *td) { + struct kse_upcall *ku = td->td_upcall; - if (td->td_upcall) { - td->td_upcall->ku_owner = NULL; - upcall_unlink(td->td_upcall); + mtx_assert(&sched_lock, MA_OWNED); + if (ku) { + if (ku->ku_owner == td) + ku->ku_owner = NULL; + ku->ku_refcount--; + if (ku->ku_refcount == 0) + upcall_unlink(ku); td->td_upcall = 0; } } @@ -421,16 +427,18 @@ { struct proc *p; struct ksegrp *kg; + struct kse_upcall *ku; struct kse *ke; p = td->td_proc; - if (td->td_upcall == NULL || TD_CAN_UNBIND(td)) + ku = td->td_upcall; + if (td->td_upcall == NULL || TD_CAN_UNBIND(td) || !TD_IS_OWNER(td)) return (EINVAL); kg = td->td_ksegrp; /* Serialize removing upcall */ PROC_LOCK(p); mtx_lock_spin(&sched_lock); - if ((kg->kg_numupcalls == 1) && (kg->kg_numthreads > 1)) { + if (ku->ku_refcount > 1) { mtx_unlock_spin(&sched_lock); PROC_UNLOCK(p); return (EDEADLK); @@ -468,14 +476,16 @@ { struct proc *p; struct ksegrp *kg; + struct kse_upcall *ku; struct timespec ts, ts2, ts3, timeout; struct timeval tv; int error; p = td->td_proc; kg = td->td_ksegrp; - if (td->td_upcall == NULL || TD_CAN_UNBIND(td)) + if (td->td_upcall == NULL || TD_CAN_UNBIND(td) || !TD_IS_OWNER(td)) return (EINVAL); + ku = td->td_upcall; if (uap->timeout != NULL) { if ((error = copyin(uap->timeout, &timeout, sizeof(timeout)))) return (error); @@ -493,11 +503,11 @@ mtx_unlock_spin(&sched_lock); PROC_LOCK(p); while ((td->td_upcall->ku_flags & KUF_DOUPCALL) == 0 && - (kg->kg_completed == NULL)) { - kg->kg_upsleeps++; - error = msleep(&kg->kg_completed, &p->p_mtx, PPAUSE|PCATCH, + (ku->ku_completed == NULL)) { + ku->ku_upsleep++; + error = msleep(&ku->ku_completed, &p->p_mtx, PPAUSE|PCATCH, "kse_rel", (uap->timeout ? tvtohz(&tv) : 0)); - kg->kg_upsleeps--; + ku->ku_upsleep--; PROC_UNLOCK(p); if (uap->timeout == NULL || error != EWOULDBLOCK) return (0); @@ -543,19 +553,22 @@ } } else { kg = td->td_ksegrp; - if (kg->kg_upsleeps) { - wakeup_one(&kg->kg_completed); - mtx_unlock_spin(&sched_lock); - PROC_UNLOCK(p); - return (0); + FOREACH_UPCALL_IN_GROUP(kg, ku) { + if (ku->ku_upsleep) { + wakeup_one(&ku->ku_completed); + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + return (0); + } } ku = TAILQ_FIRST(&kg->kg_upcalls); } if (ku) { if ((td2 = ku->ku_owner) == NULL) { - panic("%s: no owner", __func__); + if (!(p->p_flag & P_SINGLE_EXIT)) + panic("%s: no owner", __func__); } else if (TD_ON_SLEEPQ(td2) && - (td2->td_wchan == &kg->kg_completed)) { + (td2->td_wchan == &ku->ku_completed)) { abortsleep(td2); } else { ku->ku_flags |= KUF_DOUPCALL; @@ -709,6 +722,7 @@ if (td->td_upcall == NULL) { newku->ku_owner = td; td->td_upcall = newku; + newku->ku_refcount = 1; } else { /* * Create a new upcall thread to own it. @@ -958,15 +972,15 @@ thread_export_context(struct thread *td) { struct proc *p; - struct ksegrp *kg; + struct kse_upcall *ku; uintptr_t mbx; void *addr; int error,temp; ucontext_t uc; p = td->td_proc; - kg = td->td_ksegrp; - + ku = td->td_upcall; + KASSERT(ku != NULL, ("%s: null upcall pointer ", __func__)); /* Export the user/machine context. */ addr = (void *)(&td->td_mailbox->tm_context); error = copyin(addr, &uc, sizeof(ucontext_t)); @@ -991,14 +1005,14 @@ * entry into this one */ for (;;) { - mbx = (uintptr_t)kg->kg_completed; + mbx = (uintptr_t)ku->ku_completed; if (suword(addr, mbx)) { error = EFAULT; goto bad; } PROC_LOCK(p); - if (mbx == (uintptr_t)kg->kg_completed) { - kg->kg_completed = td->td_mailbox; + if (mbx == (uintptr_t)ku->ku_completed) { + ku->ku_completed = td->td_mailbox; /* * The thread context may be taken away by * other upcall threads when we unlock @@ -1037,7 +1051,7 @@ addr = (void *)(&ku->ku_mailbox->km_completed); for (;;) { - mbx = (uintptr_t)kg->kg_completed; + mbx = (uintptr_t)ku->ku_completed; if (suword(addr, mbx)) { PROC_LOCK(p); psignal(p, SIGSEGV); @@ -1045,8 +1059,8 @@ return (EFAULT); } PROC_LOCK(p); - if (mbx == (uintptr_t)kg->kg_completed) { - kg->kg_completed = NULL; + if (mbx == (uintptr_t)ku->ku_completed) { + ku->ku_completed = NULL; PROC_UNLOCK(p); break; } @@ -1413,6 +1427,7 @@ cpu_set_upcall(td2, td->td_pcb); /* Let the new thread become owner of the upcall */ ku->ku_owner = td2; + ku->ku_refcount++; td2->td_upcall = ku; td2->td_flags = TDF_UPCALLING; #if 0 /* XXX This shouldn't be necessary */ @@ -1498,7 +1513,6 @@ */ ku = td->td_upcall; ku->ku_owner = NULL; - td->td_upcall = NULL; td->td_flags &= ~TDF_CAN_UNBIND; thread_schedule_upcall(td, ku); } @@ -1598,7 +1612,7 @@ mtx_lock_spin(&sched_lock); td->td_flags &= ~TDF_USTATCLOCK; mtx_unlock_spin(&sched_lock); - if (kg->kg_completed || + if (td->td_upcall->ku_completed || (td->td_upcall->ku_flags & KUF_DOUPCALL)) thread_user_enter(p, td); } @@ -1615,7 +1629,7 @@ mtx_lock_spin(&sched_lock); td->td_flags &= ~TDF_CAN_UNBIND; if ((td->td_flags & TDF_NEEDSIGCHK) == 0 && - (kg->kg_completed == NULL) && + (ku->ku_completed == NULL) && (ku->ku_flags & KUF_DOUPCALL) == 0 && (kg->kg_upquantum && ticks < kg->kg_nextupcall)) { mtx_unlock_spin(&sched_lock); @@ -1648,7 +1662,7 @@ mtx_lock_spin(&sched_lock); td->td_flags |= TDF_UPCALLING; mtx_unlock_spin(&sched_lock); - } else if (td->td_mailbox && (ku == NULL)) { + } else if (td->td_mailbox && !TD_IS_OWNER(td)) { error = thread_export_context(td); /* possibly upcall with error? */ PROC_LOCK(p); @@ -1657,8 +1671,8 @@ * work to do, wake one of them up. * XXXKSE Maybe wake all of them up. */ - if (!error && kg->kg_upsleeps) - wakeup_one(&kg->kg_completed); + if (!error && ku->ku_upsleep) + wakeup_one(&ku->ku_completed); mtx_lock_spin(&sched_lock); thread_stopped(p); thread_exit(); @@ -1666,7 +1680,7 @@ } KASSERT(TD_CAN_UNBIND(td) == 0, ("can unbind")); - + KASSERT(TD_IS_OWNER(td), ("not upcall owner")); if (p->p_numthreads > max_threads_per_proc) { max_threads_hits++; PROC_LOCK(p); @@ -2051,5 +2065,3 @@ } mtx_unlock_spin(&sched_lock); } - -