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