|
|
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,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:
53: /*
54: * File: ipc_tt.c
55: * Purpose:
56: * Task and thread related IPC functions.
57: */
58:
59: #include <mach/boolean.h>
60: #include <mach_rt.h>
61: #include <mach/kern_return.h>
62: #include <mach/mach_param.h>
63: #include <mach/task_special_ports.h>
64: #include <mach/thread_special_ports.h>
65: #include <mach/thread_status.h>
66: #include <mach/exception_types.h>
67: #include <mach/mach_traps.h>
68: #include <mach/task_server.h>
69: #include <mach/thread_act_server.h>
70: #include <mach/mach_host_server.h>
71: #include <mach/vm_task_server.h>
72: #include <kern/ipc_tt.h>
73: #include <kern/thread_act.h>
74: #include <kern/misc_protos.h>
75: #include <vm/vm_pageout.h>
76:
77: /*
78: * Routine: ipc_task_init
79: * Purpose:
80: * Initialize a task's IPC state.
81: *
82: * If non-null, some state will be inherited from the parent.
83: * The parent must be appropriately initialized.
84: * Conditions:
85: * Nothing locked.
86: */
87:
88: void
89: ipc_task_init(
90: task_t task,
91: task_t parent)
92: {
93: ipc_space_t space;
94: ipc_port_t kport;
95: kern_return_t kr;
96: int i;
97:
98:
99: kr = ipc_space_create(&ipc_table_entries[0], &space);
100: if (kr != KERN_SUCCESS)
101: panic("ipc_task_init");
102:
103:
104: kport = ipc_port_alloc_kernel();
105: if (kport == IP_NULL)
106: panic("ipc_task_init");
107:
108: itk_lock_init(task);
109: task->itk_self = kport;
110: task->itk_sself = ipc_port_make_send(kport);
111: task->itk_space = space;
112: space->is_fast = task->kernel_loaded;
113:
114: if (parent == TASK_NULL) {
115: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
116: task->exc_actions[i].port = IP_NULL;
117: }/* for */
118: task->exc_actions[EXC_MACH_SYSCALL].port =
119: ipc_port_make_send(realhost.host_self);
120: task->itk_bootstrap = IP_NULL;
121: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
122: task->itk_registered[i] = IP_NULL;
123: } else {
124: itk_lock(parent);
125: assert(parent->itk_self != IP_NULL);
126:
127: /* inherit registered ports */
128:
129: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
130: task->itk_registered[i] =
131: ipc_port_copy_send(parent->itk_registered[i]);
132:
133: /* inherit exception and bootstrap ports */
134:
135: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
136: task->exc_actions[i].port =
137: ipc_port_copy_send(parent->exc_actions[i].port);
138: task->exc_actions[i].flavor =
139: parent->exc_actions[i].flavor;
140: task->exc_actions[i].behavior =
141: parent->exc_actions[i].behavior;
142: }/* for */
143: task->itk_bootstrap =
144: ipc_port_copy_send(parent->itk_bootstrap);
145:
146: itk_unlock(parent);
147: }
148: }
149:
150: /*
151: * Routine: ipc_task_enable
152: * Purpose:
153: * Enable a task for IPC access.
154: * Conditions:
155: * Nothing locked.
156: */
157:
158: void
159: ipc_task_enable(
160: task_t task)
161: {
162: ipc_port_t kport;
163:
164: itk_lock(task);
165: kport = task->itk_self;
166: if (kport != IP_NULL)
167: ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
168: itk_unlock(task);
169: }
170:
171: /*
172: * Routine: ipc_task_disable
173: * Purpose:
174: * Disable IPC access to a task.
175: * Conditions:
176: * Nothing locked.
177: */
178:
179: void
180: ipc_task_disable(
181: task_t task)
182: {
183: ipc_port_t kport;
184:
185: itk_lock(task);
186: kport = task->itk_self;
187: if (kport != IP_NULL)
188: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
189: itk_unlock(task);
190: }
191:
192: /*
193: * Routine: ipc_task_terminate
194: * Purpose:
195: * Clean up and destroy a task's IPC state.
196: * Conditions:
197: * Nothing locked. The task must be suspended.
198: * (Or the current thread must be in the task.)
199: */
200:
201: void
202: ipc_task_terminate(
203: task_t task)
204: {
205: ipc_port_t kport;
206: int i;
207:
208: itk_lock(task);
209: kport = task->itk_self;
210:
211: if (kport == IP_NULL) {
212: /* the task is already terminated (can this happen?) */
213: itk_unlock(task);
214: return;
215: }
216:
217: task->itk_self = IP_NULL;
218: itk_unlock(task);
219:
220: /* release the naked send rights */
221:
222: if (IP_VALID(task->itk_sself))
223: ipc_port_release_send(task->itk_sself);
224:
225: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
226: if (IP_VALID(task->exc_actions[i].port)) {
227: ipc_port_release_send(task->exc_actions[i].port);
228: }
229: }/* for */
230: if (IP_VALID(task->itk_bootstrap))
231: ipc_port_release_send(task->itk_bootstrap);
232:
233: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
234: if (IP_VALID(task->itk_registered[i]))
235: ipc_port_release_send(task->itk_registered[i]);
236:
237: /* destroy the space, leaving just a reference for it */
238:
239: if (!task->kernel_loaded)
240: ipc_space_destroy(task->itk_space);
241:
242: /* destroy the kernel port */
243:
244: ipc_port_dealloc_kernel(kport);
245: }
246:
247: /*
248: * Routine: ipc_thread_init
249: * Purpose:
250: * Initialize a thread's IPC state.
251: * Conditions:
252: * Nothing locked.
253: */
254:
255: void
256: ipc_thread_init(
257: thread_t thread)
258: {
259: ipc_kmsg_queue_init(&thread->ith_messages);
260: thread->ith_mig_reply = MACH_PORT_NULL;
261: thread->ith_rpc_reply = IP_NULL;
262: }
263:
264: /*
265: * Routine: ipc_thread_terminate
266: * Purpose:
267: * Clean up and destroy a thread's IPC state.
268: * Conditions:
269: * Nothing locked. The thread must be suspended.
270: * (Or be the current thread.)
271: */
272:
273: void
274: ipc_thread_terminate(
275: thread_t thread)
276: {
277: assert(ipc_kmsg_queue_empty(&thread->ith_messages));
278:
279: if (thread->ith_rpc_reply != IP_NULL)
280: ipc_port_dealloc_reply(thread->ith_rpc_reply);
281: thread->ith_rpc_reply = IP_NULL;
282: }
283:
284: /*
285: * Routine: ipc_thr_act_init
286: * Purpose:
287: * Initialize an thr_act's IPC state.
288: * Conditions:
289: * Nothing locked.
290: */
291:
292: void
293: ipc_thr_act_init(task_t task, thread_act_t thr_act)
294: {
295: ipc_port_t kport; int i;
296:
297: kport = ipc_port_alloc_kernel();
298: if (kport == IP_NULL)
299: panic("ipc_thr_act_init");
300:
301: thr_act->ith_self = kport;
302: thr_act->ith_sself = ipc_port_make_send(kport);
303:
304: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
305: thr_act->exc_actions[i].port = IP_NULL;
306:
307: thr_act->exc_actions[EXC_MACH_SYSCALL].port =
308: ipc_port_make_send(realhost.host_self);
309:
310: ipc_kobject_set(kport, (ipc_kobject_t) thr_act, IKOT_ACT);
311: }
312:
313: void
314: ipc_thr_act_disable(thread_act_t thr_act)
315: {
316: int i;
317: ipc_port_t kport;
318:
319: act_lock(thr_act);
320: kport = thr_act->ith_self;
321:
322: if (kport != IP_NULL)
323: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
324: act_unlock(thr_act);
325: }
326:
327: void
328: ipc_thr_act_disable_act_locked(thread_act_t thr_act)
329: {
330: int i;
331: ipc_port_t kport;
332:
333: kport = thr_act->ith_self;
334:
335: if (kport != IP_NULL)
336: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
337: }
338:
339: void
340: ipc_thr_act_terminate(thread_act_t thr_act)
341: {
342: ipc_port_t kport; int i;
343:
344: act_lock(thr_act);
345: kport = thr_act->ith_self;
346:
347: if (kport == IP_NULL) {
348: /* the thread is already terminated (can this happen?) */
349: act_unlock(thr_act);
350: return;
351: }
352:
353: thr_act->ith_self = IP_NULL;
354: act_unlock(thr_act);
355:
356: /* release the naked send rights */
357:
358: if (IP_VALID(thr_act->ith_sself))
359: ipc_port_release_send(thr_act->ith_sself);
360: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
361: if (IP_VALID(thr_act->exc_actions[i].port))
362: ipc_port_release_send(thr_act->exc_actions[i].port);
363: }
364:
365: /* destroy the kernel port */
366: ipc_port_dealloc_kernel(kport);
367: }
368:
369: /*
370: * Routine: retrieve_task_self_fast
371: * Purpose:
372: * Optimized version of retrieve_task_self,
373: * that only works for the current task.
374: *
375: * Return a send right (possibly null/dead)
376: * for the task's user-visible self port.
377: * Conditions:
378: * Nothing locked.
379: */
380:
381: ipc_port_t
382: retrieve_task_self_fast(
383: register task_t task)
384: {
385: register ipc_port_t port;
386:
387: assert(task == current_task());
388:
389: itk_lock(task);
390: assert(task->itk_self != IP_NULL);
391:
392: if ((port = task->itk_sself) == task->itk_self) {
393: /* no interposing */
394:
395: ip_lock(port);
396: assert(ip_active(port));
397: ip_reference(port);
398: port->ip_srights++;
399: ip_unlock(port);
400: } else
401: port = ipc_port_copy_send(port);
402: itk_unlock(task);
403:
404: return port;
405: }
406:
407: /*
408: * Routine: retrieve_act_self_fast
409: * Purpose:
410: * Optimized version of retrieve_thread_self,
411: * that only works for the current thread.
412: *
413: * Return a send right (possibly null/dead)
414: * for the thread's user-visible self port.
415: * Conditions:
416: * Nothing locked.
417: */
418:
419: ipc_port_t
420: retrieve_act_self_fast(thread_act_t thr_act)
421: {
422: register ipc_port_t port;
423:
424: assert(thr_act == current_act());
425: act_lock(thr_act);
426: assert(thr_act->ith_self != IP_NULL);
427:
428: if ((port = thr_act->ith_sself) == thr_act->ith_self) {
429: /* no interposing */
430:
431: ip_lock(port);
432: assert(ip_active(port));
433: ip_reference(port);
434: port->ip_srights++;
435: ip_unlock(port);
436: } else
437: port = ipc_port_copy_send(port);
438: act_unlock(thr_act);
439:
440: return port;
441: }
442:
443: /*
444: * Routine: mach_task_self [mach trap]
445: * Purpose:
446: * Give the caller send rights for his own task port.
447: * Conditions:
448: * Nothing locked.
449: * Returns:
450: * MACH_PORT_NULL if there are any resource failures
451: * or other errors.
452: */
453:
454: mach_port_name_t
455: mach_task_self(void)
456: {
457: task_t task = current_task();
458: ipc_port_t sright;
459:
460: sright = retrieve_task_self_fast(task);
461: return ipc_port_copyout_send(sright, task->itk_space);
462: }
463:
464: /*
465: * Routine: mach_thread_self [mach trap]
466: * Purpose:
467: * Give the caller send rights for his own thread port.
468: * Conditions:
469: * Nothing locked.
470: * Returns:
471: * MACH_PORT_NULL if there are any resource failures
472: * or other errors.
473: */
474:
475: mach_port_name_t
476: mach_thread_self(void)
477: {
478: thread_act_t thr_act = current_act();
479: task_t task = thr_act->task;
480: ipc_port_t sright;
481:
482: sright = retrieve_act_self_fast(thr_act);
483: return ipc_port_copyout_send(sright, task->itk_space);
484: }
485:
486: /*
487: * Routine: mach_reply_port [mach trap]
488: * Purpose:
489: * Allocate a port for the caller.
490: * Conditions:
491: * Nothing locked.
492: * Returns:
493: * MACH_PORT_NULL if there are any resource failures
494: * or other errors.
495: */
496:
497: mach_port_name_t
498: mach_reply_port(void)
499: {
500: ipc_port_t port;
501: mach_port_name_t name;
502: kern_return_t kr;
503:
504: kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
505: if (kr == KERN_SUCCESS)
506: ip_unlock(port);
507: else
508: name = MACH_PORT_NULL;
509:
510: return name;
511: }
512:
513: /*
514: * Routine: task_get_special_port [kernel call]
515: * Purpose:
516: * Clones a send right for one of the task's
517: * special ports.
518: * Conditions:
519: * Nothing locked.
520: * Returns:
521: * KERN_SUCCESS Extracted a send right.
522: * KERN_INVALID_ARGUMENT The task is null.
523: * KERN_FAILURE The task/space is dead.
524: * KERN_INVALID_ARGUMENT Invalid special port.
525: */
526:
527: kern_return_t
528: task_get_special_port(
529: task_t task,
530: int which,
531: ipc_port_t *portp)
532: {
533: ipc_port_t *whichp;
534: ipc_port_t port;
535:
536: if (task == TASK_NULL)
537: return KERN_INVALID_ARGUMENT;
538:
539: switch (which) {
540: case TASK_KERNEL_PORT:
541: whichp = &task->itk_sself;
542: break;
543:
544: case TASK_BOOTSTRAP_PORT:
545: whichp = &task->itk_bootstrap;
546: break;
547:
548: case TASK_WIRED_LEDGER_PORT:
549: whichp = &task->wired_ledger_port;
550: break;
551:
552: case TASK_PAGED_LEDGER_PORT:
553: whichp = &task->paged_ledger_port;
554: break;
555:
556: default:
557: return KERN_INVALID_ARGUMENT;
558: }
559:
560: itk_lock(task);
561: if (task->itk_self == IP_NULL) {
562: itk_unlock(task);
563: return KERN_FAILURE;
564: }
565:
566: port = ipc_port_copy_send(*whichp);
567: itk_unlock(task);
568:
569: *portp = port;
570: return KERN_SUCCESS;
571: }
572:
573: /*
574: * Routine: task_set_special_port [kernel call]
575: * Purpose:
576: * Changes one of the task's special ports,
577: * setting it to the supplied send right.
578: * Conditions:
579: * Nothing locked. If successful, consumes
580: * the supplied send right.
581: * Returns:
582: * KERN_SUCCESS Changed the special port.
583: * KERN_INVALID_ARGUMENT The task is null.
584: * KERN_FAILURE The task/space is dead.
585: * KERN_INVALID_ARGUMENT Invalid special port.
586: */
587:
588: kern_return_t
589: task_set_special_port(
590: task_t task,
591: int which,
592: ipc_port_t port)
593: {
594: ipc_port_t *whichp;
595: ipc_port_t old;
596:
597: if (task == TASK_NULL)
598: return KERN_INVALID_ARGUMENT;
599:
600: switch (which) {
601: case TASK_KERNEL_PORT:
602: whichp = &task->itk_sself;
603: break;
604:
605: case TASK_BOOTSTRAP_PORT:
606: whichp = &task->itk_bootstrap;
607: break;
608:
609: case TASK_WIRED_LEDGER_PORT:
610: whichp = &task->wired_ledger_port;
611: break;
612:
613: case TASK_PAGED_LEDGER_PORT:
614: whichp = &task->paged_ledger_port;
615: break;
616:
617: default:
618: return KERN_INVALID_ARGUMENT;
619: }/* switch */
620:
621: itk_lock(task);
622: if (task->itk_self == IP_NULL) {
623: itk_unlock(task);
624: return KERN_FAILURE;
625: }
626:
627: old = *whichp;
628: *whichp = port;
629: itk_unlock(task);
630:
631: if (IP_VALID(old))
632: ipc_port_release_send(old);
633: return KERN_SUCCESS;
634: }
635:
636:
637: /*
638: * Routine: mach_ports_register [kernel call]
639: * Purpose:
640: * Stash a handful of port send rights in the task.
641: * Child tasks will inherit these rights, but they
642: * must use mach_ports_lookup to acquire them.
643: *
644: * The rights are supplied in a (wired) kalloc'd segment.
645: * Rights which aren't supplied are assumed to be null.
646: * Conditions:
647: * Nothing locked. If successful, consumes
648: * the supplied rights and memory.
649: * Returns:
650: * KERN_SUCCESS Stashed the port rights.
651: * KERN_INVALID_ARGUMENT The task is null.
652: * KERN_INVALID_ARGUMENT The task is dead.
653: * KERN_INVALID_ARGUMENT Too many port rights supplied.
654: */
655:
656: kern_return_t
657: mach_ports_register(
658: task_t task,
659: mach_port_array_t memory,
660: mach_msg_type_number_t portsCnt)
661: {
662: ipc_port_t ports[TASK_PORT_REGISTER_MAX];
663: int i;
664:
665: if ((task == TASK_NULL) ||
666: (portsCnt > TASK_PORT_REGISTER_MAX))
667: return KERN_INVALID_ARGUMENT;
668:
669: /*
670: * Pad the port rights with nulls.
671: */
672:
673: for (i = 0; i < portsCnt; i++)
674: ports[i] = memory[i];
675: for (; i < TASK_PORT_REGISTER_MAX; i++)
676: ports[i] = IP_NULL;
677:
678: itk_lock(task);
679: if (task->itk_self == IP_NULL) {
680: itk_unlock(task);
681: return KERN_INVALID_ARGUMENT;
682: }
683:
684: /*
685: * Replace the old send rights with the new.
686: * Release the old rights after unlocking.
687: */
688:
689: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
690: ipc_port_t old;
691:
692: old = task->itk_registered[i];
693: task->itk_registered[i] = ports[i];
694: ports[i] = old;
695: }
696:
697: itk_unlock(task);
698:
699: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
700: if (IP_VALID(ports[i]))
701: ipc_port_release_send(ports[i]);
702:
703: /*
704: * Now that the operation is known to be successful,
705: * we can free the memory.
706: */
707:
708: if (portsCnt != 0)
709: kfree((vm_offset_t) memory,
710: (vm_size_t) (portsCnt * sizeof(mach_port_t)));
711:
712: return KERN_SUCCESS;
713: }
714:
715: /*
716: * Routine: mach_ports_lookup [kernel call]
717: * Purpose:
718: * Retrieves (clones) the stashed port send rights.
719: * Conditions:
720: * Nothing locked. If successful, the caller gets
721: * rights and memory.
722: * Returns:
723: * KERN_SUCCESS Retrieved the send rights.
724: * KERN_INVALID_ARGUMENT The task is null.
725: * KERN_INVALID_ARGUMENT The task is dead.
726: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
727: */
728:
729: kern_return_t
730: mach_ports_lookup(
731: task_t task,
732: mach_port_array_t *portsp,
733: mach_msg_type_number_t *portsCnt)
734: {
735: vm_offset_t memory;
736: vm_size_t size;
737: ipc_port_t *ports;
738: int i;
739:
740: kern_return_t kr;
741: boolean_t rt = FALSE; /* ### This boolean is FALSE, because there
742: * currently exists no mechanism to determine
743: * whether or not the reply port is an RT port
744: */
745:
746: if (task == TASK_NULL)
747: return KERN_INVALID_ARGUMENT;
748:
749: size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
750:
751: memory = KALLOC(size, rt);
752: if (memory == 0)
753: return KERN_RESOURCE_SHORTAGE;
754:
755: itk_lock(task);
756: if (task->itk_self == IP_NULL) {
757: itk_unlock(task);
758:
759: KFREE(memory, size, rt);
760: return KERN_INVALID_ARGUMENT;
761: }
762:
763: ports = (ipc_port_t *) memory;
764:
765: /*
766: * Clone port rights. Because kalloc'd memory
767: * is wired, we won't fault while holding the task lock.
768: */
769:
770: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
771: ports[i] = ipc_port_copy_send(task->itk_registered[i]);
772:
773: itk_unlock(task);
774:
775: *portsp = (mach_port_array_t) ports;
776: *portsCnt = TASK_PORT_REGISTER_MAX;
777: return KERN_SUCCESS;
778: }
779:
780: /*
781: * Routine: convert_port_to_locked_task
782: * Purpose:
783: * Internal helper routine to convert from a port to a locked
784: * task. Used by several routines that try to convert from a
785: * task port to a reference on some task related object.
786: * Conditions:
787: * Nothing locked, blocking OK.
788: */
789: task_t
790: convert_port_to_locked_task(ipc_port_t port)
791: {
792: while (IP_VALID(port)) {
793: task_t task;
794:
795: ip_lock(port);
796: if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
797: ip_unlock(port);
798: return TASK_NULL;
799: }
800: task = (task_t) port->ip_kobject;
801: assert(task != TASK_NULL);
802:
803: /*
804: * Normal lock ordering puts task_lock() before ip_lock().
805: * Attempt out-of-order locking here.
806: */
807: if (task_lock_try(task)) {
808: ip_unlock(port);
809: return(task);
810: }
811:
812: ip_unlock(port);
813: mutex_pause();
814: }
815: return TASK_NULL;
816: }
817:
818: /*
819: * Routine: convert_port_to_task
820: * Purpose:
821: * Convert from a port to a task.
822: * Doesn't consume the port ref; produces a task ref,
823: * which may be null.
824: * Conditions:
825: * Nothing locked.
826: */
827: task_t
828: convert_port_to_task(
829: ipc_port_t port)
830: {
831: task_t task;
832:
833: task = convert_port_to_locked_task(port);
834: if (task) {
835: task->ref_count++;
836: task_unlock(task);
837: }
838: return task;
839: }
840:
841: /*
842: * Routine: convert_port_to_space
843: * Purpose:
844: * Convert from a port to a space.
845: * Doesn't consume the port ref; produces a space ref,
846: * which may be null.
847: * Conditions:
848: * Nothing locked.
849: */
850: ipc_space_t
851: convert_port_to_space(
852: ipc_port_t port)
853: {
854: ipc_space_t space;
855: task_t task;
856:
857: task = convert_port_to_locked_task(port);
858:
859: if (task == TASK_NULL)
860: return IPC_SPACE_NULL;
861:
862: if (!task->active) {
863: task_unlock(task);
864: return IPC_SPACE_NULL;
865: }
866:
867: space = task->itk_space;
868: is_reference(space);
869: task_unlock(task);
870: return (space);
871: }
872:
873: upl_t
874: convert_port_to_upl(
875: ipc_port_t port)
876: {
877: upl_t upl;
878:
879: ip_lock(port);
880: if (!ip_active(port) || (ip_kotype(port) != IKOT_UPL)) {
881: ip_unlock(port);
882: return (upl_t)NULL;
883: }
884: upl = (upl_t) port->ip_kobject;
885: ip_unlock(port);
886: upl_lock(upl);
887: upl->ref_count+=1;
888: upl_unlock(upl);
889: return upl;
890: }
891:
892: /*
893: * Routine: convert_port_entry_to_map
894: * Purpose:
895: * Convert from a port specifying an entry or a task
896: * to a map. Doesn't consume the port ref; produces a map ref,
897: * which may be null. Unlike convert_port_to_map, the
898: * port may be task or a named entry backed.
899: * Conditions:
900: * Nothing locked.
901: */
902:
903:
904: vm_map_t
905: convert_port_entry_to_map(
906: ipc_port_t port)
907: {
908: task_t task;
909: vm_map_t map;
910: vm_named_entry_t named_entry;
911:
912: if(IP_VALID(port) && (ip_kotype(port) == IKOT_NAMED_ENTRY)) {
913: while(TRUE) {
914: ip_lock(port);
915: if(ip_active(port) && (ip_kotype(port)
916: == IKOT_NAMED_ENTRY)) {
917: named_entry =
918: (vm_named_entry_t)port->ip_kobject;
919: if (!(mutex_try(&(named_entry)->Lock))) {
920: ip_unlock(port);
921: mutex_pause();
922: continue;
923: }
924: named_entry->ref_count++;
925: mutex_unlock(&(named_entry)->Lock);
926: ip_unlock(port);
927: if ((named_entry->is_sub_map) &&
928: (named_entry->protection
929: & VM_PROT_WRITE)) {
930: map = named_entry->backing.map;
931: } else {
932: mach_destroy_memory_entry(port);
933: return VM_MAP_NULL;
934: }
935: vm_map_reference_swap(map);
936: mach_destroy_memory_entry(port);
937: break;
938: }
939: else
940: return VM_MAP_NULL;
941: }
942: } else {
943: task_t task;
944:
945: task = convert_port_to_locked_task(port);
946:
947: if (task == TASK_NULL)
948: return VM_MAP_NULL;
949:
950: if (!task->active) {
951: task_unlock(task);
952: return VM_MAP_NULL;
953: }
954:
955: map = task->map;
956: vm_map_reference_swap(map);
957: task_unlock(task);
958: }
959:
960: return map;
961: }
962:
963: /*
964: * Routine: convert_port_entry_to_object
965: * Purpose:
966: * Convert from a port specifying a named entry to an
967: * object. Doesn't consume the port ref; produces a map ref,
968: * which may be null.
969: * Conditions:
970: * Nothing locked.
971: */
972:
973:
974: vm_object_t
975: convert_port_entry_to_object(
976: ipc_port_t port)
977: {
978: vm_object_t object;
979: vm_named_entry_t named_entry;
980:
981: if(IP_VALID(port) && (ip_kotype(port) == IKOT_NAMED_ENTRY)) {
982: while(TRUE) {
983: ip_lock(port);
984: if(ip_active(port) && (ip_kotype(port)
985: == IKOT_NAMED_ENTRY)) {
986: named_entry =
987: (vm_named_entry_t)port->ip_kobject;
988: if (!(mutex_try(&(named_entry)->Lock))) {
989: ip_unlock(port);
990: mutex_pause();
991: continue;
992: }
993: named_entry->ref_count++;
994: mutex_unlock(&(named_entry)->Lock);
995: ip_unlock(port);
996: if ((!named_entry->is_sub_map) &&
997: (named_entry->protection
998: & VM_PROT_WRITE)) {
999: object = named_entry->object;
1000: } else {
1001: mach_destroy_memory_entry(port);
1002: return (vm_object_t)NULL;
1003: }
1004: vm_object_reference(named_entry->object);
1005: mach_destroy_memory_entry(port);
1006: break;
1007: }
1008: else
1009: return (vm_object_t)NULL;
1010: }
1011: } else {
1012: return (vm_object_t)NULL;
1013: }
1014:
1015: return object;
1016: }
1017:
1018: /*
1019: * Routine: convert_port_to_map
1020: * Purpose:
1021: * Convert from a port to a map.
1022: * Doesn't consume the port ref; produces a map ref,
1023: * which may be null.
1024: * Conditions:
1025: * Nothing locked.
1026: */
1027:
1028: vm_map_t
1029: convert_port_to_map(
1030: ipc_port_t port)
1031: {
1032: task_t task;
1033: vm_map_t map;
1034:
1035: task = convert_port_to_locked_task(port);
1036:
1037: if (task == TASK_NULL)
1038: return VM_MAP_NULL;
1039:
1040: if (!task->active) {
1041: task_unlock(task);
1042: return VM_MAP_NULL;
1043: }
1044:
1045: map = task->map;
1046: vm_map_reference_swap(map);
1047: task_unlock(task);
1048: return map;
1049: }
1050:
1051:
1052: /*
1053: * Routine: convert_port_to_act
1054: * Purpose:
1055: * Convert from a port to a thr_act.
1056: * Doesn't consume the port ref; produces an thr_act ref,
1057: * which may be null.
1058: * Conditions:
1059: * Nothing locked.
1060: */
1061:
1062: thread_act_t
1063: convert_port_to_act( ipc_port_t port )
1064: {
1065: boolean_t r;
1066: thread_act_t thr_act = 0;
1067:
1068: r = FALSE;
1069: while (!r && IP_VALID(port)) {
1070: ip_lock(port);
1071: r = ref_act_port_locked(port, &thr_act);
1072: /* port unlocked */
1073: }
1074: return (thr_act);
1075: }
1076:
1077: boolean_t
1078: ref_act_port_locked( ipc_port_t port, thread_act_t *pthr_act )
1079: {
1080: thread_act_t thr_act;
1081:
1082: thr_act = 0;
1083: if (ip_active(port) &&
1084: (ip_kotype(port) == IKOT_ACT)) {
1085: thr_act = (thread_act_t) port->ip_kobject;
1086: assert(thr_act != THR_ACT_NULL);
1087:
1088: /*
1089: * Normal lock ordering is act_lock(), then ip_lock().
1090: * Allow out-of-order locking here, using
1091: * act_reference_act_locked() to accomodate it.
1092: */
1093: if (!act_lock_try(thr_act)) {
1094: ip_unlock(port);
1095: mutex_pause();
1096: return (FALSE);
1097: }
1098: act_locked_act_reference(thr_act);
1099: act_unlock(thr_act);
1100: }
1101: *pthr_act = thr_act;
1102: ip_unlock(port);
1103: return (TRUE);
1104: }
1105:
1106: /*
1107: * Routine: convert_task_to_port
1108: * Purpose:
1109: * Convert from a task to a port.
1110: * Consumes a task ref; produces a naked send right
1111: * which may be invalid.
1112: * Conditions:
1113: * Nothing locked.
1114: */
1115:
1116: ipc_port_t
1117: convert_task_to_port(
1118: task_t task)
1119: {
1120: ipc_port_t port;
1121:
1122: itk_lock(task);
1123: if (task->itk_self != IP_NULL)
1124: #if NORMA_TASK
1125: if (task->map == VM_MAP_NULL)
1126: /* norma placeholder task */
1127: port = ipc_port_copy_send(task->itk_self);
1128: else
1129: #endif /* NORMA_TASK */
1130: port = ipc_port_make_send(task->itk_self);
1131: else
1132: port = IP_NULL;
1133: itk_unlock(task);
1134:
1135: task_deallocate(task);
1136: return port;
1137: }
1138:
1139: /*
1140: * Routine: convert_act_to_port
1141: * Purpose:
1142: * Convert from a thr_act to a port.
1143: * Consumes an thr_act ref; produces a naked send right
1144: * which may be invalid.
1145: * Conditions:
1146: * Nothing locked.
1147: */
1148:
1149: ipc_port_t
1150: convert_act_to_port(thr_act)
1151: thread_act_t thr_act;
1152: {
1153: ipc_port_t port;
1154:
1155: act_lock(thr_act);
1156: if (thr_act->ith_self != IP_NULL)
1157: port = ipc_port_make_send(thr_act->ith_self);
1158: else
1159: port = IP_NULL;
1160: act_unlock(thr_act);
1161:
1162: act_deallocate(thr_act);
1163: return port;
1164: }
1165:
1166: /*
1167: * Routine: space_deallocate
1168: * Purpose:
1169: * Deallocate a space ref produced by convert_port_to_space.
1170: * Conditions:
1171: * Nothing locked.
1172: */
1173:
1174: void
1175: space_deallocate(
1176: ipc_space_t space)
1177: {
1178: if (space != IS_NULL)
1179: is_release(space);
1180: }
1181:
1182: /*
1183: * Routine: thread/task_set_exception_ports [kernel call]
1184: * Purpose:
1185: * Sets the thread/task exception port, flavor and
1186: * behavior for the exception types specified by the mask.
1187: * There will be one send right per exception per valid
1188: * port.
1189: * Conditions:
1190: * Nothing locked. If successful, consumes
1191: * the supplied send right.
1192: * Returns:
1193: * KERN_SUCCESS Changed the special port.
1194: * KERN_INVALID_ARGUMENT The thread is null,
1195: * Illegal mask bit set.
1196: * Illegal exception behavior
1197: * KERN_FAILURE The thread is dead.
1198: */
1199:
1200: kern_return_t
1201: thread_set_exception_ports(
1202: thread_act_t thr_act,
1203: exception_mask_t exception_mask,
1204: ipc_port_t new_port,
1205: exception_behavior_t new_behavior,
1206: thread_state_flavor_t new_flavor)
1207: {
1208: register int i;
1209: ipc_port_t old_port[EXC_TYPES_COUNT];
1210:
1211: if (!thr_act)
1212: return KERN_INVALID_ARGUMENT;
1213:
1214: if (exception_mask & ~EXC_MASK_ALL)
1215: return KERN_INVALID_ARGUMENT;
1216:
1217: if (IP_VALID(new_port)) {
1218: switch (new_behavior) {
1219: case EXCEPTION_DEFAULT:
1220: case EXCEPTION_STATE:
1221: case EXCEPTION_STATE_IDENTITY:
1222: break;
1223: default:
1224: return KERN_INVALID_ARGUMENT;
1225: }
1226: }
1227: /* Cannot easily check "flavor", but that just means that the flavor
1228: * in the generated exception message might be garbage. GIGO */
1229:
1230: act_lock(thr_act);
1231: if (!thr_act->active) {
1232: act_unlock(thr_act);
1233: return KERN_FAILURE;
1234: }
1235:
1236: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1237: if (exception_mask & (1 << i)) {
1238: old_port[i] = thr_act->exc_actions[i].port;
1239: thr_act->exc_actions[i].port =
1240: ipc_port_copy_send(new_port);
1241: thr_act->exc_actions[i].behavior = new_behavior;
1242: thr_act->exc_actions[i].flavor = new_flavor;
1243: } else
1244: old_port[i] = IP_NULL;
1245: }/* for */
1246: /*
1247: * Consume send rights without any lock held.
1248: */
1249: act_unlock(thr_act);
1250: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1251: if (IP_VALID(old_port[i]))
1252: ipc_port_release_send(old_port[i]);
1253: if (IP_VALID(new_port)) /* consume send right */
1254: ipc_port_release_send(new_port);
1255:
1256: return KERN_SUCCESS;
1257: }/* thread_set_exception_port */
1258:
1259: kern_return_t
1260: task_set_exception_ports(
1261: task_t task,
1262: exception_mask_t exception_mask,
1263: ipc_port_t new_port,
1264: exception_behavior_t new_behavior,
1265: thread_state_flavor_t new_flavor)
1266: {
1267: register int i;
1268: ipc_port_t old_port[EXC_TYPES_COUNT];
1269:
1270: if (task == TASK_NULL) {
1271: return KERN_INVALID_ARGUMENT;
1272: }
1273:
1274: if (exception_mask & ~EXC_MASK_ALL) {
1275: return KERN_INVALID_ARGUMENT;
1276: }
1277:
1278: if (IP_VALID(new_port)) {
1279: switch (new_behavior) {
1280: case EXCEPTION_DEFAULT:
1281: case EXCEPTION_STATE:
1282: case EXCEPTION_STATE_IDENTITY:
1283: break;
1284: default:
1285: return KERN_INVALID_ARGUMENT;
1286: }
1287: }
1288: /* Cannot easily check "new_flavor", but that just means that
1289: * the flavor in the generated exception message might be garbage:
1290: * GIGO */
1291:
1292: itk_lock(task);
1293: if (task->itk_self == IP_NULL) {
1294: itk_unlock(task);
1295: return KERN_FAILURE;
1296: }
1297:
1298: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1299: if (exception_mask & (1 << i)) {
1300: old_port[i] = task->exc_actions[i].port;
1301: task->exc_actions[i].port =
1302: ipc_port_copy_send(new_port);
1303: task->exc_actions[i].behavior = new_behavior;
1304: task->exc_actions[i].flavor = new_flavor;
1305: } else
1306: old_port[i] = IP_NULL;
1307: }/* for */
1308:
1309: /*
1310: * Consume send rights without any lock held.
1311: */
1312: itk_unlock(task);
1313: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1314: if (IP_VALID(old_port[i]))
1315: ipc_port_release_send(old_port[i]);
1316: if (IP_VALID(new_port)) /* consume send right */
1317: ipc_port_release_send(new_port);
1318:
1319: return KERN_SUCCESS;
1320: }/* task_set_exception_port */
1321:
1322: /*
1323: * Routine: thread/task_swap_exception_ports [kernel call]
1324: * Purpose:
1325: * Sets the thread/task exception port, flavor and
1326: * behavior for the exception types specified by the
1327: * mask.
1328: *
1329: * The old ports, behavior and flavors are returned
1330: * Count specifies the array sizes on input and
1331: * the number of returned ports etc. on output. The
1332: * arrays must be large enough to hold all the returned
1333: * data, MIG returnes an error otherwise. The masks
1334: * array specifies the corresponding exception type(s).
1335: *
1336: * Conditions:
1337: * Nothing locked. If successful, consumes
1338: * the supplied send right.
1339: *
1340: * Returns upto [in} CountCnt elements.
1341: * Returns:
1342: * KERN_SUCCESS Changed the special port.
1343: * KERN_INVALID_ARGUMENT The thread is null,
1344: * Illegal mask bit set.
1345: * Illegal exception behavior
1346: * KERN_FAILURE The thread is dead.
1347: */
1348:
1349: kern_return_t
1350: thread_swap_exception_ports(
1351: thread_act_t thr_act,
1352: exception_mask_t exception_mask,
1353: ipc_port_t new_port,
1354: exception_behavior_t new_behavior,
1355: thread_state_flavor_t new_flavor,
1356: exception_mask_array_t masks,
1357: mach_msg_type_number_t * CountCnt,
1358: exception_port_array_t ports,
1359: exception_behavior_array_t behaviors,
1360: thread_state_flavor_array_t flavors )
1361: {
1362: register int i,
1363: j,
1364: count;
1365: ipc_port_t old_port[EXC_TYPES_COUNT];
1366:
1367: if (!thr_act)
1368: return KERN_INVALID_ARGUMENT;
1369:
1370: if (exception_mask & ~EXC_MASK_ALL) {
1371: return KERN_INVALID_ARGUMENT;
1372: }
1373:
1374: if (IP_VALID(new_port)) {
1375: switch (new_behavior) {
1376: case EXCEPTION_DEFAULT:
1377: case EXCEPTION_STATE:
1378: case EXCEPTION_STATE_IDENTITY:
1379: break;
1380: default:
1381: return KERN_INVALID_ARGUMENT;
1382: }
1383: }
1384: /* Cannot easily check "new_flavor", but that just means that
1385: * the flavor in the generated exception message might be garbage:
1386: * GIGO */
1387:
1388: act_lock(thr_act);
1389: if (!thr_act->active) {
1390: act_unlock(thr_act);
1391: return KERN_FAILURE;
1392: }
1393:
1394: count = 0;
1395:
1396: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1397: if (exception_mask & (1 << i)) {
1398: for (j = 0; j < count; j++) {
1399: /*
1400: * search for an identical entry, if found
1401: * set corresponding mask for this exception.
1402: */
1403: if (thr_act->exc_actions[i].port == ports[j] &&
1404: thr_act->exc_actions[i].behavior ==behaviors[j]
1405: && thr_act->exc_actions[i].flavor ==flavors[j])
1406: {
1407: masks[j] |= (1 << i);
1408: break;
1409: }
1410: }/* for */
1411: if (j == count) {
1412: masks[j] = (1 << i);
1413: ports[j] =
1414: ipc_port_copy_send(thr_act->exc_actions[i].port);
1415:
1416: behaviors[j] = thr_act->exc_actions[i].behavior;
1417: flavors[j] = thr_act->exc_actions[i].flavor;
1418: count++;
1419: }
1420:
1421: old_port[i] = thr_act->exc_actions[i].port;
1422: thr_act->exc_actions[i].port =
1423: ipc_port_copy_send(new_port);
1424: thr_act->exc_actions[i].behavior = new_behavior;
1425: thr_act->exc_actions[i].flavor = new_flavor;
1426: if (count > *CountCnt) {
1427: break;
1428: }
1429: } else
1430: old_port[i] = IP_NULL;
1431: }/* for */
1432:
1433: /*
1434: * Consume send rights without any lock held.
1435: */
1436: act_unlock(thr_act);
1437: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1438: if (IP_VALID(old_port[i]))
1439: ipc_port_release_send(old_port[i]);
1440: if (IP_VALID(new_port)) /* consume send right */
1441: ipc_port_release_send(new_port);
1442: *CountCnt = count;
1443: return KERN_SUCCESS;
1444: }/* thread_swap_exception_ports */
1445:
1446: kern_return_t
1447: task_swap_exception_ports(
1448: task_t task,
1449: exception_mask_t exception_mask,
1450: ipc_port_t new_port,
1451: exception_behavior_t new_behavior,
1452: thread_state_flavor_t new_flavor,
1453: exception_mask_array_t masks,
1454: mach_msg_type_number_t * CountCnt,
1455: exception_port_array_t ports,
1456: exception_behavior_array_t behaviors,
1457: thread_state_flavor_array_t flavors )
1458: {
1459: register int i,
1460: j,
1461: count;
1462: ipc_port_t old_port[EXC_TYPES_COUNT];
1463:
1464: if (task == TASK_NULL)
1465: return KERN_INVALID_ARGUMENT;
1466:
1467: if (exception_mask & ~EXC_MASK_ALL) {
1468: return KERN_INVALID_ARGUMENT;
1469: }
1470:
1471: if (IP_VALID(new_port)) {
1472: switch (new_behavior) {
1473: case EXCEPTION_DEFAULT:
1474: case EXCEPTION_STATE:
1475: case EXCEPTION_STATE_IDENTITY:
1476: break;
1477: default:
1478: return KERN_INVALID_ARGUMENT;
1479: }
1480: }
1481: /* Cannot easily check "new_flavor", but that just means that
1482: * the flavor in the generated exception message might be garbage:
1483: * GIGO */
1484:
1485: itk_lock(task);
1486: if (task->itk_self == IP_NULL) {
1487: itk_unlock(task);
1488: return KERN_FAILURE;
1489: }
1490:
1491: count = 0;
1492:
1493: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1494: if (exception_mask & (1 << i)) {
1495: for (j = 0; j < count; j++) {
1496: /*
1497: * search for an identical entry, if found
1498: * set corresponding mask for this exception.
1499: */
1500: if (task->exc_actions[i].port == ports[j] &&
1501: task->exc_actions[i].behavior == behaviors[j]
1502: && task->exc_actions[i].flavor == flavors[j])
1503: {
1504: masks[j] |= (1 << i);
1505: break;
1506: }
1507: }/* for */
1508: if (j == count) {
1509: masks[j] = (1 << i);
1510: ports[j] =
1511: ipc_port_copy_send(task->exc_actions[i].port);
1512: behaviors[j] = task->exc_actions[i].behavior;
1513: flavors[j] = task->exc_actions[i].flavor;
1514: count++;
1515: }
1516: old_port[i] = task->exc_actions[i].port;
1517: task->exc_actions[i].port =
1518: ipc_port_copy_send(new_port);
1519: task->exc_actions[i].behavior = new_behavior;
1520: task->exc_actions[i].flavor = new_flavor;
1521: if (count > *CountCnt) {
1522: break;
1523: }
1524: } else
1525: old_port[i] = IP_NULL;
1526: }/* for */
1527:
1528:
1529: /*
1530: * Consume send rights without any lock held.
1531: */
1532: itk_unlock(task);
1533: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1534: if (IP_VALID(old_port[i]))
1535: ipc_port_release_send(old_port[i]);
1536: if (IP_VALID(new_port)) /* consume send right */
1537: ipc_port_release_send(new_port);
1538: *CountCnt = count;
1539:
1540: return KERN_SUCCESS;
1541: }/* task_swap_exception_ports */
1542:
1543: /*
1544: * Routine: thread/task_get_exception_ports [kernel call]
1545: * Purpose:
1546: * Clones a send right for each of the thread/task's exception
1547: * ports specified in the mask and returns the behaviour
1548: * and flavor of said port.
1549: *
1550: * Returns upto [in} CountCnt elements.
1551: *
1552: * Conditions:
1553: * Nothing locked.
1554: * Returns:
1555: * KERN_SUCCESS Extracted a send right.
1556: * KERN_INVALID_ARGUMENT The thread is null,
1557: * Invalid special port,
1558: * Illegal mask bit set.
1559: * KERN_FAILURE The thread is dead.
1560: */
1561:
1562: kern_return_t
1563: thread_get_exception_ports(
1564: thread_act_t thr_act,
1565: exception_mask_t exception_mask,
1566: exception_mask_array_t masks,
1567: mach_msg_type_number_t * CountCnt,
1568: exception_port_array_t ports,
1569: exception_behavior_array_t behaviors,
1570: thread_state_flavor_array_t flavors )
1571: {
1572: register int i,
1573: j,
1574: count;
1575:
1576: if (!thr_act)
1577: return KERN_INVALID_ARGUMENT;
1578:
1579: if (exception_mask & ~EXC_MASK_ALL) {
1580: return KERN_INVALID_ARGUMENT;
1581: }
1582:
1583: act_lock(thr_act);
1584: if (!thr_act->active) {
1585: act_unlock(thr_act);
1586: return KERN_FAILURE;
1587: }
1588:
1589: count = 0;
1590:
1591: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1592: if (exception_mask & (1 << i)) {
1593: for (j = 0; j < count; j++) {
1594: /*
1595: * search for an identical entry, if found
1596: * set corresponding mask for this exception.
1597: */
1598: if (thr_act->exc_actions[i].port == ports[j] &&
1599: thr_act->exc_actions[i].behavior ==behaviors[j]
1600: && thr_act->exc_actions[i].flavor == flavors[j])
1601: {
1602: masks[j] |= (1 << i);
1603: break;
1604: }
1605: }/* for */
1606: if (j == count) {
1607: masks[j] = (1 << i);
1608: ports[j] =
1609: ipc_port_copy_send(thr_act->exc_actions[i].port);
1610: behaviors[j] = thr_act->exc_actions[i].behavior;
1611: flavors[j] = thr_act->exc_actions[i].flavor;
1612: count++;
1613: if (count >= *CountCnt) {
1614: break;
1615: }
1616: }
1617: }
1618: }/* for */
1619:
1620: act_unlock(thr_act);
1621:
1622: *CountCnt = count;
1623: return KERN_SUCCESS;
1624: }/* thread_get_exception_ports */
1625:
1626: kern_return_t
1627: task_get_exception_ports(
1628: task_t task,
1629: exception_mask_t exception_mask,
1630: exception_mask_array_t masks,
1631: mach_msg_type_number_t * CountCnt,
1632: exception_port_array_t ports,
1633: exception_behavior_array_t behaviors,
1634: thread_state_flavor_array_t flavors )
1635: {
1636: register int i,
1637: j,
1638: count;
1639:
1640: if (task == TASK_NULL)
1641: return KERN_INVALID_ARGUMENT;
1642:
1643: if (exception_mask & ~EXC_MASK_ALL) {
1644: return KERN_INVALID_ARGUMENT;
1645: }
1646:
1647: itk_lock(task);
1648: if (task->itk_self == IP_NULL) {
1649: itk_unlock(task);
1650: return KERN_FAILURE;
1651: }
1652:
1653: count = 0;
1654:
1655: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1656: if (exception_mask & (1 << i)) {
1657: for (j = 0; j < count; j++) {
1658: /*
1659: * search for an identical entry, if found
1660: * set corresponding mask for this exception.
1661: */
1662: if (task->exc_actions[i].port == ports[j] &&
1663: task->exc_actions[i].behavior == behaviors[j]
1664: && task->exc_actions[i].flavor == flavors[j])
1665: {
1666: masks[j] |= (1 << i);
1667: break;
1668: }
1669: }/* for */
1670: if (j == count) {
1671: masks[j] = (1 << i);
1672: ports[j] =
1673: ipc_port_copy_send(task->exc_actions[i].port);
1674: behaviors[j] = task->exc_actions[i].behavior;
1675: flavors[j] = task->exc_actions[i].flavor;
1676: count++;
1677: if (count > *CountCnt) {
1678: break;
1679: }
1680: }
1681: }
1682: }/* for */
1683:
1684: itk_unlock(task);
1685:
1686: *CountCnt = count;
1687: return KERN_SUCCESS;
1688: }/* task_get_exception_ports */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.