svn commit: r367605 - head/sys/kern

Mateusz Guzik mjg at FreeBSD.org
Thu Nov 12 00:29:23 UTC 2020


Author: mjg
Date: Thu Nov 12 00:29:23 2020
New Revision: 367605
URL: https://svnweb.freebsd.org/changeset/base/367605

Log:
  thread: move nthread management out of tid_alloc
  
  While this adds more work single-threaded, it also enables SMP-related
  speed ups.

Modified:
  head/sys/kern/kern_thread.c

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Wed Nov 11 22:35:23 2020	(r367604)
+++ head/sys/kern/kern_thread.c	Thu Nov 12 00:29:23 2020	(r367605)
@@ -144,7 +144,7 @@ static int maxthread;
 SYSCTL_INT(_kern, OID_AUTO, maxthread, CTLFLAG_RDTUN,
     &maxthread, 0, "Maximum number of threads");
 
-static int nthreads;
+static __exclusive_cache_line int nthreads;
 
 static LIST_HEAD(tidhashhead, thread) *tidhashtbl;
 static u_long	tidhash;
@@ -158,29 +158,52 @@ EVENTHANDLER_LIST_DEFINE(thread_dtor);
 EVENTHANDLER_LIST_DEFINE(thread_init);
 EVENTHANDLER_LIST_DEFINE(thread_fini);
 
-static lwpid_t
-tid_alloc(void)
+static bool
+thread_count_inc(void)
 {
 	static struct timeval lastfail;
 	static int curfail;
-	static lwpid_t trytid;
-	lwpid_t tid;
+	int nthreads_new;
 
-	mtx_lock(&tid_lock);
-	if (nthreads + 1 >= maxthread - 100) {
+	thread_reap();
+
+	nthreads_new = atomic_fetchadd_int(&nthreads, 1) + 1;
+	if (nthreads_new >= maxthread - 100) {
 		if (priv_check_cred(curthread->td_ucred, PRIV_MAXPROC) != 0 ||
-		    nthreads + 1 >= maxthread) {
-			mtx_unlock(&tid_lock);
+		    nthreads_new >= maxthread) {
+			atomic_subtract_int(&nthreads, 1);
 			if (ppsratecheck(&lastfail, &curfail, 1)) {
 				printf("maxthread limit exceeded by uid %u "
 				"(pid %d); consider increasing kern.maxthread\n",
 				curthread->td_ucred->cr_ruid, curproc->p_pid);
 			}
-			return (-1);
+			return (false);
 		}
 	}
+	return (true);
+}
 
-	nthreads++;
+static void
+thread_count_sub(int n)
+{
+
+	atomic_subtract_int(&nthreads, n);
+}
+
+static void
+thread_count_dec(void)
+{
+
+	thread_count_sub(1);
+}
+
+static lwpid_t
+tid_alloc(void)
+{
+	static lwpid_t trytid;
+	lwpid_t tid;
+
+	mtx_lock(&tid_lock);
 	/*
 	 * It is an invariant that the bitmap is big enough to hold maxthread
 	 * IDs. If we got to this point there has to be at least one free.
@@ -212,7 +235,6 @@ tid_free_locked(lwpid_t rtid)
 	KASSERT(bit_test(tid_bitmap, tid) != 0,
 	    ("thread ID %d not allocated\n", rtid));
 	bit_clear(tid_bitmap, tid);
-	nthreads--;
 }
 
 static void
@@ -398,6 +420,10 @@ threadinit(void)
 
 	mtx_init(&tid_lock, "TID lock", NULL, MTX_DEF);
 	tid_bitmap = bit_alloc(maxthread, M_TIDHASH, M_WAITOK);
+	/*
+	 * Handle thread0.
+	 */
+	thread_count_inc();
 	tid0 = tid_alloc();
 	if (tid0 != THREAD0_TID)
 		panic("tid0 %d != %d\n", tid0, THREAD0_TID);
@@ -482,6 +508,7 @@ thread_reap(void)
 		thread_free_batched(itd);
 		if (tidbatchn == nitems(tidbatch)) {
 			tid_free_batch(tidbatch, tidbatchn);
+			thread_count_sub(tidbatchn);
 			tidbatchn = 0;
 		}
 		itd = ntd;
@@ -489,6 +516,7 @@ thread_reap(void)
 
 	if (tidbatchn != 0) {
 		tid_free_batch(tidbatch, tidbatchn);
+		thread_count_sub(tidbatchn);
 	}
 }
 
@@ -501,18 +529,17 @@ thread_alloc(int pages)
 	struct thread *td;
 	lwpid_t tid;
 
-	thread_reap(); /* check if any zombies to get */
-
-	tid = tid_alloc();
-	if (tid == -1) {
+	if (!thread_count_inc()) {
 		return (NULL);
 	}
 
+	tid = tid_alloc();
 	td = uma_zalloc(thread_zone, M_WAITOK);
 	KASSERT(td->td_kstack == 0, ("thread_alloc got thread with kstack"));
 	if (!vm_thread_new(td, pages)) {
 		uma_zfree(thread_zone, td);
 		tid_free(tid);
+		thread_count_dec();
 		return (NULL);
 	}
 	td->td_tid = tid;
@@ -564,6 +591,7 @@ thread_free(struct thread *td)
 	tid = td->td_tid;
 	thread_free_batched(td);
 	tid_free(tid);
+	thread_count_dec();
 }
 
 void


More information about the svn-src-head mailing list