1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#include <norma_vm.h>
61#include <mach_kdb.h>
62#include <zone_debug.h>
63#include <mach_assert.h>
64
65#include <mach/port.h>
66#include <mach/kern_return.h>
67#include <kern/lock.h>
68#include <kern/ipc_kobject.h>
69#include <kern/thread.h>
70#include <kern/misc_protos.h>
71#include <kern/wait_queue.h>
72#include <ipc/ipc_entry.h>
73#include <ipc/ipc_space.h>
74#include <ipc/ipc_object.h>
75#include <ipc/ipc_port.h>
76#include <ipc/ipc_pset.h>
77#include <ipc/ipc_kmsg.h>
78#include <ipc/ipc_mqueue.h>
79#include <ipc/ipc_notify.h>
80#include <ipc/ipc_print.h>
81#include <ipc/ipc_table.h>
82
83#if MACH_KDB
84#include <machine/db_machdep.h>
85#include <ddb/db_command.h>
86#include <ddb/db_expr.h>
87#endif
88
89#include <string.h>
90
91decl_mutex_data(, ipc_port_multiple_lock_data)
92decl_mutex_data(, ipc_port_timestamp_lock_data)
93ipc_port_timestamp_t ipc_port_timestamp_data;
94
95#if MACH_ASSERT
96void ipc_port_init_debug(
97 ipc_port_t port);
98#endif
99
100#if MACH_KDB && ZONE_DEBUG
101
102void print_type_ports(unsigned, unsigned);
103void print_ports(void);
104#endif
105
106
107
108
109
110
111
112ipc_port_timestamp_t
113ipc_port_timestamp(void)
114{
115 ipc_port_timestamp_t timestamp;
116
117 ipc_port_timestamp_lock();
118 timestamp = ipc_port_timestamp_data++;
119 ipc_port_timestamp_unlock();
120
121 return timestamp;
122}
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137kern_return_t
138ipc_port_dnrequest(
139 ipc_port_t port,
140 mach_port_name_t name,
141 ipc_port_t soright,
142 ipc_port_request_index_t *indexp)
143{
144 ipc_port_request_t ipr, table;
145 ipc_port_request_index_t index;
146
147 assert(ip_active(port));
148 assert(name != MACH_PORT_NULL);
149 assert(soright != IP_NULL);
150
151 table = port->ip_dnrequests;
152 if (table == IPR_NULL)
153 return KERN_NO_SPACE;
154
155 index = table->ipr_next;
156 if (index == 0)
157 return KERN_NO_SPACE;
158
159 ipr = &table[index];
160 assert(ipr->ipr_name == MACH_PORT_NULL);
161
162 table->ipr_next = ipr->ipr_next;
163 ipr->ipr_name = name;
164 ipr->ipr_soright = soright;
165
166 *indexp = index;
167 return KERN_SUCCESS;
168}
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186kern_return_t
187ipc_port_dngrow(
188 ipc_port_t port,
189 ipc_table_elems_t target_size)
190{
191 ipc_table_size_t its;
192 ipc_port_request_t otable, ntable;
193
194 assert(ip_active(port));
195
196 otable = port->ip_dnrequests;
197 if (otable == IPR_NULL)
198 its = &ipc_table_dnrequests[0];
199 else
200 its = otable->ipr_size + 1;
201
202 if (target_size != ITS_SIZE_NONE) {
203 if ((otable != IPR_NULL) &&
204 (target_size <= otable->ipr_size->its_size)) {
205 ip_unlock(port);
206 return KERN_SUCCESS;
207 }
208 while ((its->its_size) && (its->its_size < target_size)) {
209 its++;
210 }
211 if (its->its_size == 0) {
212 ip_unlock(port);
213 return KERN_NO_SPACE;
214 }
215 }
216
217 ip_reference(port);
218 ip_unlock(port);
219
220 if ((its->its_size == 0) ||
221 ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
222 ipc_port_release(port);
223 return KERN_RESOURCE_SHORTAGE;
224 }
225
226 ip_lock(port);
227 ip_release(port);
228
229
230
231
232
233
234
235
236 if (ip_active(port) &&
237 (port->ip_dnrequests == otable) &&
238 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
239 ipc_table_size_t oits;
240 ipc_table_elems_t osize, nsize;
241 ipc_port_request_index_t free, i;
242
243
244
245 if (otable != IPR_NULL) {
246 oits = otable->ipr_size;
247 osize = oits->its_size;
248 free = otable->ipr_next;
249
250 (void) memcpy((void *)(ntable + 1),
251 (const void *)(otable + 1),
252 (osize - 1) * sizeof(struct ipc_port_request));
253 } else {
254 osize = 1;
255 oits = 0;
256 free = 0;
257 }
258
259 nsize = its->its_size;
260 assert(nsize > osize);
261
262
263
264 for (i = osize; i < nsize; i++) {
265 ipc_port_request_t ipr = &ntable[i];
266
267 ipr->ipr_name = MACH_PORT_NULL;
268 ipr->ipr_next = free;
269 free = i;
270 }
271
272 ntable->ipr_next = free;
273 ntable->ipr_size = its;
274 port->ip_dnrequests = ntable;
275 ip_unlock(port);
276
277 if (otable != IPR_NULL) {
278 it_dnrequests_free(oits, otable);
279 }
280 } else {
281 ip_check_unlock(port);
282 it_dnrequests_free(its, ntable);
283 }
284
285 return KERN_SUCCESS;
286}
287
288
289
290
291
292
293
294
295
296ipc_port_t
297ipc_port_dncancel(
298 ipc_port_t port,
299 __assert_only mach_port_name_t name,
300 ipc_port_request_index_t index)
301{
302 ipc_port_request_t ipr, table;
303 ipc_port_t dnrequest;
304
305 assert(ip_active(port));
306 assert(name != MACH_PORT_NULL);
307 assert(index != 0);
308
309 table = port->ip_dnrequests;
310 assert(table != IPR_NULL);
311
312 ipr = &table[index];
313 dnrequest = ipr->ipr_soright;
314 assert(ipr->ipr_name == name);
315
316
317
318 ipr->ipr_name = MACH_PORT_NULL;
319 ipr->ipr_next = table->ipr_next;
320 table->ipr_next = index;
321
322 return dnrequest;
323}
324
325
326
327
328
329
330
331
332
333
334
335
336
337void
338ipc_port_pdrequest(
339 ipc_port_t port,
340 ipc_port_t notify,
341 ipc_port_t *previousp)
342{
343 ipc_port_t previous;
344
345 assert(ip_active(port));
346
347 previous = port->ip_pdrequest;
348 port->ip_pdrequest = notify;
349 ip_unlock(port);
350
351 *previousp = previous;
352}
353
354
355
356
357
358
359
360
361
362
363
364
365
366void
367ipc_port_nsrequest(
368 ipc_port_t port,
369 mach_port_mscount_t sync,
370 ipc_port_t notify,
371 ipc_port_t *previousp)
372{
373 ipc_port_t previous;
374 mach_port_mscount_t mscount;
375
376 assert(ip_active(port));
377
378 previous = port->ip_nsrequest;
379 mscount = port->ip_mscount;
380
381 if ((port->ip_srights == 0) && (sync <= mscount) &&
382 (notify != IP_NULL)) {
383 port->ip_nsrequest = IP_NULL;
384 ip_unlock(port);
385 ipc_notify_no_senders(notify, mscount);
386 } else {
387 port->ip_nsrequest = notify;
388 ip_unlock(port);
389 }
390
391 *previousp = previous;
392}
393
394
395
396
397
398
399
400
401
402
403void
404ipc_port_clear_receiver(
405 ipc_port_t port)
406{
407 spl_t s;
408
409 assert(ip_active(port));
410
411
412
413
414 if (port->ip_pset_count != 0) {
415 ipc_pset_remove_from_all(port);
416 assert(port->ip_pset_count == 0);
417 }
418
419
420
421
422
423 s = splsched();
424 imq_lock(&port->ip_messages);
425 ipc_mqueue_changed(&port->ip_messages);
426 ipc_port_set_mscount(port, 0);
427 port->ip_messages.imq_seqno = 0;
428 imq_unlock(&port->ip_messages);
429 splx(s);
430}
431
432
433
434
435
436
437
438
439void
440ipc_port_init(
441 ipc_port_t port,
442 ipc_space_t space,
443 mach_port_name_t name)
444{
445
446
447 port->ip_receiver = space;
448 port->ip_receiver_name = name;
449
450 port->ip_mscount = 0;
451 port->ip_srights = 0;
452 port->ip_sorights = 0;
453
454 port->ip_nsrequest = IP_NULL;
455 port->ip_pdrequest = IP_NULL;
456 port->ip_dnrequests = IPR_NULL;
457
458 port->ip_pset_count = 0;
459 port->ip_premsg = IKM_NULL;
460
461#if MACH_ASSERT
462 ipc_port_init_debug(port);
463#endif
464
465 ipc_mqueue_init(&port->ip_messages, FALSE );
466}
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482kern_return_t
483ipc_port_alloc(
484 ipc_space_t space,
485 mach_port_name_t *namep,
486 ipc_port_t *portp)
487{
488 ipc_port_t port;
489 mach_port_name_t name;
490 kern_return_t kr;
491
492 kr = ipc_object_alloc(space, IOT_PORT,
493 MACH_PORT_TYPE_RECEIVE, 0,
494 &name, (ipc_object_t *) &port);
495 if (kr != KERN_SUCCESS)
496 return kr;
497
498
499
500 ipc_port_init(port, space, name);
501
502 *namep = name;
503 *portp = port;
504
505 return KERN_SUCCESS;
506}
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522kern_return_t
523ipc_port_alloc_name(
524 ipc_space_t space,
525 mach_port_name_t name,
526 ipc_port_t *portp)
527{
528 ipc_port_t port;
529 kern_return_t kr;
530
531 kr = ipc_object_alloc_name(space, IOT_PORT,
532 MACH_PORT_TYPE_RECEIVE, 0,
533 name, (ipc_object_t *) &port);
534 if (kr != KERN_SUCCESS)
535 return kr;
536
537
538
539 ipc_port_init(port, space, name);
540
541 *portp = port;
542
543 return KERN_SUCCESS;
544}
545
546
547
548
549
550
551
552void
553ipc_port_dnnotify(
554 __unused ipc_port_t port,
555 ipc_port_request_t dnrequests)
556{
557 ipc_table_size_t its = dnrequests->ipr_size;
558 ipc_table_elems_t size = its->its_size;
559 ipc_port_request_index_t index;
560
561 for (index = 1; index < size; index++) {
562 ipc_port_request_t ipr = &dnrequests[index];
563 mach_port_name_t name = ipr->ipr_name;
564 ipc_port_t soright;
565
566 if (name == MACH_PORT_NULL)
567 continue;
568
569 soright = ipr->ipr_soright;
570 assert(soright != IP_NULL);
571
572 ipc_notify_dead_name(soright, name);
573 }
574
575 it_dnrequests_free(its, dnrequests);
576}
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591void
592ipc_port_destroy(
593 ipc_port_t port)
594{
595 ipc_port_t pdrequest, nsrequest;
596 ipc_mqueue_t mqueue;
597 ipc_kmsg_t kmsg;
598 ipc_port_request_t dnrequests;
599
600 assert(ip_active(port));
601
602
603 assert(port->ip_pset_count == 0);
604 assert(port->ip_mscount == 0);
605
606
607
608 pdrequest = port->ip_pdrequest;
609 if (pdrequest != IP_NULL) {
610
611 port->ip_pdrequest = IP_NULL;
612
613
614 port->ip_receiver_name = MACH_PORT_NULL;
615 port->ip_destination = IP_NULL;
616 ip_unlock(port);
617
618
619 ipc_notify_port_destroyed(pdrequest, port);
620 return;
621 }
622
623
624
625 port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
626 port->ip_timestamp = ipc_port_timestamp();
627
628
629 dnrequests = port->ip_dnrequests;
630 port->ip_dnrequests = IPR_NULL;
631
632
633
634
635
636
637
638 if (IP_PREALLOC(port)) {
639 kmsg = port->ip_premsg;
640 assert(kmsg != IKM_NULL);
641 IP_CLEAR_PREALLOC(port, kmsg);
642 if (!ikm_prealloc_inuse(kmsg))
643 ipc_kmsg_free(kmsg);
644 }
645 ip_unlock(port);
646
647
648
649 nsrequest = port->ip_nsrequest;
650 if (nsrequest != IP_NULL)
651 ipc_notify_send_once(nsrequest);
652
653
654 mqueue = &port->ip_messages;
655 ipc_mqueue_destroy(mqueue);
656
657
658 if (dnrequests != IPR_NULL) {
659 ipc_port_dnnotify(port, dnrequests);
660 }
661
662 ipc_kobject_destroy(port);
663
664 ipc_port_release(port);
665}
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683boolean_t
684ipc_port_check_circularity(
685 ipc_port_t port,
686 ipc_port_t dest)
687{
688 ipc_port_t base;
689
690 assert(port != IP_NULL);
691 assert(dest != IP_NULL);
692
693 if (port == dest)
694 return TRUE;
695 base = dest;
696
697
698
699
700
701
702 ip_lock(port);
703 if (ip_lock_try(dest)) {
704 if (!ip_active(dest) ||
705 (dest->ip_receiver_name != MACH_PORT_NULL) ||
706 (dest->ip_destination == IP_NULL))
707 goto not_circular;
708
709
710
711 ip_unlock(dest);
712 }
713 ip_unlock(port);
714
715 ipc_port_multiple_lock();
716
717
718
719
720
721
722 for (;;) {
723 ip_lock(base);
724
725 if (!ip_active(base) ||
726 (base->ip_receiver_name != MACH_PORT_NULL) ||
727 (base->ip_destination == IP_NULL))
728 break;
729
730 base = base->ip_destination;
731 }
732
733
734
735 if (port == base) {
736
737
738 ipc_port_multiple_unlock();
739
740
741
742 assert(ip_active(port));
743 assert(port->ip_receiver_name == MACH_PORT_NULL);
744 assert(port->ip_destination == IP_NULL);
745
746 while (dest != IP_NULL) {
747 ipc_port_t next;
748
749
750
751 assert(ip_active(dest));
752 assert(dest->ip_receiver_name == MACH_PORT_NULL);
753
754 next = dest->ip_destination;
755 ip_unlock(dest);
756 dest = next;
757 }
758
759 return TRUE;
760 }
761
762
763
764
765
766
767
768 ip_lock(port);
769 ipc_port_multiple_unlock();
770
771 not_circular:
772
773
774
775 assert(ip_active(port));
776 assert(port->ip_receiver_name == MACH_PORT_NULL);
777 assert(port->ip_destination == IP_NULL);
778
779 ip_reference(dest);
780 port->ip_destination = dest;
781
782
783
784 while (port != base) {
785 ipc_port_t next;
786
787
788
789 assert(ip_active(port));
790 assert(port->ip_receiver_name == MACH_PORT_NULL);
791 assert(port->ip_destination != IP_NULL);
792
793 next = port->ip_destination;
794 ip_unlock(port);
795 port = next;
796 }
797
798
799
800 assert(!ip_active(base) ||
801 (base->ip_receiver_name != MACH_PORT_NULL) ||
802 (base->ip_destination == IP_NULL));
803 ip_unlock(base);
804
805 return FALSE;
806}
807
808
809
810
811
812
813
814
815
816
817
818
819
820ipc_port_t
821ipc_port_lookup_notify(
822 ipc_space_t space,
823 mach_port_name_t name)
824{
825 ipc_port_t port;
826 ipc_entry_t entry;
827
828 assert(space->is_active);
829
830 entry = ipc_entry_lookup(space, name);
831 if (entry == IE_NULL)
832 return IP_NULL;
833 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
834 return IP_NULL;
835
836 port = (ipc_port_t) entry->ie_object;
837 assert(port != IP_NULL);
838
839 ip_lock(port);
840 assert(ip_active(port));
841 assert(port->ip_receiver_name == name);
842 assert(port->ip_receiver == space);
843
844 ip_reference(port);
845 port->ip_sorights++;
846 ip_unlock(port);
847
848 return port;
849}
850
851
852
853
854
855
856
857
858
859ipc_port_t
860ipc_port_make_send_locked(
861 ipc_port_t port)
862{
863 assert(ip_active(port));
864 port->ip_mscount++;
865 port->ip_srights++;
866 ip_reference(port);
867 ip_unlock(port);
868 return port;
869}
870
871
872
873
874
875
876
877ipc_port_t
878ipc_port_make_send(
879 ipc_port_t port)
880{
881
882 if (!IP_VALID(port))
883 return port;
884
885 ip_lock(port);
886 if (ip_active(port)) {
887 port->ip_mscount++;
888 port->ip_srights++;
889 ip_reference(port);
890 ip_unlock(port);
891 return port;
892 }
893 ip_unlock(port);
894 return IP_DEAD;
895}
896
897
898
899
900
901
902
903
904
905
906
907
908
909ipc_port_t
910ipc_port_copy_send(
911 ipc_port_t port)
912{
913 ipc_port_t sright;
914
915 if (!IP_VALID(port))
916 return port;
917
918 ip_lock(port);
919 if (ip_active(port)) {
920 assert(port->ip_srights > 0);
921
922 ip_reference(port);
923 port->ip_srights++;
924 sright = port;
925 } else
926 sright = IP_DEAD;
927 ip_unlock(port);
928
929 return sright;
930}
931
932
933
934
935
936
937
938
939
940
941mach_port_name_t
942ipc_port_copyout_send(
943 ipc_port_t sright,
944 ipc_space_t space)
945{
946 mach_port_name_t name;
947
948 if (IP_VALID(sright)) {
949 kern_return_t kr;
950
951 kr = ipc_object_copyout(space, (ipc_object_t) sright,
952 MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
953 if (kr != KERN_SUCCESS) {
954 ipc_port_release_send(sright);
955
956 if (kr == KERN_INVALID_CAPABILITY)
957 name = MACH_PORT_DEAD;
958 else
959 name = MACH_PORT_NULL;
960 }
961 } else
962 name = (mach_port_name_t) sright;
963
964 return name;
965}
966
967
968
969
970
971
972
973
974
975
976void
977ipc_port_release_send(
978 ipc_port_t port)
979{
980 ipc_port_t nsrequest = IP_NULL;
981 mach_port_mscount_t mscount;
982
983 assert(IP_VALID(port));
984
985 ip_lock(port);
986 ip_release(port);
987
988 if (!ip_active(port)) {
989 ip_check_unlock(port);
990 return;
991 }
992
993 assert(port->ip_srights > 0);
994
995 if (--port->ip_srights == 0 &&
996 port->ip_nsrequest != IP_NULL) {
997 nsrequest = port->ip_nsrequest;
998 port->ip_nsrequest = IP_NULL;
999 mscount = port->ip_mscount;
1000 ip_unlock(port);
1001 ipc_notify_no_senders(nsrequest, mscount);
1002 } else
1003 ip_unlock(port);
1004}
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014ipc_port_t
1015ipc_port_make_sonce(
1016 ipc_port_t port)
1017{
1018 assert(IP_VALID(port));
1019
1020 ip_lock(port);
1021 assert(ip_active(port));
1022 port->ip_sorights++;
1023 ip_reference(port);
1024 ip_unlock(port);
1025
1026 return port;
1027}
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043void
1044ipc_port_release_sonce(
1045 ipc_port_t port)
1046{
1047 assert(IP_VALID(port));
1048
1049 ip_lock(port);
1050
1051 assert(port->ip_sorights > 0);
1052
1053 port->ip_sorights--;
1054
1055 ip_release(port);
1056
1057 if (!ip_active(port)) {
1058 ip_check_unlock(port);
1059 return;
1060 }
1061
1062 ip_unlock(port);
1063}
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074void
1075ipc_port_release_receive(
1076 ipc_port_t port)
1077{
1078 ipc_port_t dest;
1079
1080 assert(IP_VALID(port));
1081
1082 ip_lock(port);
1083 assert(ip_active(port));
1084 assert(port->ip_receiver_name == MACH_PORT_NULL);
1085 dest = port->ip_destination;
1086
1087 ipc_port_destroy(port);
1088
1089 if (dest != IP_NULL)
1090 ipc_port_release(dest);
1091}
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103ipc_port_t
1104ipc_port_alloc_special(
1105 ipc_space_t space)
1106{
1107 ipc_port_t port;
1108
1109 port = (ipc_port_t) io_alloc(IOT_PORT);
1110 if (port == IP_NULL)
1111 return IP_NULL;
1112
1113 bzero((char *)port, sizeof(*port));
1114 io_lock_init(&port->ip_object);
1115 port->ip_references = 1;
1116 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
1117
1118 ipc_port_init(port, space, 1);
1119
1120 return port;
1121}
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132void
1133ipc_port_dealloc_special(
1134 ipc_port_t port,
1135 __assert_only ipc_space_t space)
1136{
1137 ip_lock(port);
1138 assert(ip_active(port));
1139
1140 assert(port->ip_receiver == space);
1141
1142
1143
1144
1145
1146
1147 port->ip_receiver_name = MACH_PORT_NULL;
1148 port->ip_receiver = IS_NULL;
1149
1150
1151 ipc_port_set_mscount(port, 0);
1152 port->ip_messages.imq_seqno = 0;
1153
1154 ipc_port_destroy(port);
1155}
1156
1157
1158#if MACH_ASSERT
1159#include <kern/machine.h>
1160
1161
1162
1163
1164
1165
1166queue_head_t port_alloc_queue;
1167decl_mutex_data(,port_alloc_queue_lock)
1168
1169unsigned long port_count = 0;
1170unsigned long port_count_warning = 20000;
1171unsigned long port_timestamp = 0;
1172
1173void db_port_stack_trace(
1174 ipc_port_t port);
1175void db_ref(
1176 int refs);
1177int db_port_walk(
1178 unsigned int verbose,
1179 unsigned int display,
1180 unsigned int ref_search,
1181 unsigned int ref_target);
1182
1183
1184
1185
1186
1187void
1188ipc_port_debug_init(void)
1189{
1190 queue_init(&port_alloc_queue);
1191 mutex_init(&port_alloc_queue_lock, 0);
1192}
1193
1194
1195
1196
1197
1198
1199void
1200ipc_port_init_debug(
1201 ipc_port_t port)
1202{
1203 unsigned int i;
1204
1205 port->ip_thread = current_thread();
1206 port->ip_timetrack = port_timestamp++;
1207 for (i = 0; i < IP_CALLSTACK_MAX; ++i)
1208 port->ip_callstack[i] = 0;
1209 for (i = 0; i < IP_NSPARES; ++i)
1210 port->ip_spares[i] = 0;
1211
1212
1213
1214
1215
1216
1217 machine_callstack(&port->ip_callstack[0], IP_CALLSTACK_MAX);
1218
1219#if 0
1220 mutex_lock(&port_alloc_queue_lock);
1221 ++port_count;
1222 if (port_count_warning > 0 && port_count >= port_count_warning)
1223 assert(port_count < port_count_warning);
1224 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1225 mutex_unlock(&port_alloc_queue_lock);
1226#endif
1227}
1228
1229
1230
1231
1232
1233
1234
1235#if 1
1236void
1237ipc_port_track_dealloc(
1238 __unused ipc_port_t port)
1239{
1240}
1241#else
1242void
1243ipc_port_track_dealloc(
1244 ipc_port_t port)
1245{
1246 mutex_lock(&port_alloc_queue_lock);
1247 assert(port_count > 0);
1248 --port_count;
1249 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
1250 mutex_unlock(&port_alloc_queue_lock);
1251}
1252#endif
1253
1254#endif
1255
1256
1257#if MACH_KDB
1258
1259#include <ddb/db_output.h>
1260#include <ddb/db_print.h>
1261
1262#define printf kdbprintf
1263
1264int
1265db_port_queue_print(
1266 ipc_port_t port);
1267
1268
1269
1270
1271
1272
1273int ipc_port_print_long = 0;
1274
1275void
1276ipc_port_print(
1277 ipc_port_t port,
1278 __unused boolean_t have_addr,
1279 __unused db_expr_t count,
1280 char *modif)
1281{
1282 db_addr_t task;
1283 int task_id;
1284 int nmsgs;
1285 int verbose = 0;
1286#if MACH_ASSERT
1287 int i, needs_db_indent, items_printed;
1288#endif
1289
1290 if (db_option(modif, 'l') || db_option(modif, 'v'))
1291 ++verbose;
1292
1293 printf("port 0x%x\n", port);
1294
1295 db_indent += 2;
1296
1297 ipc_object_print(&port->ip_object);
1298
1299 if (ipc_port_print_long) {
1300 printf("\n");
1301 }
1302
1303 if (!ip_active(port)) {
1304 iprintf("timestamp=0x%x", port->ip_timestamp);
1305 } else if (port->ip_receiver_name == MACH_PORT_NULL) {
1306 iprintf("destination=0x%x (", port->ip_destination);
1307 if (port->ip_destination != MACH_PORT_NULL &&
1308 (task = db_task_from_space(port->ip_destination->
1309 ip_receiver, &task_id)))
1310 printf("task%d at 0x%x", task_id, task);
1311 else
1312 printf("unknown");
1313 printf(")");
1314 } else {
1315 iprintf("receiver=0x%x (", port->ip_receiver);
1316 if (port->ip_receiver == ipc_space_kernel)
1317 printf("kernel");
1318 else if (port->ip_receiver == ipc_space_reply)
1319 printf("reply");
1320 else if (port->ip_receiver == default_pager_space)
1321 printf("default_pager");
1322 else if ((task = db_task_from_space(port->ip_receiver, &task_id)) != (db_addr_t)0)
1323 printf("task%d at 0x%x", task_id, task);
1324 else
1325 printf("unknown");
1326 printf(")");
1327 }
1328 printf(", receiver_name=0x%x\n", port->ip_receiver_name);
1329
1330 iprintf("mscount=%d", port->ip_mscount);
1331 printf(", srights=%d", port->ip_srights);
1332 printf(", sorights=%d\n", port->ip_sorights);
1333
1334 iprintf("nsrequest=0x%x", port->ip_nsrequest);
1335 printf(", pdrequest=0x%x", port->ip_pdrequest);
1336 printf(", dnrequests=0x%x\n", port->ip_dnrequests);
1337
1338 iprintf("pset_count=0x%x", port->ip_pset_count);
1339 printf(", seqno=%d", port->ip_messages.imq_seqno);
1340 printf(", msgcount=%d", port->ip_messages.imq_msgcount);
1341 printf(", qlimit=%d\n", port->ip_messages.imq_qlimit);
1342
1343 iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
1344 printf(", rcvrs queue=0x%x", port->ip_messages.imq_wait_queue);
1345 printf(", kobj=0x%x\n", port->ip_kobject);
1346
1347 iprintf("premsg=0x%x", port->ip_premsg);
1348
1349#if MACH_ASSERT
1350
1351 iprintf("ip_thread=0x%x, ip_timetrack=0x%x\n",
1352 port->ip_thread, port->ip_timetrack);
1353 items_printed = 0;
1354 needs_db_indent = 1;
1355 for (i = 0; i < IP_NSPARES; ++i) {
1356 if (port->ip_spares[i] != 0) {
1357 if (needs_db_indent) {
1358 iprintf("");
1359 needs_db_indent = 0;
1360 }
1361 printf("%sip_spares[%d] = %d",
1362 items_printed ? ", " : "", i,
1363 port->ip_spares[i]);
1364 if (++items_printed >= 4) {
1365 needs_db_indent = 1;
1366 printf("\n");
1367 items_printed = 0;
1368 }
1369 }
1370 }
1371#endif
1372
1373 if (verbose) {
1374 iprintf("kmsg queue contents:\n");
1375 db_indent += 2;
1376 nmsgs = db_port_queue_print(port);
1377 db_indent -= 2;
1378 iprintf("...total kmsgs: %d\n", nmsgs);
1379 }
1380
1381 db_indent -=2;
1382}
1383
1384ipc_port_t
1385ipc_name_to_data(
1386 task_t task,
1387 mach_port_name_t name)
1388{
1389 ipc_space_t space;
1390 ipc_entry_t entry;
1391
1392 if (task == TASK_NULL) {
1393 db_printf("port_name_to_data: task is null\n");
1394 return (0);
1395 }
1396 if ((space = task->itk_space) == 0) {
1397 db_printf("port_name_to_data: task->itk_space is null\n");
1398 return (0);
1399 }
1400 if (!space->is_active) {
1401 db_printf("port_name_to_data: task->itk_space not active\n");
1402 return (0);
1403 }
1404 if ((entry = ipc_entry_lookup(space, name)) == 0) {
1405 db_printf("port_name_to_data: lookup yields zero\n");
1406 return (0);
1407 }
1408 return ((ipc_port_t)entry->ie_object);
1409}
1410
1411#if ZONE_DEBUG
1412void
1413print_type_ports(type, dead)
1414 unsigned type;
1415 unsigned dead;
1416{
1417 ipc_port_t port;
1418 int n;
1419
1420 n = 0;
1421 for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
1422 port;
1423 port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT],
1424 port))
1425 if (ip_kotype(port) == type &&
1426 (!dead || !ip_active(port))) {
1427 if (++n % 5)
1428 printf("0x%x\t", port);
1429 else
1430 printf("0x%x\n", port);
1431 }
1432 if (n % 5)
1433 printf("\n");
1434}
1435
1436void
1437print_ports(void)
1438{
1439 ipc_port_t port;
1440 int total_port_count;
1441 int space_null_count;
1442 int space_kernel_count;
1443 int space_reply_count;
1444 int space_pager_count;
1445 int space_other_count;
1446
1447 struct {
1448 int total_count;
1449 int dead_count;
1450 } port_types[IKOT_MAX_TYPE];
1451
1452 total_port_count = 0;
1453
1454 bzero((char *)&port_types[0], sizeof(port_types));
1455 space_null_count = 0;
1456 space_kernel_count = 0;
1457 space_reply_count = 0;
1458 space_pager_count = 0;
1459 space_other_count = 0;
1460
1461 for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
1462 port;
1463 port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT],
1464 port)) {
1465 total_port_count++;
1466 if (ip_kotype(port) >= IKOT_MAX_TYPE) {
1467 port_types[IKOT_UNKNOWN].total_count++;
1468 if (!io_active(&port->ip_object))
1469 port_types[IKOT_UNKNOWN].dead_count++;
1470 } else {
1471 port_types[ip_kotype(port)].total_count++;
1472 if (!io_active(&port->ip_object))
1473 port_types[ip_kotype(port)].dead_count++;
1474 }
1475
1476 if (!port->ip_receiver)
1477 space_null_count++;
1478 else if (port->ip_receiver == ipc_space_kernel)
1479 space_kernel_count++;
1480 else if (port->ip_receiver == ipc_space_reply)
1481 space_reply_count++;
1482 else if (port->ip_receiver == default_pager_space)
1483 space_pager_count++;
1484 else
1485 space_other_count++;
1486 }
1487 printf("\n%7d total ports\n\n", total_port_count);
1488
1489#define PRINT_ONE_PORT_TYPE(name) \
1490 printf("%7d %s", port_types[IKOT_##name].total_count, # name); \
1491 if (port_types[IKOT_##name].dead_count) \
1492 printf(" (%d dead ports)", port_types[IKOT_##name].dead_count);\
1493 printf("\n");
1494
1495 PRINT_ONE_PORT_TYPE(NONE);
1496 PRINT_ONE_PORT_TYPE(THREAD);
1497 PRINT_ONE_PORT_TYPE(TASK);
1498 PRINT_ONE_PORT_TYPE(HOST);
1499 PRINT_ONE_PORT_TYPE(HOST_PRIV);
1500 PRINT_ONE_PORT_TYPE(PROCESSOR);
1501 PRINT_ONE_PORT_TYPE(PSET);
1502 PRINT_ONE_PORT_TYPE(PSET_NAME);
1503 PRINT_ONE_PORT_TYPE(PAGING_REQUEST);
1504 PRINT_ONE_PORT_TYPE(MEMORY_OBJECT);
1505 PRINT_ONE_PORT_TYPE(MIG);
1506 PRINT_ONE_PORT_TYPE(XMM_PAGER);
1507 PRINT_ONE_PORT_TYPE(XMM_KERNEL);
1508 PRINT_ONE_PORT_TYPE(XMM_REPLY);
1509 PRINT_ONE_PORT_TYPE(CLOCK);
1510 PRINT_ONE_PORT_TYPE(CLOCK_CTRL);
1511 PRINT_ONE_PORT_TYPE(MASTER_DEVICE);
1512 PRINT_ONE_PORT_TYPE(UNKNOWN);
1513 printf("\nipc_space:\n\n");
1514 printf("NULL KERNEL REPLY PAGER OTHER\n");
1515 printf("%d %d %d %d %d\n",
1516 space_null_count,
1517 space_kernel_count,
1518 space_reply_count,
1519 space_pager_count,
1520 space_other_count
1521 );
1522}
1523
1524#endif
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535#define KMSG_MATCH_FIELD(kmsg) (kmsg->ikm_header->msgh_id)
1536#define DKQP_LONG(kmsg) FALSE
1537const char *dkqp_long_format = "(%3d) <%10d> 0x%x %10d %10d\n";
1538const char *dkqp_format = "(%3d) <%10d> 0x%x %10d %10d\n";
1539
1540int
1541db_kmsg_queue_print(
1542 ipc_kmsg_t kmsg);
1543int
1544db_kmsg_queue_print(
1545 ipc_kmsg_t kmsg)
1546{
1547 ipc_kmsg_t ikmsg, first_kmsg;
1548 register int icount;
1549 mach_msg_id_t cur_id;
1550 unsigned int inline_total, ool_total;
1551 int nmsgs;
1552
1553 iprintf("Count msgh_id kmsg addr inline bytes ool bytes\n");
1554 inline_total = ool_total = (vm_size_t) 0;
1555 cur_id = KMSG_MATCH_FIELD(kmsg);
1556 for (icount = 0, nmsgs = 0, first_kmsg = ikmsg = kmsg;
1557 kmsg != IKM_NULL && (kmsg != first_kmsg || nmsgs == 0);
1558 kmsg = kmsg->ikm_next) {
1559 ++nmsgs;
1560 if (!(KMSG_MATCH_FIELD(kmsg) == cur_id)) {
1561 iprintf(DKQP_LONG(kmsg) ? dkqp_long_format:dkqp_format,
1562 icount, cur_id, ikmsg, inline_total,ool_total);
1563 cur_id = KMSG_MATCH_FIELD(kmsg);
1564 icount = 1;
1565 ikmsg = kmsg;
1566 inline_total = ool_total = 0;
1567 } else {
1568 icount++;
1569 }
1570 if (DKQP_LONG(kmsg))
1571 inline_total += kmsg->ikm_size;
1572 else
1573 inline_total += kmsg->ikm_header->msgh_size;
1574 }
1575 iprintf(DKQP_LONG(kmsg) ? dkqp_long_format : dkqp_format,
1576 icount, cur_id, ikmsg, inline_total, ool_total);
1577 return nmsgs;
1578}
1579
1580
1581
1582
1583
1584
1585
1586int
1587db_port_queue_print(
1588 ipc_port_t port)
1589{
1590 ipc_kmsg_t kmsg;
1591
1592 if (ipc_kmsg_queue_empty(&port->ip_messages.imq_messages))
1593 return 0;
1594 kmsg = ipc_kmsg_queue_first(&port->ip_messages.imq_messages);
1595 return db_kmsg_queue_print(kmsg);
1596}
1597
1598
1599#if MACH_ASSERT
1600#include <ddb/db_sym.h>
1601#include <ddb/db_access.h>
1602
1603#define FUNC_NULL ((void (*)) 0)
1604#define MAX_REFS 5
1605
1606
1607
1608
1609
1610void
1611db_port_stack_trace(
1612 ipc_port_t port)
1613{
1614 unsigned int i;
1615
1616 for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
1617 iprintf("[%d] 0x%x\t", i, port->ip_callstack[i]);
1618 if (port->ip_callstack[i] != 0 &&
1619 DB_VALID_KERN_ADDR(port->ip_callstack[i]))
1620 db_printsym(port->ip_callstack[i], DB_STGY_PROC);
1621 printf("\n");
1622 }
1623}
1624
1625
1626typedef struct port_item {
1627 unsigned long item;
1628 unsigned long count;
1629} port_item;
1630
1631
1632#define ITEM_MAX 400
1633typedef struct port_track {
1634 const char *name;
1635 unsigned long max;
1636 unsigned long warning;
1637 port_item items[ITEM_MAX];
1638} port_track;
1639
1640port_track port_callers;
1641port_track port_threads;
1642port_track port_spaces;
1643
1644void port_track_init(
1645 port_track *trackp,
1646 const char *name);
1647void port_item_add(
1648 port_track *trackp,
1649 unsigned long item);
1650void port_track_sort(
1651 port_track *trackp);
1652void port_track_print(
1653 port_track *trackp,
1654 void (*func)(port_item *));
1655void port_callers_print(
1656 port_item *p);
1657
1658void
1659port_track_init(
1660 port_track *trackp,
1661 const char *name)
1662{
1663 port_item *i;
1664
1665 trackp->max = trackp->warning = 0;
1666 trackp->name = name;
1667 for (i = trackp->items; i < trackp->items + ITEM_MAX; ++i)
1668 i->item = i->count = 0;
1669}
1670
1671
1672void
1673port_item_add(
1674 port_track *trackp,
1675 unsigned long item)
1676{
1677 port_item *limit, *i;
1678
1679 limit = trackp->items + trackp->max;
1680 for (i = trackp->items; i < limit; ++i)
1681 if (i->item == item) {
1682 i->count++;
1683 return;
1684 }
1685 if (trackp->max >= ITEM_MAX) {
1686 if (trackp->warning++ == 0)
1687 iprintf("%s: no room\n", trackp->name);
1688 return;
1689 }
1690 i->item = item;
1691 i->count = 1;
1692 trackp->max++;
1693}
1694
1695
1696
1697
1698
1699void
1700port_track_sort(
1701 port_track *trackp)
1702{
1703 port_item *limit, *p;
1704 port_item temp;
1705 boolean_t unsorted;
1706
1707 limit = trackp->items + trackp->max - 1;
1708 do {
1709 unsorted = FALSE;
1710 for (p = trackp->items; p < limit - 1; ++p) {
1711 if (p->count < (p+1)->count) {
1712 temp = *p;
1713 *p = *(p+1);
1714 *(p+1) = temp;
1715 unsorted = TRUE;
1716 }
1717 }
1718 } while (unsorted == TRUE);
1719}
1720
1721
1722void
1723port_track_print(
1724 port_track *trackp,
1725 void (*func)(port_item *))
1726{
1727 port_item *limit, *p;
1728
1729 limit = trackp->items + trackp->max;
1730 iprintf("%s:\n", trackp->name);
1731 for (p = trackp->items; p < limit; ++p) {
1732 if (func != FUNC_NULL)
1733 (*func)(p);
1734 else
1735 iprintf("0x%x\t%8d\n", p->item, p->count);
1736 }
1737}
1738
1739
1740void
1741port_callers_print(
1742 port_item *p)
1743{
1744 iprintf("0x%x\t%8d\t", p->item, p->count);
1745 db_printsym(p->item, DB_STGY_PROC);
1746 printf("\n");
1747}
1748
1749
1750
1751
1752
1753void
1754db_ref(
1755 int refs)
1756{
1757 db_port_walk(1, 1, 1, refs);
1758}
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770int
1771db_port_walk(
1772 unsigned int verbose,
1773 unsigned int display,
1774 unsigned int ref_search,
1775 unsigned int ref_target)
1776{
1777 ipc_port_t port;
1778 unsigned int ref_overflow, refs, i, ref_inactive_overflow;
1779 unsigned int no_receiver, no_match;
1780 unsigned int ref_counts[MAX_REFS];
1781 unsigned int inactive[MAX_REFS];
1782 unsigned int ipc_ports = 0;
1783
1784 iprintf("Allocated port count is %d\n", port_count);
1785 no_receiver = no_match = ref_overflow = 0;
1786 ref_inactive_overflow = 0;
1787 for (i = 0; i < MAX_REFS; ++i) {
1788 ref_counts[i] = 0;
1789 inactive[i] = 0;
1790 }
1791 port_track_init(&port_callers, "port callers");
1792 port_track_init(&port_threads, "port threads");
1793 port_track_init(&port_spaces, "port spaces");
1794 if (ref_search)
1795 iprintf("Walking ports of ref_count=%d.\n", ref_target);
1796 else
1797 iprintf("Walking all ports.\n");
1798
1799 queue_iterate(&port_alloc_queue, port, ipc_port_t, ip_port_links) {
1800 const char *port_type;
1801
1802 port_type = " IPC port";
1803 if (ip_active(port))
1804 ipc_ports++;
1805
1806 refs = port->ip_references;
1807 if (ref_search && refs != ref_target)
1808 continue;
1809
1810 if (refs >= MAX_REFS) {
1811 if (ip_active(port))
1812 ++ref_overflow;
1813 else
1814 ++ref_inactive_overflow;
1815 } else {
1816 if (refs == 0 && verbose)
1817 iprintf("%s 0x%x has ref count of zero!\n",
1818 port_type, port);
1819 if (ip_active(port))
1820 ref_counts[refs]++;
1821 else
1822 inactive[refs]++;
1823 }
1824 port_item_add(&port_threads, (unsigned long) port->ip_thread);
1825 for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
1826 if (port->ip_callstack[i] != 0 &&
1827 DB_VALID_KERN_ADDR(port->ip_callstack[i]))
1828 port_item_add(&port_callers,
1829 port->ip_callstack[i]);
1830 }
1831 if (!ip_active(port)) {
1832 if (verbose)
1833 iprintf("%s 0x%x, inactive, refcnt %d\n",
1834 port_type, port, refs);
1835 continue;
1836 }
1837
1838 if (port->ip_receiver_name == MACH_PORT_NULL) {
1839 iprintf("%s 0x%x, no receiver, refcnt %d\n",
1840 port, refs);
1841 ++no_receiver;
1842 continue;
1843 }
1844 if (port->ip_receiver == ipc_space_kernel ||
1845 port->ip_receiver == ipc_space_reply ||
1846 ipc_entry_lookup(port->ip_receiver,
1847 port->ip_receiver_name)
1848 != IE_NULL) {
1849 port_item_add(&port_spaces,
1850 (unsigned long)port->ip_receiver);
1851 if (display) {
1852 iprintf( "%s 0x%x time 0x%x ref_cnt %d\n",
1853 port_type, port,
1854 port->ip_timetrack, refs);
1855 }
1856 continue;
1857 }
1858 iprintf("%s 0x%x, rcvr 0x%x, name 0x%x, ref %d, no match\n",
1859 port_type, port, port->ip_receiver,
1860 port->ip_receiver_name, refs);
1861 ++no_match;
1862 }
1863 iprintf("Active port type summary:\n");
1864 iprintf("\tlocal IPC %6d\n", ipc_ports);
1865 iprintf("summary:\tcallers %d threads %d spaces %d\n",
1866 port_callers.max, port_threads.max, port_spaces.max);
1867
1868 iprintf("\tref_counts:\n");
1869 for (i = 0; i < MAX_REFS; ++i)
1870 iprintf("\t ref_counts[%d] = %d\n", i, ref_counts[i]);
1871
1872 iprintf("\t%d ports w/o receivers, %d w/o matches\n",
1873 no_receiver, no_match);
1874
1875 iprintf("\tinactives:");
1876 if ( ref_inactive_overflow || inactive[0] || inactive[1] ||
1877 inactive[2] || inactive[3] || inactive[4] )
1878 printf(" [0]=%d [1]=%d [2]=%d [3]=%d [4]=%d [5+]=%d\n",
1879 inactive[0], inactive[1], inactive[2],
1880 inactive[3], inactive[4], ref_inactive_overflow);
1881 else
1882 printf(" No inactive ports.\n");
1883
1884 port_track_sort(&port_spaces);
1885 port_track_print(&port_spaces, FUNC_NULL);
1886 port_track_sort(&port_threads);
1887 port_track_print(&port_threads, FUNC_NULL);
1888 port_track_sort(&port_callers);
1889 port_track_print(&port_callers, port_callers_print);
1890 return 0;
1891}
1892
1893
1894#endif
1895
1896#endif
1897