1/* 2 * Copyright (c) 2003 Daniel M. Eischen <deischen@freebsd.org> 3 * Copyright (c) 2003 Sergey Osokin <osa@freebsd.org.ru>. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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. 14 * 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 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30#include "namespace.h" 31#include <errno.h> 32#include <pthread.h> 33#include <sys/types.h> 34#include <sys/sysctl.h> 35#include "un-namespace.h" 36 37#include "thr_private.h" 38 39/*#define DEBUG_CONCURRENCY */ 40#ifdef DEBUG_CONCURRENCY 41#define DBG_MSG stdout_debug 42#else 43#define DBG_MSG(x...) 44#endif 45 46static int level = 0; 47 48__weak_reference(_pthread_getconcurrency, pthread_getconcurrency); 49__weak_reference(_pthread_setconcurrency, pthread_setconcurrency); 50 51int 52_pthread_getconcurrency(void) 53{ 54 return (level); 55} 56 57int 58_pthread_setconcurrency(int new_level) 59{ 60 int ret; 61 62 if (new_level < 0) 63 ret = EINVAL; 64 else if (new_level == level) 65 ret = 0; 66 else if (new_level == 0) { 67 level = 0; 68 ret = 0; 69 } else if ((_kse_isthreaded() == 0) && (_kse_setthreaded(1) != 0)) { 70 DBG_MSG("Can't enable threading.\n"); 71 ret = EAGAIN; 72 } else { 73 ret = _thr_setconcurrency(new_level); 74 if (ret == 0) 75 level = new_level; 76 } 77 return (ret); 78} 79 80int 81_thr_setconcurrency(int new_level) 82{ 83 struct pthread *curthread; 84 struct kse *newkse, *kse; 85 kse_critical_t crit; 86 int kse_count; 87 int i; 88 int ret; 89 90 /* 91 * Turn on threaded mode, if failed, it is unnecessary to 92 * do further work. 93 */ 94 if (_kse_isthreaded() == 0 && _kse_setthreaded(1)) 95 return (EAGAIN); 96 97 ret = 0; 98 curthread = _get_curthread(); 99 /* Race condition, but so what. */ 100 kse_count = _kse_initial->k_kseg->kg_ksecount; 101 if (new_level > kse_count) { 102 for (i = kse_count; i < new_level; i++) { 103 newkse = _kse_alloc(curthread, 0); 104 if (newkse == NULL) { 105 DBG_MSG("Can't alloc new KSE.\n"); 106 ret = EAGAIN; 107 break; 108 } 109 newkse->k_kseg = _kse_initial->k_kseg; 110 newkse->k_schedq = _kse_initial->k_schedq; 111 newkse->k_curthread = NULL; 112 crit = _kse_critical_enter(); 113 KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg); 114 TAILQ_INSERT_TAIL(&newkse->k_kseg->kg_kseq, 115 newkse, k_kgqe); 116 newkse->k_kseg->kg_ksecount++; 117 newkse->k_flags |= KF_STARTED; 118 KSE_SCHED_UNLOCK(curthread->kse, newkse->k_kseg); 119 if (kse_create(&newkse->k_kcb->kcb_kmbx, 0) != 0) { 120 KSE_SCHED_LOCK(curthread->kse, newkse->k_kseg); 121 TAILQ_REMOVE(&newkse->k_kseg->kg_kseq, 122 newkse, k_kgqe); 123 newkse->k_kseg->kg_ksecount--; 124 KSE_SCHED_UNLOCK(curthread->kse, 125 newkse->k_kseg); 126 _kse_critical_leave(crit); 127 _kse_free(curthread, newkse); 128 DBG_MSG("kse_create syscall failed.\n"); 129 ret = EAGAIN; 130 break; 131 } else { 132 _kse_critical_leave(crit); 133 } 134 } 135 } else if (new_level < kse_count) { 136 kse_count = 0; 137 crit = _kse_critical_enter(); 138 KSE_SCHED_LOCK(curthread->kse, _kse_initial->k_kseg); 139 /* Count the number of active KSEs */ 140 TAILQ_FOREACH(kse, &_kse_initial->k_kseg->kg_kseq, k_kgqe) { 141 if ((kse->k_flags & KF_TERMINATED) == 0) 142 kse_count++; 143 } 144 /* Reduce the number of active KSEs appropriately. */ 145 kse = TAILQ_FIRST(&_kse_initial->k_kseg->kg_kseq); 146 while ((kse != NULL) && (kse_count > new_level)) { 147 if ((kse != _kse_initial) && 148 ((kse->k_flags & KF_TERMINATED) == 0)) { 149 kse->k_flags |= KF_TERMINATED; 150 kse_count--; 151 /* Wakup the KSE in case it is idle. */ 152 kse_wakeup(&kse->k_kcb->kcb_kmbx); 153 } 154 kse = TAILQ_NEXT(kse, k_kgqe); 155 } 156 KSE_SCHED_UNLOCK(curthread->kse, _kse_initial->k_kseg); 157 _kse_critical_leave(crit); 158 } 159 return (ret); 160} 161 162int 163_thr_setmaxconcurrency(void) 164{ 165 int vcpu; 166 size_t len; 167 int ret; 168 169 len = sizeof(vcpu); 170 ret = sysctlbyname("kern.threads.virtual_cpu", &vcpu, &len, NULL, 0); 171 if (ret == 0 && vcpu > 0) 172 ret = _thr_setconcurrency(vcpu); 173 return (ret); 174} 175 176