Index: kern_synch.c =================================================================== RCS file: /cvs/src/sys/kern/kern_synch.c,v diff -u -p -r1.213 kern_synch.c --- kern_synch.c 11 Nov 2024 13:28:29 -0000 1.213 +++ kern_synch.c 24 Nov 2024 23:11:34 -0000 @@ -63,8 +63,6 @@ #endif int sleep_signal_check(struct proc *, int); -int thrsleep(struct proc *, struct sys___thrsleep_args *); -int thrsleep_unlock(void *); extern void proc_stop(struct proc *p, int); @@ -620,28 +623,67 @@ sys_sched_yield(struct proc *p, void *v, return (0); } -int +static inline int thrsleep_unlock(void *lock) { static _atomic_lock_t unlocked = _ATOMIC_LOCK_UNLOCKED; _atomic_lock_t *atomiclock = lock; - if (!lock) + if (lock == NULL) return 0; return copyout(&unlocked, atomiclock, sizeof(unlocked)); } struct tslpentry { - TAILQ_ENTRY(tslpentry) tslp_link; - long tslp_ident; + TAILQ_ENTRY(tslpentry) tslp_link; + struct process *tslp_ps; + volatile long tslp_ident; + struct proc *tslp_p; }; +struct tslp_bucket { + struct tslpqueue tsb_list; + struct mutex tsb_lock; +} __aligned(64); + /* thrsleep queue shared between processes */ -static struct tslpqueue thrsleep_queue = TAILQ_HEAD_INITIALIZER(thrsleep_queue); -static struct rwlock thrsleep_lock = RWLOCK_INITIALIZER("thrsleeplk"); +static struct tslp_bucket tsb_shared; -int +#define TSLP_BUCKET_BITS 6 +#define TSLP_BUCKET_SIZE (1UL << TSLP_BUCKET_BITS) +#define TSLP_BUCKET_MASK (TSLP_BUCKET_SIZE - 1) + +static struct tslp_bucket tsb_buckets[TSLP_BUCKET_SIZE]; + +void +tslp_init(void) +{ + struct tslp_bucket *tsb; + size_t i; + + TAILQ_INIT(&tsb_shared.tsb_list); + mtx_init(&tsb_shared.tsb_lock, IPL_NONE); + + for (i = 0; i < nitems(tsb_buckets); i++) { + tsb = &tsb_buckets[i]; + + TAILQ_INIT(&tsb->tsb_list); + mtx_init(&tsb->tsb_lock, IPL_NONE); + } +} + +static struct tslp_bucket * +thrsleep_bucket(long ident) +{ + ident >>= 3; + ident ^= ident >> TSLP_BUCKET_BITS; + ident &= TSLP_BUCKET_MASK; + + return &tsb_buckets[ident]; +} + +static int thrsleep(struct proc *p, struct sys___thrsleep_args *v) { struct sys___thrsleep_args /* { @@ -653,13 +695,13 @@ thrsleep(struct proc *p, struct sys___th } */ *uap = v; long ident = (long)SCARG(uap, ident); struct tslpentry entry; - struct tslpqueue *queue; - struct rwlock *qlock; + struct tslp_bucket *tsb; struct timespec *tsp = (struct timespec *)SCARG(uap, tp); void *lock = SCARG(uap, lock); uint64_t nsecs = INFSLP; int abort = 0, error; clockid_t clock_id = SCARG(uap, clock_id); + int to_ticks = 0; if (ident == 0) return (EINVAL); @@ -682,49 +724,56 @@ thrsleep(struct proc *p, struct sys___th timespecsub(tsp, &now, tsp); nsecs = MIN(TIMESPEC_TO_NSEC(tsp), MAXTSLP); + to_ticks = (nsecs + tick_nsec - 1) / (tick_nsec + 1) + 1; + if (to_ticks > INT_MAX) + to_ticks = INT_MAX; } - if (ident == -1) { - queue = &thrsleep_queue; - qlock = &thrsleep_lock; - } else { - queue = &p->p_p->ps_tslpqueue; - qlock = &p->p_p->ps_lock; - } + tsb = (ident == -1) ? &tsb_shared : thrsleep_bucket(ident); /* Interlock with wakeup. */ + entry.tslp_ps = p->p_p; entry.tslp_ident = ident; - rw_enter_write(qlock); - TAILQ_INSERT_TAIL(queue, &entry, tslp_link); - rw_exit_write(qlock); + entry.tslp_p = p; - error = thrsleep_unlock(lock); + mtx_enter(&tsb->tsb_lock); + TAILQ_INSERT_TAIL(&tsb->tsb_list, &entry, tslp_link); + mtx_leave(&tsb->tsb_lock); - if (error == 0 && SCARG(uap, abort) != NULL) - error = copyin(SCARG(uap, abort), &abort, sizeof(abort)); + error = thrsleep_unlock(lock); + if (error != 0) + goto leave; - rw_enter_write(qlock); + error = copyin(SCARG(uap, abort), &abort, sizeof(abort)); if (error != 0) - goto out; + goto leave; if (abort != 0) { error = EINTR; - goto out; - } - if (entry.tslp_ident != 0) { - error = rwsleep_nsec(&entry, qlock, PWAIT|PCATCH, "thrsleep", - nsecs); + goto leave; } -out: - if (entry.tslp_ident != 0) - TAILQ_REMOVE(queue, &entry, tslp_link); - rw_exit_write(qlock); + sleep_setup(&entry, PWAIT|PCATCH, "thrsleep"); + error = sleep_finish(to_ticks, entry.tslp_ident != 0); + if (error != 0 || entry.tslp_ident != 0) { + mtx_enter(&tsb->tsb_lock); + if (entry.tslp_ident != 0) + TAILQ_REMOVE(&tsb->tsb_list, &entry, tslp_link); + else + error = 0; + mtx_leave(&tsb->tsb_lock); - if (error == ERESTART) - error = ECANCELED; + if (error == ERESTART) + error = ECANCELED; + } return (error); +leave: + mtx_enter(&tsb->tsb_lock); + TAILQ_REMOVE(&tsb->tsb_list, &entry, tslp_link); + mtx_leave(&tsb->tsb_lock); + + return (error); } int @@ -763,50 +812,68 @@ sys___thrwakeup(struct proc *p, void *v, syscallarg(const volatile void *) ident; syscallarg(int) n; } */ *uap = v; - struct tslpentry *entry, *tmp; - struct tslpqueue *queue; - struct rwlock *qlock; + struct tslpentry *entry, *nentry; + struct tslp_bucket *tsb; long ident = (long)SCARG(uap, ident); int n = SCARG(uap, n); int found = 0; + struct tslpqueue wq = TAILQ_HEAD_INITIALIZER(wq); + struct proc *wp; - if (ident == 0) + if (ident == 0) { *retval = EINVAL; - else { - if (ident == -1) { - queue = &thrsleep_queue; - qlock = &thrsleep_lock; - /* - * Wake up all waiters with ident -1. This is needed - * because ident -1 can be shared by multiple userspace - * lock state machines concurrently. The implementation - * has no way to direct the wakeup to a particular - * state machine. - */ - n = 0; - } else { - queue = &p->p_p->ps_tslpqueue; - qlock = &p->p_p->ps_lock; - } + return (0); + } - rw_enter_write(qlock); - TAILQ_FOREACH_SAFE(entry, queue, tslp_link, tmp) { - if (entry->tslp_ident == ident) { - TAILQ_REMOVE(queue, entry, tslp_link); - entry->tslp_ident = 0; - wakeup_one(entry); - if (++found == n) - break; - } + if (ident == -1) { + /* + * Wake up all waiters with ident -1. This is needed + * because ident -1 can be shared by multiple userspace + * lock state machines concurrently. The implementation + * has no way to direct the wakeup to a particular + * state machine. + */ + mtx_enter(&tsb_shared.tsb_lock); + SCHED_LOCK(); + TAILQ_FOREACH_SAFE(entry, &tsb_shared.tsb_list, tslp_link, nentry) { + wp = entry->tslp_p; + entry->tslp_ident = 0; + wakeup_proc(wp, 0); } - rw_exit_write(qlock); + SCHED_UNLOCK(); + TAILQ_INIT(&tsb_shared.tsb_list); + mtx_leave(&tsb_shared.tsb_lock); - if (ident == -1) - *retval = 0; - else - *retval = found ? 0 : ESRCH; + *retval = 0; + return (0); + } + + tsb = thrsleep_bucket(ident); + + mtx_enter(&tsb->tsb_lock); + TAILQ_FOREACH_SAFE(entry, &tsb->tsb_list, tslp_link, nentry) { + if (entry->tslp_ident != ident || entry->tslp_ps != p->p_p) + continue; + + TAILQ_REMOVE(&tsb->tsb_list, entry, tslp_link); + TAILQ_INSERT_TAIL(&wq, entry, tslp_link); + + if (++found == n) + break; + } + + if (found) { + SCHED_LOCK(); + TAILQ_FOREACH_SAFE(entry, &wq, tslp_link, nentry) { + wp = entry->tslp_p; + entry->tslp_ident = 0; + wakeup_proc(wp, 0); + } + SCHED_UNLOCK(); } + mtx_leave(&tsb->tsb_lock); + *retval = found ? 0 : ESRCH; return (0); } Index: init_main.c =================================================================== RCS file: /cvs/src/sys/kern/init_main.c,v diff -u -p -r1.326 init_main.c --- init_main.c 2 Apr 2024 08:39:16 -0000 1.326 +++ init_main.c 24 Nov 2024 23:11:34 -0000 @@ -140,6 +140,7 @@ void db_ctf_init(void); void prof_init(void); void init_exec(void); void futex_init(void); +void tslp_init(void); void taskq_init(void); void timeout_proc_init(void); void pool_gc_pages(void *); @@ -250,6 +251,7 @@ main(void *framep) * Initialize futexes. */ futex_init(); + tslp_init(); /* Create credentials. */ p->p_ucred = crget();