xref: /NextBSD/sys/compat/mach/mach_thread.c (revision 6283aa8b8e910d10094766cf10d892a509825cc1)
1 /*-
2  * Copyright (c) 2014-2015, Matthew Macy <mmacy@nextbsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *
11  *  2. Neither the name of Matthew Macy nor the names of its
12  *     contributors may be used to endorse or promote products derived from
13  *     this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND 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 COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/eventhandler.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/proc.h>
39 #include <sys/queue.h>
40 #include <sys/resource.h>
41 #include <sys/resourcevar.h>
42 #include <sys/rwlock.h>
43 #include <sys/sched.h>
44 #include <sys/sleepqueue.h>
45 #include <sys/signal.h>
46 
47 #include <sys/mach/mach_types.h>
48 #include <sys/mach/mach_traps.h>
49 
50 #include <sys/mach/ipc/ipc_kmsg.h>
51 #include <sys/mach/thread.h>
52 #include <sys/mach/ipc_tt.h>
53 #include <sys/mach/thread_switch.h>
54 
55 #define MT_SETRUNNABLE 0x1
56 
57 #ifdef notyet
58 /*
59  * Am assuming that Mach lacks the concept of uninterruptible
60  * sleep - this may need to be changed back to what is in pci_pass.c
61  */
62 static int
_intr_tdsigwakeup(struct thread * td,int intrval)63 _intr_tdsigwakeup(struct thread *td, int intrval)
64 {
65 	struct proc *p = td->td_proc;
66 	int rc = 0;
67 
68 	PROC_SLOCK(p);
69 	thread_lock(td);
70 	if (TD_ON_SLEEPQ(td)) {
71 		/*
72 		 * Give low priority threads a better chance to run.
73 		 */
74 		if (td->td_priority > PUSER)
75 			sched_prio(td, PUSER);
76 
77 		sleepq_abort(td, intrval);
78 		rc = 1;
79 	}
80 	PROC_SUNLOCK(p);
81 	thread_unlock(td);
82 	return (rc);
83 }
84 #endif
85 
86 
87 int
mach_thread_switch(mach_port_name_t thread_name,int option,mach_msg_timeout_t option_time)88 mach_thread_switch(mach_port_name_t thread_name, int option, mach_msg_timeout_t option_time)
89 {
90        int timeout;
91        struct mach_emuldata *med;
92 	   struct thread *td = curthread;
93 
94        med = (struct mach_emuldata *)td->td_proc->p_emuldata;
95        timeout = option_time * hz / 1000;
96 
97        /*
98         * The day we will be able to find out the struct proc from
99         * the port number, try to use preempt() to call the right thread.
100         * [- but preempt() is for _involuntary_ context switches.]
101         */
102        switch(option) {
103        case SWITCH_OPTION_NONE:
104                sched_relinquish(curthread);
105                break;
106 
107        case SWITCH_OPTION_WAIT:
108 #ifdef notyet
109                med->med_thpri = 1;
110                while (med->med_thpri != 0) {
111                        rw_wlock(&med->med_rightlock);
112                        (void)msleep(&med->med_thpri, &med->med_rightlock, PZERO|PCATCH,
113                                                 "thread_switch", timeout);
114                        rw_wunlock(&med->med_rightlock);
115               }
116                break;
117 #endif
118        case SWITCH_OPTION_DEPRESS:
119                /* Use a callout to restore the priority after depression? */
120                td->td_priority = PRI_MAX_TIMESHARE;
121                break;
122 
123        default:
124               uprintf("sys_mach_syscall_thread_switch(): unknown option %d\n", option);
125                break;
126        }
127        return (0);
128 }
129 
130 void
thread_go(thread_t thread)131 thread_go(thread_t thread)
132 {
133 	int needunlock = 0;
134 	struct mtx *block_lock = thread->ith_block_lock_data;
135 
136 	MPASS(thread->ith_state != MACH_SEND_IN_PROGRESS &&
137 		  thread->ith_state != MACH_RCV_IN_PROGRESS &&
138 		  thread->ith_state != MACH_RCV_IN_PROGRESS_TIMED);
139 
140 	if (block_lock != NULL && !mtx_owned(block_lock)) {
141 		needunlock = 1;
142 		mtx_lock(block_lock);
143 	}
144 	wakeup(thread);
145 	if (needunlock)
146 		mtx_unlock(block_lock);
147 }
148 
149 void
thread_block(void)150 thread_block(void)
151 {
152 	thread_t thread = current_thread();
153 	int rc;
154 
155 	MPASS(curthread == thread->ith_td);
156 
157 	rc = msleep(thread, thread->ith_block_lock_data, PCATCH|PSOCK, "thread_block", thread->timeout);
158 	switch (rc) {
159 	case EINTR:
160 	case ERESTART:
161 		thread->wait_result = THREAD_INTERRUPTED;
162 		break;
163 	case EWOULDBLOCK:
164 		thread->wait_result = THREAD_TIMED_OUT;
165 		break;
166 	case 0:
167 		thread->wait_result = THREAD_AWAKENED;
168 		break;
169 	default:
170 		panic("unexpected return from msleep: %d\n", rc);
171 	}
172 #ifdef INVARIANTS
173 	if (thread->timeout == 0) {
174 		if(rc == 0)
175 			MPASS(thread->ith_state == MACH_MSG_SUCCESS);
176 		else
177 			MPASS(rc == EINTR || rc == ERESTART);
178 	}
179 #endif
180 }
181 
182 void
thread_will_wait_with_timeout(thread_t thread,int timeout)183 thread_will_wait_with_timeout(thread_t thread, int timeout)
184 {
185 
186 	thread->sleep_stamp = ticks;
187 	thread->timeout = timeout;
188 }
189 
190 
191 void
thread_will_wait(thread_t thread)192 thread_will_wait(thread_t thread)
193 {
194 
195 	thread->sleep_stamp = ticks;
196 	thread->timeout = 0;
197 }
198 
199 static void
mach_thread_create(struct thread * td,thread_t thread)200 mach_thread_create(struct thread *td, thread_t thread)
201 {
202 
203 	thread->ref_count = 1;
204 	ipc_thread_init(thread);
205 }
206 
207 
208 static uma_zone_t thread_shuttle_zone;
209 
210 static int
uma_thread_init(void * _thread,int a,int b)211 uma_thread_init(void *_thread, int a, int b)
212 {
213 	/* allocate thread substructures */
214 	return (0);
215 }
216 
217 static void
uma_thread_fini(void * _thread,int a)218 uma_thread_fini(void *_thread, int a)
219 {
220 	/* deallocate thread substructures */
221 }
222 
223 static void
mach_thread_init(void * arg __unused,struct thread * td)224 mach_thread_init(void *arg __unused, struct thread *td)
225 {
226 	thread_t thread;
227 
228 	thread = uma_zalloc(thread_shuttle_zone, M_WAITOK|M_ZERO);
229 	mtx_init(&thread->ith_lock_data, "mach_thread lock", NULL, MTX_DEF);
230 
231 	MPASS(td->td_machdata == NULL);
232 	td->td_machdata = thread;
233 	thread->ith_td = td;
234 	ipc_thr_act_init(thread);
235 }
236 
237 static void
mach_thread_fini(void * arg __unused,struct thread * td)238 mach_thread_fini(void *arg __unused, struct thread *td)
239 {
240 	thread_t thread = td->td_machdata;
241 
242 	MPASS(thread->ith_kmsg == NULL);
243 	MPASS(thread->ith_td == td);
244 	ipc_thr_act_terminate(thread);
245 	mtx_destroy(&thread->ith_lock_data);
246 	uma_zfree(thread_shuttle_zone, thread);
247 }
248 
249 static void
mach_thread_ctor(void * arg __unused,struct thread * td)250 mach_thread_ctor(void *arg __unused, struct thread *td)
251 {
252 	thread_t thread = td->td_machdata;
253 
254 	MPASS(thread->ith_td == td);
255 	mach_thread_create(td, thread);
256 	thread->ith_block_lock_data = NULL;
257 }
258 
259 static void
thread_sysinit(void * arg __unused)260 thread_sysinit(void *arg __unused)
261 {
262 	thread_shuttle_zone = uma_zcreate("thread_shuttle_zone",
263 									  sizeof(struct thread_shuttle),
264 									  NULL, NULL, uma_thread_init,
265 									  uma_thread_fini, 1, 0);
266 
267 	EVENTHANDLER_REGISTER(thread_ctor, mach_thread_ctor, NULL, EVENTHANDLER_PRI_ANY);
268 	EVENTHANDLER_REGISTER(thread_init, mach_thread_init, NULL, EVENTHANDLER_PRI_ANY);
269 	EVENTHANDLER_REGISTER(thread_fini, mach_thread_fini, NULL, EVENTHANDLER_PRI_ANY);
270 }
271 
272 /* before SI_SUB_INTRINSIC and after SI_SUB_EVENTHANDLER */
273 SYSINIT(mach_thread, SI_SUB_KLD, SI_ORDER_ANY, thread_sysinit, NULL);
274