Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F106330671
D27185.id79480.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D27185.id79480.diff
View Options
Index: sys/kern/kern_thread.c
===================================================================
--- sys/kern/kern_thread.c
+++ sys/kern/kern_thread.c
@@ -52,6 +52,7 @@
#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/turnstile.h>
+#include <sys/taskqueue.h>
#include <sys/ktr.h>
#include <sys/rwlock.h>
#include <sys/umtx.h>
@@ -128,9 +129,27 @@
*/
static uma_zone_t thread_zone;
-static __exclusive_cache_line struct thread *thread_zombies;
+struct thread_domain_data {
+ struct thread *tdd_zombies;
+ int tdd_reapticks;
+} __aligned(CACHE_LINE_SIZE);
+
+static struct thread_domain_data thread_domain_data[MAXMEMDOM];
+
+static int
+struct_thread_domain(struct thread *td)
+{
+
+ return (uma_item_domain(td));
+}
+
+static struct task thread_reap_task;
+static struct callout thread_reap_callout;
static void thread_zombie(struct thread *);
+static void thread_reap_all(void);
+static void thread_reap_task_cb(void *, int);
+static void thread_reap_callout_cb(void *);
static int thread_unsuspend_one(struct thread *td, struct proc *p,
bool boundary);
static void thread_free_batched(struct thread *td);
@@ -159,30 +178,45 @@
EVENTHANDLER_LIST_DEFINE(thread_fini);
static bool
-thread_count_inc(void)
+thread_count_inc_try(void)
{
- static struct timeval lastfail;
- static int curfail;
int nthreads_new;
- 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_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 (false);
}
}
return (true);
}
+static bool
+thread_count_inc(void)
+{
+ static struct timeval lastfail;
+ static int curfail;
+
+ thread_reap();
+ if (thread_count_inc_try()) {
+ return (true);
+ }
+
+ thread_reap_all();
+ if (thread_count_inc_try()) {
+ return (true);
+ }
+
+ 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 (false);
+}
+
static void
thread_count_sub(int n)
{
@@ -450,6 +484,10 @@
M_TIDHASH, M_WAITOK | M_ZERO);
for (i = 0; i < tidhashlock + 1; i++)
rw_init(&tidhashtbl_lock[i], "tidhash");
+
+ TASK_INIT(&thread_reap_task, 0, thread_reap_task_cb, NULL);
+ callout_init(&thread_reap_callout, 1);
+ callout_reset(&thread_reap_callout, 5 * hz, thread_reap_callout_cb, NULL);
}
/*
@@ -458,12 +496,14 @@
void
thread_zombie(struct thread *td)
{
+ struct thread_domain_data *tdd;
struct thread *ztd;
- ztd = atomic_load_ptr(&thread_zombies);
+ tdd = &thread_domain_data[struct_thread_domain(td)];
+ ztd = atomic_load_ptr(&tdd->tdd_zombies);
for (;;) {
td->td_zombie = ztd;
- if (atomic_fcmpset_rel_ptr((uintptr_t *)&thread_zombies,
+ if (atomic_fcmpset_rel_ptr((uintptr_t *)&tdd->tdd_zombies,
(uintptr_t *)&ztd, (uintptr_t)td))
break;
continue;
@@ -481,10 +521,10 @@
}
/*
- * Reap zombie threads.
+ * Reap zombies from passed domain.
*/
-void
-thread_reap(void)
+static void
+thread_reap_domain(struct thread_domain_data *tdd)
{
struct thread *itd, *ntd;
lwpid_t tidbatch[16];
@@ -494,11 +534,20 @@
* Reading upfront is pessimal if followed by concurrent atomic_swap,
* but most of the time the list is empty.
*/
- if (thread_zombies == NULL)
+ if (tdd->tdd_zombies == NULL)
return;
- itd = (struct thread *)atomic_swap_ptr((uintptr_t *)&thread_zombies,
+ itd = (struct thread *)atomic_swap_ptr((uintptr_t *)&tdd->tdd_zombies,
(uintptr_t)NULL);
+ if (itd == NULL)
+ return;
+
+ /*
+ * Multiple CPUs can get here, the race is fine as ticks is only
+ * advisory.
+ */
+ tdd->tdd_reapticks = ticks;
+
tidbatchn = 0;
while (itd != NULL) {
ntd = itd->td_zombie;
@@ -520,6 +569,68 @@
}
}
+/*
+ * Reap zombies from all domains.
+ */
+static void
+thread_reap_all(void)
+{
+ struct thread_domain_data *tdd;
+ int i, domain;
+
+ domain = PCPU_GET(domain);
+ for (i = 0; i < vm_ndomains; i++) {
+ tdd = &thread_domain_data[(i + domain) % vm_ndomains];
+ thread_reap_domain(tdd);
+ }
+}
+
+/*
+ * Reap zombies from local domain.
+ */
+void
+thread_reap(void)
+{
+ struct thread_domain_data *tdd;
+ int domain;
+
+ domain = PCPU_GET(domain);
+ tdd = &thread_domain_data[domain];
+
+ thread_reap_domain(tdd);
+}
+
+static void
+thread_reap_task_cb(void *arg __unused, int pending __unused)
+{
+
+ thread_reap_all();
+}
+
+static void
+thread_reap_callout_cb(void *arg __unused)
+{
+ struct thread_domain_data *tdd;
+ int i, cticks, lticks;
+ bool wantreap;
+
+ wantreap = false;
+ cticks = atomic_load_int(&ticks);
+ for (i = 0; i < vm_ndomains; i++) {
+ tdd = &thread_domain_data[i];
+ lticks = tdd->tdd_reapticks;
+ if (tdd->tdd_zombies != NULL &&
+ (u_int)(cticks - lticks) > 5 * hz) {
+ wantreap = true;
+ break;
+ }
+ }
+
+ if (wantreap)
+ taskqueue_enqueue(taskqueue_thread, &thread_reap_task);
+ callout_reset(&thread_reap_callout, 5 * hz, thread_reap_callout_cb, NULL);
+}
+
/*
* Allocate a thread.
*/
Index: sys/vm/uma.h
===================================================================
--- sys/vm/uma.h
+++ sys/vm/uma.h
@@ -300,6 +300,20 @@
#define UMA_ANYDOMAIN -1 /* Special value for domain search. */
+/*
+ * Returns domain backing the passed pointer.
+ */
+#ifdef NUMA
+int uma_item_domain(void *item);
+#else
+static inline int
+uma_item_domain(void *item)
+{
+
+ return (0);
+}
+#endif
+
/*
* Destroys an empty uma zone. If the zone is not empty uma complains loudly.
*
Index: sys/vm/uma_core.c
===================================================================
--- sys/vm/uma_core.c
+++ sys/vm/uma_core.c
@@ -3259,6 +3259,16 @@
("%s: unknown domain for item %p", __func__, item));
return (domain);
}
+
+int
+uma_item_domain(void *item)
+{
+
+ /*
+ * XXX assert passed object was allocated by UMA.
+ */
+ return (item_domain(item));
+}
#endif
#if defined(INVARIANTS) || defined(DEBUG_MEMGUARD) || defined(WITNESS)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 29, 7:54 PM (7 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15632646
Default Alt Text
D27185.id79480.diff (6 KB)
Attached To
Mode
D27185: thread: numa-aware zombie reaping
Attached
Detach File
Event Timeline
Log In to Comment