|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: ipc/mach_port.c
54: * Author: Rich Draves
55: * Date: 1989
56: *
57: * Exported kernel calls. See mach/mach_port.defs.
58: */
59:
60: #include <mach_debug.h>
61: #include <mach_rt.h>
62:
63: #include <mach/port.h>
64: #include <mach/kern_return.h>
65: #include <mach/notify.h>
66: #include <mach/mach_param.h>
67: #include <mach/vm_param.h>
68: #include <mach/vm_prot.h>
69: #include <kern/task.h>
70: #include <kern/counters.h>
71: #include <kern/thread_act.h>
72: #include <kern/thread_pool.h>
73: #include <mach/mach_port_server.h>
74: #include <vm/vm_map.h>
75: #include <vm/vm_kern.h>
76: #include <vm/vm_user.h>
77: #include <ipc/ipc_entry.h>
78: #include <ipc/ipc_space.h>
79: #include <ipc/ipc_object.h>
80: #include <ipc/ipc_notify.h>
81: #include <ipc/ipc_port.h>
82: #include <ipc/ipc_pset.h>
83: #include <ipc/ipc_right.h>
84: #include <kern/misc_protos.h>
85:
86: /*
87: * Forward declarations
88: */
89: void mach_port_names_helper(
90: ipc_port_timestamp_t timestamp,
91: ipc_entry_t entry,
92: mach_port_name_t name,
93: mach_port_name_t *names,
94: mach_port_type_t *types,
95: ipc_entry_num_t *actualp,
96: ipc_space_t space);
97:
98: void mach_port_gst_helper(
99: ipc_pset_t pset,
100: ipc_port_t port,
101: ipc_entry_num_t maxnames,
102: mach_port_name_t *names,
103: ipc_entry_num_t *actualp);
104:
105:
106: /* Zeroed template of qos flags */
107:
108: static mach_port_qos_t qos_template;
109:
110: /*
111: * Routine: mach_port_names_helper
112: * Purpose:
113: * A helper function for mach_port_names.
114: */
115:
116: void
117: mach_port_names_helper(
118: ipc_port_timestamp_t timestamp,
119: ipc_entry_t entry,
120: mach_port_name_t name,
121: mach_port_name_t *names,
122: mach_port_type_t *types,
123: ipc_entry_num_t *actualp,
124: ipc_space_t space)
125: {
126: ipc_entry_bits_t bits;
127: ipc_port_request_index_t request;
128: mach_port_type_t type;
129: ipc_entry_num_t actual;
130:
131: bits = entry->ie_bits;
132: request = entry->ie_request;
133: if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
134: ipc_port_t port;
135: boolean_t died;
136:
137: port = (ipc_port_t) entry->ie_object;
138: assert(port != IP_NULL);
139:
140: /*
141: * The timestamp serializes mach_port_names
142: * with ipc_port_destroy. If the port died,
143: * but after mach_port_names started, pretend
144: * that it isn't dead.
145: */
146:
147: ip_lock(port);
148: died = (!ip_active(port) &&
149: IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
150: ip_unlock(port);
151:
152: if (died) {
153: /* pretend this is a dead-name entry */
154:
155: bits &= ~(IE_BITS_TYPE_MASK);
156: bits |= MACH_PORT_TYPE_DEAD_NAME;
157: if (request != 0)
158: bits++;
159: request = 0;
160: }
161: }
162:
163: type = IE_BITS_TYPE(bits);
164: if (request != 0)
165: type |= MACH_PORT_TYPE_DNREQUEST;
166:
167: actual = *actualp;
168: names[actual] = name;
169: types[actual] = type;
170: *actualp = actual+1;
171: }
172:
173: /*
174: * Routine: mach_port_names [kernel call]
175: * Purpose:
176: * Retrieves a list of the rights present in the space,
177: * along with type information. (Same as returned
178: * by mach_port_type.) The names are returned in
179: * no particular order, but they (and the type info)
180: * are an accurate snapshot of the space.
181: * Conditions:
182: * Nothing locked.
183: * Returns:
184: * KERN_SUCCESS Arrays of names and types returned.
185: * KERN_INVALID_TASK The space is null.
186: * KERN_INVALID_TASK The space is dead.
187: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
188: */
189:
190: kern_return_t
191: mach_port_names(
192: ipc_space_t space,
193: mach_port_name_t **namesp,
194: mach_msg_type_number_t *namesCnt,
195: mach_port_type_t **typesp,
196: mach_msg_type_number_t *typesCnt)
197: {
198: ipc_entry_bits_t *capability;
199: ipc_tree_entry_t tentry;
200: ipc_entry_t table;
201: ipc_entry_num_t tsize;
202: mach_port_index_t index;
203: ipc_entry_num_t actual; /* this many names */
204: ipc_port_timestamp_t timestamp; /* logical time of this operation */
205: mach_port_name_t *names;
206: mach_port_type_t *types;
207: kern_return_t kr;
208:
209: vm_size_t size; /* size of allocated memory */
210: vm_offset_t addr1; /* allocated memory, for names */
211: vm_offset_t addr2; /* allocated memory, for types */
212: vm_map_copy_t memory1; /* copied-in memory, for names */
213: vm_map_copy_t memory2; /* copied-in memory, for types */
214:
215: /* safe simplifying assumption */
216: assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
217:
218: if (space == IS_NULL)
219: return KERN_INVALID_TASK;
220:
221: size = 0;
222:
223: for (;;) {
224: ipc_entry_num_t bound;
225: vm_size_t size_needed;
226:
227: is_read_lock(space);
228: if (!space->is_active) {
229: is_read_unlock(space);
230: if (size != 0) {
231: kmem_free(ipc_kernel_map, addr1, size);
232: kmem_free(ipc_kernel_map, addr2, size);
233: }
234: return KERN_INVALID_TASK;
235: }
236:
237: /* upper bound on number of names in the space */
238:
239: bound = space->is_table_size + space->is_tree_total;
240: size_needed = round_page(bound * sizeof(mach_port_name_t));
241:
242: if (size_needed <= size)
243: break;
244:
245: is_read_unlock(space);
246:
247: if (size != 0) {
248: kmem_free(ipc_kernel_map, addr1, size);
249: kmem_free(ipc_kernel_map, addr2, size);
250: }
251: size = size_needed;
252:
253: kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE);
254: if (kr != KERN_SUCCESS)
255: return KERN_RESOURCE_SHORTAGE;
256:
257: kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE);
258: if (kr != KERN_SUCCESS) {
259: kmem_free(ipc_kernel_map, addr1, size);
260: return KERN_RESOURCE_SHORTAGE;
261: }
262:
263: /* can't fault while we hold locks */
264:
265: kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size,
266: VM_PROT_READ|VM_PROT_WRITE, FALSE);
267: assert(kr == KERN_SUCCESS);
268:
269: kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size,
270: VM_PROT_READ|VM_PROT_WRITE, FALSE);
271: assert(kr == KERN_SUCCESS);
272: }
273: /* space is read-locked and active */
274:
275: names = (mach_port_name_t *) addr1;
276: types = (mach_port_type_t *) addr2;
277: actual = 0;
278:
279: timestamp = ipc_port_timestamp();
280:
281: table = space->is_table;
282: tsize = space->is_table_size;
283:
284: for (index = 0; index < tsize; index++) {
285: ipc_entry_t entry = &table[index];
286: ipc_entry_bits_t bits = entry->ie_bits;
287:
288: if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
289: mach_port_name_t name;
290:
291: name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
292: mach_port_names_helper(timestamp, entry, name, names,
293: types, &actual, space);
294: }
295: }
296:
297: for (tentry = ipc_splay_traverse_start(&space->is_tree);
298: tentry != ITE_NULL;
299: tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
300: ipc_entry_t entry = &tentry->ite_entry;
301: mach_port_name_t name = tentry->ite_name;
302:
303: assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE);
304: mach_port_names_helper(timestamp, entry, name, names,
305: types, &actual, space);
306: }
307: ipc_splay_traverse_finish(&space->is_tree);
308: is_read_unlock(space);
309:
310: if (actual == 0) {
311: memory1 = VM_MAP_COPY_NULL;
312: memory2 = VM_MAP_COPY_NULL;
313:
314: if (size != 0) {
315: kmem_free(ipc_kernel_map, addr1, size);
316: kmem_free(ipc_kernel_map, addr2, size);
317: }
318: } else {
319: vm_size_t size_used;
320: vm_size_t vm_size_used;
321:
322: size_used = actual * sizeof(mach_port_name_t);
323: vm_size_used = round_page(size_used);
324:
325: /*
326: * Make used memory pageable and get it into
327: * copied-in form. Free any unused memory.
328: */
329:
330: kr = vm_map_unwire(ipc_kernel_map,
331: addr1, addr1 + vm_size_used, FALSE);
332: assert(kr == KERN_SUCCESS);
333:
334: kr = vm_map_unwire(ipc_kernel_map,
335: addr2, addr2 + vm_size_used, FALSE);
336: assert(kr == KERN_SUCCESS);
337:
338: kr = vm_map_copyin(ipc_kernel_map, addr1, size_used,
339: TRUE, &memory1);
340: assert(kr == KERN_SUCCESS);
341:
342: kr = vm_map_copyin(ipc_kernel_map, addr2, size_used,
343: TRUE, &memory2);
344: assert(kr == KERN_SUCCESS);
345:
346: if (vm_size_used != size) {
347: kmem_free(ipc_kernel_map,
348: addr1 + vm_size_used, size - vm_size_used);
349: kmem_free(ipc_kernel_map,
350: addr2 + vm_size_used, size - vm_size_used);
351: }
352: }
353:
354: *namesp = (mach_port_name_t *) memory1;
355: *namesCnt = actual;
356: *typesp = (mach_port_type_t *) memory2;
357: *typesCnt = actual;
358: return KERN_SUCCESS;
359: }
360:
361: /*
362: * Routine: mach_port_type [kernel call]
363: * Purpose:
364: * Retrieves the type of a right in the space.
365: * The type is a bitwise combination of one or more
366: * of the following type bits:
367: * MACH_PORT_TYPE_SEND
368: * MACH_PORT_TYPE_RECEIVE
369: * MACH_PORT_TYPE_SEND_ONCE
370: * MACH_PORT_TYPE_PORT_SET
371: * MACH_PORT_TYPE_DEAD_NAME
372: * In addition, the following pseudo-type bits may be present:
373: * MACH_PORT_TYPE_DNREQUEST
374: * A dead-name notification is requested.
375: * Conditions:
376: * Nothing locked.
377: * Returns:
378: * KERN_SUCCESS Type is returned.
379: * KERN_INVALID_TASK The space is null.
380: * KERN_INVALID_TASK The space is dead.
381: * KERN_INVALID_NAME The name doesn't denote a right.
382: */
383:
384: kern_return_t
385: mach_port_type(
386: ipc_space_t space,
387: mach_port_name_t name,
388: mach_port_type_t *typep)
389: {
390: mach_port_urefs_t urefs;
391: ipc_entry_t entry;
392: kern_return_t kr;
393:
394: if (space == IS_NULL)
395: return KERN_INVALID_TASK;
396:
397: kr = ipc_right_lookup_write(space, name, &entry);
398: if (kr != KERN_SUCCESS)
399: return kr;
400: /* space is write-locked and active */
401:
402: kr = ipc_right_info(space, name, entry, typep, &urefs);
403: if (kr == KERN_SUCCESS)
404: is_write_unlock(space);
405: /* space is unlocked */
406: return kr;
407: }
408:
409: /*
410: * Routine: mach_port_rename [kernel call]
411: * Purpose:
412: * Changes the name denoting a right,
413: * from oname to nname.
414: * Conditions:
415: * Nothing locked.
416: * Returns:
417: * KERN_SUCCESS The right is renamed.
418: * KERN_INVALID_TASK The space is null.
419: * KERN_INVALID_TASK The space is dead.
420: * KERN_INVALID_NAME The oname doesn't denote a right.
421: * KERN_INVALID_VALUE The nname isn't a legal name.
422: * KERN_NAME_EXISTS The nname already denotes a right.
423: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
424: */
425:
426: kern_return_t
427: mach_port_rename(
428: ipc_space_t space,
429: mach_port_name_t oname,
430: mach_port_name_t nname)
431: {
432: if (space == IS_NULL)
433: return KERN_INVALID_TASK;
434:
435: if (!MACH_PORT_VALID(nname))
436: return KERN_INVALID_VALUE;
437:
438: return ipc_object_rename(space, oname, nname);
439: }
440:
441: /*
442: * Routine: mach_port_allocate_name [kernel call]
443: * Purpose:
444: * Allocates a right in a space, using a specific name
445: * for the new right. Possible rights:
446: * MACH_PORT_RIGHT_RECEIVE
447: * MACH_PORT_RIGHT_PORT_SET
448: * MACH_PORT_RIGHT_DEAD_NAME
449: *
450: * A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
451: * has no extant send or send-once rights and no queued
452: * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT
453: * and its make-send count is 0. It is not a member of
454: * a port set. It has no registered no-senders or
455: * port-destroyed notification requests.
456: *
457: * A new port set has no members.
458: *
459: * A new dead name has one user reference.
460: * Conditions:
461: * Nothing locked.
462: * Returns:
463: * KERN_SUCCESS The right is allocated.
464: * KERN_INVALID_TASK The space is null.
465: * KERN_INVALID_TASK The space is dead.
466: * KERN_INVALID_VALUE The name isn't a legal name.
467: * KERN_INVALID_VALUE "right" isn't a legal kind of right.
468: * KERN_NAME_EXISTS The name already denotes a right.
469: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
470: *
471: * Restrictions on name allocation: NT bits are reserved by kernel,
472: * must be set on any chosen name. Can't do this at all in kernel
473: * loaded server.
474: */
475:
476: kern_return_t
477: mach_port_allocate_name(
478: ipc_space_t space,
479: mach_port_right_t right,
480: mach_port_name_t name)
481: {
482: kern_return_t kr;
483: mach_port_qos_t qos = qos_template;
484:
485: qos.name = TRUE;
486:
487: kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL,
488: &qos, &name);
489: return (kr);
490: }
491:
492: /*
493: * Routine: mach_port_allocate [kernel call]
494: * Purpose:
495: * Allocates a right in a space. Like mach_port_allocate_name,
496: * except that the implementation picks a name for the right.
497: * The name may be any legal name in the space that doesn't
498: * currently denote a right.
499: * Conditions:
500: * Nothing locked.
501: * Returns:
502: * KERN_SUCCESS The right is allocated.
503: * KERN_INVALID_TASK The space is null.
504: * KERN_INVALID_TASK The space is dead.
505: * KERN_INVALID_VALUE "right" isn't a legal kind of right.
506: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
507: * KERN_NO_SPACE No room in space for another right.
508: */
509:
510: kern_return_t
511: mach_port_allocate(
512: ipc_space_t space,
513: mach_port_right_t right,
514: mach_port_name_t *namep)
515: {
516: kern_return_t kr;
517: mach_port_qos_t qos = qos_template;
518:
519: kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL,
520: &qos, namep);
521: return (kr);
522: }
523:
524: /*
525: * Routine: mach_port_allocate_qos [kernel call]
526: * Purpose:
527: * Allocates a right, with qos options, in a space. Like
528: * mach_port_allocate_name, except that the implementation
529: * picks a name for the right. The name may be any legal name
530: * in the space that doesn't currently denote a right.
531: * Conditions:
532: * Nothing locked.
533: * Returns:
534: * KERN_SUCCESS The right is allocated.
535: * KERN_INVALID_TASK The space is null.
536: * KERN_INVALID_TASK The space is dead.
537: * KERN_INVALID_VALUE "right" isn't a legal kind of right.
538: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
539: * KERN_NO_SPACE No room in space for another right.
540: */
541:
542: kern_return_t
543: mach_port_allocate_qos(
544: ipc_space_t space,
545: mach_port_right_t right,
546: mach_port_qos_t *qosp,
547: mach_port_name_t *namep)
548: {
549: kern_return_t kr;
550:
551: kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL,
552: qosp, namep);
553: return (kr);
554: }
555:
556: /*
557: * Routine: mach_port_allocate_subsystem [kernel call]
558: * Purpose:
559: * Allocates a receive right in a space. Like
560: * mach_port_allocate, except that the caller specifies an
561: * RPC subsystem that is to be used to implement RPC's to the
562: * port. When possible, allocate rpc subsystem ports without
563: * nms, since within RPC ports are intended to be used for
564: * identity only (i.e. nms is painful in the distributed case
565: * and we don't need or want it for RPC anyway).
566: * Conditions:
567: * Nothing locked.
568: * Returns:
569: * KERN_SUCCESS The right is allocated.
570: * KERN_INVALID_TASK The space is null.
571: * KERN_INVALID_TASK The space is dead.
572: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
573: * KERN_NO_SPACE No room in space for another right.
574: * KERN_INVALID_ARGUMENT bogus subsystem
575: */
576:
577: kern_return_t
578: mach_port_allocate_subsystem(
579: ipc_space_t space,
580: subsystem_t subsystem,
581: mach_port_name_t *namep)
582: {
583: kern_return_t kr;
584: ipc_port_t port;
585: mach_port_qos_t qos = qos_template;
586:
587: kr = mach_port_allocate_full (space,
588: #if TEMPORARY_NO_NMS
589: MACH_PORT_RIGHT_RECEIVE_NO_NMS,
590: #else
591: MACH_PORT_RIGHT_RECEIVE,
592: #endif /* TEMPORARY_NO_NMS */
593: subsystem, &qos, namep);
594: return (kr);
595: }
596:
597: /*
598: * Routine: mach_port_allocate_full [kernel call]
599: * Purpose:
600: * Allocates a right in a space. Supports all of the
601: * special cases, such as specifying a subsystem,
602: * a specific name, a real-time port, etc.
603: * The name may be any legal name in the space that doesn't
604: * currently denote a right.
605: * Conditions:
606: * Nothing locked.
607: * Returns:
608: * KERN_SUCCESS The right is allocated.
609: * KERN_INVALID_TASK The space is null.
610: * KERN_INVALID_TASK The space is dead.
611: * KERN_INVALID_VALUE "right" isn't a legal kind of right.
612: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
613: * KERN_NO_SPACE No room in space for another right.
614: */
615: #if TEMPORARY_NO_NMS
616: counter(unsigned int c_mpalloc_fast = 0;)
617: #endif /* TEMPORARY_NO_NMS */
618:
619: kern_return_t
620: mach_port_allocate_full(
621: ipc_space_t space,
622: mach_port_right_t right,
623: subsystem_t subsystem,
624: mach_port_qos_t *qosp,
625: mach_port_name_t *namep)
626: {
627: kern_return_t kr;
628:
629: if (space == IS_NULL)
630: return (KERN_INVALID_TASK);
631:
632: if (qosp->name) {
633: if (!MACH_PORT_VALID (*namep))
634: return (KERN_INVALID_VALUE);
635: if (is_fast_space (space))
636: return (KERN_FAILURE);
637: }
638:
639: if (subsystem != SUBSYSTEM_NULL) {
640: if (right != MACH_PORT_RIGHT_RECEIVE
641: #if TEMPORARY_NO_NMS
642: && right != MACH_PORT_RIGHT_RECEIVE_NO_NMS
643: #endif /* TEMPORARY_NO_NMS */
644: )
645: return (KERN_INVALID_VALUE);
646: }
647:
648: if (qosp->rt) {
649: #if MACH_RT
650: if (right != MACH_PORT_RIGHT_RECEIVE)
651: return (KERN_INVALID_VALUE);
652: #else /* MACH_RT */
653: return (KERN_INVALID_ARGUMENT);
654: #endif /* MACH_RT */
655: }
656:
657: switch (right) {
658: #if TEMPORARY_NO_NMS
659: case MACH_PORT_RIGHT_RECEIVE_NO_NMS:
660: {
661: ipc_port_t port;
662:
663: if (qosp->name)
664: kr = ipc_port_alloc_name(space, *namep, &port);
665: else
666: kr = ipc_port_alloc(space, namep, &port);
667: if (kr == KERN_SUCCESS) {
668: counter(++c_mpalloc_fast);
669: IP_CLEAR_NMS(port);
670:
671: #if MACH_RT
672: if (qosp->rt)
673: port->ip_flags |= IPC_PORT_FLAGS_RT;
674: #endif /* MACH_RT */
675:
676: if (subsystem != SUBSYSTEM_NULL) {
677: port->ip_subsystem = &subsystem->user;
678: subsystem_reference (subsystem);
679: }
680: ip_unlock(port);
681: }
682: break;
683: }
684: #endif /* TEMPORARY_NO_NMS */
685:
686: case MACH_PORT_RIGHT_RECEIVE:
687: {
688: ipc_port_t port;
689:
690: if (qosp->name)
691: kr = ipc_port_alloc_name(space, *namep, &port);
692: else
693: kr = ipc_port_alloc(space, namep, &port);
694: if (kr == KERN_SUCCESS) {
695: #if MACH_RT
696: if (qosp->rt)
697: port->ip_flags |= IPC_PORT_FLAGS_RT;
698: #endif /* MACH_RT */
699:
700: if (subsystem != SUBSYSTEM_NULL) {
701: port->ip_subsystem = &subsystem->user;
702: subsystem_reference (subsystem);
703: }
704: ip_unlock(port);
705: }
706: break;
707: }
708:
709: case MACH_PORT_RIGHT_PORT_SET:
710: {
711: ipc_pset_t pset;
712:
713: if (qosp->name)
714: kr = ipc_pset_alloc_name(space, *namep, &pset);
715: else
716: kr = ipc_pset_alloc(space, namep, &pset);
717: if (kr == KERN_SUCCESS)
718: ips_unlock(pset);
719: break;
720: }
721:
722: case MACH_PORT_RIGHT_DEAD_NAME:
723: kr = ipc_object_alloc_dead(space, namep);
724: break;
725:
726: default:
727: kr = KERN_INVALID_VALUE;
728: break;
729: }
730:
731: return (kr);
732: }
733:
734: /*
735: * Routine: mach_port_destroy [kernel call]
736: * Purpose:
737: * Cleans up and destroys all rights denoted by a name
738: * in a space. The destruction of a receive right
739: * destroys the port, unless a port-destroyed request
740: * has been made for it; the destruction of a port-set right
741: * destroys the port set.
742: * Conditions:
743: * Nothing locked.
744: * Returns:
745: * KERN_SUCCESS The name is destroyed.
746: * KERN_INVALID_TASK The space is null.
747: * KERN_INVALID_TASK The space is dead.
748: * KERN_INVALID_NAME The name doesn't denote a right.
749: */
750:
751: kern_return_t
752: mach_port_destroy(
753: ipc_space_t space,
754: mach_port_name_t name)
755: {
756: ipc_entry_t entry;
757: kern_return_t kr;
758:
759: if (space == IS_NULL)
760: return KERN_INVALID_TASK;
761:
762: kr = ipc_right_lookup_write(space, name, &entry);
763: if (kr != KERN_SUCCESS)
764: return kr;
765: /* space is write-locked and active */
766:
767: kr = ipc_right_destroy(space, name, entry);
768: is_write_unlock(space);
769: return kr;
770: }
771:
772: /*
773: * Routine: mach_port_deallocate [kernel call]
774: * Purpose:
775: * Deallocates a user reference from a send right,
776: * send-once right, or a dead-name right. May
777: * deallocate the right, if this is the last uref,
778: * and destroy the name, if it doesn't denote
779: * other rights.
780: * Conditions:
781: * Nothing locked.
782: * Returns:
783: * KERN_SUCCESS The uref is deallocated.
784: * KERN_INVALID_TASK The space is null.
785: * KERN_INVALID_TASK The space is dead.
786: * KERN_INVALID_NAME The name doesn't denote a right.
787: * KERN_INVALID_RIGHT The right isn't correct.
788: */
789:
790: kern_return_t
791: mach_port_deallocate(
792: ipc_space_t space,
793: mach_port_name_t name)
794: {
795: ipc_entry_t entry;
796: kern_return_t kr;
797:
798: if (space == IS_NULL)
799: return KERN_INVALID_TASK;
800:
801: kr = ipc_right_lookup_write(space, name, &entry);
802: if (kr != KERN_SUCCESS)
803: return kr;
804: /* space is write-locked */
805:
806: kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
807: return kr;
808: }
809:
810: /*
811: * Routine: mach_port_get_refs [kernel call]
812: * Purpose:
813: * Retrieves the number of user references held by a right.
814: * Receive rights, port-set rights, and send-once rights
815: * always have one user reference. Returns zero if the
816: * name denotes a right, but not the queried right.
817: * Conditions:
818: * Nothing locked.
819: * Returns:
820: * KERN_SUCCESS Number of urefs returned.
821: * KERN_INVALID_TASK The space is null.
822: * KERN_INVALID_TASK The space is dead.
823: * KERN_INVALID_VALUE "right" isn't a legal value.
824: * KERN_INVALID_NAME The name doesn't denote a right.
825: */
826:
827: kern_return_t
828: mach_port_get_refs(
829: ipc_space_t space,
830: mach_port_name_t name,
831: mach_port_right_t right,
832: mach_port_urefs_t *urefsp)
833: {
834: mach_port_type_t type;
835: mach_port_urefs_t urefs;
836: ipc_entry_t entry;
837: kern_return_t kr;
838:
839: if (space == IS_NULL)
840: return KERN_INVALID_TASK;
841:
842: if (right >= MACH_PORT_RIGHT_NUMBER)
843: return KERN_INVALID_VALUE;
844:
845: kr = ipc_right_lookup_write(space, name, &entry);
846: if (kr != KERN_SUCCESS)
847: return kr;
848: /* space is write-locked and active */
849:
850: kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
851: if (kr != KERN_SUCCESS)
852: return kr; /* space is unlocked */
853: is_write_unlock(space);
854:
855: if (type & MACH_PORT_TYPE(right))
856: switch (right) {
857: case MACH_PORT_RIGHT_SEND_ONCE:
858: assert(urefs == 1);
859: /* fall-through */
860:
861: case MACH_PORT_RIGHT_PORT_SET:
862: case MACH_PORT_RIGHT_RECEIVE:
863: *urefsp = 1;
864: break;
865:
866: case MACH_PORT_RIGHT_DEAD_NAME:
867: case MACH_PORT_RIGHT_SEND:
868: assert(urefs > 0);
869: *urefsp = urefs;
870: break;
871:
872: default:
873: panic("mach_port_get_refs: strange rights");
874: }
875: else
876: *urefsp = 0;
877:
878: return kr;
879: }
880:
881: /*
882: * Routine: mach_port_mod_refs
883: * Purpose:
884: * Modifies the number of user references held by a right.
885: * The resulting number of user references must be non-negative.
886: * If it is zero, the right is deallocated. If the name
887: * doesn't denote other rights, it is destroyed.
888: * Conditions:
889: * Nothing locked.
890: * Returns:
891: * KERN_SUCCESS Modified number of urefs.
892: * KERN_INVALID_TASK The space is null.
893: * KERN_INVALID_TASK The space is dead.
894: * KERN_INVALID_VALUE "right" isn't a legal value.
895: * KERN_INVALID_NAME The name doesn't denote a right.
896: * KERN_INVALID_RIGHT Name doesn't denote specified right.
897: * KERN_INVALID_VALUE Impossible modification to urefs.
898: * KERN_UREFS_OVERFLOW Urefs would overflow.
899: */
900:
901: kern_return_t
902: mach_port_mod_refs(
903: ipc_space_t space,
904: mach_port_name_t name,
905: mach_port_right_t right,
906: mach_port_delta_t delta)
907: {
908: ipc_entry_t entry;
909: kern_return_t kr;
910:
911: if (space == IS_NULL)
912: return KERN_INVALID_TASK;
913:
914: if (right >= MACH_PORT_RIGHT_NUMBER)
915: return KERN_INVALID_VALUE;
916:
917: kr = ipc_right_lookup_write(space, name, &entry);
918: if (kr != KERN_SUCCESS)
919: return kr;
920: /* space is write-locked and active */
921:
922: kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
923: return kr;
924: }
925:
926:
927: /*
928: * Routine: mach_port_set_mscount [kernel call]
929: * Purpose:
930: * Changes a receive right's make-send count.
931: * Conditions:
932: * Nothing locked.
933: * Returns:
934: * KERN_SUCCESS Set make-send count.
935: * KERN_INVALID_TASK The space is null.
936: * KERN_INVALID_TASK The space is dead.
937: * KERN_INVALID_NAME The name doesn't denote a right.
938: * KERN_INVALID_RIGHT Name doesn't denote receive rights.
939: */
940:
941: kern_return_t
942: mach_port_set_mscount(
943: ipc_space_t space,
944: mach_port_name_t name,
945: mach_port_mscount_t mscount)
946: {
947: ipc_port_t port;
948: kern_return_t kr;
949:
950: if (space == IS_NULL)
951: return KERN_INVALID_TASK;
952:
953: kr = ipc_port_translate_receive(space, name, &port);
954: if (kr != KERN_SUCCESS)
955: return kr;
956: /* port is locked and active */
957:
958: ipc_port_set_mscount(port, mscount);
959:
960: ip_unlock(port);
961: return KERN_SUCCESS;
962: }
963:
964: /*
965: * Routine: mach_port_set_seqno [kernel call]
966: * Purpose:
967: * Changes a receive right's sequence number.
968: * Conditions:
969: * Nothing locked.
970: * Returns:
971: * KERN_SUCCESS Set sequence number.
972: * KERN_INVALID_TASK The space is null.
973: * KERN_INVALID_TASK The space is dead.
974: * KERN_INVALID_NAME The name doesn't denote a right.
975: * KERN_INVALID_RIGHT Name doesn't denote receive rights.
976: */
977:
978: kern_return_t
979: mach_port_set_seqno(
980: ipc_space_t space,
981: mach_port_name_t name,
982: mach_port_seqno_t seqno)
983: {
984: ipc_port_t port;
985: kern_return_t kr;
986:
987: if (space == IS_NULL)
988: return KERN_INVALID_TASK;
989:
990: kr = ipc_port_translate_receive(space, name, &port);
991: if (kr != KERN_SUCCESS)
992: return kr;
993: /* port is locked and active */
994:
995: ipc_mqueue_set_seqno(&port->ip_messages, seqno);
996:
997: ip_unlock(port);
998: return KERN_SUCCESS;
999: }
1000:
1001: /*
1002: * Routine: mach_port_gst_helper
1003: * Purpose:
1004: * A helper function for mach_port_get_set_status.
1005: */
1006:
1007: void
1008: mach_port_gst_helper(
1009: ipc_pset_t pset,
1010: ipc_port_t port,
1011: ipc_entry_num_t maxnames,
1012: mach_port_name_t *names,
1013: ipc_entry_num_t *actualp)
1014: {
1015: ipc_pset_t ip_pset;
1016: mach_port_name_t name;
1017:
1018: assert(port != IP_NULL);
1019:
1020: ip_lock(port);
1021: assert(ip_active(port));
1022:
1023: name = port->ip_receiver_name;
1024: assert(name != MACH_PORT_NULL);
1025:
1026: ip_unlock(port);
1027:
1028: if (ipc_pset_member(pset, port)) {
1029: ipc_entry_num_t actual = *actualp;
1030:
1031: if (actual < maxnames)
1032: names[actual] = name;
1033:
1034: *actualp = actual+1;
1035: }
1036: }
1037:
1038: /*
1039: * Routine: mach_port_get_set_status [kernel call]
1040: * Purpose:
1041: * Retrieves a list of members in a port set.
1042: * Returns the space's name for each receive right member.
1043: * Conditions:
1044: * Nothing locked.
1045: * Returns:
1046: * KERN_SUCCESS Retrieved list of members.
1047: * KERN_INVALID_TASK The space is null.
1048: * KERN_INVALID_TASK The space is dead.
1049: * KERN_INVALID_NAME The name doesn't denote a right.
1050: * KERN_INVALID_RIGHT Name doesn't denote a port set.
1051: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1052: */
1053:
1054: kern_return_t
1055: mach_port_get_set_status(
1056: ipc_space_t space,
1057: mach_port_name_t name,
1058: mach_port_name_t **members,
1059: mach_msg_type_number_t *membersCnt)
1060: {
1061: ipc_entry_num_t actual; /* this many members */
1062: ipc_entry_num_t maxnames; /* space for this many members */
1063: kern_return_t kr;
1064:
1065: vm_size_t size; /* size of allocated memory */
1066: vm_offset_t addr; /* allocated memory */
1067: vm_map_copy_t memory; /* copied-in memory */
1068:
1069: if (space == IS_NULL)
1070: return KERN_INVALID_TASK;
1071:
1072: size = PAGE_SIZE; /* initial guess */
1073:
1074: for (;;) {
1075: ipc_tree_entry_t tentry;
1076: ipc_entry_t entry, table;
1077: ipc_entry_num_t tsize;
1078: mach_port_index_t index;
1079: mach_port_name_t *names;
1080: ipc_pset_t pset;
1081:
1082: kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE);
1083: if (kr != KERN_SUCCESS)
1084: return KERN_RESOURCE_SHORTAGE;
1085:
1086: /* can't fault while we hold locks */
1087:
1088: kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
1089: VM_PROT_READ|VM_PROT_WRITE, FALSE);
1090: assert(kr == KERN_SUCCESS);
1091:
1092: kr = ipc_right_lookup_read(space, name, &entry);
1093: if (kr != KERN_SUCCESS) {
1094: kmem_free(ipc_kernel_map, addr, size);
1095: return kr;
1096: }
1097: /* space is read-locked and active */
1098:
1099: if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
1100: is_read_unlock(space);
1101: kmem_free(ipc_kernel_map, addr, size);
1102: return KERN_INVALID_RIGHT;
1103: }
1104:
1105: pset = (ipc_pset_t) entry->ie_object;
1106: assert(pset != IPS_NULL);
1107: /* the port set must be active */
1108:
1109: names = (mach_port_name_t *) addr;
1110: maxnames = size / sizeof(mach_port_name_t);
1111: actual = 0;
1112:
1113: table = space->is_table;
1114: tsize = space->is_table_size;
1115:
1116: for (index = 0; index < tsize; index++) {
1117: ipc_entry_t ientry = &table[index];
1118:
1119: if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) {
1120: ipc_port_t port =
1121: (ipc_port_t) ientry->ie_object;
1122:
1123: mach_port_gst_helper(pset, port,
1124: maxnames, names, &actual);
1125: }
1126: }
1127:
1128: for (tentry = ipc_splay_traverse_start(&space->is_tree);
1129: tentry != ITE_NULL;
1130: tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
1131: ipc_entry_bits_t bits = tentry->ite_bits;
1132:
1133: assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
1134:
1135: if (bits & MACH_PORT_TYPE_RECEIVE) {
1136: ipc_port_t port = (ipc_port_t) tentry->ite_object;
1137:
1138: mach_port_gst_helper(pset, port, maxnames,
1139: names, &actual);
1140: }
1141: }
1142: ipc_splay_traverse_finish(&space->is_tree);
1143: is_read_unlock(space);
1144:
1145: if (actual <= maxnames)
1146: break;
1147:
1148: /* didn't have enough memory; allocate more */
1149:
1150: kmem_free(ipc_kernel_map, addr, size);
1151: size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE;
1152: }
1153:
1154: if (actual == 0) {
1155: memory = VM_MAP_COPY_NULL;
1156:
1157: kmem_free(ipc_kernel_map, addr, size);
1158: } else {
1159: vm_size_t size_used;
1160: vm_size_t vm_size_used;
1161:
1162: size_used = actual * sizeof(mach_port_name_t);
1163: vm_size_used = round_page(size_used);
1164:
1165: /*
1166: * Make used memory pageable and get it into
1167: * copied-in form. Free any unused memory.
1168: */
1169:
1170: kr = vm_map_unwire(ipc_kernel_map,
1171: addr, addr + vm_size_used, FALSE);
1172: assert(kr == KERN_SUCCESS);
1173:
1174: kr = vm_map_copyin(ipc_kernel_map, addr, size_used,
1175: TRUE, &memory);
1176: assert(kr == KERN_SUCCESS);
1177:
1178: if (vm_size_used != size)
1179: kmem_free(ipc_kernel_map,
1180: addr + vm_size_used, size - vm_size_used);
1181: }
1182:
1183: *members = (mach_port_name_t *) memory;
1184: *membersCnt = actual;
1185: return KERN_SUCCESS;
1186: }
1187:
1188: /*
1189: * Routine: mach_port_move_member [kernel call]
1190: * Purpose:
1191: * If after is MACH_PORT_NULL, removes member
1192: * from the port set it is in. Otherwise, adds
1193: * member to after, removing it from any set
1194: * it might already be in.
1195: * Conditions:
1196: * Nothing locked.
1197: * Returns:
1198: * KERN_SUCCESS Moved the port.
1199: * KERN_INVALID_TASK The space is null.
1200: * KERN_INVALID_TASK The space is dead.
1201: * KERN_INVALID_NAME Member didn't denote a right.
1202: * KERN_INVALID_RIGHT Member didn't denote a receive right.
1203: * KERN_INVALID_NAME After didn't denote a right.
1204: * KERN_INVALID_RIGHT After didn't denote a port set right.
1205: * KERN_NOT_IN_SET
1206: * After is MACH_PORT_NULL and Member isn't in a port set.
1207: */
1208:
1209: kern_return_t
1210: mach_port_move_member(
1211: ipc_space_t space,
1212: mach_port_name_t member,
1213: mach_port_name_t after)
1214: {
1215: ipc_entry_t entry;
1216: ipc_port_t port;
1217: ipc_pset_t nset;
1218: kern_return_t kr;
1219:
1220: if (space == IS_NULL)
1221: return KERN_INVALID_TASK;
1222:
1223: kr = ipc_right_lookup_read(space, member, &entry);
1224: if (kr != KERN_SUCCESS)
1225: return kr;
1226: /* space is read-locked and active */
1227:
1228: if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
1229: is_read_unlock(space);
1230: return KERN_INVALID_RIGHT;
1231: }
1232:
1233: port = (ipc_port_t) entry->ie_object;
1234: assert(port != IP_NULL);
1235:
1236: if (after == MACH_PORT_NULL)
1237: nset = IPS_NULL;
1238: else {
1239: entry = ipc_entry_lookup(space, after);
1240: if (entry == IE_NULL) {
1241: is_read_unlock(space);
1242: return KERN_INVALID_NAME;
1243: }
1244:
1245: if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
1246: is_read_unlock(space);
1247: return KERN_INVALID_RIGHT;
1248: }
1249:
1250: nset = (ipc_pset_t) entry->ie_object;
1251: assert(nset != IPS_NULL);
1252: }
1253: ip_lock(port);
1254: ipc_pset_remove_all(port);
1255:
1256: if (nset != IPS_NULL) {
1257: ips_lock(nset);
1258: kr = ipc_pset_add(nset, port);
1259: ips_unlock(nset);
1260: }
1261: ip_unlock(port);
1262: is_read_unlock(space);
1263: return kr;
1264: }
1265:
1266: /*
1267: * Routine: mach_port_request_notification [kernel call]
1268: * Purpose:
1269: * Requests a notification. The caller supplies
1270: * a send-once right for the notification to use,
1271: * and the call returns the previously registered
1272: * send-once right, if any. Possible types:
1273: *
1274: * MACH_NOTIFY_PORT_DESTROYED
1275: * Requests a port-destroyed notification
1276: * for a receive right. Sync should be zero.
1277: * MACH_NOTIFY_NO_SENDERS
1278: * Requests a no-senders notification for a
1279: * receive right. If there are currently no
1280: * senders, sync is less than or equal to the
1281: * current make-send count, and a send-once right
1282: * is supplied, then an immediate no-senders
1283: * notification is generated.
1284: * MACH_NOTIFY_DEAD_NAME
1285: * Requests a dead-name notification for a send
1286: * or receive right. If the name is already a
1287: * dead name, sync is non-zero, and a send-once
1288: * right is supplied, then an immediate dead-name
1289: * notification is generated.
1290: * Conditions:
1291: * Nothing locked.
1292: * Returns:
1293: * KERN_SUCCESS Requested a notification.
1294: * KERN_INVALID_TASK The space is null.
1295: * KERN_INVALID_TASK The space is dead.
1296: * KERN_INVALID_VALUE Bad id value.
1297: * KERN_INVALID_NAME Name doesn't denote a right.
1298: * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1299: * KERN_INVALID_CAPABILITY The notify port is dead.
1300: * MACH_NOTIFY_PORT_DESTROYED:
1301: * KERN_INVALID_VALUE Sync isn't zero.
1302: * MACH_NOTIFY_DEAD_NAME:
1303: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1304: * KERN_INVALID_ARGUMENT Name denotes dead name, but
1305: * sync is zero or notify is IP_NULL.
1306: * KERN_UREFS_OVERFLOW Name denotes dead name, but
1307: * generating immediate notif. would overflow urefs.
1308: */
1309:
1310: kern_return_t
1311: mach_port_request_notification(
1312: ipc_space_t space,
1313: mach_port_name_t name,
1314: mach_msg_id_t id,
1315: mach_port_mscount_t sync,
1316: ipc_port_t notify,
1317: ipc_port_t *previousp)
1318: {
1319: kern_return_t kr;
1320: ipc_entry_t entry;
1321: ipc_port_t port;
1322:
1323:
1324: if (space == IS_NULL)
1325: return KERN_INVALID_TASK;
1326:
1327: if (notify == IP_DEAD)
1328: return KERN_INVALID_CAPABILITY;
1329:
1330: #if NOTYET
1331: /*
1332: * Requesting notifications on RPC ports is an error.
1333: */
1334: kr = ipc_right_lookup_write(space, name, &entry);
1335: if (kr != KERN_SUCCESS)
1336: return kr;
1337:
1338: port = (ipc_port_t) entry->ie_object;
1339:
1340: if (port->ip_subsystem != NULL) {
1341: is_write_unlock(space);
1342: panic("mach_port_request_notification: on RPC port!!");
1343: return KERN_INVALID_CAPABILITY;
1344: }
1345: is_write_unlock(space);
1346: #endif /* NOTYET */
1347:
1348:
1349: switch (id) {
1350: case MACH_NOTIFY_PORT_DESTROYED: {
1351: ipc_port_t port, previous;
1352:
1353: if (sync != 0)
1354: return KERN_INVALID_VALUE;
1355:
1356: kr = ipc_port_translate_receive(space, name, &port);
1357: if (kr != KERN_SUCCESS)
1358: return kr;
1359: /* port is locked and active */
1360:
1361: ipc_port_pdrequest(port, notify, &previous);
1362: /* port is unlocked */
1363:
1364: *previousp = previous;
1365: break;
1366: }
1367:
1368: case MACH_NOTIFY_NO_SENDERS: {
1369: ipc_port_t port;
1370:
1371: kr = ipc_port_translate_receive(space, name, &port);
1372: if (kr != KERN_SUCCESS)
1373: return kr;
1374: /* port is locked and active */
1375:
1376: if (!IP_NMS(port)) {
1377: ip_unlock(port);
1378: return KERN_INVALID_RIGHT;
1379: }
1380:
1381: ipc_port_nsrequest(port, sync, notify, previousp);
1382: /* port is unlocked */
1383: break;
1384: }
1385:
1386: case MACH_NOTIFY_DEAD_NAME:
1387: kr = ipc_right_dnrequest(space, name, sync != 0,
1388: notify, previousp);
1389: if (kr != KERN_SUCCESS)
1390: return kr;
1391: break;
1392:
1393: default:
1394: return KERN_INVALID_VALUE;
1395: }
1396:
1397: return KERN_SUCCESS;
1398: }
1399:
1400: /*
1401: * Routine: mach_port_insert_right [kernel call]
1402: * Purpose:
1403: * Inserts a right into a space, as if the space
1404: * voluntarily received the right in a message,
1405: * except that the right gets the specified name.
1406: * Conditions:
1407: * Nothing locked.
1408: * Returns:
1409: * KERN_SUCCESS Inserted the right.
1410: * KERN_INVALID_TASK The space is null.
1411: * KERN_INVALID_TASK The space is dead.
1412: * KERN_INVALID_VALUE The name isn't a legal name.
1413: * KERN_NAME_EXISTS The name already denotes a right.
1414: * KERN_INVALID_VALUE Message doesn't carry a port right.
1415: * KERN_INVALID_CAPABILITY Port is null or dead.
1416: * KERN_UREFS_OVERFLOW Urefs limit would be exceeded.
1417: * KERN_RIGHT_EXISTS Space has rights under another name.
1418: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1419: */
1420:
1421: kern_return_t
1422: mach_port_insert_right(
1423: ipc_space_t space,
1424: mach_port_name_t name,
1425: ipc_port_t poly,
1426: mach_msg_type_name_t polyPoly)
1427: {
1428: if (space == IS_NULL)
1429: return KERN_INVALID_TASK;
1430:
1431: if (!MACH_PORT_VALID(name) ||
1432: !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
1433: return KERN_INVALID_VALUE;
1434:
1435: if (!IO_VALID((ipc_object_t) poly))
1436: return KERN_INVALID_CAPABILITY;
1437:
1438: return ipc_object_copyout_name(space, (ipc_object_t) poly,
1439: polyPoly, FALSE, name);
1440: }
1441:
1442: /*
1443: * Routine: mach_port_extract_right [kernel call]
1444: * Purpose:
1445: * Extracts a right from a space, as if the space
1446: * voluntarily sent the right to the caller.
1447: * Conditions:
1448: * Nothing locked.
1449: * Returns:
1450: * KERN_SUCCESS Extracted the right.
1451: * KERN_INVALID_TASK The space is null.
1452: * KERN_INVALID_TASK The space is dead.
1453: * KERN_INVALID_VALUE Requested type isn't a port right.
1454: * KERN_INVALID_NAME Name doesn't denote a right.
1455: * KERN_INVALID_RIGHT Name doesn't denote appropriate right.
1456: */
1457:
1458: kern_return_t
1459: mach_port_extract_right(
1460: ipc_space_t space,
1461: mach_port_name_t name,
1462: mach_msg_type_name_t msgt_name,
1463: ipc_port_t *poly,
1464: mach_msg_type_name_t *polyPoly)
1465: {
1466: kern_return_t kr;
1467:
1468: if (space == IS_NULL)
1469: return KERN_INVALID_TASK;
1470:
1471: if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
1472: return KERN_INVALID_VALUE;
1473:
1474: kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
1475:
1476: if (kr == KERN_SUCCESS)
1477: *polyPoly = ipc_object_copyin_type(msgt_name);
1478: return kr;
1479: }
1480:
1481:
1482: kern_return_t
1483: mach_port_get_attributes(
1484: ipc_space_t space,
1485: mach_port_name_t name,
1486: int flavor,
1487: mach_port_info_t info,
1488: mach_msg_type_number_t *count)
1489: {
1490: ipc_port_t port;
1491: kern_return_t kr;
1492:
1493: if (space == IS_NULL)
1494: return KERN_INVALID_TASK;
1495:
1496: switch (flavor) {
1497: case MACH_PORT_LIMITS_INFO: {
1498: mach_port_limits_t *lp = (mach_port_limits_t *)info;
1499:
1500: if (*count < MACH_PORT_LIMITS_INFO_COUNT)
1501: return KERN_FAILURE;
1502:
1503: kr = ipc_port_translate_receive(space, name, &port);
1504: if (kr != KERN_SUCCESS)
1505: return kr;
1506: /* port is locked and active */
1507:
1508: lp->mpl_qlimit = port->ip_messages.imq_qlimit;
1509: *count = MACH_PORT_LIMITS_INFO_COUNT;
1510: ip_unlock(port);
1511: break;
1512: }
1513:
1514: case MACH_PORT_RECEIVE_STATUS: {
1515: mach_port_status_t *statusp = (mach_port_status_t *)info;
1516:
1517: if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
1518: return KERN_FAILURE;
1519:
1520: kr = ipc_port_translate_receive(space, name, &port);
1521: if (kr != KERN_SUCCESS)
1522: return kr;
1523: /* port is locked and active */
1524:
1525: statusp->mps_pset = port->ip_pset_count;
1526: imq_lock(&port->ip_messages);
1527: statusp->mps_seqno = port->ip_messages.imq_seqno;
1528: statusp->mps_qlimit = port->ip_messages.imq_qlimit;
1529: statusp->mps_msgcount = port->ip_messages.imq_msgcount;
1530: imq_unlock(&port->ip_messages);
1531:
1532: statusp->mps_mscount = port->ip_mscount;
1533: statusp->mps_sorights = port->ip_sorights;
1534: statusp->mps_srights = port->ip_srights > 0;
1535: statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
1536: statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
1537: statusp->mps_flags = port->ip_flags;
1538:
1539: *count = MACH_PORT_RECEIVE_STATUS_COUNT;
1540: ip_unlock(port);
1541: break;
1542: }
1543:
1544: case MACH_PORT_DNREQUESTS_SIZE: {
1545: ipc_port_request_t table;
1546:
1547: if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1548: return KERN_FAILURE;
1549:
1550: kr = ipc_port_translate_receive(space, name, &port);
1551: if (kr != KERN_SUCCESS)
1552: return kr;
1553: /* port is locked and active */
1554:
1555: table = port->ip_dnrequests;
1556: if (table == IPR_NULL)
1557: *(int *)info = 0;
1558: else
1559: *(int *)info = table->ipr_size->its_size;
1560: *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
1561: ip_unlock(port);
1562: break;
1563: }
1564:
1565: default:
1566: return KERN_INVALID_ARGUMENT;
1567: /*NOTREACHED*/
1568: }
1569:
1570: return KERN_SUCCESS;
1571: }
1572:
1573: kern_return_t
1574: mach_port_set_attributes(
1575: ipc_space_t space,
1576: mach_port_name_t name,
1577: int flavor,
1578: mach_port_info_t info,
1579: mach_msg_type_number_t count)
1580: {
1581: ipc_port_t port;
1582: kern_return_t kr;
1583:
1584: if (space == IS_NULL)
1585: return KERN_INVALID_TASK;
1586:
1587: switch (flavor) {
1588:
1589: case MACH_PORT_LIMITS_INFO: {
1590: mach_port_limits_t *mplp = (mach_port_limits_t *)info;
1591:
1592: if (count < MACH_PORT_LIMITS_INFO_COUNT)
1593: return KERN_FAILURE;
1594:
1595: if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
1596: return KERN_INVALID_VALUE;
1597:
1598: kr = ipc_port_translate_receive(space, name, &port);
1599: if (kr != KERN_SUCCESS)
1600: return kr;
1601: /* port is locked and active */
1602:
1603: ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
1604: ip_unlock(port);
1605: break;
1606: }
1607: case MACH_PORT_DNREQUESTS_SIZE: {
1608: if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
1609: return KERN_FAILURE;
1610:
1611: kr = ipc_port_translate_receive(space, name, &port);
1612: if (kr != KERN_SUCCESS)
1613: return kr;
1614: /* port is locked and active */
1615:
1616: kr = ipc_port_dngrow(port, *(int *)info);
1617: if (kr != KERN_SUCCESS)
1618: return kr;
1619: break;
1620: }
1621: default:
1622: return KERN_INVALID_ARGUMENT;
1623: /*NOTREACHED*/
1624: }
1625: return KERN_SUCCESS;
1626: }
1627:
1628:
1629: /*
1630: * Create an empty thread_activation (sans thread_shuttle) attached to
1631: * a port or port set in a given task to receive incoming threads.
1632: */
1633: /*
1634: * NOTE: the following calls targeted at a thread_act port may be
1635: * called on an empty thread_act:
1636: *
1637: * thread_get_exception_ports thread_set_exception_ports
1638: * thread_get_special_port thread_set_special_port
1639: * thread_get_state thread_suspend
1640: * thread_resume thread_swap_exception_ports
1641: * thread_sample thread_terminate
1642: *
1643: * The following calls targeted at a thread_act port may _not_ be
1644: * called on an empty thread_act (and will return KERN_INVALID_ARGUMENT
1645: * if they are called with one):
1646: *
1647: * thread_abort thread_info
1648: * thread_abort_safely thread_wire
1649: * thread_depress_abort
1650: *
1651: * Also, if thread_switch() is called with an empty thread_act as
1652: * its first argument, the argument will be ignored (i.e., the
1653: * function will behave as if a zero-valued argument had been
1654: * given).
1655: */
1656: kern_return_t
1657: thread_activation_create(
1658: task_t task,
1659: mach_port_name_t name,
1660: act_params_t act_params,
1661: thread_act_t *new_act)
1662: {
1663: ipc_space_t space;
1664: ipc_object_t object;
1665: kern_return_t kr;
1666: thread_act_t thr_act;
1667: int is_port = 1;
1668: thread_act_params_t params = (thread_act_params_t)act_params;
1669:
1670: if (task == TASK_NULL)
1671: return KERN_INVALID_TASK;
1672:
1673: /* First create the new activation. */
1674: /*
1675: * We'll need this stack later -- make sure it's present.
1676: */
1677: assert(params != 0);
1678: assert(params->stack != 0);
1679: kr = act_create(task, params, &thr_act);
1680: if (kr != KERN_SUCCESS)
1681: return kr;
1682:
1683: space = task->itk_space;
1684:
1685: kr = ipc_object_translate(space, name,
1686: MACH_PORT_RIGHT_PORT_SET, &object);
1687: if (kr != KERN_SUCCESS) {
1688: kr = ipc_object_translate(space, name,
1689: MACH_PORT_RIGHT_RECEIVE, &object);
1690: if (kr != KERN_SUCCESS) {
1691: thread_terminate(thr_act);
1692: act_deallocate(thr_act);
1693: return kr;
1694: }
1695: is_port = 0;
1696: }
1697: /* port/pset is locked and active */
1698:
1699: #if MACH_ASSERT
1700: if (watchacts & WA_PORT)
1701: printf("thr_act on %s=%x stack=%x thr_act=%x\n",
1702: (is_port ? "port" : "pset"),
1703: object, params->stack, thr_act);
1704: #endif /* MACH_ASSERT */
1705:
1706: /* Assign the activation to the thread_pool. */
1707: kr = act_set_thread_pool(thr_act, (ipc_port_t)object);
1708: if (kr != KERN_SUCCESS) {
1709: io_unlock(object);
1710: thread_terminate(thr_act);
1711: act_deallocate(thr_act);
1712: return kr;
1713: }
1714: io_unlock(object);
1715:
1716: #if MACH_ASSERT
1717: if (watchacts & WA_PORT)
1718: printf("\tpool_port=%x thr_act=%x\n", (ipc_port_t)object, thr_act);
1719: #endif /* MACH_ASSERT */
1720:
1721: /* Pass our reference to the activation back to the user. */
1722: *new_act = thr_act;
1723:
1724: return KERN_SUCCESS;
1725: }
1726:
1727: /*
1728: * Routine: mach_port_insert_member [kernel call]
1729: * Purpose:
1730: * Add the receive right, specified by name, to
1731: * a portset.
1732: * The port cannot already be a member of the set.
1733: * Conditions:
1734: * Nothing locked.
1735: * Returns:
1736: * KERN_SUCCESS Moved the port.
1737: * KERN_INVALID_TASK The space is null.
1738: * KERN_INVALID_TASK The space is dead.
1739: * KERN_INVALID_NAME name didn't denote a right.
1740: * KERN_INVALID_RIGHT name didn't denote a receive right.
1741: * KERN_INVALID_NAME pset_name didn't denote a right.
1742: * KERN_INVALID_RIGHT pset_name didn't denote a portset right.
1743: * KERN_ALREADY_IN_SET name was already a member of pset.
1744: */
1745:
1746: kern_return_t
1747: mach_port_insert_member(
1748: ipc_space_t space,
1749: mach_port_name_t name,
1750: mach_port_name_t pset_name)
1751: {
1752: ipc_object_t obj;
1753: ipc_object_t pset_obj;
1754: kern_return_t kr;
1755:
1756: if (space == IS_NULL)
1757: return KERN_INVALID_TASK;
1758:
1759: kr = ipc_object_translate(space, pset_name, MACH_PORT_RIGHT_PORT_SET,
1760: &pset_obj); /* pset locked */
1761: if (kr != KERN_SUCCESS)
1762: return kr;
1763: assert(pset_obj != IO_NULL);
1764:
1765: kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE, &obj);
1766:
1767: if (kr != KERN_SUCCESS) {
1768: io_unlock(pset_obj);
1769: return kr;
1770: }
1771:
1772: assert(obj != IO_NULL);
1773:
1774: kr = ipc_pset_add((ipc_pset_t)pset_obj, (ipc_port_t)obj);
1775: io_unlock(pset_obj);
1776: io_unlock(obj);
1777: return kr;
1778: }
1779:
1780: /*
1781: * Routine: mach_port_extract_member [kernel call]
1782: * Purpose:
1783: * If after is MACH_PORT_NULL, removes member
1784: * from the port set it is in.
1785: * Conditions:
1786: * Nothing locked.
1787: * Returns:
1788: * KERN_SUCCESS Moved the port.
1789: * KERN_INVALID_TASK The space is null.
1790: * KERN_INVALID_TASK The space is dead.
1791: * KERN_INVALID_NAME Member didn't denote a right.
1792: * KERN_INVALID_RIGHT Member didn't denote a receive right.
1793: * KERN_INVALID_NAME After didn't denote a right.
1794: * KERN_INVALID_RIGHT After didn't denote a port set right.
1795: * KERN_NOT_IN_SET
1796: * After is MACH_PORT_NULL and Member isn't in a port set.
1797: */
1798:
1799: kern_return_t
1800: mach_port_extract_member(
1801: ipc_space_t space,
1802: mach_port_name_t name,
1803: mach_port_name_t pset_name)
1804: {
1805: mach_port_name_t oldname;
1806: ipc_object_t pset_obj;
1807: ipc_object_t obj;
1808: kern_return_t kr;
1809:
1810: if (space == IS_NULL)
1811: return KERN_INVALID_TASK;
1812:
1813: kr = ipc_object_translate(space, pset_name, MACH_PORT_RIGHT_PORT_SET,
1814: &pset_obj); /* pset locked and active */
1815: if (kr != KERN_SUCCESS)
1816: return kr;
1817: assert(pset_obj != IO_NULL);
1818:
1819: kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE,
1820: &obj); /* obj locked and active */
1821: if (kr != KERN_SUCCESS) {
1822: io_unlock(pset_obj);
1823: return kr;
1824: }
1825:
1826: kr = ipc_pset_remove((ipc_pset_t)pset_obj, (ipc_port_t)obj);
1827: io_unlock(pset_obj);
1828: io_unlock(obj);
1829:
1830: if (kr != KERN_SUCCESS)
1831: return kr;
1832:
1833: return kr;
1834: }
1835:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.