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