xref: /trueos/sys/compat/mach/mach_thread.c (revision 194ed1a2f2ba33176bff2ba5b65e326ce70fba07)
1 #include <sys/cdefs.h>
2 __FBSDID("$FreeBSD$");
3 
4 #include <sys/types.h>
5 #include <sys/param.h>
6 #include <sys/systm.h>
7 #include <sys/eventhandler.h>
8 #include <sys/kernel.h>
9 #include <sys/lock.h>
10 #include <sys/mutex.h>
11 #include <sys/proc.h>
12 #include <sys/queue.h>
13 #include <sys/resource.h>
14 #include <sys/resourcevar.h>
15 #include <sys/rwlock.h>
16 #include <sys/sched.h>
17 #include <sys/sleepqueue.h>
18 #include <sys/signal.h>
19 
20 #include <sys/mach/mach_types.h>
21 #include <sys/mach/mach_traps.h>
22 
23 #include <sys/mach/ipc/ipc_kmsg.h>
24 #include <sys/mach/thread.h>
25 #include <sys/mach/ipc_tt.h>
26 #include <sys/mach/thread_switch.h>
27 
28 #define MT_SETRUNNABLE 0x1
29 
30 #ifdef notyet
31 /*
32  * Am assuming that Mach lacks the concept of uninterruptible
33  * sleep - this may need to be changed back to what is in pci_pass.c
34  */
35 static int
_intr_tdsigwakeup(struct thread * td,int intrval)36 _intr_tdsigwakeup(struct thread *td, int intrval)
37 {
38 	struct proc *p = td->td_proc;
39 	int rc = 0;
40 
41 	PROC_SLOCK(p);
42 	thread_lock(td);
43 	if (TD_ON_SLEEPQ(td)) {
44 		/*
45 		 * Give low priority threads a better chance to run.
46 		 */
47 		if (td->td_priority > PUSER)
48 			sched_prio(td, PUSER);
49 
50 		sleepq_abort(td, intrval);
51 		rc = 1;
52 	}
53 	PROC_SUNLOCK(p);
54 	thread_unlock(td);
55 	return (rc);
56 }
57 #endif
58 
59 
60 int
mach_thread_switch(mach_port_name_t thread_name,int option,mach_msg_timeout_t option_time)61 mach_thread_switch(mach_port_name_t thread_name, int option, mach_msg_timeout_t option_time)
62 {
63        int timeout;
64        struct mach_emuldata *med;
65 	   struct thread *td = curthread;
66 
67        med = (struct mach_emuldata *)td->td_proc->p_emuldata;
68        timeout = option_time * hz / 1000;
69 
70        /*
71         * The day we will be able to find out the struct proc from
72         * the port number, try to use preempt() to call the right thread.
73         * [- but preempt() is for _involuntary_ context switches.]
74         */
75        switch(option) {
76        case SWITCH_OPTION_NONE:
77                sched_relinquish(curthread);
78                break;
79 
80        case SWITCH_OPTION_WAIT:
81 #ifdef notyet
82                med->med_thpri = 1;
83                while (med->med_thpri != 0) {
84                        rw_wlock(&med->med_rightlock);
85                        (void)msleep(&med->med_thpri, &med->med_rightlock, PZERO|PCATCH,
86                                                 "thread_switch", timeout);
87                        rw_wunlock(&med->med_rightlock);
88               }
89                break;
90 #endif
91        case SWITCH_OPTION_DEPRESS:
92                /* Use a callout to restore the priority after depression? */
93                td->td_priority = PRI_MAX_TIMESHARE;
94                break;
95 
96        default:
97               uprintf("sys_mach_syscall_thread_switch(): unknown option %d\n", option);
98                break;
99        }
100        return (0);
101 }
102 
103 void
thread_go(thread_t thread)104 thread_go(thread_t thread)
105 {
106 	int needunlock = 0;
107 	struct mtx *block_lock = thread->ith_block_lock_data;
108 
109 	MPASS(thread->ith_state != MACH_SEND_IN_PROGRESS &&
110 		  thread->ith_state != MACH_RCV_IN_PROGRESS &&
111 		  thread->ith_state != MACH_RCV_IN_PROGRESS_TIMED);
112 
113 	if (block_lock != NULL && !mtx_owned(block_lock)) {
114 		needunlock = 1;
115 		mtx_lock(block_lock);
116 	}
117 	wakeup(thread);
118 	if (needunlock)
119 		mtx_unlock(block_lock);
120 }
121 
122 void
thread_block(void)123 thread_block(void)
124 {
125 	thread_t thread = current_thread();
126 	int rc;
127 
128 	MPASS(curthread == thread->ith_td);
129 
130 	rc = msleep(thread, thread->ith_block_lock_data, PCATCH|PSOCK, "thread_block", thread->timeout);
131 	switch (rc) {
132 	case EINTR:
133 	case ERESTART:
134 		thread->wait_result = THREAD_INTERRUPTED;
135 		break;
136 	case EWOULDBLOCK:
137 		thread->wait_result = THREAD_TIMED_OUT;
138 		break;
139 	case 0:
140 		thread->wait_result = THREAD_AWAKENED;
141 		break;
142 	default:
143 		panic("unexpected return from msleep: %d\n", rc);
144 	}
145 #ifdef INVARIANTS
146 	if (thread->timeout == 0) {
147 		if(rc == 0)
148 			MPASS(thread->ith_state == MACH_MSG_SUCCESS);
149 		else
150 			MPASS(rc == EINTR || rc == ERESTART);
151 	}
152 #endif
153 }
154 
155 void
thread_will_wait_with_timeout(thread_t thread,int timeout)156 thread_will_wait_with_timeout(thread_t thread, int timeout)
157 {
158 
159 	thread->sleep_stamp = ticks;
160 	thread->timeout = timeout;
161 }
162 
163 
164 void
thread_will_wait(thread_t thread)165 thread_will_wait(thread_t thread)
166 {
167 
168 	thread->sleep_stamp = ticks;
169 	thread->timeout = 0;
170 }
171 
172 static void
mach_thread_create(struct thread * td,thread_t thread)173 mach_thread_create(struct thread *td, thread_t thread)
174 {
175 
176 	thread->ref_count = 1;
177 	ipc_thread_init(thread);
178 }
179 
180 
181 static uma_zone_t thread_shuttle_zone;
182 
183 static int
uma_thread_init(void * _thread,int a,int b)184 uma_thread_init(void *_thread, int a, int b)
185 {
186 	/* allocate thread substructures */
187 	return (0);
188 }
189 
190 static void
uma_thread_fini(void * _thread,int a)191 uma_thread_fini(void *_thread, int a)
192 {
193 	/* deallocate thread substructures */
194 }
195 
196 static void
mach_thread_init(void * arg __unused,struct thread * td)197 mach_thread_init(void *arg __unused, struct thread *td)
198 {
199 	thread_t thread;
200 
201 	thread = uma_zalloc(thread_shuttle_zone, M_WAITOK|M_ZERO);
202 	mtx_init(&thread->ith_lock_data, "mach_thread lock", NULL, MTX_DEF);
203 
204 	MPASS(td->td_machdata == NULL);
205 	td->td_machdata = thread;
206 	thread->ith_td = td;
207 	ipc_thr_act_init(thread);
208 }
209 
210 static void
mach_thread_fini(void * arg __unused,struct thread * td)211 mach_thread_fini(void *arg __unused, struct thread *td)
212 {
213 	thread_t thread = td->td_machdata;
214 
215 	MPASS(thread->ith_kmsg == NULL);
216 	MPASS(thread->ith_td == td);
217 	ipc_thr_act_terminate(thread);
218 	mtx_destroy(&thread->ith_lock_data);
219 	uma_zfree(thread_shuttle_zone, thread);
220 }
221 
222 static void
mach_thread_ctor(void * arg __unused,struct thread * td)223 mach_thread_ctor(void *arg __unused, struct thread *td)
224 {
225 	thread_t thread = td->td_machdata;
226 
227 	MPASS(thread->ith_td == td);
228 	mach_thread_create(td, thread);
229 	thread->ith_block_lock_data = NULL;
230 }
231 
232 static void
thread_sysinit(void * arg __unused)233 thread_sysinit(void *arg __unused)
234 {
235 	thread_shuttle_zone = uma_zcreate("thread_shuttle_zone",
236 									  sizeof(struct thread_shuttle),
237 									  NULL, NULL, uma_thread_init,
238 									  uma_thread_fini, 1, 0);
239 
240 	EVENTHANDLER_REGISTER(thread_ctor, mach_thread_ctor, NULL, EVENTHANDLER_PRI_ANY);
241 	EVENTHANDLER_REGISTER(thread_init, mach_thread_init, NULL, EVENTHANDLER_PRI_ANY);
242 	EVENTHANDLER_REGISTER(thread_fini, mach_thread_fini, NULL, EVENTHANDLER_PRI_ANY);
243 }
244 
245 /* before SI_SUB_INTRINSIC and after SI_SUB_EVENTHANDLER */
246 SYSINIT(mach_thread, SI_SUB_KLD, SI_ORDER_ANY, thread_sysinit, NULL);
247