PERFORCE change 65317 for review

Julian Elischer julian at FreeBSD.org
Wed Nov 17 02:27:23 PST 2004


http://perforce.freebsd.org/chv.cgi?CH=65317

Change 65317 by julian at julian_ref on 2004/11/17 10:27:14

	small hack to cached fully functional threads.
	not tested..
	some stuff is definitly out of scope (wrong word but I can't
	think of the right one now). KSE specific stuff is seen out
	of the kse file..

Affected files ...

.. //depot/projects/nsched/sys/kern/kern_kse.c#35 edit
.. //depot/projects/nsched/sys/kern/kern_synch.c#19 edit
.. //depot/projects/nsched/sys/kern/kern_thread.c#46 edit
.. //depot/projects/nsched/sys/sys/proc.h#41 edit

Differences ...

==== //depot/projects/nsched/sys/kern/kern_kse.c#35 (text+ko) ====

@@ -1022,25 +1022,83 @@
  * from the schedlock as it has a mutex op itself.
  * XXX BUG.. we need to get the cr ref after the thread has 
  * checked and chenged its own, not 6 months before...  
+ * 
+ * If we have already some cached fully running threads, use them
+ * in preference as they need no setup.
  */
 void
 thread_alloc_spare(struct thread *td)
 {
 	struct thread *spare;
+	struct ksegrp *kg;
+
 
 	if (td->td_standin)
 		return;
-	spare = thread_alloc();
+	kg = td->td_ksegrp;
+	spare = TAILQ_FIRST(&kg->kg_ghostq);
+	if (spare) {
+		TAILQ_REMOVE(&kg->kg_ghostq, spare, td_runq);
+		kg->kg_numghosts--;
+	} else {
+		spare = thread_alloc();
+		bzero(&spare->td_startzero,
+		    (unsigned)RANGEOF(struct thread, td_startzero, td_endzero));
+		spare->td_proc = td->td_proc;
+		spare->td_ucred = crhold(td->td_ucred);
+	}
 	td->td_standin = spare;
-	bzero(&spare->td_startzero,
-	    (unsigned) RANGEOF(struct thread, td_startzero, td_endzero));
-	spare->td_proc = td->td_proc;
-	spare->td_ucred = crhold(td->td_ucred);
+}
+
+/*
+ * Divert exiting threads to be held in a ksegrp cache of 
+ * threads that are already in thread_userret().
+ * if they are run, they will exit unless they have an upcall
+ * (see thread_userret() )
+ * 
+ * Called from:
+ * thread_userret()
+ * 
+ */
+void
+thread_hold(struct thread *td)
+{
+	struct ksegrp *kg = td->td_ksegrp;
+
+	mtx_assert(&sched_lock, MA_OWNED);
+	TAILQ_INSERT_HEAD(&kg->kg_ghostq, td, td_runq);
+	kg->kg_numghosts++;
+	thread_unlink(td);
+	KASSERT((kg->kg_numthreads != 0), ("thread_hold: Cached last thread."));
+	mi_switch(0, NULL);
+}
+
+/* 
+ * Because we are exiting the ksegrp, 
+ * we should let all the cached threads run so that they can 
+ * suicide.
+ * 
+ * Called from:
+ * thread_exit()
+ */
+void
+thread_unhold_all(struct ksegrp *kg)
+{
+	struct thread *td;
+
+	mtx_assert(&sched_lock, MA_OWNED);
+	while ((td = TAILQ_FIRST(&kg->kg_ghostq))) {
+		TAILQ_REMOVE(&kg->kg_ghostq, td, td_runq);
+		kg->kg_numghosts--;
+		setrunnable(td);
+		thread_link(td, kg);
+	}
 }
 
 /*
  * Create a thread and schedule it for upcall on the KSE given.
  * Use our thread's standin so that we don't have to allocate one.
+ * If the standin is a ghost then just rescusitate it and use it.
  */
 struct thread *
 thread_schedule_upcall(struct thread *td, struct kse_upcall *ku)
@@ -1064,6 +1122,15 @@
 	CTR3(KTR_PROC, "thread_schedule_upcall: thread %p (pid %d, %s)",
 	     td2, td->td_proc->p_pid, td->td_proc->p_comm);
 	/*
+	 * if it's a ghost we are already all set up to run..
+	 * just give it the upcall and release it.
+	 */
+	if (td2->td_state == TDS_GHOST) {
+		td2->td_upcall = ku;
+		thread_link(td2, td->td_ksegrp);
+		return(td2);
+	}
+	/*
 	 * Bzero already done in thread_alloc_spare() because we can't
 	 * do the crhold here because we are in schedlock already.
 	 */
@@ -1315,9 +1382,12 @@
 			wakeup(&kg->kg_completed);
 		mtx_lock_spin(&sched_lock);
 		thread_stopped(p);
-		thread_exit();
-		/* NOTREACHED */
-	}
+		thread_hold(td);  /* thread effectively stops running */
+		if ((ku = td->td_upcall) == NULL)
+			thread_exit();
+		td->td_pflags |= TDP_UPCALLING;
+		mtx_unlock_spin(&sched_lock);
+	}	
 
 	KASSERT(ku != NULL, ("upcall is NULL"));
 	KASSERT(TD_CAN_UNBIND(td) == 0, ("can unbind"));

==== //depot/projects/nsched/sys/kern/kern_synch.c#19 (text+ko) ====

@@ -374,6 +374,12 @@
 	case TDS_RUNNING:
 	case TDS_RUNQ:
 		return;
