|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 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: * File: ipc_tt.c
53: * Purpose:
54: * Task and thread related IPC functions.
55: */
56:
57: #include <mach_ipc_compat.h>
58:
59: #include <mach/boolean.h>
60: #include <mach/kern_return.h>
61: #include <mach/mach_param.h>
62: #include <mach/task_special_ports.h>
63: #include <mach/thread_special_ports.h>
64: #include <vm/vm_kern.h>
65: #include <kern/task.h>
66: #include <kern/thread.h>
67: #include <kern/ipc_kobject.h>
68: #include <kern/ipc_tt.h>
69: #include <ipc/ipc_space.h>
70: #include <ipc/ipc_table.h>
71: #include <ipc/ipc_port.h>
72: #include <ipc/ipc_right.h>
73: #include <ipc/ipc_entry.h>
74: #include <ipc/ipc_object.h>
75:
76:
77:
78: /*
79: * Routine: ipc_task_init
80: * Purpose:
81: * Initialize a task's IPC state.
82: *
83: * If non-null, some state will be inherited from the parent.
84: * The parent must be appropriately initialized.
85: * Conditions:
86: * Nothing locked.
87: */
88:
89: void
90: ipc_task_init(task, parent)
91: task_t task;
92: task_t parent;
93: {
94: ipc_space_t space;
95: ipc_port_t kport;
96: kern_return_t kr;
97: int i;
98:
99: kr = ipc_space_create(&ipc_table_entries[0], &space);
100: if (kr != KERN_SUCCESS)
101: panic("ipc_task_init");
102:
103: kport = ipc_port_alloc_kernel();
104: if (kport == IP_NULL)
105: panic("ipc_task_init");
106:
107: itk_lock_init(task);
108: task->itk_self = kport;
109: task->itk_sself = ipc_port_make_send(kport);
110: task->itk_space = space;
111:
112: if (parent == TASK_NULL) {
113: task->itk_exception = IP_NULL;
114: task->itk_bootstrap = IP_NULL;
115: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
116: task->itk_registered[i] = IP_NULL;
117: } else {
118: itk_lock(parent);
119: assert(parent->itk_self != IP_NULL);
120:
121: /* inherit registered ports */
122:
123: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
124: task->itk_registered[i] =
125: ipc_port_copy_send(parent->itk_registered[i]);
126:
127: /* inherit exception and bootstrap ports */
128:
129: task->itk_exception =
130: ipc_port_copy_send(parent->itk_exception);
131: task->itk_bootstrap =
132: ipc_port_copy_send(parent->itk_bootstrap);
133:
134: itk_unlock(parent);
135: }
136: }
137:
138: /*
139: * Routine: ipc_task_enable
140: * Purpose:
141: * Enable a task for IPC access.
142: * Conditions:
143: * Nothing locked.
144: */
145:
146: void
147: ipc_task_enable(task)
148: task_t task;
149: {
150: ipc_port_t kport;
151:
152: itk_lock(task);
153: kport = task->itk_self;
154: if (kport != IP_NULL)
155: ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
156: itk_unlock(task);
157: }
158:
159: /*
160: * Routine: ipc_task_disable
161: * Purpose:
162: * Disable IPC access to a task.
163: * Conditions:
164: * Nothing locked.
165: */
166:
167: void
168: ipc_task_disable(task)
169: task_t task;
170: {
171: ipc_port_t kport;
172:
173: itk_lock(task);
174: kport = task->itk_self;
175: if (kport != IP_NULL)
176: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
177: itk_unlock(task);
178: }
179:
180: /*
181: * Routine: ipc_task_terminate
182: * Purpose:
183: * Clean up and destroy a task's IPC state.
184: * Conditions:
185: * Nothing locked. The task must be suspended.
186: * (Or the current thread must be in the task.)
187: */
188:
189: void
190: ipc_task_terminate(task)
191: task_t task;
192: {
193: ipc_port_t kport;
194: int i;
195:
196: itk_lock(task);
197: kport = task->itk_self;
198:
199: if (kport == IP_NULL) {
200: /* the task is already terminated (can this happen?) */
201: itk_unlock(task);
202: return;
203: }
204:
205: task->itk_self = IP_NULL;
206: itk_unlock(task);
207:
208: /* release the naked send rights */
209:
210: if (IP_VALID(task->itk_sself))
211: ipc_port_release_send(task->itk_sself);
212: if (IP_VALID(task->itk_exception))
213: ipc_port_release_send(task->itk_exception);
214: if (IP_VALID(task->itk_bootstrap))
215: ipc_port_release_send(task->itk_bootstrap);
216:
217: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
218: if (IP_VALID(task->itk_registered[i]))
219: ipc_port_release_send(task->itk_registered[i]);
220:
221: /* destroy the space, leaving just a reference for it */
222:
223: ipc_space_destroy(task->itk_space);
224:
225: /* destroy the kernel port */
226:
227: ipc_port_dealloc_kernel(kport);
228: }
229:
230: /*
231: * Routine: ipc_thread_init
232: * Purpose:
233: * Initialize a thread's IPC state.
234: * Conditions:
235: * Nothing locked.
236: */
237:
238: void
239: ipc_thread_init(thread)
240: thread_t thread;
241: {
242: ipc_port_t kport;
243:
244: kport = ipc_port_alloc_kernel();
245: if (kport == IP_NULL)
246: panic("ipc_thread_init");
247:
248: ipc_thread_links_init(thread);
249: ipc_kmsg_queue_init(&thread->ith_messages);
250:
251: ith_lock_init(thread);
252: thread->ith_self = kport;
253: thread->ith_sself = ipc_port_make_send(kport);
254: thread->ith_exception = IP_NULL;
255:
256: thread->ith_mig_reply = MACH_PORT_NULL;
257: thread->ith_rpc_reply = IP_NULL;
258:
259: #if MACH_IPC_COMPAT
260: {
261: ipc_space_t space = thread->task->itk_space;
262: ipc_port_t port;
263: mach_port_t name;
264: kern_return_t kr;
265:
266: kr = ipc_port_alloc_compat(space, &name, &port);
267: if (kr != KERN_SUCCESS)
268: panic("ipc_thread_init");
269: /* port is locked and active */
270:
271: /*
272: * Now we have a reply port. We need to make a naked
273: * send right to stash in ith_reply. We can't use
274: * ipc_port_make_send, because we can't unlock the port
275: * before making the right. Also we don't want to
276: * increment ip_mscount. The net effect of all this
277: * is the same as doing
278: * ipc_port_alloc_kernel get the port
279: * ipc_port_make_send make the send right
280: * ipc_object_copyin_from_kernel grab receive right
281: * ipc_object_copyout_compat and give to user
282: */
283:
284: port->ip_srights++;
285: ip_reference(port);
286: ip_unlock(port);
287:
288: thread->ith_reply = port;
289: }
290: #endif MACH_IPC_COMPAT
291: }
292:
293: /*
294: * Routine: ipc_thread_enable
295: * Purpose:
296: * Enable a thread for IPC access.
297: * Conditions:
298: * Nothing locked.
299: */
300:
301: void
302: ipc_thread_enable(thread)
303: thread_t thread;
304: {
305: ipc_port_t kport;
306:
307: ith_lock(thread);
308: kport = thread->ith_self;
309: if (kport != IP_NULL)
310: ipc_kobject_set(kport, (ipc_kobject_t) thread, IKOT_THREAD);
311: ith_unlock(thread);
312: }
313:
314: /*
315: * Routine: ipc_thread_disable
316: * Purpose:
317: * Disable IPC access to a thread.
318: * Conditions:
319: * Nothing locked.
320: */
321:
322: void
323: ipc_thread_disable(thread)
324: thread_t thread;
325: {
326: ipc_port_t kport;
327:
328: ith_lock(thread);
329: kport = thread->ith_self;
330: if (kport != IP_NULL)
331: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
332: ith_unlock(thread);
333: }
334:
335: /*
336: * Routine: ipc_thread_terminate
337: * Purpose:
338: * Clean up and destroy a thread's IPC state.
339: * Conditions:
340: * Nothing locked. The thread must be suspended.
341: * (Or be the current thread.)
342: */
343:
344: void
345: ipc_thread_terminate(thread)
346: thread_t thread;
347: {
348: ipc_port_t kport;
349:
350: ith_lock(thread);
351: kport = thread->ith_self;
352:
353: if (kport == IP_NULL) {
354: /* the thread is already terminated (can this happen?) */
355: ith_unlock(thread);
356: return;
357: }
358:
359: thread->ith_self = IP_NULL;
360: ith_unlock(thread);
361:
362: assert(ipc_kmsg_queue_empty(&thread->ith_messages));
363:
364: /* release the naked send rights */
365:
366: if (IP_VALID(thread->ith_sself))
367: ipc_port_release_send(thread->ith_sself);
368: if (IP_VALID(thread->ith_exception))
369: ipc_port_release_send(thread->ith_exception);
370:
371: /* nuke the outbound rpc reply port, if one exists */
372:
373: if (IP_VALID(thread->ith_rpc_reply))
374: ipc_port_dealloc_reply(thread->ith_rpc_reply);
375:
376: #if MACH_IPC_COMPAT
377: if (IP_VALID(thread->ith_reply)) {
378: ipc_space_t space = thread->task->itk_space;
379: ipc_port_t port = thread->ith_reply;
380: ipc_entry_t entry;
381: mach_port_t name;
382:
383: /* destroy any rights the task may have for the port */
384:
385: is_write_lock(space);
386: if (space->is_active &&
387: ipc_right_reverse(space, (ipc_object_t) port,
388: &name, &entry)) {
389: /* reply port is locked and active */
390: ip_unlock(port);
391:
392: (void) ipc_right_destroy(space, name, entry);
393: /* space is unlocked */
394: } else
395: is_write_unlock(space);
396:
397: ipc_port_release_send(port);
398: }
399:
400: /*
401: * Note we do *not* destroy any rights the space may have
402: * for the thread's kernel port. The old IPC code did this,
403: * to avoid generating a notification when the port is
404: * destroyed. However, this isn't a good idea when
405: * the kernel port is interposed, because then it doesn't
406: * happen, exposing the interposition to the task.
407: * Because we don't need the efficiency hack, I flushed
408: * this behaviour, introducing a small incompatibility
409: * with the old IPC code.
410: */
411: #endif MACH_IPC_COMPAT
412:
413: /* destroy the kernel port */
414:
415: ipc_port_dealloc_kernel(kport);
416: }
417:
418: /*
419: * Routine: retrieve_task_self
420: * Purpose:
421: * Return a send right (possibly null/dead)
422: * for the task's user-visible self port.
423: * Conditions:
424: * Nothing locked.
425: */
426:
427: ipc_port_t
428: retrieve_task_self(task)
429: task_t task;
430: {
431: ipc_port_t port;
432:
433: assert(task != TASK_NULL);
434:
435: itk_lock(task);
436: if (task->itk_self != IP_NULL)
437: port = ipc_port_copy_send(task->itk_sself);
438: else
439: port = IP_NULL;
440: itk_unlock(task);
441:
442: return port;
443: }
444:
445: /*
446: * Routine: retrieve_thread_self
447: * Purpose:
448: * Return a send right (possibly null/dead)
449: * for the thread's user-visible self port.
450: * Conditions:
451: * Nothing locked.
452: */
453:
454: ipc_port_t
455: retrieve_thread_self(thread)
456: thread_t thread;
457: {
458: ipc_port_t port;
459:
460: assert(thread != ITH_NULL);
461:
462: ith_lock(thread);
463: if (thread->ith_self != IP_NULL)
464: port = ipc_port_copy_send(thread->ith_sself);
465: else
466: port = IP_NULL;
467: ith_unlock(thread);
468:
469: return port;
470: }
471:
472: /*
473: * Routine: retrieve_task_self_fast
474: * Purpose:
475: * Optimized version of retrieve_task_self,
476: * that only works for the current task.
477: *
478: * Return a send right (possibly null/dead)
479: * for the task's user-visible self port.
480: * Conditions:
481: * Nothing locked.
482: */
483:
484: ipc_port_t
485: retrieve_task_self_fast(task)
486: register task_t task;
487: {
488: register ipc_port_t port;
489:
490: assert(task == current_task());
491:
492: itk_lock(task);
493: assert(task->itk_self != IP_NULL);
494:
495: if ((port = task->itk_sself) == task->itk_self) {
496: /* no interposing */
497:
498: ip_lock(port);
499: assert(ip_active(port));
500: ip_reference(port);
501: port->ip_srights++;
502: ip_unlock(port);
503: } else
504: port = ipc_port_copy_send(port);
505: itk_unlock(task);
506:
507: return port;
508: }
509:
510: /*
511: * Routine: retrieve_thread_self_fast
512: * Purpose:
513: * Optimized version of retrieve_thread_self,
514: * that only works for the current thread.
515: *
516: * Return a send right (possibly null/dead)
517: * for the thread's user-visible self port.
518: * Conditions:
519: * Nothing locked.
520: */
521:
522: ipc_port_t
523: retrieve_thread_self_fast(thread)
524: register thread_t thread;
525: {
526: register ipc_port_t port;
527:
528: assert(thread == current_thread());
529:
530: ith_lock(thread);
531: assert(thread->ith_self != IP_NULL);
532:
533: if ((port = thread->ith_sself) == thread->ith_self) {
534: /* no interposing */
535:
536: ip_lock(port);
537: assert(ip_active(port));
538: ip_reference(port);
539: port->ip_srights++;
540: ip_unlock(port);
541: } else
542: port = ipc_port_copy_send(port);
543: ith_unlock(thread);
544:
545: return port;
546: }
547:
548: #if 0
549: /*
550: * Routine: retrieve_task_exception
551: * Purpose:
552: * Return a send right (possibly null/dead)
553: * for the task's exception port.
554: * Conditions:
555: * Nothing locked.
556: */
557:
558: ipc_port_t
559: retrieve_task_exception(task)
560: task_t task;
561: {
562: ipc_port_t port;
563:
564: assert(task != TASK_NULL);
565:
566: itk_lock(task);
567: if (task->itk_self != IP_NULL)
568: port = ipc_port_copy_send(task->itk_exception);
569: else
570: port = IP_NULL;
571: itk_unlock(task);
572:
573: return port;
574: }
575:
576: /*
577: * Routine: retrieve_thread_exception
578: * Purpose:
579: * Return a send right (possibly null/dead)
580: * for the thread's exception port.
581: * Conditions:
582: * Nothing locked.
583: */
584:
585: ipc_port_t
586: retrieve_thread_exception(thread)
587: thread_t thread;
588: {
589: ipc_port_t port;
590:
591: assert(thread != ITH_NULL);
592:
593: ith_lock(thread);
594: if (thread->ith_self != IP_NULL)
595: port = ipc_port_copy_send(thread->ith_exception);
596: else
597: port = IP_NULL;
598: ith_unlock(thread);
599:
600: return port;
601: }
602: #endif 0
603:
604: /*
605: * Routine: mach_task_self [mach trap]
606: * Purpose:
607: * Give the caller send rights for his own task port.
608: * Conditions:
609: * Nothing locked.
610: * Returns:
611: * MACH_PORT_NULL if there are any resource failures
612: * or other errors.
613: */
614:
615: mach_port_t
616: mach_task_self()
617: {
618: task_t task = current_task();
619: ipc_port_t sright;
620:
621: sright = retrieve_task_self_fast(task);
622: return ipc_port_copyout_send(sright, task->itk_space);
623: }
624:
625: /*
626: * Routine: mach_thread_self [mach trap]
627: * Purpose:
628: * Give the caller send rights for his own thread port.
629: * Conditions:
630: * Nothing locked.
631: * Returns:
632: * MACH_PORT_NULL if there are any resource failures
633: * or other errors.
634: */
635:
636: mach_port_t
637: mach_thread_self()
638: {
639: thread_t thread = current_thread();
640: task_t task = thread->task;
641: ipc_port_t sright;
642:
643: sright = retrieve_thread_self_fast(thread);
644: return ipc_port_copyout_send(sright, task->itk_space);
645: }
646:
647: /*
648: * Routine: mach_reply_port [mach trap]
649: * Purpose:
650: * Allocate a port for the caller.
651: * Conditions:
652: * Nothing locked.
653: * Returns:
654: * MACH_PORT_NULL if there are any resource failures
655: * or other errors.
656: */
657:
658: mach_port_t
659: mach_reply_port()
660: {
661: ipc_port_t port;
662: mach_port_t name;
663: kern_return_t kr;
664:
665: kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
666: if (kr == KERN_SUCCESS)
667: ip_unlock(port);
668: else
669: name = MACH_PORT_NULL;
670:
671: return name;
672: }
673:
674: #if MACH_IPC_COMPAT
675:
676: /*
677: * Routine: retrieve_task_notify
678: * Purpose:
679: * Return a reference (or null) for
680: * the task's notify port.
681: * Conditions:
682: * Nothing locked.
683: */
684:
685: ipc_port_t
686: retrieve_task_notify(task)
687: task_t task;
688: {
689: ipc_space_t space = task->itk_space;
690: ipc_port_t port;
691:
692: is_read_lock(space);
693: if (space->is_active) {
694: port = space->is_notify;
695: if (IP_VALID(port))
696: ipc_port_reference(port);
697: } else
698: port = IP_NULL;
699: is_read_unlock(space);
700:
701: return port;
702: }
703:
704: /*
705: * Routine: retrieve_thread_reply
706: * Purpose:
707: * Return a reference (or null) for
708: * the thread's reply port.
709: * Conditions:
710: * Nothing locked.
711: */
712:
713: ipc_port_t
714: retrieve_thread_reply(thread)
715: thread_t thread;
716: {
717: ipc_port_t port;
718:
719: ith_lock(thread);
720: if (thread->ith_self != IP_NULL) {
721: port = thread->ith_reply;
722: if (IP_VALID(port))
723: ipc_port_reference(port);
724: } else
725: port = IP_NULL;
726: ith_unlock(thread);
727:
728: return port;
729: }
730:
731: /*
732: * Routine: task_self [mach trap]
733: * Purpose:
734: * Give the caller send rights for his task port.
735: * If new, the send right is marked with IE_BITS_COMPAT.
736: * Conditions:
737: * Nothing locked.
738: * Returns:
739: * MACH_PORT_NULL if there are any resource failures
740: * or other errors.
741: */
742:
743: port_name_t
744: task_self()
745: {
746: task_t task = current_task();
747: ipc_port_t sright;
748: mach_port_t name;
749:
750: sright = retrieve_task_self_fast(task);
751: name = ipc_port_copyout_send_compat(sright, task->itk_space);
752: return (port_name_t) name;
753: }
754:
755: /*
756: * Routine: task_notify [mach trap]
757: * Purpose:
758: * Give the caller the name of his own notify port.
759: * Conditions:
760: * Nothing locked.
761: * Returns:
762: * MACH_PORT_NULL if there isn't a notify port,
763: * if it is dead, or if the caller doesn't hold
764: * receive rights for it.
765: */
766:
767: port_name_t
768: task_notify()
769: {
770: task_t task = current_task();
771: ipc_port_t notify;
772: mach_port_t name;
773:
774: notify = retrieve_task_notify(task);
775: name = ipc_port_copyout_receiver(notify, task->itk_space);
776: return (port_name_t) name;
777: }
778:
779: /*
780: * Routine: thread_self [mach trap]
781: * Purpose:
782: * Give the caller send rights for his own thread port.
783: * If new, the send right is marked with IE_BITS_COMPAT.
784: * Conditions:
785: * Nothing locked.
786: * Returns:
787: * MACH_PORT_NULL if there are any resource failures
788: * or other errors.
789: */
790:
791: port_name_t
792: thread_self()
793: {
794: thread_t thread = current_thread();
795: task_t task = thread->task;
796: ipc_port_t sright;
797: mach_port_t name;
798:
799: sright = retrieve_thread_self_fast(thread);
800: name = ipc_port_copyout_send_compat(sright, task->itk_space);
801: return (port_name_t) name;
802: }
803:
804: /*
805: * Routine: thread_reply [mach trap]
806: * Purpose:
807: * Give the caller the name of his own reply port.
808: * Conditions:
809: * Nothing locked.
810: * Returns:
811: * MACH_PORT_NULL if there isn't a reply port,
812: * if it is dead, or if the caller doesn't hold
813: * receive rights for it.
814: */
815:
816: port_name_t
817: thread_reply()
818: {
819: task_t task = current_task();
820: thread_t thread = current_thread();
821: ipc_port_t reply;
822: mach_port_t name;
823:
824: reply = retrieve_thread_reply(thread);
825: name = ipc_port_copyout_receiver(reply, task->itk_space);
826: return (port_name_t) name;
827: }
828:
829: #endif MACH_IPC_COMPAT
830:
831: /*
832: * Routine: task_get_special_port [kernel call]
833: * Purpose:
834: * Clones a send right for one of the task's
835: * special ports.
836: * Conditions:
837: * Nothing locked.
838: * Returns:
839: * KERN_SUCCESS Extracted a send right.
840: * KERN_INVALID_ARGUMENT The task is null.
841: * KERN_FAILURE The task/space is dead.
842: * KERN_INVALID_ARGUMENT Invalid special port.
843: */
844:
845: kern_return_t
846: task_get_special_port(task, which, portp)
847: task_t task;
848: int which;
849: ipc_port_t *portp;
850: {
851: ipc_port_t *whichp;
852: ipc_port_t port;
853:
854: if (task == TASK_NULL)
855: return KERN_INVALID_ARGUMENT;
856:
857: switch (which) {
858: #if MACH_IPC_COMPAT
859: case TASK_NOTIFY_PORT: {
860: ipc_space_t space = task->itk_space;
861:
862: is_read_lock(space);
863: if (!space->is_active) {
864: is_read_unlock(space);
865: return KERN_FAILURE;
866: }
867:
868: port = ipc_port_copy_send(space->is_notify);
869: is_read_unlock(space);
870:
871: *portp = port;
872: return KERN_SUCCESS;
873: }
874: #endif MACH_IPC_COMPAT
875:
876: case TASK_KERNEL_PORT:
877: whichp = &task->itk_sself;
878: break;
879:
880: case TASK_EXCEPTION_PORT:
881: whichp = &task->itk_exception;
882: break;
883:
884: case TASK_BOOTSTRAP_PORT:
885: whichp = &task->itk_bootstrap;
886: break;
887:
888: default:
889: return KERN_INVALID_ARGUMENT;
890: }
891:
892: itk_lock(task);
893: if (task->itk_self == IP_NULL) {
894: itk_unlock(task);
895: return KERN_FAILURE;
896: }
897:
898: port = ipc_port_copy_send(*whichp);
899: itk_unlock(task);
900:
901: *portp = port;
902: return KERN_SUCCESS;
903: }
904:
905: /*
906: * Routine: task_set_special_port [kernel call]
907: * Purpose:
908: * Changes one of the task's special ports,
909: * setting it to the supplied send right.
910: * Conditions:
911: * Nothing locked. If successful, consumes
912: * the supplied send right.
913: * Returns:
914: * KERN_SUCCESS Changed the special port.
915: * KERN_INVALID_ARGUMENT The task is null.
916: * KERN_FAILURE The task/space is dead.
917: * KERN_INVALID_ARGUMENT Invalid special port.
918: */
919:
920: kern_return_t
921: task_set_special_port(task, which, port)
922: task_t task;
923: int which;
924: ipc_port_t port;
925: {
926: ipc_port_t *whichp;
927: ipc_port_t old;
928:
929: if (task == TASK_NULL)
930: return KERN_INVALID_ARGUMENT;
931:
932: switch (which) {
933: #if MACH_IPC_COMPAT
934: case TASK_NOTIFY_PORT: {
935: ipc_space_t space = task->itk_space;
936:
937: is_write_lock(space);
938: if (!space->is_active) {
939: is_write_unlock(space);
940: return KERN_FAILURE;
941: }
942:
943: old = space->is_notify;
944: space->is_notify = port;
945: is_write_unlock(space);
946:
947: if (IP_VALID(old))
948: ipc_port_release_send(old);
949: return KERN_SUCCESS;
950: }
951: #endif MACH_IPC_COMPAT
952:
953: case TASK_KERNEL_PORT:
954: whichp = &task->itk_sself;
955: break;
956:
957: case TASK_EXCEPTION_PORT:
958: whichp = &task->itk_exception;
959: break;
960:
961: case TASK_BOOTSTRAP_PORT:
962: whichp = &task->itk_bootstrap;
963: break;
964:
965: default:
966: return KERN_INVALID_ARGUMENT;
967: }
968:
969: itk_lock(task);
970: if (task->itk_self == IP_NULL) {
971: itk_unlock(task);
972: return KERN_FAILURE;
973: }
974:
975: old = *whichp;
976: *whichp = port;
977: itk_unlock(task);
978:
979: if (IP_VALID(old))
980: ipc_port_release_send(old);
981: return KERN_SUCCESS;
982: }
983:
984: /*
985: * Routine: thread_get_special_port [kernel call]
986: * Purpose:
987: * Clones a send right for one of the thread's
988: * special ports.
989: * Conditions:
990: * Nothing locked.
991: * Returns:
992: * KERN_SUCCESS Extracted a send right.
993: * KERN_INVALID_ARGUMENT The thread is null.
994: * KERN_FAILURE The thread is dead.
995: * KERN_INVALID_ARGUMENT Invalid special port.
996: */
997:
998: kern_return_t
999: thread_get_special_port(thread, which, portp)
1000: thread_t thread;
1001: int which;
1002: ipc_port_t *portp;
1003: {
1004: ipc_port_t *whichp;
1005: ipc_port_t port;
1006:
1007: if (thread == ITH_NULL)
1008: return KERN_INVALID_ARGUMENT;
1009:
1010: switch (which) {
1011: #if MACH_IPC_COMPAT
1012: case THREAD_REPLY_PORT:
1013: whichp = &thread->ith_reply;
1014: break;
1015: #endif MACH_IPC_COMPAT
1016:
1017: case THREAD_KERNEL_PORT:
1018: whichp = &thread->ith_sself;
1019: break;
1020:
1021: case THREAD_EXCEPTION_PORT:
1022: whichp = &thread->ith_exception;
1023: break;
1024:
1025: default:
1026: return KERN_INVALID_ARGUMENT;
1027: }
1028:
1029: ith_lock(thread);
1030: if (thread->ith_self == IP_NULL) {
1031: ith_unlock(thread);
1032: return KERN_FAILURE;
1033: }
1034:
1035: port = ipc_port_copy_send(*whichp);
1036: ith_unlock(thread);
1037:
1038: *portp = port;
1039: return KERN_SUCCESS;
1040: }
1041:
1042: /*
1043: * Routine: thread_set_special_port [kernel call]
1044: * Purpose:
1045: * Changes one of the thread's special ports,
1046: * setting it to the supplied send right.
1047: * Conditions:
1048: * Nothing locked. If successful, consumes
1049: * the supplied send right.
1050: * Returns:
1051: * KERN_SUCCESS Changed the special port.
1052: * KERN_INVALID_ARGUMENT The thread is null.
1053: * KERN_FAILURE The thread is dead.
1054: * KERN_INVALID_ARGUMENT Invalid special port.
1055: */
1056:
1057: kern_return_t
1058: thread_set_special_port(thread, which, port)
1059: thread_t thread;
1060: int which;
1061: ipc_port_t port;
1062: {
1063: ipc_port_t *whichp;
1064: ipc_port_t old;
1065:
1066: if (thread == ITH_NULL)
1067: return KERN_INVALID_ARGUMENT;
1068:
1069: switch (which) {
1070: #if MACH_IPC_COMPAT
1071: case THREAD_REPLY_PORT:
1072: whichp = &thread->ith_reply;
1073: break;
1074: #endif MACH_IPC_COMPAT
1075:
1076: case THREAD_KERNEL_PORT:
1077: whichp = &thread->ith_sself;
1078: break;
1079:
1080: case THREAD_EXCEPTION_PORT:
1081: whichp = &thread->ith_exception;
1082: break;
1083:
1084: default:
1085: return KERN_INVALID_ARGUMENT;
1086: }
1087:
1088: ith_lock(thread);
1089: if (thread->ith_self == IP_NULL) {
1090: ith_unlock(thread);
1091: return KERN_FAILURE;
1092: }
1093:
1094: old = *whichp;
1095: *whichp = port;
1096: ith_unlock(thread);
1097:
1098: if (IP_VALID(old))
1099: ipc_port_release_send(old);
1100: return KERN_SUCCESS;
1101: }
1102:
1103: /*
1104: * Routine: mach_ports_register [kernel call]
1105: * Purpose:
1106: * Stash a handful of port send rights in the task.
1107: * Child tasks will inherit these rights, but they
1108: * must use mach_ports_lookup to acquire them.
1109: *
1110: * The rights are supplied in a (wired) kalloc'd segment.
1111: * Rights which aren't supplied are assumed to be null.
1112: * Conditions:
1113: * Nothing locked. If successful, consumes
1114: * the supplied rights and memory.
1115: * Returns:
1116: * KERN_SUCCESS Stashed the port rights.
1117: * KERN_INVALID_ARGUMENT The task is null.
1118: * KERN_INVALID_ARGUMENT The task is dead.
1119: * KERN_INVALID_ARGUMENT Too many port rights supplied.
1120: */
1121:
1122: kern_return_t
1123: mach_ports_register(task, memory, portsCnt)
1124: task_t task;
1125: ipc_port_t *memory;
1126: mach_msg_type_number_t portsCnt;
1127: {
1128: ipc_port_t ports[TASK_PORT_REGISTER_MAX];
1129: int i;
1130:
1131: if ((task == TASK_NULL) ||
1132: (portsCnt > TASK_PORT_REGISTER_MAX))
1133: return KERN_INVALID_ARGUMENT;
1134:
1135: /*
1136: * Pad the port rights with nulls.
1137: */
1138:
1139: for (i = 0; i < portsCnt; i++)
1140: ports[i] = memory[i];
1141: for (; i < TASK_PORT_REGISTER_MAX; i++)
1142: ports[i] = IP_NULL;
1143:
1144: itk_lock(task);
1145: if (task->itk_self == IP_NULL) {
1146: itk_unlock(task);
1147: return KERN_INVALID_ARGUMENT;
1148: }
1149:
1150: /*
1151: * Replace the old send rights with the new.
1152: * Release the old rights after unlocking.
1153: */
1154:
1155: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
1156: ipc_port_t old;
1157:
1158: old = task->itk_registered[i];
1159: task->itk_registered[i] = ports[i];
1160: ports[i] = old;
1161: }
1162:
1163: itk_unlock(task);
1164:
1165: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1166: if (IP_VALID(ports[i]))
1167: ipc_port_release_send(ports[i]);
1168:
1169: /*
1170: * Now that the operation is known to be successful,
1171: * we can free the memory.
1172: */
1173:
1174: if (portsCnt != 0)
1175: kfree((vm_offset_t) memory,
1176: (vm_size_t) (portsCnt * sizeof(mach_port_t)));
1177:
1178: return KERN_SUCCESS;
1179: }
1180:
1181: /*
1182: * Routine: mach_ports_lookup [kernel call]
1183: * Purpose:
1184: * Retrieves (clones) the stashed port send rights.
1185: * Conditions:
1186: * Nothing locked. If successful, the caller gets
1187: * rights and memory.
1188: * Returns:
1189: * KERN_SUCCESS Retrieved the send rights.
1190: * KERN_INVALID_ARGUMENT The task is null.
1191: * KERN_INVALID_ARGUMENT The task is dead.
1192: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
1193: */
1194:
1195: kern_return_t
1196: mach_ports_lookup(task, portsp, portsCnt)
1197: task_t task;
1198: ipc_port_t **portsp;
1199: mach_msg_type_number_t *portsCnt;
1200: {
1201: vm_offset_t memory;
1202: vm_size_t size;
1203: ipc_port_t *ports;
1204: int i;
1205:
1206: if (task == TASK_NULL)
1207: return KERN_INVALID_ARGUMENT;
1208:
1209: size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
1210:
1211: memory = kalloc(size);
1212: if (memory == 0)
1213: return KERN_RESOURCE_SHORTAGE;
1214:
1215: itk_lock(task);
1216: if (task->itk_self == IP_NULL) {
1217: itk_unlock(task);
1218:
1219: kfree(memory, size);
1220: return KERN_INVALID_ARGUMENT;
1221: }
1222:
1223: ports = (ipc_port_t *) memory;
1224:
1225: /*
1226: * Clone port rights. Because kalloc'd memory
1227: * is wired, we won't fault while holding the task lock.
1228: */
1229:
1230: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
1231: ports[i] = ipc_port_copy_send(task->itk_registered[i]);
1232:
1233: itk_unlock(task);
1234:
1235: *portsp = ports;
1236: *portsCnt = TASK_PORT_REGISTER_MAX;
1237: return KERN_SUCCESS;
1238: }
1239:
1240: /*
1241: * Routine: convert_port_to_task
1242: * Purpose:
1243: * Convert from a port to a task.
1244: * Doesn't consume the port ref; produces a task ref,
1245: * which may be null.
1246: * Conditions:
1247: * Nothing locked.
1248: */
1249:
1250: task_t
1251: convert_port_to_task(port)
1252: ipc_port_t port;
1253: {
1254: task_t task = TASK_NULL;
1255:
1256: if (IP_VALID(port)) {
1257: ip_lock(port);
1258: if (ip_active(port) &&
1259: (ip_kotype(port) == IKOT_TASK)) {
1260: task = (task_t) port->ip_kobject;
1261: task_reference(task);
1262: }
1263: ip_unlock(port);
1264: }
1265:
1266: return task;
1267: }
1268:
1269: /*
1270: * Routine: convert_port_to_space
1271: * Purpose:
1272: * Convert from a port to a space.
1273: * Doesn't consume the port ref; produces a space ref,
1274: * which may be null.
1275: * Conditions:
1276: * Nothing locked.
1277: */
1278:
1279: ipc_space_t
1280: convert_port_to_space(port)
1281: ipc_port_t port;
1282: {
1283: ipc_space_t space = IS_NULL;
1284:
1285: if (IP_VALID(port)) {
1286: ip_lock(port);
1287: if (ip_active(port) &&
1288: (ip_kotype(port) == IKOT_TASK)) {
1289: space = ((task_t) port->ip_kobject)->itk_space;
1290: is_reference(space);
1291: }
1292: ip_unlock(port);
1293: }
1294:
1295: return space;
1296: }
1297:
1298: /*
1299: * Routine: convert_port_to_map
1300: * Purpose:
1301: * Convert from a port to a map.
1302: * Doesn't consume the port ref; produces a map ref,
1303: * which may be null.
1304: * Conditions:
1305: * Nothing locked.
1306: */
1307:
1308: vm_map_t
1309: convert_port_to_map(port)
1310: ipc_port_t port;
1311: {
1312: vm_map_t map = VM_MAP_NULL;
1313:
1314: if (IP_VALID(port)) {
1315: ip_lock(port);
1316: if (ip_active(port) &&
1317: (ip_kotype(port) == IKOT_TASK)) {
1318: map = ((task_t) port->ip_kobject)->map;
1319: vm_map_reference(map);
1320: }
1321: ip_unlock(port);
1322: }
1323:
1324: return map;
1325: }
1326:
1327: /*
1328: * Routine: convert_port_to_thread
1329: * Purpose:
1330: * Convert from a port to a thread.
1331: * Doesn't consume the port ref; produces a thread ref,
1332: * which may be null.
1333: * Conditions:
1334: * Nothing locked.
1335: */
1336:
1337: thread_t
1338: convert_port_to_thread(port)
1339: ipc_port_t port;
1340: {
1341: thread_t thread = THREAD_NULL;
1342:
1343: if (IP_VALID(port)) {
1344: ip_lock(port);
1345: if (ip_active(port) &&
1346: (ip_kotype(port) == IKOT_THREAD)) {
1347: thread = (thread_t) port->ip_kobject;
1348: thread_reference(thread);
1349: }
1350: ip_unlock(port);
1351: }
1352:
1353: return thread;
1354: }
1355:
1356: /*
1357: * Routine: convert_task_to_port
1358: * Purpose:
1359: * Convert from a task to a port.
1360: * Consumes a task ref; produces a naked send right
1361: * which may be invalid.
1362: * Conditions:
1363: * Nothing locked.
1364: */
1365:
1366: ipc_port_t
1367: convert_task_to_port(task)
1368: task_t task;
1369: {
1370: ipc_port_t port;
1371:
1372: itk_lock(task);
1373: if (task->itk_self != IP_NULL)
1374: port = ipc_port_make_send(task->itk_self);
1375: else
1376: port = IP_NULL;
1377: itk_unlock(task);
1378:
1379: task_deallocate(task);
1380: return port;
1381: }
1382:
1383: /*
1384: * Routine: convert_thread_to_port
1385: * Purpose:
1386: * Convert from a thread to a port.
1387: * Consumes a thread ref; produces a naked send right
1388: * which may be invalid.
1389: * Conditions:
1390: * Nothing locked.
1391: */
1392:
1393: ipc_port_t
1394: convert_thread_to_port(thread)
1395: thread_t thread;
1396: {
1397: ipc_port_t port;
1398:
1399: ith_lock(thread);
1400: if (thread->ith_self != IP_NULL)
1401: port = ipc_port_make_send(thread->ith_self);
1402: else
1403: port = IP_NULL;
1404: ith_unlock(thread);
1405:
1406: thread_deallocate(thread);
1407: return port;
1408: }
1409:
1410: /*
1411: * Routine: space_deallocate
1412: * Purpose:
1413: * Deallocate a space ref produced by convert_port_to_space.
1414: * Conditions:
1415: * Nothing locked.
1416: */
1417:
1418: void
1419: space_deallocate(space)
1420: ipc_space_t space;
1421: {
1422: if (space != IS_NULL)
1423: is_release(space);
1424: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.