xref: /freebsd/lib/libthr/thread/thr_kern.c (revision 716fd348)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
5  * Copyright (C) 2003 Daniel M. Eischen <deischen@freebsd.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/types.h>
34 #include <sys/signalvar.h>
35 #include <sys/rtprio.h>
36 #include <sys/mman.h>
37 #include <pthread.h>
38 
39 #include "thr_private.h"
40 
41 /*#define DEBUG_THREAD_KERN */
42 #ifdef DEBUG_THREAD_KERN
43 #define DBG_MSG		stdout_debug
44 #else
45 #define DBG_MSG(x...)
46 #endif
47 
48 static struct umutex	addr_lock;
49 static struct wake_addr *wake_addr_head;
50 static struct wake_addr default_wake_addr;
51 
52 /*
53  * This is called when the first thread (other than the initial
54  * thread) is created.
55  */
56 void
57 _thr_setthreaded(int threaded)
58 {
59 	__isthreaded = threaded;
60 }
61 
62 void
63 _thr_assert_lock_level(void)
64 {
65 	PANIC("locklevel <= 0");
66 }
67 
68 int
69 _rtp_to_schedparam(const struct rtprio *rtp, int *policy,
70 	struct sched_param *param)
71 {
72 	switch(rtp->type) {
73 	case RTP_PRIO_REALTIME:
74 		*policy = SCHED_RR;
75 		param->sched_priority = RTP_PRIO_MAX - rtp->prio;
76 		break;
77 	case RTP_PRIO_FIFO:
78 		*policy = SCHED_FIFO;
79 		param->sched_priority = RTP_PRIO_MAX - rtp->prio;
80 		break;
81 	default:
82 		*policy = SCHED_OTHER;
83 		param->sched_priority = 0;
84 		break;
85 	}
86 	return (0);
87 }
88 
89 int
90 _schedparam_to_rtp(int policy, const struct sched_param *param,
91 	struct rtprio *rtp)
92 {
93 	switch(policy) {
94 	case SCHED_RR:
95 		rtp->type = RTP_PRIO_REALTIME;
96 		rtp->prio = RTP_PRIO_MAX - param->sched_priority;
97 		break;
98 	case SCHED_FIFO:
99 		rtp->type = RTP_PRIO_FIFO;
100 		rtp->prio = RTP_PRIO_MAX - param->sched_priority;
101 		break;
102 	case SCHED_OTHER:
103 	default:
104 		rtp->type = RTP_PRIO_NORMAL;
105 		rtp->prio = 0;
106 		break;
107 	}
108 	return (0);
109 }
110 
111 int
112 _thr_getscheduler(lwpid_t lwpid, int *policy, struct sched_param *param)
113 {
114 	struct rtprio rtp;
115 	int ret;
116 
117 	ret = rtprio_thread(RTP_LOOKUP, lwpid, &rtp);
118 	if (ret == -1)
119 		return (ret);
120 	_rtp_to_schedparam(&rtp, policy, param);
121 	return (0);
122 }
123 
124 int
125 _thr_setscheduler(lwpid_t lwpid, int policy, const struct sched_param *param)
126 {
127 	struct rtprio rtp;
128 
129 	_schedparam_to_rtp(policy, param, &rtp);
130 	return (rtprio_thread(RTP_SET, lwpid, &rtp));
131 }
132 
133 void
134 _thr_wake_addr_init(void)
135 {
136 	_thr_umutex_init(&addr_lock);
137 	wake_addr_head = NULL;
138 }
139 
140 /*
141  * Allocate wake-address, the memory area is never freed after
142  * allocated, this becauses threads may be referencing it.
143  */
144 struct wake_addr *
145 _thr_alloc_wake_addr(void)
146 {
147 	struct pthread *curthread;
148 	struct wake_addr *p;
149 
150 	if (_thr_initial == NULL) {
151 		return &default_wake_addr;
152 	}
153 
154 	curthread = _get_curthread();
155 
156 	THR_LOCK_ACQUIRE(curthread, &addr_lock);
157 	if (wake_addr_head == NULL) {
158 		unsigned i;
159 		unsigned pagesize = getpagesize();
160 		struct wake_addr *pp = (struct wake_addr *)
161 			mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
162 			MAP_ANON|MAP_PRIVATE, -1, 0);
163 		for (i = 1; i < pagesize/sizeof(struct wake_addr); ++i)
164 			pp[i].link = &pp[i+1];
165 		pp[i-1].link = NULL;
166 		wake_addr_head = &pp[1];
167 		p = &pp[0];
168 	} else {
169 		p = wake_addr_head;
170 		wake_addr_head = p->link;
171 	}
172 	THR_LOCK_RELEASE(curthread, &addr_lock);
173 	p->value = 0;
174 	return (p);
175 }
176 
177 void
178 _thr_release_wake_addr(struct wake_addr *wa)
179 {
180 	struct pthread *curthread = _get_curthread();
181 
182 	if (wa == &default_wake_addr)
183 		return;
184 	THR_LOCK_ACQUIRE(curthread, &addr_lock);
185 	wa->link = wake_addr_head;
186 	wake_addr_head = wa;
187 	THR_LOCK_RELEASE(curthread, &addr_lock);
188 }
189 
190 /* Sleep on thread wakeup address */
191 int
192 _thr_sleep(struct pthread *curthread, int clockid,
193 	const struct timespec *abstime)
194 {
195 
196 	if (curthread->wake_addr->value != 0)
197 		return (0);
198 
199 	return _thr_umtx_timedwait_uint(&curthread->wake_addr->value, 0,
200                  clockid, abstime, 0);
201 }
202 
203 void
204 _thr_wake_all(unsigned int *waddrs[], int count)
205 {
206 	int i;
207 
208 	for (i = 0; i < count; ++i)
209 		*waddrs[i] = 1;
210 	_umtx_op(waddrs, UMTX_OP_NWAKE_PRIVATE, count, NULL, NULL);
211 }
212