Bug Summary

File:obj-scan-build/../ipc/ipc_port.c
Location:line 422, column 2
Description:Value stored to 'mqueue' is never read

Annotated Source Code

1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
4 * Copyright (c) 1993,1994 The University of Utah and
5 * the Computer Systems Laboratory (CSL).
6 * All rights reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
13 *
14 * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15 * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16 * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17 * THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie Mellon
27 * the rights to redistribute these changes.
28 */
29/*
30 * File: ipc/ipc_port.c
31 * Author: Rich Draves
32 * Date: 1989
33 *
34 * Functions to manipulate IPC ports.
35 */
36
37#include <kern/printf.h>
38#include <string.h>
39
40#include <mach/port.h>
41#include <mach/kern_return.h>
42#include <kern/lock.h>
43#include <kern/ipc_sched.h>
44#include <kern/ipc_kobject.h>
45#include <ipc/ipc_entry.h>
46#include <ipc/ipc_space.h>
47#include <ipc/ipc_object.h>
48#include <ipc/ipc_port.h>
49#include <ipc/ipc_pset.h>
50#include <ipc/ipc_thread.h>
51#include <ipc/ipc_mqueue.h>
52#include <ipc/ipc_notify.h>
53
54#if MACH_KDB0
55#include <ddb/db_output.h>
56#include <ipc/ipc_print.h>
57#endif /* MACH_KDB */
58
59
60decl_simple_lock_data(, ipc_port_multiple_lock_data)
61
62decl_simple_lock_data(, ipc_port_timestamp_lock_data)
63ipc_port_timestamp_t ipc_port_timestamp_data;
64
65/*
66 * Routine: ipc_port_timestamp
67 * Purpose:
68 * Retrieve a timestamp value.
69 */
70
71ipc_port_timestamp_t
72ipc_port_timestamp(void)
73{
74 ipc_port_timestamp_t timestamp;
75
76 ipc_port_timestamp_lock();
77 timestamp = ipc_port_timestamp_data++;
78 ipc_port_timestamp_unlock();
79
80 return timestamp;
81}
82
83/*
84 * Routine: ipc_port_dnrequest
85 * Purpose:
86 * Try to allocate a dead-name request slot.
87 * If successful, returns the request index.
88 * Otherwise returns zero.
89 * Conditions:
90 * The port is locked and active.
91 * Returns:
92 * KERN_SUCCESS A request index was found.
93 * KERN_NO_SPACE No index allocated.
94 */
95
96kern_return_t
97ipc_port_dnrequest(port, name, soright, indexp)
98 ipc_port_t port;
99 mach_port_t name;
100 ipc_port_t soright;
101 ipc_port_request_index_t *indexp;
102{
103 ipc_port_request_t ipr, table;
104 ipc_port_request_index_t index;
105
106 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 106
); })
;
107 assert(name != MACH_PORT_NULL)({ if (!(name != ((mach_port_t) 0))) Assert("name != MACH_PORT_NULL"
, "../ipc/ipc_port.c", 107); })
;
108 assert(soright != IP_NULL)({ if (!(soright != ((ipc_port_t) ((ipc_object_t) 0)))) Assert
("soright != IP_NULL", "../ipc/ipc_port.c", 108); })
;
109
110 table = port->ip_dnrequests;
111 if (table == IPR_NULL((ipc_port_request_t) 0))
112 return KERN_NO_SPACE3;
113
114 index = table->ipr_nextnotify.index;
115 if (index == 0)
116 return KERN_NO_SPACE3;
117
118 ipr = &table[index];
119 assert(ipr->ipr_name == MACH_PORT_NULL)({ if (!(ipr->name.name == ((mach_port_t) 0))) Assert("ipr->ipr_name == MACH_PORT_NULL"
, "../ipc/ipc_port.c", 119); })
;
120
121 table->ipr_nextnotify.index = ipr->ipr_nextnotify.index;
122 ipr->ipr_namename.name = name;
123 ipr->ipr_sorightnotify.port = soright;
124
125 *indexp = index;
126 return KERN_SUCCESS0;
127}
128
129/*
130 * Routine: ipc_port_dngrow
131 * Purpose:
132 * Grow a port's table of dead-name requests.
133 * Conditions:
134 * The port must be locked and active.
135 * Nothing else locked; will allocate memory.
136 * Upon return the port is unlocked.
137 * Returns:
138 * KERN_SUCCESS Grew the table.
139 * KERN_SUCCESS Somebody else grew the table.
140 * KERN_SUCCESS The port died.
141 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table.
142 */
143
144kern_return_t
145ipc_port_dngrow(port)
146 ipc_port_t port;
147{
148 ipc_table_size_t its;
149 ipc_port_request_t otable, ntable;
150
151 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 151
); })
;
152
153 otable = port->ip_dnrequests;
154 if (otable == IPR_NULL((ipc_port_request_t) 0))
155 its = &ipc_table_dnrequests[0];
156 else
157 its = otable->ipr_sizename.size + 1;
158
159 ip_reference(port)({ (&(port)->ip_target.ipt_object)->io_references++
; })
;
160 ip_unlock(port);
161
162 if ((its->its_size == 0) ||
163 ((ntable = it_dnrequests_alloc(its)((ipc_port_request_t) ipc_table_alloc((its)->its_size * sizeof
(struct ipc_port_request)))
) == IPR_NULL((ipc_port_request_t) 0))) {
164 ipc_port_release(port)ipc_object_release(&(port)->ip_target.ipt_object);
165 return KERN_RESOURCE_SHORTAGE6;
166 }
167
168 ip_lock(port);
169 ip_release(port)({ (&(port)->ip_target.ipt_object)->io_references--
; })
;
170
171 /*
172 * Check that port is still active and that nobody else
173 * has slipped in and grown the table on us. Note that
174 * just checking port->ip_dnrequests == otable isn't
175 * sufficient; must check ipr_size.
176 */
177
178 if (ip_active(port)((int)(&(port)->ip_target.ipt_object)->io_bits <
0)
&&
179 (port->ip_dnrequests == otable) &&
180 ((otable == IPR_NULL((ipc_port_request_t) 0)) || (otable->ipr_sizename.size+1 == its))) {
181 ipc_table_size_t oits = 0; /* '=0' to shut up lint */
182 ipc_table_elems_t osize, nsize;
183 ipc_port_request_index_t free, i;
184
185 /* copy old table to new table */
186
187 if (otable != IPR_NULL((ipc_port_request_t) 0)) {
188 oits = otable->ipr_sizename.size;
189 osize = oits->its_size;
190 free = otable->ipr_nextnotify.index;
191
192 memcpy((ntable + 1), (otable + 1),
193 (osize - 1) * sizeof(struct ipc_port_request));
194 } else {
195 osize = 1;
196 free = 0;
197 }
198
199 nsize = its->its_size;
200 assert(nsize > osize)({ if (!(nsize > osize)) Assert("nsize > osize", "../ipc/ipc_port.c"
, 200); })
;
201
202 /* add new elements to the new table's free list */
203
204 for (i = osize; i < nsize; i++) {
205 ipc_port_request_t ipr = &ntable[i];
206
207 ipr->ipr_namename.name = MACH_PORT_NULL((mach_port_t) 0);
208 ipr->ipr_nextnotify.index = free;
209 free = i;
210 }
211
212 ntable->ipr_nextnotify.index = free;
213 ntable->ipr_sizename.size = its;
214 port->ip_dnrequests = ntable;
215 ip_unlock(port);
216
217 if (otable != IPR_NULL((ipc_port_request_t) 0))
218 it_dnrequests_free(oits, otable)ipc_table_free((oits)->its_size * sizeof(struct ipc_port_request
), (vm_offset_t)(otable))
;
219 } else {
220 ip_check_unlock(port)({ ipc_object_refs_t _refs = (&(port)->ip_target.ipt_object
)->io_references; ; if (_refs == 0) kmem_cache_free(&ipc_object_caches
[((((&(port)->ip_target.ipt_object)->io_bits & 0x7fff0000
) >> 16))], (vm_offset_t) (&(port)->ip_target.ipt_object
)); })
;
221 it_dnrequests_free(its, ntable)ipc_table_free((its)->its_size * sizeof(struct ipc_port_request
), (vm_offset_t)(ntable))
;
222 }
223
224 return KERN_SUCCESS0;
225}
226
227/*
228 * Routine: ipc_port_dncancel
229 * Purpose:
230 * Cancel a dead-name request and return the send-once right.
231 * Conditions:
232 * The port must locked and active.
233 */
234
235ipc_port_t
236ipc_port_dncancel(
237 ipc_port_t port,
238 mach_port_t name,
239 ipc_port_request_index_t index)
240{
241 ipc_port_request_t ipr, table;
242 ipc_port_t dnrequest;
243
244 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 244
); })
;
245 assert(name != MACH_PORT_NULL)({ if (!(name != ((mach_port_t) 0))) Assert("name != MACH_PORT_NULL"
, "../ipc/ipc_port.c", 245); })
;
246 assert(index != 0)({ if (!(index != 0)) Assert("index != 0", "../ipc/ipc_port.c"
, 246); })
;
247
248 table = port->ip_dnrequests;
249 assert(table != IPR_NULL)({ if (!(table != ((ipc_port_request_t) 0))) Assert("table != IPR_NULL"
, "../ipc/ipc_port.c", 249); })
;
250
251 ipr = &table[index];
252 dnrequest = ipr->ipr_sorightnotify.port;
253 assert(ipr->ipr_name == name)({ if (!(ipr->name.name == name)) Assert("ipr->ipr_name == name"
, "../ipc/ipc_port.c", 253); })
;
254
255 /* return ipr to the free list inside the table */
256
257 ipr->ipr_namename.name = MACH_PORT_NULL((mach_port_t) 0);
258 ipr->ipr_nextnotify.index = table->ipr_nextnotify.index;
259 table->ipr_nextnotify.index = index;
260
261 return dnrequest;
262}
263
264/*
265 * Routine: ipc_port_pdrequest
266 * Purpose:
267 * Make a port-deleted request, returning the
268 * previously registered send-once right.
269 * Just cancels the previous request if notify is IP_NULL.
270 * Conditions:
271 * The port is locked and active. It is unlocked.
272 * Consumes a ref for notify (if non-null), and
273 * returns previous with a ref (if non-null).
274 */
275
276void
277ipc_port_pdrequest(
278 ipc_port_t port,
279 ipc_port_t notify,
280 ipc_port_t *previousp)
281{
282 ipc_port_t previous;
283
284 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 284
); })
;
285
286 previous = port->ip_pdrequest;
287 port->ip_pdrequest = notify;
288 ip_unlock(port);
289
290 *previousp = previous;
291}
292
293/*
294 * Routine: ipc_port_nsrequest
295 * Purpose:
296 * Make a no-senders request, returning the
297 * previously registered send-once right.
298 * Just cancels the previous request if notify is IP_NULL.
299 * Conditions:
300 * The port is locked and active. It is unlocked.
301 * Consumes a ref for notify (if non-null), and
302 * returns previous with a ref (if non-null).
303 */
304
305void
306ipc_port_nsrequest(
307 ipc_port_t port,
308 mach_port_mscount_t sync,
309 ipc_port_t notify,
310 ipc_port_t *previousp)
311{
312 ipc_port_t previous;
313 mach_port_mscount_t mscount;
314
315 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 315
); })
;
316
317 previous = port->ip_nsrequest;
318 mscount = port->ip_mscount;
319
320 if ((port->ip_srights == 0) &&
321 (sync <= mscount) &&
322 (notify != IP_NULL((ipc_port_t) ((ipc_object_t) 0)))) {
323 port->ip_nsrequest = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
324 ip_unlock(port);
325 ipc_notify_no_senders(notify, mscount);
326 } else {
327 port->ip_nsrequest = notify;
328 ip_unlock(port);
329 }
330
331 *previousp = previous;
332}
333
334/*
335 * Routine: ipc_port_set_qlimit
336 * Purpose:
337 * Changes a port's queue limit; the maximum number
338 * of messages which may be queued to the port.
339 * Conditions:
340 * The port is locked and active.
341 */
342
343void
344ipc_port_set_qlimit(
345 ipc_port_t port,
346 mach_port_msgcount_t qlimit)
347{
348 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 348
); })
;
349
350 /* wake up senders allowed by the new qlimit */
351
352 if (qlimit > port->ip_qlimit) {
353 mach_port_msgcount_t i, wakeup;
354
355 /* caution: wakeup, qlimit are unsigned */
356
357 wakeup = qlimit - port->ip_qlimit;
358
359 for (i = 0; i < wakeup; i++) {
360 ipc_thread_t th;
361
362 th = ipc_thread_dequeue(&port->ip_blocked);
363 if (th == ITH_NULL((thread_t) 0))
364 break;
365
366 th->ith_state = MACH_MSG_SUCCESS0x00000000;
367 thread_go(th);
368 }
369 }
370
371 port->ip_qlimit = qlimit;
372}
373
374/*
375 * Routine: ipc_port_lock_mqueue
376 * Purpose:
377 * Locks and returns the message queue that the port is using.
378 * The message queue may be in the port or in its port set.
379 * Conditions:
380 * The port is locked and active.
381 * Port set, message queue locks may be taken.
382 */
383
384ipc_mqueue_t
385ipc_port_lock_mqueue(port)
386 ipc_port_t port;
387{
388 if (port->ip_pset != IPS_NULL((ipc_pset_t) ((ipc_object_t) 0))) {
389 ipc_pset_t pset = port->ip_pset;
390
391 ips_lock(pset);
392 if (ips_active(pset)((int)(&(pset)->ips_target.ipt_object)->io_bits <
0)
) {
393 imq_lock(&pset->ips_messages);
394 ips_unlock(pset);
395 return &pset->ips_messagesips_target.ipt_messages;
396 }
397
398 ipc_pset_remove(pset, port);
399 ips_check_unlock(pset)({ ipc_object_refs_t _refs = (&(pset)->ips_target.ipt_object
)->io_references; ; if (_refs == 0) kmem_cache_free(&ipc_object_caches
[((((&(pset)->ips_target.ipt_object)->io_bits &
0x7fff0000) >> 16))], (vm_offset_t) (&(pset)->ips_target
.ipt_object)); })
;
400 }
401
402 imq_lock(&port->ip_messages);
403 return &port->ip_messagesip_target.ipt_messages;
404}
405
406/*
407 * Routine: ipc_port_set_seqno
408 * Purpose:
409 * Changes a port's sequence number.
410 * Conditions:
411 * The port is locked and active.
412 * Port set, message queue locks may be taken.
413 */
414
415void
416ipc_port_set_seqno(port, seqno)
417 ipc_port_t port;
418 mach_port_seqno_t seqno;
419{
420 ipc_mqueue_t mqueue;
421
422 mqueue = ipc_port_lock_mqueue(port);
Value stored to 'mqueue' is never read
423 port->ip_seqno = seqno;
424 imq_unlock(mqueue);
425}
426
427/*
428 * Routine: ipc_port_clear_receiver
429 * Purpose:
430 * Prepares a receive right for transmission/destruction.
431 * Conditions:
432 * The port is locked and active.
433 */
434
435void
436ipc_port_clear_receiver(
437 ipc_port_t port)
438{
439 ipc_pset_t pset;
440
441 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 441
); })
;
442
443 pset = port->ip_pset;
444 if (pset != IPS_NULL((ipc_pset_t) ((ipc_object_t) 0))) {
445 /* No threads receiving from port, but must remove from set. */
446
447 ips_lock(pset);
448 ipc_pset_remove(pset, port);
449 ips_check_unlock(pset)({ ipc_object_refs_t _refs = (&(pset)->ips_target.ipt_object
)->io_references; ; if (_refs == 0) kmem_cache_free(&ipc_object_caches
[((((&(pset)->ips_target.ipt_object)->io_bits &
0x7fff0000) >> 16))], (vm_offset_t) (&(pset)->ips_target
.ipt_object)); })
;
450 } else {
451 /* Else, wake up all receivers, indicating why. */
452
453 imq_lock(&port->ip_messages);
454 ipc_mqueue_changed(&port->ip_messagesip_target.ipt_messages, MACH_RCV_PORT_DIED0x10004009);
455 imq_unlock(&port->ip_messages);
456 }
457
458 ipc_port_set_mscount(port, 0)({ ({ if (!(((int)(&(port)->ip_target.ipt_object)->
io_bits < 0))) Assert("ip_active(port)", "../ipc/ipc_port.c"
, 458); }); (port)->ip_mscount = (0); })
;
459 imq_lock(&port->ip_messages);
460 port->ip_seqno = 0;
461 imq_unlock(&port->ip_messages);
462}
463
464/*
465 * Routine: ipc_port_init
466 * Purpose:
467 * Initializes a newly-allocated port.
468 * Doesn't touch the ip_object fields.
469 */
470
471void
472ipc_port_init(
473 ipc_port_t port,
474 ipc_space_t space,
475 mach_port_t name)
476{
477 /* port->ip_kobject doesn't have to be initialized */
478
479 ipc_target_init(&port->ip_target, name);
480
481 port->ip_receiverdata.receiver = space;
482
483 port->ip_mscount = 0;
484 port->ip_srights = 0;
485 port->ip_sorights = 0;
486
487 port->ip_nsrequest = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
488 port->ip_pdrequest = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
489 port->ip_dnrequests = IPR_NULL((ipc_port_request_t) 0);
490
491 port->ip_pset = IPS_NULL((ipc_pset_t) ((ipc_object_t) 0));
492 port->ip_cur_target = &port->ip_target;
493 port->ip_seqno = 0;
494 port->ip_msgcount = 0;
495 port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT((mach_port_msgcount_t) 5);
496
497 ipc_mqueue_init(&port->ip_messagesip_target.ipt_messages);
498 ipc_thread_queue_init(&port->ip_blocked)({ (&port->ip_blocked)->ithq_base = ((thread_t) 0);
})
;
499}
500
501/*
502 * Routine: ipc_port_alloc
503 * Purpose:
504 * Allocate a port.
505 * Conditions:
506 * Nothing locked. If successful, the port is returned
507 * locked. (The caller doesn't have a reference.)
508 * Returns:
509 * KERN_SUCCESS The port is allocated.
510 * KERN_INVALID_TASK The space is dead.
511 * KERN_NO_SPACE No room for an entry in the space.
512 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
513 */
514
515kern_return_t
516ipc_port_alloc(
517 ipc_space_t space,
518 mach_port_t *namep,
519 ipc_port_t *portp)
520{
521 ipc_port_t port;
522 mach_port_t name;
523 kern_return_t kr;
524
525 kr = ipc_object_alloc(space, IOT_PORT0,
526 MACH_PORT_TYPE_RECEIVE((mach_port_type_t)(1 << ((((mach_port_right_t) 1))+16)
))
, 0,
527 &name, (ipc_object_t *) &port);
528 if (kr != KERN_SUCCESS0)
529 return kr;
530
531 /* port is locked */
532
533 ipc_port_init(port, space, name);
534
535 *namep = name;
536 *portp = port;
537
538 return KERN_SUCCESS0;
539}
540
541/*
542 * Routine: ipc_port_alloc_name
543 * Purpose:
544 * Allocate a port, with a specific name.
545 * Conditions:
546 * Nothing locked. If successful, the port is returned
547 * locked. (The caller doesn't have a reference.)
548 * Returns:
549 * KERN_SUCCESS The port is allocated.
550 * KERN_INVALID_TASK The space is dead.
551 * KERN_NAME_EXISTS The name already denotes a right.
552 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
553 */
554
555kern_return_t
556ipc_port_alloc_name(
557 ipc_space_t space,
558 mach_port_t name,
559 ipc_port_t *portp)
560{
561 ipc_port_t port;
562 kern_return_t kr;
563
564 kr = ipc_object_alloc_name(space, IOT_PORT0,
565 MACH_PORT_TYPE_RECEIVE((mach_port_type_t)(1 << ((((mach_port_right_t) 1))+16)
))
, 0,
566 name, (ipc_object_t *) &port);
567 if (kr != KERN_SUCCESS0)
568 return kr;
569 /* port is locked */
570
571 ipc_port_init(port, space, name);
572
573 *portp = port;
574 return KERN_SUCCESS0;
575}
576
577/*
578 * Routine: ipc_port_destroy
579 * Purpose:
580 * Destroys a port. Cleans up queued messages.
581 *
582 * If the port has a backup, it doesn't get destroyed,
583 * but is sent in a port-destroyed notification to the backup.
584 * Conditions:
585 * The port is locked and alive; nothing else locked.
586 * The caller has a reference, which is consumed.
587 * Afterwards, the port is unlocked and dead.
588 */
589
590void
591ipc_port_destroy(
592 ipc_port_t port)
593{
594 ipc_port_t pdrequest, nsrequest;
595 ipc_mqueue_t mqueue;
596 ipc_kmsg_queue_t kmqueue;
597 ipc_kmsg_t kmsg;
598 ipc_thread_t sender;
599 ipc_port_request_t dnrequests;
600
601 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 601
); })
;
602 /* port->ip_receiver_name is garbage */
603 /* port->ip_receiver/port->ip_destination is garbage */
604 assert(port->ip_pset == IPS_NULL)({ if (!(port->ip_pset == ((ipc_pset_t) ((ipc_object_t) 0)
))) Assert("port->ip_pset == IPS_NULL", "../ipc/ipc_port.c"
, 604); })
;
605 assert(port->ip_mscount == 0)({ if (!(port->ip_mscount == 0)) Assert("port->ip_mscount == 0"
, "../ipc/ipc_port.c", 605); })
;
606 assert(port->ip_seqno == 0)({ if (!(port->ip_seqno == 0)) Assert("port->ip_seqno == 0"
, "../ipc/ipc_port.c", 606); })
;
607
608 /* first check for a backup port */
609
610 pdrequest = port->ip_pdrequest;
611 if (pdrequest != IP_NULL((ipc_port_t) ((ipc_object_t) 0))) {
612 /* we assume the ref for pdrequest */
613 port->ip_pdrequest = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
614
615 /* make port be in limbo */
616 port->ip_receiver_nameip_target.ipt_name = MACH_PORT_NULL((mach_port_t) 0);
617 port->ip_destinationdata.destination = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
618 ip_unlock(port);
619
620 if (!ipc_port_check_circularity(port, pdrequest)) {
621 /* consumes our refs for port and pdrequest */
622 ipc_notify_port_destroyed(pdrequest, port);
623 return;
624 } else {
625 /* consume pdrequest and destroy port */
626 ipc_port_release_sonce(pdrequest);
627 }
628
629 ip_lock(port);
630 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 630
); })
;
631 assert(port->ip_pset == IPS_NULL)({ if (!(port->ip_pset == ((ipc_pset_t) ((ipc_object_t) 0)
))) Assert("port->ip_pset == IPS_NULL", "../ipc/ipc_port.c"
, 631); })
;
632 assert(port->ip_mscount == 0)({ if (!(port->ip_mscount == 0)) Assert("port->ip_mscount == 0"
, "../ipc/ipc_port.c", 632); })
;
633 assert(port->ip_seqno == 0)({ if (!(port->ip_seqno == 0)) Assert("port->ip_seqno == 0"
, "../ipc/ipc_port.c", 633); })
;
634 assert(port->ip_pdrequest == IP_NULL)({ if (!(port->ip_pdrequest == ((ipc_port_t) ((ipc_object_t
) 0)))) Assert("port->ip_pdrequest == IP_NULL", "../ipc/ipc_port.c"
, 634); })
;
635 assert(port->ip_receiver_name == MACH_PORT_NULL)({ if (!(port->ip_target.ipt_name == ((mach_port_t) 0))) Assert
("port->ip_receiver_name == MACH_PORT_NULL", "../ipc/ipc_port.c"
, 635); })
;
636 assert(port->ip_destination == IP_NULL)({ if (!(port->data.destination == ((ipc_port_t) ((ipc_object_t
) 0)))) Assert("port->ip_destination == IP_NULL", "../ipc/ipc_port.c"
, 636); })
;
637
638 /* fall through and destroy the port */
639 }
640
641 /*
642 * rouse all blocked senders
643 *
644 * This must be done with the port locked, because
645 * ipc_mqueue_send can play with the ip_blocked queue
646 * of a dead port.
647 */
648
649 while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL((thread_t) 0)) {
650 sender->ith_state = MACH_MSG_SUCCESS0x00000000;
651 thread_go(sender);
652 }
653
654 /* once port is dead, we don't need to keep it locked */
655
656 port->ip_objectip_target.ipt_object.io_bits &= ~IO_BITS_ACTIVE0x80000000U;
657 port->ip_timestampdata.timestamp = ipc_port_timestamp();
658 ip_unlock(port);
659
660 /* throw away no-senders request */
661
662 nsrequest = port->ip_nsrequest;
663 if (nsrequest != IP_NULL((ipc_port_t) ((ipc_object_t) 0)))
664 ipc_notify_send_once(nsrequest); /* consumes ref */
665
666 /* destroy any queued messages */
667
668 mqueue = &port->ip_messagesip_target.ipt_messages;
669 imq_lock(mqueue);
670 assert(ipc_thread_queue_empty(&mqueue->imq_threads))({ if (!(((&mqueue->imq_threads)->ithq_base == ((thread_t
) 0)))) Assert("ipc_thread_queue_empty(&mqueue->imq_threads)"
, "../ipc/ipc_port.c", 670); })
;
671 kmqueue = &mqueue->imq_messages;
672
673 while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL((ipc_kmsg_t) 0)) {
674 imq_unlock(mqueue);
675
676 assert(kmsg->ikm_header.msgh_remote_port ==({ if (!(kmsg->ikm_header.msgh_remote_port == (mach_port_t
) port)) Assert("kmsg->ikm_header.msgh_remote_port == (mach_port_t) port"
, "../ipc/ipc_port.c", 677); })
677 (mach_port_t) port)({ if (!(kmsg->ikm_header.msgh_remote_port == (mach_port_t
) port)) Assert("kmsg->ikm_header.msgh_remote_port == (mach_port_t) port"
, "../ipc/ipc_port.c", 677); })
;
678
679 ipc_port_release(port)ipc_object_release(&(port)->ip_target.ipt_object);
680 kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL((mach_port_t) 0);
681 ipc_kmsg_destroy(kmsg);
682
683 imq_lock(mqueue);
684 }
685
686 imq_unlock(mqueue);
687
688 /* generate dead-name notifications */
689
690 dnrequests = port->ip_dnrequests;
691 if (dnrequests != IPR_NULL((ipc_port_request_t) 0)) {
692 ipc_table_size_t its = dnrequests->ipr_sizename.size;
693 ipc_table_elems_t size = its->its_size;
694 ipc_port_request_index_t index;
695
696 for (index = 1; index < size; index++) {
697 ipc_port_request_t ipr = &dnrequests[index];
698 mach_port_t name = ipr->ipr_namename.name;
699 ipc_port_t soright;
700
701 if (name == MACH_PORT_NULL((mach_port_t) 0))
702 continue;
703
704 soright = ipr->ipr_sorightnotify.port;
705 assert(soright != IP_NULL)({ if (!(soright != ((ipc_port_t) ((ipc_object_t) 0)))) Assert
("soright != IP_NULL", "../ipc/ipc_port.c", 705); })
;
706
707 ipc_notify_dead_name(soright, name);
708 }
709
710 it_dnrequests_free(its, dnrequests)ipc_table_free((its)->its_size * sizeof(struct ipc_port_request
), (vm_offset_t)(dnrequests))
;
711 }
712
713 if (ip_kotype(port)((&(port)->ip_target.ipt_object)->io_bits & 0x0000ffff
)
!= IKOT_NONE0)
714 ipc_kobject_destroy(port);
715
716 /* Common destruction for the IPC target. */
717 ipc_target_terminate(&port->ip_target);
718
719 ipc_port_release(port)ipc_object_release(&(port)->ip_target.ipt_object); /* consume caller's ref */
720}
721
722/*
723 * Routine: ipc_port_check_circularity
724 * Purpose:
725 * Check if queueing "port" in a message for "dest"
726 * would create a circular group of ports and messages.
727 *
728 * If no circularity (FALSE returned), then "port"
729 * is changed from "in limbo" to "in transit".
730 *
731 * That is, we want to set port->ip_destination == dest,
732 * but guaranteeing that this doesn't create a circle
733 * port->ip_destination->ip_destination->... == port
734 * Conditions:
735 * No ports locked. References held for "port" and "dest".
736 */
737
738boolean_t
739ipc_port_check_circularity(
740 ipc_port_t port,
741 ipc_port_t dest)
742{
743 ipc_port_t base;
744
745 assert(port != IP_NULL)({ if (!(port != ((ipc_port_t) ((ipc_object_t) 0)))) Assert("port != IP_NULL"
, "../ipc/ipc_port.c", 745); })
;
746 assert(dest != IP_NULL)({ if (!(dest != ((ipc_port_t) ((ipc_object_t) 0)))) Assert("dest != IP_NULL"
, "../ipc/ipc_port.c", 746); })
;
747
748 if (port == dest)
749 return TRUE((boolean_t) 1);
750 base = dest;
751
752 /*
753 * First try a quick check that can run in parallel.
754 * No circularity if dest is not in transit.
755 */
756
757 ip_lock(port);
758 if (ip_lock_try(dest)(((boolean_t) 1))) {
759 if (!ip_active(dest)((int)(&(dest)->ip_target.ipt_object)->io_bits <
0)
||
760 (dest->ip_receiver_nameip_target.ipt_name != MACH_PORT_NULL((mach_port_t) 0)) ||
761 (dest->ip_destinationdata.destination == IP_NULL((ipc_port_t) ((ipc_object_t) 0))))
762 goto not_circular;
763
764 /* dest is in transit; further checking necessary */
765
766 ip_unlock(dest);
767 }
768 ip_unlock(port);
769
770 ipc_port_multiple_lock(); /* massive serialization */
771
772 /*
773 * Search for the end of the chain (a port not in transit),
774 * acquiring locks along the way.
775 */
776
777 for (;;) {
778 ip_lock(base);
779
780 if (!ip_active(base)((int)(&(base)->ip_target.ipt_object)->io_bits <
0)
||
781 (base->ip_receiver_nameip_target.ipt_name != MACH_PORT_NULL((mach_port_t) 0)) ||
782 (base->ip_destinationdata.destination == IP_NULL((ipc_port_t) ((ipc_object_t) 0))))
783 break;
784
785 base = base->ip_destinationdata.destination;
786 }
787
788 /* all ports in chain from dest to base, inclusive, are locked */
789
790 if (port == base) {
791 /* circularity detected! */
792
793 ipc_port_multiple_unlock();
794
795 /* port (== base) is in limbo */
796
797 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 797
); })
;
798 assert(port->ip_receiver_name == MACH_PORT_NULL)({ if (!(port->ip_target.ipt_name == ((mach_port_t) 0))) Assert
("port->ip_receiver_name == MACH_PORT_NULL", "../ipc/ipc_port.c"
, 798); })
;
799 assert(port->ip_destination == IP_NULL)({ if (!(port->data.destination == ((ipc_port_t) ((ipc_object_t
) 0)))) Assert("port->ip_destination == IP_NULL", "../ipc/ipc_port.c"
, 799); })
;
800
801 while (dest != IP_NULL((ipc_port_t) ((ipc_object_t) 0))) {
802 ipc_port_t next;
803
804 /* dest is in transit or in limbo */
805
806 assert(ip_active(dest))({ if (!(((int)(&(dest)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(dest)", "../ipc/ipc_port.c", 806
); })
;
807 assert(dest->ip_receiver_name == MACH_PORT_NULL)({ if (!(dest->ip_target.ipt_name == ((mach_port_t) 0))) Assert
("dest->ip_receiver_name == MACH_PORT_NULL", "../ipc/ipc_port.c"
, 807); })
;
808
809 next = dest->ip_destinationdata.destination;
810 ip_unlock(dest);
811 dest = next;
812 }
813
814 return TRUE((boolean_t) 1);
815 }
816
817 /*
818 * The guarantee: lock port while the entire chain is locked.
819 * Once port is locked, we can take a reference to dest,
820 * add port to the chain, and unlock everything.
821 */
822
823 ip_lock(port);
824 ipc_port_multiple_unlock();
825
826 not_circular:
827
828 /* port is in limbo */
829
830 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 830
); })
;
831 assert(port->ip_receiver_name == MACH_PORT_NULL)({ if (!(port->ip_target.ipt_name == ((mach_port_t) 0))) Assert
("port->ip_receiver_name == MACH_PORT_NULL", "../ipc/ipc_port.c"
, 831); })
;
832 assert(port->ip_destination == IP_NULL)({ if (!(port->data.destination == ((ipc_port_t) ((ipc_object_t
) 0)))) Assert("port->ip_destination == IP_NULL", "../ipc/ipc_port.c"
, 832); })
;
833
834 ip_reference(dest)({ (&(dest)->ip_target.ipt_object)->io_references++
; })
;
835 port->ip_destinationdata.destination = dest;
836
837 /* now unlock chain */
838
839 while (port != base) {
840 ipc_port_t next;
841
842 /* port is in transit */
843
844 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 844
); })
;
845 assert(port->ip_receiver_name == MACH_PORT_NULL)({ if (!(port->ip_target.ipt_name == ((mach_port_t) 0))) Assert
("port->ip_receiver_name == MACH_PORT_NULL", "../ipc/ipc_port.c"
, 845); })
;
846 assert(port->ip_destination != IP_NULL)({ if (!(port->data.destination != ((ipc_port_t) ((ipc_object_t
) 0)))) Assert("port->ip_destination != IP_NULL", "../ipc/ipc_port.c"
, 846); })
;
847
848 next = port->ip_destinationdata.destination;
849 ip_unlock(port);
850 port = next;
851 }
852
853 /* base is not in transit */
854
855 assert(!ip_active(base) ||({ if (!(!((int)(&(base)->ip_target.ipt_object)->io_bits
< 0) || (base->ip_target.ipt_name != ((mach_port_t) 0)
) || (base->data.destination == ((ipc_port_t) ((ipc_object_t
) 0))))) Assert("!ip_active(base) || (base->ip_receiver_name != MACH_PORT_NULL) || (base->ip_destination == IP_NULL)"
, "../ipc/ipc_port.c", 857); })
856 (base->ip_receiver_name != MACH_PORT_NULL) ||({ if (!(!((int)(&(base)->ip_target.ipt_object)->io_bits
< 0) || (base->ip_target.ipt_name != ((mach_port_t) 0)
) || (base->data.destination == ((ipc_port_t) ((ipc_object_t
) 0))))) Assert("!ip_active(base) || (base->ip_receiver_name != MACH_PORT_NULL) || (base->ip_destination == IP_NULL)"
, "../ipc/ipc_port.c", 857); })
857 (base->ip_destination == IP_NULL))({ if (!(!((int)(&(base)->ip_target.ipt_object)->io_bits
< 0) || (base->ip_target.ipt_name != ((mach_port_t) 0)
) || (base->data.destination == ((ipc_port_t) ((ipc_object_t
) 0))))) Assert("!ip_active(base) || (base->ip_receiver_name != MACH_PORT_NULL) || (base->ip_destination == IP_NULL)"
, "../ipc/ipc_port.c", 857); })
;
858 ip_unlock(base);
859
860 return FALSE((boolean_t) 0);
861}
862
863/*
864 * Routine: ipc_port_lookup_notify
865 * Purpose:
866 * Make a send-once notify port from a receive right.
867 * Returns IP_NULL if name doesn't denote a receive right.
868 * Conditions:
869 * The space must be locked (read or write) and active.
870 */
871
872ipc_port_t
873ipc_port_lookup_notify(
874 ipc_space_t space,
875 mach_port_t name)
876{
877 ipc_port_t port;
878 ipc_entry_t entry;
879
880 assert(space->is_active)({ if (!(space->is_active)) Assert("space->is_active", "../ipc/ipc_port.c"
, 880); })
;
881
882 entry = ipc_entry_lookup(space, name);
883 if (entry == IE_NULL((ipc_entry_t) 0))
884 return IP_NULL((ipc_port_t) ((ipc_object_t) 0));
885
886 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE((mach_port_type_t)(1 << ((((mach_port_right_t) 1))+16)
))
) == 0)
887 return IP_NULL((ipc_port_t) ((ipc_object_t) 0));
888
889 port = (ipc_port_t) entry->ie_object;
890 assert(port != IP_NULL)({ if (!(port != ((ipc_port_t) ((ipc_object_t) 0)))) Assert("port != IP_NULL"
, "../ipc/ipc_port.c", 890); })
;
891
892 ip_lock(port);
893 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 893
); })
;
894 assert(port->ip_receiver_name == name)({ if (!(port->ip_target.ipt_name == name)) Assert("port->ip_receiver_name == name"
, "../ipc/ipc_port.c", 894); })
;
895 assert(port->ip_receiver == space)({ if (!(port->data.receiver == space)) Assert("port->ip_receiver == space"
, "../ipc/ipc_port.c", 895); })
;
896
897 ip_reference(port)({ (&(port)->ip_target.ipt_object)->io_references++
; })
;
898 port->ip_sorights++;
899 ip_unlock(port);
900
901 return port;
902}
903
904/*
905 * Routine: ipc_port_make_send
906 * Purpose:
907 * Make a naked send right from a receive right.
908 * Conditions:
909 * The port is not locked but it is active.
910 */
911
912ipc_port_t
913ipc_port_make_send(
914 ipc_port_t port)
915{
916 assert(IP_VALID(port))({ if (!((((&(port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(port)->ip_target.ipt_object) != (
(ipc_object_t) -1))))) Assert("IP_VALID(port)", "../ipc/ipc_port.c"
, 916); })
;
917
918 ip_lock(port);
919 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 919
); })
;
920 port->ip_mscount++;
921 port->ip_srights++;
922 ip_reference(port)({ (&(port)->ip_target.ipt_object)->io_references++
; })
;
923 ip_unlock(port);
924
925 return port;
926}
927
928/*
929 * Routine: ipc_port_copy_send
930 * Purpose:
931 * Make a naked send right from another naked send right.
932 * IP_NULL -> IP_NULL
933 * IP_DEAD -> IP_DEAD
934 * dead port -> IP_DEAD
935 * live port -> port + ref
936 * Conditions:
937 * Nothing locked except possibly a space.
938 */
939
940ipc_port_t
941ipc_port_copy_send(
942 ipc_port_t port)
943{
944 ipc_port_t sright;
945
946 if (!IP_VALID(port)(((&(port)->ip_target.ipt_object) != ((ipc_object_t) 0
)) && ((&(port)->ip_target.ipt_object) != ((ipc_object_t
) -1)))
)
947 return port;
948
949 ip_lock(port);
950 if (ip_active(port)((int)(&(port)->ip_target.ipt_object)->io_bits <
0)
) {
951 assert(port->ip_srights > 0)({ if (!(port->ip_srights > 0)) Assert("port->ip_srights > 0"
, "../ipc/ipc_port.c", 951); })
;
952
953 ip_reference(port)({ (&(port)->ip_target.ipt_object)->io_references++
; })
;
954 port->ip_srights++;
955 sright = port;
956 } else
957 sright = IP_DEAD((ipc_port_t) ((ipc_object_t) -1));
958 ip_unlock(port);
959
960 return sright;
961}
962
963/*
964 * Routine: ipc_port_copyout_send
965 * Purpose:
966 * Copyout a naked send right (possibly null/dead),
967 * or if that fails, destroy the right.
968 * Conditions:
969 * Nothing locked.
970 */
971
972mach_port_t
973ipc_port_copyout_send(
974 ipc_port_t sright,
975 ipc_space_t space)
976{
977 mach_port_t name;
978
979 if (IP_VALID(sright)(((&(sright)->ip_target.ipt_object) != ((ipc_object_t)
0)) && ((&(sright)->ip_target.ipt_object) != (
(ipc_object_t) -1)))
) {
980 kern_return_t kr;
981
982 kr = ipc_object_copyout(space, (ipc_object_t) sright,
983 MACH_MSG_TYPE_PORT_SEND17, TRUE((boolean_t) 1), &name);
984 if (kr != KERN_SUCCESS0) {
985 ipc_port_release_send(sright);
986
987 if (kr == KERN_INVALID_CAPABILITY20)
988 name = MACH_PORT_DEAD((mach_port_t) ~0);
989 else
990 name = MACH_PORT_NULL((mach_port_t) 0);
991 }
992 } else
993 name = (mach_port_t) sright;
994
995 return name;
996}
997
998/*
999 * Routine: ipc_port_release_send
1000 * Purpose:
1001 * Release a (valid) naked send right.
1002 * Consumes a ref for the port.
1003 * Conditions:
1004 * Nothing locked.
1005 */
1006
1007void
1008ipc_port_release_send(
1009 ipc_port_t port)
1010{
1011 ipc_port_t nsrequest = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
1012 mach_port_mscount_t mscount;
1013
1014 assert(IP_VALID(port))({ if (!((((&(port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(port)->ip_target.ipt_object) != (
(ipc_object_t) -1))))) Assert("IP_VALID(port)", "../ipc/ipc_port.c"
, 1014); })
;
1015
1016 ip_lock(port);
1017 ip_release(port)({ (&(port)->ip_target.ipt_object)->io_references--
; })
;
1018
1019 if (!ip_active(port)((int)(&(port)->ip_target.ipt_object)->io_bits <
0)
) {
1020 ip_check_unlock(port)({ ipc_object_refs_t _refs = (&(port)->ip_target.ipt_object
)->io_references; ; if (_refs == 0) kmem_cache_free(&ipc_object_caches
[((((&(port)->ip_target.ipt_object)->io_bits & 0x7fff0000
) >> 16))], (vm_offset_t) (&(port)->ip_target.ipt_object
)); })
;
1021 return;
1022 }
1023
1024 assert(port->ip_srights > 0)({ if (!(port->ip_srights > 0)) Assert("port->ip_srights > 0"
, "../ipc/ipc_port.c", 1024); })
;
1025
1026 if (--port->ip_srights == 0) {
1027 nsrequest = port->ip_nsrequest;
1028 if (nsrequest != IP_NULL((ipc_port_t) ((ipc_object_t) 0))) {
1029 port->ip_nsrequest = IP_NULL((ipc_port_t) ((ipc_object_t) 0));
1030 mscount = port->ip_mscount;
1031 }
1032 }
1033
1034 ip_unlock(port);
1035
1036 if (nsrequest != IP_NULL((ipc_port_t) ((ipc_object_t) 0)))
1037 ipc_notify_no_senders(nsrequest, mscount);
1038}
1039
1040/*
1041 * Routine: ipc_port_make_sonce
1042 * Purpose:
1043 * Make a naked send-once right from a receive right.
1044 * Conditions:
1045 * The port is not locked but it is active.
1046 */
1047
1048ipc_port_t
1049ipc_port_make_sonce(
1050 ipc_port_t port)
1051{
1052 assert(IP_VALID(port))({ if (!((((&(port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(port)->ip_target.ipt_object) != (
(ipc_object_t) -1))))) Assert("IP_VALID(port)", "../ipc/ipc_port.c"
, 1052); })
;
1053
1054 ip_lock(port);
1055 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 1055
); })
;
1056 port->ip_sorights++;
1057 ip_reference(port)({ (&(port)->ip_target.ipt_object)->io_references++
; })
;
1058 ip_unlock(port);
1059
1060 return port;
1061}
1062
1063/*
1064 * Routine: ipc_port_release_sonce
1065 * Purpose:
1066 * Release a naked send-once right.
1067 * Consumes a ref for the port.
1068 *
1069 * In normal situations, this is never used.
1070 * Send-once rights are only consumed when
1071 * a message (possibly a send-once notification)
1072 * is sent to them.
1073 * Conditions:
1074 * Nothing locked except possibly a space.
1075 */
1076
1077void
1078ipc_port_release_sonce(
1079 ipc_port_t port)
1080{
1081 assert(IP_VALID(port))({ if (!((((&(port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(port)->ip_target.ipt_object) != (
(ipc_object_t) -1))))) Assert("IP_VALID(port)", "../ipc/ipc_port.c"
, 1081); })
;
1082
1083 ip_lock(port);
1084
1085 assert(port->ip_sorights > 0)({ if (!(port->ip_sorights > 0)) Assert("port->ip_sorights > 0"
, "../ipc/ipc_port.c", 1085); })
;
1086
1087 port->ip_sorights--;
1088
1089 ip_release(port)({ (&(port)->ip_target.ipt_object)->io_references--
; })
;
1090
1091 if (!ip_active(port)((int)(&(port)->ip_target.ipt_object)->io_bits <
0)
) {
1092 ip_check_unlock(port)({ ipc_object_refs_t _refs = (&(port)->ip_target.ipt_object
)->io_references; ; if (_refs == 0) kmem_cache_free(&ipc_object_caches
[((((&(port)->ip_target.ipt_object)->io_bits & 0x7fff0000
) >> 16))], (vm_offset_t) (&(port)->ip_target.ipt_object
)); })
;
1093 return;
1094 }
1095
1096 ip_unlock(port);
1097}
1098
1099/*
1100 * Routine: ipc_port_release_receive
1101 * Purpose:
1102 * Release a naked (in limbo or in transit) receive right.
1103 * Consumes a ref for the port; destroys the port.
1104 * Conditions:
1105 * Nothing locked.
1106 */
1107
1108void
1109ipc_port_release_receive(
1110 ipc_port_t port)
1111{
1112 ipc_port_t dest;
1113
1114 assert(IP_VALID(port))({ if (!((((&(port)->ip_target.ipt_object) != ((ipc_object_t
) 0)) && ((&(port)->ip_target.ipt_object) != (
(ipc_object_t) -1))))) Assert("IP_VALID(port)", "../ipc/ipc_port.c"
, 1114); })
;
1115
1116 ip_lock(port);
1117 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 1117
); })
;
1118 assert(port->ip_receiver_name == MACH_PORT_NULL)({ if (!(port->ip_target.ipt_name == ((mach_port_t) 0))) Assert
("port->ip_receiver_name == MACH_PORT_NULL", "../ipc/ipc_port.c"
, 1118); })
;
1119 dest = port->ip_destinationdata.destination;
1120
1121 ipc_port_destroy(port); /* consumes ref, unlocks */
1122
1123 if (dest != IP_NULL((ipc_port_t) ((ipc_object_t) 0)))
1124 ipc_port_release(dest)ipc_object_release(&(dest)->ip_target.ipt_object);
1125}
1126
1127/*
1128 * Routine: ipc_port_alloc_special
1129 * Purpose:
1130 * Allocate a port in a special space.
1131 * The new port is returned with one ref.
1132 * If unsuccessful, IP_NULL is returned.
1133 * Conditions:
1134 * Nothing locked.
1135 */
1136
1137ipc_port_t
1138ipc_port_alloc_special(space)
1139 ipc_space_t space;
1140{
1141 ipc_port_t port;
1142
1143 port = (ipc_port_t) io_alloc(IOT_PORT)((ipc_object_t) kmem_cache_alloc(&ipc_object_caches[(0)])
)
;
1144 if (port == IP_NULL((ipc_port_t) ((ipc_object_t) 0)))
1145 return IP_NULL((ipc_port_t) ((ipc_object_t) 0));
1146
1147 io_lock_init(&port->ip_object);
1148 port->ip_referencesip_target.ipt_object.io_references = 1;
1149 port->ip_objectip_target.ipt_object.io_bits = io_makebits(TRUE, IOT_PORT, 0)(((((boolean_t) 1)) ? 0x80000000U : 0) | ((0) << 16) | (
0))
;
1150
1151 /*
1152 * The actual values of ip_receiver_name aren't important,
1153 * as long as they are valid (not null/dead).
1154 *
1155 * Mach4: we set it to the internal port structure address
1156 * so we can always just pass on ip_receiver_name during
1157 * an rpc regardless of whether the destination is user or
1158 * kernel (i.e. no special-casing code for the kernel along
1159 * the fast rpc path).
1160 */
1161
1162 ipc_port_init(port, space, (mach_port_t)port);
1163
1164 return port;
1165}
1166
1167/*
1168 * Routine: ipc_port_dealloc_special
1169 * Purpose:
1170 * Deallocate a port in a special space.
1171 * Consumes one ref for the port.
1172 * Conditions:
1173 * Nothing locked.
1174 */
1175
1176void
1177ipc_port_dealloc_special(
1178 ipc_port_t port,
1179 ipc_space_t space)
1180{
1181 ip_lock(port);
1182 assert(ip_active(port))({ if (!(((int)(&(port)->ip_target.ipt_object)->io_bits
< 0))) Assert("ip_active(port)", "../ipc/ipc_port.c", 1182
); })
;
1183 assert(port->ip_receiver_name != MACH_PORT_NULL)({ if (!(port->ip_target.ipt_name != ((mach_port_t) 0))) Assert
("port->ip_receiver_name != MACH_PORT_NULL", "../ipc/ipc_port.c"
, 1183); })
;
1184 assert(port->ip_receiver == space)({ if (!(port->data.receiver == space)) Assert("port->ip_receiver == space"
, "../ipc/ipc_port.c", 1184); })
;
1185
1186 /*
1187 * We clear ip_receiver_name and ip_receiver to simplify
1188 * the ipc_space_kernel check in ipc_mqueue_send.
1189 */
1190
1191 port->ip_receiver_nameip_target.ipt_name = MACH_PORT_NULL((mach_port_t) 0);
1192 port->ip_receiverdata.receiver = IS_NULL((ipc_space_t) 0);
1193
1194 /*
1195 * For ipc_space_kernel, all ipc_port_clear_receiver does
1196 * is clean things up for the assertions in ipc_port_destroy.
1197 * For ipc_space_reply, there might be a waiting receiver.
1198 */
1199
1200 ipc_port_clear_receiver(port);
1201 ipc_port_destroy(port);
1202}
1203
1204#if MACH_KDB0
1205#define printf kdbprintf
1206
1207/*
1208 * Routine: ipc_port_print
1209 * Purpose:
1210 * Pretty-print a port for kdb.
1211 */
1212
1213void
1214ipc_port_print(port)
1215 ipc_port_t port;
1216{
1217 printf("port 0x%x\n", port);
1218
1219 indent += 2;
1220
1221 ipc_object_print(&port->ip_objectip_target.ipt_object);
1222 iprintf("receiver=0x%x", port->ip_receiverdata.receiver);
1223 printf(", receiver_name=0x%x\n", port->ip_receiver_nameip_target.ipt_name);
1224
1225 iprintf("mscount=%d", port->ip_mscount);
1226 printf(", srights=%d", port->ip_srights);
1227 printf(", sorights=%d\n", port->ip_sorights);
1228
1229 iprintf("nsrequest=0x%x", port->ip_nsrequest);
1230 printf(", pdrequest=0x%x", port->ip_pdrequest);
1231 printf(", dnrequests=0x%x\n", port->ip_dnrequests);
1232
1233 iprintf("pset=0x%x", port->ip_pset);
1234 printf(", seqno=%d", port->ip_seqno);
1235 printf(", msgcount=%d", port->ip_msgcount);
1236 printf(", qlimit=%d\n", port->ip_qlimit);
1237
1238 iprintf("kmsgs=0x%x", port->ip_messagesip_target.ipt_messages.imq_messages.ikmq_base);
1239 printf(", rcvrs=0x%x", port->ip_messagesip_target.ipt_messages.imq_threads.ithq_base);
1240 printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
1241 printf(", kobj=0x%x\n", port->ip_kobject);
1242
1243 indent -=2;
1244}
1245
1246#endif /* MACH_KDB */