2 * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org>
3 * Copyright (c) 2003 Sergey Osokin <osa@freebsd.org.ru>.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Neither the name of the author nor the names of any co-contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/types.h>
32 #include <sys/sysctl.h>
34 #include "thr_private.h"
36 /*#define DEBUG_CONCURRENCY */
37 #ifdef DEBUG_CONCURRENCY
38 #define DBG_MSG stdout_debug
45 __weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
46 __weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
49 _pthread_getconcurrency(void)
55 _pthread_setconcurrency(int new_level)
61 else if (new_level == level)
63 else if (new_level == 0) {
66 } else if ((_kse_isthreaded() == 0) && (_kse_setthreaded(1) != 0)) {
67 DBG_MSG("Can't enable threading.\n");
70 ret = _thr_setconcurrency(new_level);
78 _thr_setconcurrency(int new_level)
80 struct pthread *curthread;
81 struct kse *newkse, *kse;
88 * Turn on threaded mode, if failed, it is unnecessary to
91 if (_kse_isthreaded() == 0 && _kse_setthreaded(1))
95 curthread = _get_curthread();
96 /* Race condition, but so what. */
97 kse_count = _kse_initial->k_kseg->kg_ksecount;
98 if (new_level > kse_count) {
99 for (i = kse_count; i < new_level; i++) {
100 newkse = _kse_alloc(curthread, 0);
101 if (newkse == NULL) {
102 DBG_MSG("Can't alloc new KSE.\n");
106 newkse->k_kseg = _kse_initial->k_kseg;
107 newkse->k_schedq = _kse_initial->k_schedq;
108 newkse->k_curthread = NULL;
109 crit = _kse_critical_enter();
110 KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
111 TAILQ_INSERT_TAIL(&newkse->k_kseg->kg_kseq,
113 newkse->k_kseg->kg_ksecount++;
114 newkse->k_flags |= KF_STARTED;
115 KSE_SCHED_UNLOCK(curthread->kse, newkse->k_kseg);
116 if (kse_create(&newkse->k_kcb->kcb_kmbx, 0) != 0) {
117 KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg);
118 TAILQ_REMOVE(&newkse->k_kseg->kg_kseq,
120 newkse->k_kseg->kg_ksecount--;
121 KSE_SCHED_UNLOCK(curthread->kse,
123 _kse_critical_leave(crit);
124 _kse_free(curthread, newkse);
125 DBG_MSG("kse_create syscall failed.\n");
129 _kse_critical_leave(crit);
132 } else if (new_level < kse_count) {
134 crit = _kse_critical_enter();
135 KSE_SCHED_LOCK(curthread->kse, _kse_initial->k_kseg);
136 /* Count the number of active KSEs */
137 TAILQ_FOREACH(kse, &_kse_initial->k_kseg->kg_kseq, k_kgqe) {
138 if ((kse->k_flags & KF_TERMINATED) == 0)
141 /* Reduce the number of active KSEs appropriately. */
142 kse = TAILQ_FIRST(&_kse_initial->k_kseg->kg_kseq);
143 while ((kse != NULL) && (kse_count > new_level)) {
144 if ((kse != _kse_initial) &&
145 ((kse->k_flags & KF_TERMINATED) == 0)) {
146 kse->k_flags |= KF_TERMINATED;
148 /* Wakup the KSE in case it is idle. */
149 kse_wakeup(&kse->k_kcb->kcb_kmbx);
151 kse = TAILQ_NEXT(kse, k_kgqe);
153 KSE_SCHED_UNLOCK(curthread->kse, _kse_initial->k_kseg);
154 _kse_critical_leave(crit);
160 _thr_setmaxconcurrency(void)
167 ret = sysctlbyname("kern.threads.virtual_cpu", &vcpu, &len, NULL, 0);
168 if (ret == 0 && vcpu > 0)
169 ret = _thr_setconcurrency(vcpu);