diff options
author | deischen <deischen@FreeBSD.org> | 2003-04-22 20:28:33 +0000 |
---|---|---|
committer | deischen <deischen@FreeBSD.org> | 2003-04-22 20:28:33 +0000 |
commit | 23350dd1f55e20a596f9e469feca743c7fe997ec (patch) | |
tree | 19f3d1be5afa27ed30120ee055e1c276564167d9 /lib/libpthread | |
parent | 18f0a39a3fe1da16212e6fc2c570431b6fac7fff (diff) | |
download | FreeBSD-src-23350dd1f55e20a596f9e469feca743c7fe997ec.zip FreeBSD-src-23350dd1f55e20a596f9e469feca743c7fe997ec.tar.gz |
Add a couple asserts to pthread_cond_foo to ensure the (low-level)
lock level is 0. Thus far, the threads implementation doesn't use
mutexes or condition variables so the lock level should be 0.
Save the return value when trying to schedule a new thread and
use this to return an error from pthread_create().
Change the max sleep time for an idle KSE to 1 minute from 2 minutes.
Maintain a count of the number of KSEs within a KSEG.
With these changes scope system threads seem to work, but heavy
use of them crash the kernel (supposedly VM bugs).
Diffstat (limited to 'lib/libpthread')
-rw-r--r-- | lib/libpthread/thread/thr_cond.c | 6 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_create.c | 16 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_init.c | 3 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_kern.c | 64 | ||||
-rw-r--r-- | lib/libpthread/thread/thr_private.h | 4 |
5 files changed, 72 insertions, 21 deletions
diff --git a/lib/libpthread/thread/thr_cond.c b/lib/libpthread/thread/thr_cond.c index c6bffeb..537c264 100644 --- a/lib/libpthread/thread/thr_cond.c +++ b/lib/libpthread/thread/thr_cond.c @@ -373,6 +373,8 @@ _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, int unlock_mutex = 1; int seqno; + THR_ASSERT(curthread->locklevel == 0, + "cv_timedwait: locklevel is not zero!"); _thr_enter_cancellation_point(curthread); if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || @@ -575,6 +577,8 @@ _pthread_cond_signal(pthread_cond_t * cond) struct pthread *pthread; int rval = 0; + THR_ASSERT(curthread->locklevel == 0, + "cv_timedwait: locklevel is not zero!"); if (cond == NULL) rval = EINVAL; /* @@ -632,6 +636,8 @@ _pthread_cond_broadcast(pthread_cond_t * cond) struct pthread *pthread; int rval = 0; + THR_ASSERT(curthread->locklevel == 0, + "cv_timedwait: locklevel is not zero!"); if (cond == NULL) rval = EINVAL; /* diff --git a/lib/libpthread/thread/thr_create.c b/lib/libpthread/thread/thr_create.c index c38b267..deb26de 100644 --- a/lib/libpthread/thread/thr_create.c +++ b/lib/libpthread/thread/thr_create.c @@ -57,6 +57,7 @@ int _thread_ctx_offset = OFF(tmbx.tm_context); int _thread_PS_RUNNING_value = PS_RUNNING; int _thread_PS_DEAD_value = PS_DEAD; +static void free_thread(struct pthread *curthread, struct pthread *thread); static int create_stack(struct pthread_attr *pattr); static void thread_start(struct pthread *curthread, void *(*start_routine) (void *), void *arg); @@ -295,8 +296,10 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, * Schedule the new thread starting a new KSEG/KSE * pair if necessary. */ - _thr_schedule_add(curthread, new_thread); + ret = _thr_schedule_add(curthread, new_thread); _kse_critical_leave(crit); + if (ret != 0) + free_thread(curthread, new_thread); /* Return a pointer to the thread structure: */ (*thread) = new_thread; @@ -307,6 +310,17 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, return (ret); } +static void +free_thread(struct pthread *curthread, struct pthread *thread) +{ + if ((thread->attr.flags & PTHREAD_SCOPE_SYSTEM) != 0) { + /* Free the KSE and KSEG. */ + _kseg_free(thread->kseg); + _kse_free(curthread, thread->kse); + } + _thr_free(curthread, thread); +} + static int create_stack(struct pthread_attr *pattr) { diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c index 626a134..804462c 100644 --- a/lib/libpthread/thread/thr_init.c +++ b/lib/libpthread/thread/thr_init.c @@ -264,6 +264,9 @@ _libpthread_init(struct pthread *curthread) PANIC("Can't allocate initial kseg."); _kse_initial->k_schedq = &_kse_initial->k_kseg->kg_schedq; + TAILQ_INSERT_TAIL(&_kse_initial->k_kseg->kg_kseq, _kse_initial, k_kgqe); + _kse_initial->k_kseg->kg_ksecount = 1; + /* Set the initial thread. */ if (curthread == NULL) { /* Create and initialize the initial thread. */ diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c index 6176b71..c4e9d5e 100644 --- a/lib/libpthread/thread/thr_kern.c +++ b/lib/libpthread/thread/thr_kern.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <machine/atomic.h> #include <assert.h> +#include <errno.h> #include <signal.h> #include <stdlib.h> #include <string.h> @@ -134,7 +135,7 @@ static void kse_sched_single(struct kse *curkse); static void kse_switchout_thread(struct kse *kse, struct pthread *thread); static void kse_wait(struct kse *kse, struct pthread *td_wait); static void kse_free_unlocked(struct kse *kse); -static void kseg_free(struct kse_group *kseg); +static void kseg_free_unlocked(struct kse_group *kseg); static void kseg_init(struct kse_group *kseg); static void kseg_reinit(struct kse_group *kseg); static void kse_waitq_insert(struct pthread *thread); @@ -404,7 +405,7 @@ _kse_lock_wait(struct lock *lock, struct lockuser *lu) * is granted. */ saved_flags = curkse->k_mbx.km_flags; - curkse->k_mbx.km_flags |= KMF_NOUPCALL; + curkse->k_mbx.km_flags |= KMF_NOUPCALL | KMF_NOCOMPLETED; kse_release(&ts); curkse->k_mbx.km_flags = saved_flags; @@ -703,6 +704,9 @@ kse_sched_multi(struct kse *curkse) struct pthread_sigframe *curframe; int ret; + THR_ASSERT(curkse->k_mbx.km_curthread == NULL, + "Mailbox not null in kse_sched_multi"); + /* Check for first time initialization: */ if ((curkse->k_flags & KF_INITIALIZED) == 0) { /* Setup this KSEs specific data. */ @@ -714,8 +718,10 @@ kse_sched_multi(struct kse *curkse) } /* This may have returned from a kse_release(). */ - if (KSE_WAITING(curkse)) + if (KSE_WAITING(curkse)) { + DBG_MSG("Entered upcall when KSE is waiting."); KSE_CLEAR_WAIT(curkse); + } /* Lock the scheduling lock. */ KSE_SCHED_LOCK(curkse, curkse->k_kseg); @@ -1067,7 +1073,7 @@ _thr_gc(struct pthread *curthread) crit = _kse_critical_enter(); KSE_LOCK_ACQUIRE(curthread->kse, &kse_lock); kse_free_unlocked(td->kse); - kseg_free(td->kseg); + kseg_free_unlocked(td->kseg); KSE_LOCK_RELEASE(curthread->kse, &kse_lock); _kse_critical_leave(crit); } @@ -1080,12 +1086,13 @@ _thr_gc(struct pthread *curthread) /* * Only new threads that are running or suspended may be scheduled. */ -void +int _thr_schedule_add(struct pthread *curthread, struct pthread *newthread) { struct kse *curkse; kse_critical_t crit; int need_start; + int ret; /* * If this is the first time creating a thread, make sure @@ -1106,6 +1113,7 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread) KSEG_THRQ_ADD(newthread->kseg, newthread); TAILQ_INSERT_TAIL(&newthread->kseg->kg_kseq, newthread->kse, k_kgqe); + newthread->kseg->kg_ksecount = 1; if (newthread->state == PS_RUNNING) THR_RUNQ_INSERT_TAIL(newthread); newthread->kse->k_curthread = NULL; @@ -1119,7 +1127,9 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread) curkse = _get_curkse(); _ksd_setprivate(&newthread->kse->k_ksd); newthread->kse->k_flags |= KF_INITIALIZED; - kse_create(&newthread->kse->k_mbx, 1); + ret = kse_create(&newthread->kse->k_mbx, 1); + if (ret != 0) + ret = errno; _ksd_setprivate(&curkse->k_ksd); _kse_critical_leave(crit); } @@ -1156,7 +1166,9 @@ _thr_schedule_add(struct pthread *curthread, struct pthread *newthread) */ KSE_WAKEUP(newthread->kse); } + ret = 0; } + return (ret); } void @@ -1420,13 +1432,13 @@ kse_wait(struct kse *kse, struct pthread *td_wait) KSE_GET_TOD(kse, &ts); if ((td_wait == NULL) || (td_wait->wakeup_time.tv_sec < 0)) { - /* Limit sleep to no more than 2 minutes. */ - ts_sleep.tv_sec = 120; + /* Limit sleep to no more than 1 minute. */ + ts_sleep.tv_sec = 60; ts_sleep.tv_nsec = 0; } else { TIMESPEC_SUB(&ts_sleep, &td_wait->wakeup_time, &ts); - if (ts_sleep.tv_sec > 120) { - ts_sleep.tv_sec = 120; + if (ts_sleep.tv_sec > 60) { + ts_sleep.tv_sec = 60; ts_sleep.tv_nsec = 0; } } @@ -1462,6 +1474,7 @@ kse_fini(struct kse *kse) /* Remove this KSE from the KSEG's list of KSEs. */ KSE_SCHED_LOCK(kse, kse->k_kseg); TAILQ_REMOVE(&kse->k_kseg->kg_kseq, kse, k_kgqe); + kse->k_kseg->kg_ksecount--; if (TAILQ_EMPTY(&kse->k_kseg->kg_kseq)) free_kseg = kse->k_kseg; KSE_SCHED_UNLOCK(kse, kse->k_kseg); @@ -1472,7 +1485,7 @@ kse_fini(struct kse *kse) */ KSE_LOCK_ACQUIRE(kse, &kse_lock); if (free_kseg != NULL) - kseg_free(free_kseg); + kseg_free_unlocked(free_kseg); kse_free_unlocked(kse); KSE_LOCK_RELEASE(kse, &kse_lock); kse_exit(); @@ -1491,14 +1504,11 @@ kse_fini(struct kse *kse) if ((active_kse_count > 1) && (kse->k_kseg->kg_threadcount == 0)) { KSE_SCHED_UNLOCK(kse, kse->k_kseg); - /* - * XXX - We need a way for the KSE to do a timed - * wait. - */ kse_release(&ts); /* The above never returns. */ } - KSE_SCHED_UNLOCK(kse, kse->k_kseg); + else + KSE_SCHED_UNLOCK(kse, kse->k_kseg); /* There are no more threads; exit this process: */ if (kse->k_kseg->kg_threadcount == 0) { @@ -1708,7 +1718,7 @@ _kseg_alloc(struct pthread *curthread) * no more threads that reference it. */ static void -kseg_free(struct kse_group *kseg) +kseg_free_unlocked(struct kse_group *kseg) { TAILQ_REMOVE(&active_kse_groupq, kseg, kg_qe); TAILQ_INSERT_HEAD(&free_kse_groupq, kseg, kg_qe); @@ -1716,6 +1726,20 @@ kseg_free(struct kse_group *kseg) active_kseg_count--; } +void +_kseg_free(struct kse_group *kseg) +{ + struct kse *curkse; + kse_critical_t crit; + + crit = _kse_critical_enter(); + curkse = _get_curkse(); + KSE_LOCK_ACQUIRE(curkse, &kse_lock); + kseg_free_unlocked(kseg); + KSE_LOCK_RELEASE(curkse, &kse_lock); + _kse_critical_leave(crit); +} + /* * Allocate a new KSE. * @@ -1747,8 +1771,8 @@ _kse_alloc(struct pthread *curthread) if (kse != NULL) { TAILQ_REMOVE(&free_kseq, kse, k_qe); free_kse_count--; - active_kse_count++; TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe); + active_kse_count++; } KSE_LOCK_RELEASE(curthread->kse, &kse_lock); _kse_critical_leave(crit); @@ -1817,8 +1841,8 @@ _kse_alloc(struct pthread *curthread) return (NULL); } kse->k_flags = 0; - active_kse_count++; TAILQ_INSERT_TAIL(&active_kseq, kse, k_qe); + active_kse_count++; if (curthread != NULL) { KSE_LOCK_RELEASE(curthread->kse, &kse_lock); _kse_critical_leave(crit); @@ -1830,6 +1854,7 @@ _kse_alloc(struct pthread *curthread) void kse_free_unlocked(struct kse *kse) { + TAILQ_REMOVE(&active_kseq, kse, k_qe); active_kse_count--; kse->k_kseg = NULL; kse->k_flags &= ~KF_INITIALIZED; @@ -1868,6 +1893,7 @@ kseg_reinit(struct kse_group *kseg) TAILQ_INIT(&kseg->kg_threadq); TAILQ_INIT(&kseg->kg_schedq.sq_waitq); kseg->kg_threadcount = 0; + kseg->kg_ksecount = 0; kseg->kg_idle_kses = 0; kseg->kg_flags = 0; } diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h index 87bc05a..a554796 100644 --- a/lib/libpthread/thread/thr_private.h +++ b/lib/libpthread/thread/thr_private.h @@ -215,6 +215,7 @@ struct kse_group { struct sched_queue kg_schedq; /* scheduling queue */ struct lock kg_lock; int kg_threadcount; /* # of assigned threads */ + int kg_ksecount; /* # of assigned KSEs */ int kg_idle_kses; int kg_flags; #define KGF_SINGLE_THREAD 0x0001 /* scope system kse group */ @@ -1023,6 +1024,7 @@ void _kse_single_thread(struct pthread *); void _kse_start(struct kse *); int _kse_setthreaded(int); int _kse_isthreaded(void); +void _kseg_free(struct kse_group *); int _mutex_cv_lock(pthread_mutex_t *); int _mutex_cv_unlock(pthread_mutex_t *); void _mutex_lock_backout(struct pthread *); @@ -1060,7 +1062,7 @@ void _thr_lock_wait(struct lock *lock, struct lockuser *lu); void _thr_lock_wakeup(struct lock *lock, struct lockuser *lu); int _thr_ref_add(struct pthread *, struct pthread *, int); void _thr_ref_delete(struct pthread *, struct pthread *); -void _thr_schedule_add(struct pthread *, struct pthread *); +int _thr_schedule_add(struct pthread *, struct pthread *); void _thr_schedule_remove(struct pthread *, struct pthread *); void _thr_setrunnable(struct pthread *curthread, struct pthread *thread); void _thr_setrunnable_unlocked(struct pthread *thread); |