+	case TDS_GHOST:
+		if (td->td_inhibitors == 0) {
+			td->td_state = TDS_CAN_RUN;
+			break;
+		} else
+			td->td_state = TDS_INHIBITED;
 	case TDS_INHIBITED:
 		/*
 		 * If we are only inhibited because we are swapped out

==== //depot/projects/nsched/sys/kern/kern_thread.c#46 (text+ko) ====

@@ -557,6 +557,12 @@
 	 * takes the short path.
 	 */
 	if (p->p_flag & P_HADTHREADS) {
+		/*
+		 * If only one thread make sure we free any cached ghosts.
+		 * which may make numhreads >1 for a moment.
+		 */
+		if (p->p_numthreads > 1)
+			thread_unhold_all(kg);
 		if (p->p_numthreads > 1) {
 			thread_unlink(td);
 
@@ -596,7 +602,11 @@
 			/*
 			 * If the thread we unlinked above was the last one,
 			 * then this ksegrp should go away too.
+			 * but first lett any cached "ghost" threads suicide.
+			 * This may temporarily increase the number of threads.
 			 */
+			if (kg->kg_numthreads == 0)
+				thread_unhold_all(kg);
 			if (kg->kg_numthreads == 0) {
 				/*
 				 * let the scheduler know about this in case
@@ -614,6 +624,7 @@
 				 * This is probably not fair so think of
  				 * a better answer.
 				 */
+				thread_unhold_all(kg);
 				sched_exit_ksegrp(FIRST_KSEGRP_IN_PROC(p), td);
 				sched_set_concurrency(kg, 0); /* XXX TEMP */
 				ksegrp_unlink(kg);
@@ -687,6 +698,7 @@
  *  proc_linkup()
  *  thread_schedule_upcall()
  *  thr_create()
+ *  thread_unhold_all()
  */
 void
 thread_link(struct thread *td, struct ksegrp *kg)
@@ -710,6 +722,7 @@
 
 /*
  * Convert a process with one thread to an unthreaded process.
+ * 
  * Called from:
  *  thread_single(exit)  (called from execve and exit)
  *  kse_exit()		XXX may need cleaning up wrt KSE stuff
@@ -718,22 +731,30 @@
 thread_unthread(struct thread *td)
 {
 	struct proc *p = td->td_proc;
+	struct thread *spare;
 
 	KASSERT((p->p_numthreads == 1), ("Unthreading with >1 threads"));
+	if (td->td_standin != NULL) {
+		spare = td->td_standin;
+		td->td_standin = NULL;
+		if (spare->td_state == TDS_GHOST) {
+			thread_link(spare, td->td_ksegrp);	
+			mi_switch(0, spare);
+		} else {
+			thread_stash(spare);
+		}
+	}
 	upcall_remove(td);
 	p->p_flag &= ~(P_SA|P_HADTHREADS);
 	td->td_mailbox = NULL;
 	td->td_pflags &= ~(TDP_SA | TDP_CAN_UNBIND);
-	if (td->td_standin != NULL) {
-		thread_stash(td->td_standin);
-		td->td_standin = NULL;
-	}
 	sched_set_concurrency(td->td_ksegrp, 1);
 }
 
 /*
  * Called from:
  *  thread_exit()
+ *  thread_hold()
  */
 void
 thread_unlink(struct thread *td)

==== //depot/projects/nsched/sys/sys/proc.h#41 (text+ko) ====

@@ -304,6 +304,7 @@
 	struct pcb	*td_pcb;	/* (k) Kernel VA of pcb and kstack. */
 	enum {
 		TDS_INACTIVE = 0x0,
+		TDS_GHOST,		/* not allowed to die yet.. cached */
 		TDS_INHIBITED,
 		TDS_CAN_RUN,
 		TDS_RUNQ,
@@ -327,7 +328,7 @@
  * Flags kept in td_flags:
  * To change these you MUST have the scheduler lock.
  */
-#define	TDF_UNUSED0	0x00000001 /* --available -- */
+#define	TDF_GHOST	0x00000001 /* All set up but not alive */
 #define	TDF_INPANIC	0x00000002 /* Caused a panic, let it drive crashdump. */
 #define	TDF_SINTR	0x00000008 /* Sleep is interruptible. */
 #define	TDF_TIMEOUT	0x00000010 /* Timing out during sleep. */
@@ -466,6 +467,7 @@
 	TAILQ_HEAD(, thread) kg_threads;/* (td_kglist) All threads. */
 	TAILQ_HEAD(, thread) kg_runq;	/* (td_runq) waiting RUNNABLE threads */
 	TAILQ_HEAD(, thread) kg_slpq;	/* (td_runq) NONRUNNABLE threads. */
+	TAILQ_HEAD(, thread) kg_ghostq;	/* (td_runq) cached instead of dead. */
 	TAILQ_HEAD(, kse_upcall) kg_upcalls;	/* All upcalls in the group. */
 
 #define	kg_startzero kg_estcpu
@@ -484,6 +486,7 @@
 	u_char		kg_user_pri;	/* (j) User pri from estcpu and nice. */
 #define	kg_endcopy kg_numthreads
 	int		kg_numthreads;	/* (j) Num threads in total. */
+	int		kg_numghosts;	/* (j) number of threads ghosting */
 	struct kg_sched	*kg_sched;	/* (*) Scheduler-specific data. */
 };
 
@@ -932,6 +935,8 @@
 void	upcall_remove(struct thread *td);
 void	upcall_stash(struct kse_upcall *ke);
 
+void thread_unhold_all(struct ksegrp *kg);
+void thread_hold(struct thread *td);
 #endif	/* _KERNEL */
 
 #endif	/* !_SYS_PROC_H_ */


More information about the p4-projects mailing list