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