No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / mach / mach_port.c
blobb1c2be4df216aaf27b52274accd1161b13a58fd4
1 /* $NetBSD: mach_port.c,v 1.65 2008/04/28 20:23:44 martin Exp $ */
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include "opt_compat_darwin.h"
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: mach_port.c,v 1.65 2008/04/28 20:23:44 martin Exp $");
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/signal.h>
41 #include <sys/pool.h>
42 #include <sys/queue.h>
43 #include <sys/malloc.h>
44 #include <sys/proc.h>
46 #include <compat/mach/mach_types.h>
47 #include <compat/mach/mach_message.h>
48 #include <compat/mach/mach_port.h>
49 #include <compat/mach/mach_iokit.h>
50 #include <compat/mach/mach_clock.h>
51 #include <compat/mach/mach_exec.h>
52 #include <compat/mach/mach_errno.h>
53 #include <compat/mach/mach_notify.h>
54 #include <compat/mach/mach_services.h>
55 #include <compat/mach/mach_syscallargs.h>
57 #ifdef COMPAT_DARWIN
58 #include <compat/darwin/darwin_exec.h>
59 #endif
61 /* Right and port pools, list of all rights and its lock */
62 static struct pool mach_port_pool;
63 static struct pool mach_right_pool;
65 struct mach_port *mach_bootstrap_port;
66 struct mach_port *mach_clock_port;
67 struct mach_port *mach_io_master_port;
68 struct mach_port *mach_saved_bootstrap_port;
70 int
71 mach_sys_reply_port(struct lwp *l, const void *v, register_t *retval)
73 struct mach_right *mr;
75 mr = mach_right_get(mach_port_get(), l, MACH_PORT_TYPE_RECEIVE, 0);
76 *retval = (register_t)mr->mr_name;
78 return 0;
81 int
82 mach_sys_thread_self_trap(struct lwp *l, const void *v, register_t *retval)
84 struct mach_lwp_emuldata *mle;
85 struct mach_right *mr;
87 mle = l->l_emuldata;
88 mr = mach_right_get(mle->mle_kernel, l, MACH_PORT_TYPE_SEND, 0);
89 *retval = (register_t)mr->mr_name;
91 return 0;
95 int
96 mach_sys_task_self_trap(struct lwp *l, const void *v, register_t *retval)
98 struct mach_emuldata *med;
99 struct mach_right *mr;
101 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
102 mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0);
103 *retval = (register_t)mr->mr_name;
105 return 0;
110 mach_sys_host_self_trap(struct lwp *l, const void *v, register_t *retval)
112 struct mach_emuldata *med;
113 struct mach_right *mr;
115 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
116 mr = mach_right_get(med->med_host, l, MACH_PORT_TYPE_SEND, 0);
117 *retval = (register_t)mr->mr_name;
119 return 0;
123 mach_port_deallocate(struct mach_trap_args *args)
125 mach_port_deallocate_request_t *req = args->smsg;
126 mach_port_deallocate_reply_t *rep = args->rmsg;
127 size_t *msglen = args->rsize;
128 struct lwp *l = args->l;
129 mach_port_t mn;
130 struct mach_right *mr;
132 mn = req->req_name;
133 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_REF_RIGHTS)) != NULL)
134 mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
136 *msglen = sizeof(*rep);
137 mach_set_header(rep, req, *msglen);
139 rep->rep_retval = 0;
141 mach_set_trailer(rep, *msglen);
143 return 0;
147 mach_port_destroy(struct mach_trap_args *args)
149 mach_port_destroy_request_t *req = args->smsg;
150 mach_port_destroy_reply_t *rep = args->rmsg;
151 size_t *msglen = args->rsize;
152 struct lwp *l = args->l;
153 mach_port_t mn;
154 struct mach_right *mr;
156 #ifdef DEBUG_MACH
157 printf("mach_port_destroy mn = %x\n", req->req_name);
158 #endif
159 mn = req->req_name;
160 if ((mr = mach_right_check(mn,
161 l, MACH_PORT_TYPE_ALL_RIGHTS)) != NULL) {
162 MACH_PORT_UNREF(mr->mr_port);
163 mr->mr_port = NULL;
164 mach_right_put(mr, MACH_PORT_TYPE_ALL_RIGHTS);
167 *msglen = sizeof(*rep);
168 mach_set_header(rep, req, *msglen);
170 rep->rep_retval = 0;
172 mach_set_trailer(rep, *msglen);
174 return 0;
178 mach_port_allocate(struct mach_trap_args *args)
180 mach_port_allocate_request_t *req = args->smsg;
181 mach_port_allocate_reply_t *rep = args->rmsg;
182 size_t *msglen = args->rsize;
183 struct lwp *l = args->l;
184 struct mach_right *mr;
185 struct mach_port *mp;
187 switch (req->req_right) {
188 case MACH_PORT_RIGHT_RECEIVE:
189 mp = mach_port_get();
190 mr = mach_right_get(mp, l, MACH_PORT_TYPE_RECEIVE, 0);
191 break;
193 case MACH_PORT_RIGHT_DEAD_NAME:
194 mr = mach_right_get(NULL, l, MACH_PORT_TYPE_DEAD_NAME, 0);
195 break;
197 case MACH_PORT_RIGHT_PORT_SET:
198 mr = mach_right_get(NULL, l, MACH_PORT_TYPE_PORT_SET, 0);
199 break;
201 default:
202 uprintf("mach_port_allocate: unknown right %x\n",
203 req->req_right);
204 return mach_msg_error(args, EINVAL);
205 break;
208 *msglen = sizeof(*rep);
209 mach_set_header(rep, req, *msglen);
211 rep->rep_retval = 0;
212 rep->rep_name = (mach_port_name_t)mr->mr_name;
214 mach_set_trailer(rep, *msglen);
216 return 0;
220 mach_port_insert_right(struct mach_trap_args *args)
222 mach_port_insert_right_request_t *req = args->smsg;
223 mach_port_insert_right_reply_t *rep = args->rmsg;
224 size_t *msglen = args->rsize;
225 struct lwp *l = args->l;
226 mach_port_t name;
227 mach_port_t right;
228 struct mach_right *mr;
229 struct mach_right *nmr;
231 name = req->req_name;
232 right = req->req_poly.name;
233 nmr = NULL;
235 mr = mach_right_check(right, l, MACH_PORT_TYPE_ALL_RIGHTS);
236 if (mr == NULL)
237 return mach_msg_error(args, EPERM);
239 switch (req->req_poly.disposition) {
240 case MACH_MSG_TYPE_MAKE_SEND:
241 case MACH_MSG_TYPE_MOVE_SEND:
242 case MACH_MSG_TYPE_COPY_SEND:
243 nmr = mach_right_get(mr->mr_port,
244 l, MACH_PORT_TYPE_SEND, name);
245 break;
247 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
248 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
249 nmr = mach_right_get(mr->mr_port,
250 l, MACH_PORT_TYPE_SEND_ONCE, name);
251 break;
253 case MACH_MSG_TYPE_MOVE_RECEIVE:
254 nmr = mach_right_get(mr->mr_port,
255 l, MACH_PORT_TYPE_RECEIVE, name);
256 break;
258 default:
259 uprintf("mach_port_insert_right: unknown right %x\n",
260 req->req_poly.disposition);
261 break;
264 *msglen = sizeof(*rep);
265 mach_set_header(rep, req, *msglen);
267 rep->rep_retval = 0;
269 mach_set_trailer(rep, *msglen);
271 return 0;
275 mach_port_type(struct mach_trap_args *args)
277 mach_port_type_request_t *req = args->smsg;
278 mach_port_type_reply_t *rep = args->rmsg;
279 size_t *msglen = args->rsize;
280 struct lwp *l = args->l;
281 mach_port_t mn;
282 struct mach_right *mr;
284 mn = req->req_name;
285 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
286 return mach_msg_error(args, EPERM);
288 *msglen = sizeof(*rep);
289 mach_set_header(rep, req, *msglen);
291 rep->rep_retval = 0;
292 rep->rep_ptype = mr->mr_type;
294 mach_set_trailer(rep, *msglen);
296 return 0;
300 mach_port_set_attributes(struct mach_trap_args *args)
302 mach_port_set_attributes_request_t *req = args->smsg;
303 mach_port_set_attributes_reply_t *rep = args->rmsg;
304 size_t *msglen = args->rsize;
305 int end_offset;
307 /* Sanity check req->req_count */
308 end_offset = req->req_count;
309 if (MACH_REQMSG_OVERFLOW(args, req->req_port_info[end_offset]))
310 return mach_msg_error(args, EINVAL);
312 switch(req->req_flavor) {
313 case MACH_PORT_LIMITS_INFO:
314 case MACH_PORT_RECEIVE_STATUS:
315 case MACH_PORT_DNREQUESTS_SIZE:
316 break;
317 default:
318 uprintf("mach_port_set_attributes: unknown flavor %d\n",
319 req->req_flavor);
320 break;
323 *msglen = sizeof(*rep);
324 mach_set_header(rep, req, *msglen);
326 rep->rep_retval = 0;
328 mach_set_trailer(rep, *msglen);
330 return 0;
334 mach_port_get_attributes(struct mach_trap_args *args)
336 mach_port_get_attributes_request_t *req = args->smsg;
337 mach_port_get_attributes_reply_t *rep = args->rmsg;
338 size_t *msglen = args->rsize;
339 struct lwp *l = args->l;
340 mach_port_t mn;
341 struct mach_right *mr;
343 /* Sanity check req_count */
344 if (req->req_count > 10)
345 return mach_msg_error(args, EINVAL);
347 mn = req->req_msgh.msgh_remote_port;
348 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
349 return mach_msg_error(args, EPERM);
351 switch (req->req_flavor) {
352 case MACH_PORT_LIMITS_INFO: {
353 struct mach_port_limits *mpl;
355 if (req->req_count < (sizeof(*mpl) / sizeof(rep->rep_info[0])))
356 return mach_msg_error(args, EINVAL);
358 mpl = (struct mach_port_limits *)&rep->rep_info[0];
359 mpl->mpl_qlimit = MACH_PORT_QLIMIT_DEFAULT; /* XXX fake limit */
361 rep->rep_count = sizeof(*mpl);
363 break;
366 case MACH_PORT_RECEIVE_STATUS: {
367 struct mach_port_status *mps;
368 struct mach_port *mp;
370 if (req->req_count < (sizeof(*mps) / sizeof(rep->rep_info[0])))
371 return mach_msg_error(args, EINVAL);
373 mps = (struct mach_port_status *)&rep->rep_info[0];
374 memset(mps, 0, sizeof(*mps));
376 if (mr->mr_sethead != NULL)
377 mps->mps_pset = mr->mr_sethead->mr_name;
378 mps->mps_seqno = 0; /* XXX */
379 mps->mps_qlimit = MACH_PORT_QLIMIT_DEFAULT; /* XXX fake limit */
380 if ((mp = mr->mr_port) != NULL) {
381 mps->mps_mscount = mp->mp_refcount; /* XXX */
382 mps->mps_msgcount = mp->mp_count;
383 } else {
384 mps->mps_mscount = 0;
385 mps->mps_msgcount = 0;
387 mps->mps_sorights = 0; /* XXX */
388 mps->mps_srights = 0; /* XXX */
389 if (mr->mr_notify_destroyed != NULL)
390 mps->mps_pdrequest = 1;
391 if (mr->mr_notify_no_senders != NULL)
392 mps->mps_nsrequest = 1;
393 mps->mps_flags = 0; /* XXX */
395 rep->rep_count = sizeof(*mps);
396 break;
399 default:
400 printf("mach_port_get_attributes: unknown flavor %d\n",
401 req->req_flavor);
402 return mach_msg_error(args, EINVAL);
404 break;
407 *msglen = sizeof(*rep) - 10 + rep->rep_count;
408 mach_set_header(rep, req, *msglen);
410 rep->rep_retval = 0;
412 mach_set_trailer(rep, *msglen);
414 return 0;
417 /* XXX insert a recv right into a port set without removing it from another */
419 mach_port_insert_member(struct mach_trap_args *args)
421 mach_port_insert_member_request_t *req = args->smsg;
422 mach_port_insert_member_reply_t *rep = args->rmsg;
423 size_t *msglen = args->rsize;
425 uprintf("Unimplemented mach_port_insert_member\n");
427 *msglen = sizeof(*rep);
428 mach_set_header(rep, req, *msglen);
430 rep->rep_retval = 0;
432 mach_set_trailer(rep, *msglen);
434 return 0;
438 mach_port_move_member(struct mach_trap_args *args)
440 mach_port_move_member_request_t *req = args->smsg;
441 mach_port_move_member_reply_t *rep = args->rmsg;
442 size_t *msglen = args->rsize;
443 struct lwp *l = args->l;
444 struct mach_emuldata *med = l->l_proc->p_emuldata;
445 mach_port_t member = req->req_member;
446 mach_port_t after = req->req_after;
447 struct mach_right *mrr;
448 struct mach_right *mrs;
450 mrr = mach_right_check(member, l, MACH_PORT_TYPE_RECEIVE);
451 if (mrr == NULL)
452 return mach_msg_error(args, EPERM);
454 mrs = mach_right_check(after, l, MACH_PORT_TYPE_PORT_SET);
455 if (mrs == NULL)
456 return mach_msg_error(args, EPERM);
458 rw_enter(&med->med_rightlock, RW_WRITER);
460 /* Remove it from an existing port set */
461 if (mrr->mr_sethead != mrr)
462 LIST_REMOVE(mrr, mr_setlist);
464 /* Insert it into the new port set */
465 LIST_INSERT_HEAD(&mrs->mr_set, mrr, mr_setlist);
466 mrr->mr_sethead = mrs;
468 rw_exit(&med->med_rightlock);
470 *msglen = sizeof(*rep);
471 mach_set_header(rep, req, *msglen);
473 rep->rep_retval = 0;
475 mach_set_trailer(rep, *msglen);
477 return 0;
481 mach_port_request_notification(struct mach_trap_args *args)
483 mach_port_request_notification_request_t *req = args->smsg;
484 mach_port_request_notification_reply_t *rep = args->rmsg;
485 struct lwp *l = args->l;
486 size_t *msglen = args->rsize;
487 mach_port_t mn;
488 struct mach_right *nmr;
489 struct mach_right *tmr;
490 struct mach_right *oldnmr;
491 mach_port_t oldmn;
493 #ifdef DEBUG_MACH
494 printf("mach_port_request_notification, notify = %08x, target = %08x\n",
495 req->req_notify.name, mn = req->req_name);
496 #endif
497 mn = req->req_notify.name;
498 if ((nmr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
499 return mach_msg_error(args, EINVAL);
501 mn = req->req_name;
502 if ((tmr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
503 return mach_msg_error(args, EINVAL);
505 #ifdef DEBUG_MACH
506 if (nmr->mr_port == NULL) {
507 printf("Notification right without a port\n");
508 printf("mr->mr_port = %p, mr = %08x\n", nmr->mr_port, nmr->mr_name);
509 return mach_msg_error(args, EINVAL);
511 #endif
514 oldnmr = NULL;
515 switch(req->req_msgid) {
516 case MACH_NOTIFY_DESTROYED_MSGID:
517 oldnmr = tmr->mr_notify_destroyed;
518 tmr->mr_notify_destroyed = mach_right_get(nmr->mr_port,
519 l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
520 break;
522 case MACH_NOTIFY_NO_SENDERS_MSGID:
523 oldnmr = tmr->mr_notify_no_senders;
524 tmr->mr_notify_no_senders = mach_right_get(nmr->mr_port,
525 l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
526 tmr->mr_notify_no_senders->mr_port->mp_datatype =
527 MACH_MP_NOTIFY_SYNC;
528 tmr->mr_notify_no_senders->mr_port->mp_data = (void *)
529 req->req_count;
530 break;
532 case MACH_NOTIFY_DEAD_NAME_MSGID:
533 oldnmr = tmr->mr_notify_dead_name;
534 tmr->mr_notify_dead_name = mach_right_get(nmr->mr_port,
535 l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
536 break;
538 case MACH_NOTIFY_SEND_ONCE_MSGID:
539 case MACH_NOTIFY_DELETED_MSGID:
540 default:
541 #ifdef DEBUG_MACH
542 printf("unsupported notify request %d\n", req->req_msgid);
543 return mach_msg_error(args, EINVAL);
544 #endif
545 break;
548 if (oldnmr != NULL) {
549 oldnmr->mr_refcount++;
550 oldmn = oldnmr->mr_name;
551 } else {
552 oldmn = (mach_port_t)MACH_PORT_NULL;
555 *msglen = sizeof(*rep);
556 mach_set_header(rep, req, *msglen);
557 mach_add_port_desc(rep, oldmn);
558 mach_set_trailer(rep, *msglen);
560 return 0;
564 mach_port_get_refs(struct mach_trap_args *args)
566 mach_port_get_refs_request_t *req = args->smsg;
567 mach_port_get_refs_reply_t *rep = args->rmsg;
568 size_t *msglen = args->rsize;
569 struct lwp *l = args->l;
570 mach_port_t mn;
571 struct mach_right *mr;
572 mach_port_right_t right = req->req_right;
574 mn = req->req_name;
575 if ((mr = mach_right_check(mn, l, right)) == NULL)
576 return mach_msg_error(args, EINVAL);
578 *msglen = sizeof(*rep);
579 mach_set_header(rep, req, *msglen);
581 rep->rep_retval = 0;
582 rep->rep_refs = mr->mr_refcount;
584 mach_set_trailer(rep, *msglen);
586 return 0;
590 mach_port_mod_refs(struct mach_trap_args *args)
592 mach_port_mod_refs_request_t *req = args->smsg;
593 mach_port_mod_refs_reply_t *rep = args->rmsg;
594 size_t *msglen = args->rsize;
595 #if 0
596 struct lwp *l = args->l;
597 mach_port_t mn;
598 struct mach_right *mr;
599 mach_port_right_t right = req->req_right;
601 mn = req->req_name;
602 if ((mr = mach_right_check(mn, l, right)) == NULL)
603 return mach_msg_error(args, EINVAL);
606 * Changing the refcount is likely to cause crashes,
607 * as we will free a right which might still be referenced
608 * within the kernel. Add a user refcount field?
610 mr->mr_refcount += req->req_delta;
611 if (mr->mr_refcount <= 0)
612 mach_right_put(mr, right);
613 #endif
615 *msglen = sizeof(*rep);
616 mach_set_header(rep, req, *msglen);
618 rep->rep_retval = 0;
620 mach_set_trailer(rep, *msglen);
622 return 0;
625 void
626 mach_port_init(void)
628 pool_init(&mach_port_pool, sizeof (struct mach_port),
629 0, 0, 0, "mach_port_pool", NULL, IPL_NONE);
630 pool_init(&mach_right_pool, sizeof (struct mach_right),
631 0, 0, 0, "mach_right_pool", NULL, IPL_NONE);
633 mach_bootstrap_port = mach_port_get();
634 mach_clock_port = mach_port_get();
635 mach_io_master_port = mach_port_get();
637 mach_bootstrap_port->mp_flags |= MACH_MP_INKERNEL;
638 mach_clock_port->mp_flags |= MACH_MP_INKERNEL;
639 mach_io_master_port->mp_flags |= MACH_MP_INKERNEL;
641 mach_saved_bootstrap_port = mach_bootstrap_port;
643 return;
646 struct mach_port *
647 mach_port_get(void)
649 struct mach_port *mp;
651 mp = (struct mach_port *)pool_get(&mach_port_pool, PR_WAITOK);
652 memset(mp, 0, sizeof(*mp));
653 mp->mp_recv = NULL;
654 mp->mp_count = 0;
655 mp->mp_flags = 0;
656 mp->mp_datatype = MACH_MP_NONE;
657 mp->mp_data = NULL;
658 TAILQ_INIT(&mp->mp_msglist);
659 rw_init(&mp->mp_msglock);
661 return mp;
664 void
665 mach_port_put(struct mach_port *mp)
667 struct mach_message *mm;
669 #ifdef DIAGNOSTIC
670 if (mp->mp_refcount > 0) {
671 uprintf("mach_port_put: trying to free a referenced port\n");
672 return;
674 #endif
676 rw_enter(&mp->mp_msglock, RW_WRITER);
677 while ((mm = TAILQ_FIRST(&mp->mp_msglist)) != NULL)
678 mach_message_put_exclocked(mm);
679 rw_exit(&mp->mp_msglock);
680 rw_destroy(&mp->mp_msglock);
682 if (mp->mp_flags & MACH_MP_DATA_ALLOCATED)
683 free(mp->mp_data, M_EMULDATA);
685 pool_put(&mach_port_pool, mp);
687 return;
690 struct mach_right *
691 mach_right_get(struct mach_port *mp, struct lwp *l, int type, mach_port_t hint)
693 struct mach_right *mr;
694 struct mach_emuldata *med;
695 int rights;
697 #ifdef DEBUG_MACH
698 if (type == 0)
699 uprintf("mach_right_get: right = 0\n");
700 #endif
701 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
703 if (mp != NULL)
704 MACH_PORT_REF(mp);
706 /* Send and receive right must return an existing right */
707 rights = (MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_RECEIVE);
708 if (type & rights) {
709 rw_enter(&med->med_rightlock, RW_READER);
710 LIST_FOREACH(mr, &med->med_right, mr_list) {
711 if ((mr->mr_port == mp) && (mr->mr_type & rights))
712 break;
714 rw_exit(&med->med_rightlock);
716 if (mr != NULL) {
717 mr->mr_type |= type;
718 if (type & MACH_PORT_TYPE_SEND)
719 mr->mr_refcount++;
720 goto rcvck;
724 mr = pool_get(&mach_right_pool, PR_WAITOK);
726 mr->mr_port = mp;
727 mr->mr_lwp = l;
728 mr->mr_type = type;
729 mr->mr_sethead = mr;
730 mr->mr_refcount = 1;
731 mr->mr_notify_destroyed = NULL;
732 mr->mr_notify_dead_name = NULL;
733 mr->mr_notify_no_senders = NULL;
735 LIST_INIT(&mr->mr_set);
737 /* Insert the right in the right lists */
738 if (type & MACH_PORT_TYPE_ALL_RIGHTS) {
739 rw_enter(&med->med_rightlock, RW_WRITER);
740 mr->mr_name = mach_right_newname(l, hint);
741 #ifdef DEBUG_MACH_RIGHT
742 printf("mach_right_get: insert right %x(%x)\n",
743 mr->mr_name, mr->mr_type);
744 #endif
745 LIST_INSERT_HEAD(&med->med_right, mr, mr_list);
746 rw_exit(&med->med_rightlock);
749 rcvck:
750 if (type & MACH_PORT_TYPE_RECEIVE) {
752 * Destroy the former receive right on this port, and
753 * register the new right.
755 if (mr->mr_port->mp_recv != NULL)
756 mach_right_put(mr->mr_port->mp_recv,
757 MACH_PORT_TYPE_RECEIVE);
758 mr->mr_port->mp_recv = mr;
760 return mr;
763 void
764 mach_right_put(struct mach_right *mr, int right)
766 struct mach_emuldata *med = mr->mr_lwp->l_proc->p_emuldata;
768 rw_enter(&med->med_rightlock, RW_WRITER);
769 mach_right_put_exclocked(mr, right);
770 rw_exit(&med->med_rightlock);
772 return;
775 void
776 mach_right_put_shlocked(struct mach_right *mr, int right)
778 struct mach_emuldata *med = mr->mr_lwp->l_proc->p_emuldata;
780 if (!rw_tryupgrade(&med->med_rightlock)) {
781 /* XXX */
782 rw_exit(&med->med_rightlock);
783 rw_enter(&med->med_rightlock, RW_WRITER);
785 mach_right_put_exclocked(mr, right);
786 rw_downgrade(&med->med_rightlock);
788 return;
791 void
792 mach_right_put_exclocked(struct mach_right *mr, int right)
794 struct mach_right *cmr;
795 struct mach_emuldata *med;
796 int lright;
797 int kill_right;
799 med = mr->mr_lwp->l_proc->p_emuldata;
801 #ifdef DEBUG_MACH_RIGHT
802 printf("mach_right_put: mr = %p\n", mr);
803 printf("right %x(%x) refcount %d, deallocate %x\n",
804 mr->mr_name, mr->mr_type, mr->mr_refcount, right);
805 if ((mr->mr_type & right) == 0)
806 printf("mach_right_put: dropping nonexistant right %x on %x\n",
807 right, mr->mr_name);
808 LIST_FOREACH(cmr, &med->med_right, mr_list)
809 if (cmr == mr)
810 break;
811 if (cmr == NULL) {
812 printf("mach_right_put: dropping already dropped right %x\n",
813 mr->mr_name);
814 return;
816 #endif
817 kill_right = 0;
819 /* When receive right is deallocated, the port should die */
820 lright = (right & MACH_PORT_TYPE_RECEIVE);
821 #ifdef DEBUG_MACH_RIGHT
822 printf("mr->mr_type = %x, lright = %x, right = %x, refcount = %d\n",
823 mr->mr_type, lright, right, mr->mr_refcount);
824 #endif
825 if (mr->mr_type & lright) {
826 if (mr->mr_refcount <= 0) {
827 mr->mr_type &= ~MACH_PORT_TYPE_RECEIVE;
828 kill_right = 1;
829 } else {
830 mr->mr_type &= ~MACH_PORT_TYPE_RECEIVE;
831 mr->mr_type |= MACH_PORT_TYPE_DEAD_NAME;
832 mach_notify_port_dead_name(mr->mr_lwp, mr);
834 if (mr->mr_port != NULL) {
835 /* There is no more receiver */
836 #ifdef DIAGNOSTIC
837 if (mr->mr_port->mp_recv != mr)
838 printf("several receiver on a single port\n");
839 #endif
840 mr->mr_port->mp_recv = NULL;
842 MACH_PORT_UNREF(mr->mr_port);
843 mr->mr_port = NULL;
847 /* send, send_once and dead_name */
848 lright = (right & MACH_PORT_TYPE_REF_RIGHTS);
849 if (mr->mr_type & lright) {
850 mr->mr_refcount--;
852 mach_notify_port_no_senders(mr->mr_lwp, mr);
854 if (mr->mr_refcount <= 0) {
855 mr->mr_type &= ~MACH_PORT_TYPE_REF_RIGHTS;
856 if ((mr->mr_type & MACH_PORT_TYPE_RECEIVE) == 0)
857 kill_right = 1;
861 lright = (right & MACH_PORT_TYPE_PORT_SET);
862 if ((mr->mr_type & lright) || (kill_right == 1)) {
863 while ((cmr = LIST_FIRST(&mr->mr_set)) != NULL) {
864 LIST_REMOVE(cmr, mr_setlist);
865 cmr->mr_sethead = cmr;
867 mr->mr_type &= ~MACH_PORT_TYPE_PORT_SET;
868 if ((mr->mr_type & MACH_PORT_TYPE_RECEIVE) == 0)
869 kill_right = 1;
872 /* Should we kill it? */
873 if (kill_right == 1) {
874 #ifdef DEBUG_MACH_RIGHT
875 printf("mach_right_put: kill name %x\n", mr->mr_name);
876 #endif
877 /* If the right is used for an IO notification, remove it */
878 mach_iokit_cleanup_notify(mr);
880 mach_notify_port_destroyed(mr->mr_lwp, mr);
881 LIST_REMOVE(mr, mr_list);
882 pool_put(&mach_right_pool, mr);
884 return;
888 * Check that a process has a given right.
890 struct mach_right *
891 mach_right_check(mach_port_t mn, struct lwp *l, int type)
893 struct mach_right *cmr;
894 struct mach_emuldata *med;
896 if ((mn == 0) || (mn == -1) || (l == NULL))
897 return NULL;
899 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
901 rw_enter(&med->med_rightlock, RW_READER);
903 #ifdef DEBUG_MACH_RIGHT
904 printf("mach_right_check: type = %x, mn = %x\n", type, mn);
905 #endif
906 LIST_FOREACH(cmr, &med->med_right, mr_list) {
907 #ifdef DEBUG_MACH_RIGHT
908 printf("cmr = %p, cmr->mr_name = %x, cmr->mr_type = %x\n",
909 cmr, cmr->mr_name, cmr->mr_type);
910 #endif
911 if (cmr->mr_name != mn)
912 continue;
913 if (type & cmr->mr_type)
914 break;
917 rw_exit(&med->med_rightlock);
919 return cmr;
924 * Find an usnused port name in a given lwp.
925 * Right lists should be locked.
927 mach_port_t
928 mach_right_newname(struct lwp *l, mach_port_t hint)
930 struct mach_emuldata *med;
931 struct mach_right *mr;
932 mach_port_t newname = -1;
934 med = l->l_proc->p_emuldata;
936 if (hint == 0)
937 hint = med->med_nextright;
939 while (newname == -1) {
940 LIST_FOREACH(mr, &med->med_right, mr_list)
941 if (mr->mr_name == hint)
942 break;
943 if (mr == NULL)
944 newname = hint;
945 hint++;
948 med->med_nextright = hint;
950 return newname;
953 #ifdef DEBUG_MACH
954 void
955 mach_debug_port(void)
957 struct mach_emuldata *med;
958 struct mach_right *mr;
959 struct mach_right *mrs;
960 struct proc *p;
962 PROCLIST_FOREACH(p, &allproc) {
963 if ((p->p_emul != &emul_mach) &&
964 #ifdef COMPAT_DARWIN
965 (p->p_emul != &emul_darwin) &&
966 #endif
968 continue;
970 med = p->p_emuldata;
971 LIST_FOREACH(mr, &med->med_right, mr_list) {
972 if ((mr->mr_type & MACH_PORT_TYPE_PORT_SET) == 0) {
973 printf("pid %d: %p(%x)=>%p",
974 p->p_pid, mr, mr->mr_type, mr->mr_port);
975 if (mr->mr_port && mr->mr_port->mp_recv)
976 printf("[%p]\n",
977 mr->mr_port->mp_recv->mr_sethead);
978 else
979 printf("[NULL]\n");
981 continue;
984 /* Port set... */
985 printf("pid %d: set %p(%x) ",
986 p->p_pid, mr, mr->mr_type);
987 LIST_FOREACH(mrs, &mr->mr_set, mr_setlist) {
988 printf("%p(%x)=>%p",
989 mrs, mrs->mr_type, mrs->mr_port);
990 if (mrs->mr_port && mrs->mr_port->mp_recv)
991 printf("[%p]",
992 mrs->mr_port->mp_recv->mr_sethead);
993 else
994 printf("[NULL]");
996 printf(" ");
998 printf("\n");
1001 return;
1004 #endif /* DEBUG_MACH */