]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libkse/thread/thr_concurrency.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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
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
46 static int level = 0;
47
48 __weak_reference(_pthread_getconcurrency, pthread_getconcurrency);
49 __weak_reference(_pthread_setconcurrency, pthread_setconcurrency);
50
51 int
52 _pthread_getconcurrency(void)
53 {
54         return (level);
55 }
56
57 int
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
80 int
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
162 int
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