17 |
|
|
18 |
#include "tm.h" |
#include "tm.h" |
19 |
#include "trace.h" |
#include "trace.h" |
20 |
|
#include "task.h" |
21 |
|
|
22 |
#include "ipc-object.h" |
#include "ipc-object.h" |
23 |
#include "ipc-port.h" |
#include "ipc-port.h" |
114 |
|
|
115 |
/* Convenience function for removing ENTRY from OBJECT. */ |
/* Convenience function for removing ENTRY from OBJECT. */ |
116 |
|
|
117 |
static inline bool |
static bool |
118 |
remove_entry (struct ipc_object *object, struct ipc_entry *entry) |
remove_entry (struct ipc_object *object, struct ipc_entry *entry) |
119 |
{ |
{ |
120 |
if (IE_BITS_RIGHTS (entry->ie_bits) != RTMK_PORT_TYPE_SEND_ONCE) |
if (IE_BITS_RIGHTS (entry->ie_bits) & RTMK_PORT_TYPE_SEND_RIGHTS) |
121 |
ipc_reverse_remove (entry); |
ipc_reverse_remove (entry); |
122 |
|
|
123 |
if (entry->ie_key <= MTABLERIGHTS) |
if (entry->ie_key <= MTABLERIGHTS) |
239 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
240 |
} |
} |
241 |
|
|
242 |
|
/* Deallocate ENTRY (port right name is ENTRY->ie_key) from |
243 |
/* Convenience function for reserving space in OBJECT. */ |
OBJECT. We also remove from reverse-lookup table. */ |
244 |
static bool |
kern_return_t |
245 |
reserve_entry (struct ipc_object *object, struct ipc_entry **entryp, |
ipc_entry_dealloc (struct ipc_object *object, |
246 |
rtmk_port_t *namep) |
struct ipc_entry *entry) |
247 |
{ |
{ |
248 |
rtmk_port_t low, high, key; |
if (IE_BITS_RIGHTS (entry->ie_bits) != RTMK_PORT_TYPE_SEND_ONCE) |
249 |
struct ipc_entry *entry; |
ipc_reverse_remove (entry); |
|
bool result; |
|
|
|
|
|
/* First of all we try to reserve in the table. If we don't |
|
|
succeed with that we go on and try with the splay-tree. */ |
|
|
|
|
|
result = ipc_table_reserve (&object->tbl, entryp, namep); |
|
|
if (result == true) |
|
|
return true; |
|
|
|
|
|
/* Optimize for the case when the splay tree is empty. */ |
|
|
if (object->splay_tree.root == 0) |
|
|
{ |
|
|
entry = (struct ipc_entry *) kmem_cache_alloc (ipc_entry_cache); |
|
|
entry->ie_key = MTABLERIGHTS + 1; |
|
|
|
|
|
*namep = MTABLERIGHTS + 1; |
|
|
*entryp = entry; |
|
|
|
|
|
/* We can now insert it into the splay-tree */ |
|
|
entry->ie_left = entry->ie_right = 0; |
|
|
object->splay_tree.root = entry; |
|
|
return true; |
|
|
} |
|
|
|
|
|
/* Get the first entry. */ |
|
|
|
|
|
ipc_splay_tree_first (&object->splay_tree, &entry); |
|
|
key = entry->ie_key; |
|
|
result = true; |
|
|
|
|
|
while (result == true) |
|
|
{ |
|
|
rtmk_port_t diff; |
|
|
|
|
|
result = ipc_splay_tree_bounds (&object->splay_tree, key, |
|
|
&low, &high); |
|
|
|
|
|
/* If RESULT is false, then we know this was the last entry in |
|
|
tree. So what we do is: NAME = ++LAST . */ |
|
|
|
|
|
if (result == false) |
|
|
{ |
|
|
key = high + 1; |
|
|
break; |
|
|
} |
|
|
|
|
|
diff = key - low; |
|
|
if (diff >= 2) |
|
|
{ |
|
|
key = low + 1; |
|
|
goto allocate_and_return; |
|
|
} |
|
|
|
|
|
diff = high - key; |
|
|
if (diff >= 2) |
|
|
{ |
|
|
key = key + 1; |
|
|
goto allocate_and_return; |
|
|
} |
|
|
|
|
|
result = true; |
|
|
key = high; |
|
|
} |
|
|
|
|
|
allocate_and_return: |
|
|
|
|
|
entry = (struct ipc_entry *) kmem_cache_alloc (ipc_entry_cache); |
|
|
entry->ie_key = key; |
|
|
*entryp = entry; |
|
|
*namep = key; |
|
|
|
|
|
/* We can now insert it into the splay-tree */ |
|
250 |
|
|
251 |
ipc_splay_tree_insert (&object->splay_tree, key, entry); |
if (entry->ie_key <= MTABLERIGHTS) |
252 |
return true; |
ipc_table_remove (&object->tbl, entry->ie_key); |
253 |
|
else |
254 |
|
ipc_splay_tree_delete_node (&object->splay_tree, entry->ie_key, |
255 |
|
&entry); |
256 |
|
kmem_cache_free (ipc_entry_cache, entry); |
257 |
|
return KERN_SUCCESS; |
258 |
} |
} |
259 |
|
|
260 |
|
|
281 |
entry->ie_key = name; |
entry->ie_key = name; |
282 |
entry->ie_port = port; |
entry->ie_port = port; |
283 |
entry->ie_object = object; |
entry->ie_object = object; |
284 |
entry->ie_urefs = 1; |
entry->ie_urefs = 0; |
285 |
|
|
286 |
/* Set valid bit and right for port. */ |
/* Set valid bit and right for port. */ |
287 |
entry->ie_bits = IE_BITS_VALID | RTMK_PORT_TYPE_RECEIVE; |
entry->ie_bits = IE_BITS_VALID; |
|
|
|
288 |
|
|
289 |
/* We can insert it into the revese lookup hash table. */ |
/* We can insert it into the revese lookup hash table. */ |
290 |
ipc_reverse_insert (object, entry); |
ipc_reverse_insert (object, entry); |
296 |
return true; |
return true; |
297 |
} |
} |
298 |
|
|
299 |
/* Create right for PORT in OBJECT. MSGT describes what right the |
|
300 |
object should have to the port. Name is returned in NAMEP. */ |
/* Try to locate entry named NAME in OBJECT. Return pointer to |
301 |
|
entry structure in ENTRYP if found. Normal kernel return code. */ |
302 |
kern_return_t |
kern_return_t |
303 |
ipc_object_copyout (struct ipc_object *object, struct ipc_port *port, |
ipc_object_lookup (struct ipc_object *object, rtmk_port_t name, |
304 |
int msgt, rtmk_port_t *namep) |
struct ipc_entry **entryp) |
305 |
{ |
{ |
306 |
bool sonce = false, result; |
ipc_entry entry; |
307 |
struct ipc_entry *entry; |
bool result; |
|
|
|
|
/* SONCE is true if we should create send-once right. */ |
|
|
|
|
|
if (msgt == RTMK_MSG_TYPE_MAKE_SEND_ONCE) |
|
|
sonce = true; |
|
|
|
|
|
/* If it's not a send once right we first look in the reverse |
|
|
lookup table. */ |
|
308 |
|
|
309 |
if (sonce == false |
/* Try the "fast" lookup table first. */ |
310 |
&& ipc_reverse_lookup (object, port, &entry) == KERN_SUCCESS) |
|
311 |
|
if (name <= MTABLERIGHTS) |
312 |
{ |
{ |
313 |
entry->ie_bits = entry->ie_bits | convert_name_to_right (msgt); |
result = ipc_table_lookup (&object->tbl, name, entryp); |
314 |
entry->ie_urefs++; |
if (result == false) |
315 |
|
return KERN_INVALID_NAME; |
|
if (msgt == RTMK_MSG_TYPE_MAKE_SEND) |
|
|
entry->ie_port->srights++; |
|
|
|
|
|
*namep = entry->ie_key; |
|
316 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
317 |
} |
} |
318 |
|
|
319 |
result = reserve_entry (object, &entry, namep); |
/* We look in the splay-tree instead. */ |
|
assert (result); |
|
|
|
|
|
/* Fill entry structure with needed information. */ |
|
|
|
|
|
entry->ie_key = *namep; /* XXX just in case */ |
|
|
entry->ie_port = port; |
|
|
entry->ie_object = object; |
|
|
entry->ie_urefs = 1; |
|
|
|
|
|
/* Set valid bit and right for port. */ |
|
|
|
|
|
entry->ie_bits = IE_BITS_VALID | convert_name_to_right (msgt); |
|
320 |
|
|
321 |
/* If SONCE is false, then we can insert it into the revese lookup |
entry = (ipc_entry) ipc_splay_tree_lookup (&object->splay_tree, name); |
322 |
hash table aswell. */ |
if (entry == 0) |
323 |
|
return KERN_INVALID_NAME; |
324 |
|
|
325 |
if (sonce == false) |
*entryp = entry; |
326 |
ipc_reverse_insert (object, entry); |
return KERN_SUCCESS; |
327 |
|
} |
328 |
|
|
329 |
|
/* Remove NAME for OBJECT. Return IPC entry in *ENTRYP. */ |
330 |
|
kern_return_t |
331 |
|
ipc_object_remove (struct ipc_object *object, |
332 |
|
struct ipc_entry **entryp, rtmk_port_t name) |
333 |
|
{ |
334 |
|
kern_return_t kr; |
335 |
|
|
336 |
|
kr = ipc_object_lookup (object, name, entryp); |
337 |
|
if (kr != KERN_SUCCESS) |
338 |
|
return kr; |
339 |
|
remove_entry (object, *entryp); |
340 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
341 |
} |
} |
342 |
|
|
343 |
/* Copy right named NAME from OBJECT into kernel object space. |
/* Copy right named NAME from OBJECT into kernel object space. |
344 |
MSGT describes what type of right it is. DEALLOCP is true |
MSGT describes what type of right it is. *PORTP holds |
345 |
if *ENTRYP should be deallocated after it is used. */ |
port that right NAME held. */ |
346 |
|
|
347 |
kern_return_t |
kern_return_t |
348 |
ipc_object_copyin (struct ipc_object *object, rtmk_port_t name, |
ipc_object_copyin (struct ipc_object *object, rtmk_port_t name, |
349 |
int msgt, struct ipc_entry **entryp, bool *deallocp) |
int msgt, struct ipc_port **portp) |
350 |
{ |
{ |
351 |
struct ipc_entry *entry; |
kern_return_t kr = KERN_SUCCESS; |
352 |
kern_return_t kr; |
struct ipc_port *port; |
353 |
bool sonce = false; |
struct ipc_entry *ie; |
354 |
|
|
355 |
if (msgt == RTMK_MSG_TYPE_MOVE_SEND_ONCE) |
kr = ipc_object_lookup (object, name, &ie); |
356 |
sonce = true; |
if (kr) |
|
|
|
|
kr = ipc_object_lookup (object, name, &entry); |
|
|
if (kr != KERN_SUCCESS) |
|
357 |
return kr; |
return kr; |
358 |
*entryp = entry; |
port = ie->ie_port; |
359 |
|
|
360 |
|
switch (msgt) |
361 |
|
{ |
362 |
|
case RTMK_MSG_TYPE_MOVE_RECEIVE: |
363 |
|
{ |
364 |
|
int bits = ie->ie_bits; |
365 |
|
if (! (bits & RTMK_PORT_TYPE_RECEIVE)) |
366 |
|
goto invalid_right; |
367 |
|
|
368 |
|
thread_lock_write (&port->lock); |
369 |
|
assert (port->rcvobject == object); |
370 |
|
assert (port->rcvname == name); |
371 |
|
|
372 |
|
/* We move the receive right, but we still have send |
373 |
|
right to the port. We port into reverse lookup table. */ |
374 |
|
if (bits & RTMK_PORT_TYPE_SEND) |
375 |
|
{ |
376 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_SEND_RECEIVE); |
377 |
|
assert (ie->ie_urefs > 0); |
378 |
|
assert (port->srights > 0); |
379 |
|
|
380 |
|
ipc_reverse_insert (object, ie); |
381 |
|
port->ref_count++; |
382 |
|
} |
383 |
|
|
384 |
|
/* No send right(s) to port. We can deallocate entry. */ |
385 |
|
else |
386 |
|
{ |
387 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_RECEIVE); |
388 |
|
assert (ie->ie_urefs == 0); |
389 |
|
ie->ie_port = 0; |
390 |
|
} |
391 |
|
ie->ie_bits &= ~RTMK_PORT_TYPE_RECEIVE; |
392 |
|
|
393 |
|
port->rcvobject = 0; |
394 |
|
port->rcvname = RTMK_PORT_NULL; |
395 |
|
thread_lock_unlock (&port->lock); |
396 |
|
|
397 |
|
*portp = port; |
398 |
|
break; |
399 |
|
} |
400 |
|
|
401 |
|
case RTMK_MSG_TYPE_COPY_SEND: |
402 |
|
{ |
403 |
|
int bits = ie->ie_bits; |
404 |
|
if (! (bits & RTMK_PORT_TYPE_SEND_RIGHTS)) |
405 |
|
goto invalid_right; |
406 |
|
|
407 |
|
assert (ie->ie_urefs > 0); |
408 |
|
if ((bits & RTMK_PORT_TYPE_SEND) == 0) |
409 |
|
{ |
410 |
|
assert(IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_SEND_ONCE); |
411 |
|
assert(port->sorights > 0); |
412 |
|
goto invalid_right; |
413 |
|
} |
414 |
|
|
415 |
|
thread_lock_write (&port->lock); |
416 |
|
assert (port->srights > 0); |
417 |
|
port->ref_count++; |
418 |
|
port->srights++; |
419 |
|
thread_lock_unlock (&port->lock); |
420 |
|
|
421 |
|
*portp = port; |
422 |
|
break; |
423 |
|
} |
424 |
|
|
425 |
|
case RTMK_MSG_TYPE_MAKE_SEND: |
426 |
|
{ |
427 |
|
int bits = ie->ie_bits; |
428 |
|
if (! (bits & RTMK_PORT_TYPE_RECEIVE)) |
429 |
|
goto invalid_right; |
430 |
|
|
431 |
|
thread_lock_write (&port->lock); |
432 |
|
assert (port->rcvobject == object); |
433 |
|
assert (port->rcvname == name); |
434 |
|
|
435 |
|
port->ref_count++; |
436 |
|
port->srights++; |
437 |
|
port->msrights++; |
438 |
|
thread_lock_unlock (&port->lock); |
439 |
|
|
440 |
|
*portp = port; |
441 |
|
break; |
442 |
|
} |
443 |
|
|
444 |
|
case RTMK_MSG_TYPE_MOVE_SEND: |
445 |
|
{ |
446 |
|
int bits = ie->ie_bits; |
447 |
|
if (! (bits & RTMK_PORT_TYPE_SEND)) |
448 |
|
goto invalid_right; |
449 |
|
|
450 |
|
thread_lock_write (&port->lock); |
451 |
|
assert (ie->ie_urefs > 1); |
452 |
|
assert (port->srights > 1); |
453 |
|
|
454 |
|
if (ie->ie_urefs == 1) |
455 |
|
{ |
456 |
|
if (bits & RTMK_PORT_TYPE_RECEIVE) |
457 |
|
{ |
458 |
|
assert (port->rcvname == name); |
459 |
|
assert (port->rcvobject == object); |
460 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_SEND_RECEIVE); |
461 |
|
port->ref_count++; |
462 |
|
} |
463 |
|
else |
464 |
|
{ |
465 |
|
assert (IE_BITS_RIGHTS (bits) |
466 |
|
== RTMK_PORT_TYPE_SEND); |
467 |
|
ipc_reverse_remove (ie); |
468 |
|
ie->ie_port = 0; |
469 |
|
} |
470 |
|
ie->ie_bits &= ~RTMK_PORT_TYPE_SEND; |
471 |
|
ie->ie_urefs = 0; |
472 |
|
} |
473 |
|
else |
474 |
|
{ |
475 |
|
port->srights++; |
476 |
|
port->ref_count++; |
477 |
|
ie->ie_urefs -= 1; |
478 |
|
} |
479 |
|
thread_lock_unlock (&port->lock); |
480 |
|
|
481 |
|
*portp = port; |
482 |
|
break; |
483 |
|
} |
484 |
|
|
485 |
|
case RTMK_MSG_TYPE_MOVE_SEND_ONCE: |
486 |
|
{ |
487 |
|
int bits = ie->ie_bits; |
488 |
|
if (! (bits & RTMK_PORT_TYPE_SEND_ONCE)) |
489 |
|
goto invalid_right; |
490 |
|
|
491 |
|
thread_lock_write (&port->lock); |
492 |
|
assert (ie->ie_urefs > 0); |
493 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_SEND_ONCE); |
494 |
|
assert (port->sorights > 0); |
495 |
|
thread_lock_unlock (&port->lock); |
496 |
|
|
497 |
|
ie->ie_port = 0; |
498 |
|
ie->ie_bits &= ~RTMK_PORT_TYPE_SEND_ONCE; |
499 |
|
|
500 |
|
*portp = port; |
501 |
|
break; |
502 |
|
} |
503 |
|
|
504 |
|
case RTMK_MSG_TYPE_MAKE_SEND_ONCE: |
505 |
|
{ |
506 |
|
int bits = ie->ie_bits; |
507 |
|
if (! (bits & RTMK_PORT_TYPE_RECEIVE)) |
508 |
|
goto invalid_right; |
509 |
|
|
510 |
|
thread_lock_write (&port->lock); |
511 |
|
assert (port->rcvobject == object); |
512 |
|
assert (port->rcvname == name); |
513 |
|
|
514 |
|
port->ref_count++; |
515 |
|
port->sorights++; |
516 |
|
thread_lock_unlock (&port->lock); |
517 |
|
|
518 |
|
*portp = port; |
519 |
|
break; |
520 |
|
} |
521 |
|
} |
522 |
|
|
523 |
*deallocp = false; |
if (IE_BITS_RIGHTS (ie->ie_bits) == RTMK_PORT_TYPE_NONE) |
|
if (sonce == true) |
|
524 |
{ |
{ |
525 |
(void) remove_entry (object, entry); |
if (ie->ie_key <= MTABLERIGHTS) |
526 |
*deallocp = true; |
ipc_table_remove (&object->tbl, ie->ie_key); |
527 |
|
else |
528 |
|
ipc_splay_tree_delete_node (&object->splay_tree, ie->ie_key, |
529 |
|
&ie); |
530 |
|
kmem_cache_free (ipc_entry_cache, ie); |
531 |
} |
} |
532 |
|
return kr; |
533 |
|
|
534 |
return KERN_SUCCESS; |
invalid_right: |
535 |
|
return KERN_INVALID_RIGHT; |
536 |
} |
} |
537 |
|
|
538 |
/* Try to locate entry named NAME in OBJECT. Return pointer to |
static kern_return_t |
539 |
entry structure in ENTRYP if found. Normal kernel return code. */ |
right_copyout (struct ipc_object *object, struct ipc_port *port, |
540 |
|
int msgt, struct ipc_entry *entry, rtmk_port_t name) |
|
kern_return_t |
|
|
ipc_object_lookup (struct ipc_object *object, rtmk_port_t name, |
|
|
struct ipc_entry **entryp) |
|
541 |
{ |
{ |
542 |
ipc_entry entry; |
switch (msgt) |
|
bool result; |
|
|
|
|
|
/* Try the "fast" lookup table first. */ |
|
|
|
|
|
if (name <= MTABLERIGHTS) |
|
543 |
{ |
{ |
544 |
result = ipc_table_lookup (&object->tbl, name, entryp); |
case RTMK_MSG_TYPE_COPY_SEND: |
545 |
if (result == false) |
case RTMK_MSG_TYPE_MAKE_SEND: |
546 |
return KERN_INVALID_NAME; |
case RTMK_MSG_TYPE_MOVE_SEND: |
547 |
return KERN_SUCCESS; |
{ |
548 |
|
int bits = entry->ie_bits; |
549 |
|
|
550 |
|
assert(port->srights > 0); |
551 |
|
|
552 |
|
if (bits & RTMK_PORT_TYPE_SEND) |
553 |
|
{ |
554 |
|
assert (port->srights > 1); |
555 |
|
assert (entry->ie_urefs > 0); |
556 |
|
|
557 |
|
port->srights--; |
558 |
|
thread_lock_unlock (&port->lock); |
559 |
|
ipc_port_release (port); |
560 |
|
} |
561 |
|
else if (bits & RTMK_PORT_TYPE_RECEIVE) |
562 |
|
{ |
563 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_RECEIVE); |
564 |
|
assert (entry->ie_urefs == 0); |
565 |
|
|
566 |
|
/* transfer send right to entry */ |
567 |
|
thread_lock_unlock (&port->lock); |
568 |
|
ipc_port_release (port); |
569 |
|
ipc_reverse_insert (object, entry); |
570 |
|
} |
571 |
|
else |
572 |
|
{ |
573 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_NONE); |
574 |
|
assert (entry->ie_urefs == 0); |
575 |
|
|
576 |
|
/* transfer send right and ref to entry */ |
577 |
|
thread_lock_unlock (&port->lock); |
578 |
|
ipc_reverse_insert (object, entry); |
579 |
|
} |
580 |
|
entry->ie_bits = (bits | RTMK_PORT_TYPE_SEND); |
581 |
|
entry->ie_urefs += 1; |
582 |
|
break; |
583 |
|
} |
584 |
|
|
585 |
|
case RTMK_MSG_TYPE_MAKE_SEND_ONCE: |
586 |
|
case RTMK_MSG_TYPE_MOVE_SEND_ONCE: |
587 |
|
{ |
588 |
|
int bits = entry->ie_bits; |
589 |
|
|
590 |
|
assert(IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_NONE); |
591 |
|
assert(port->sorights > 0); |
592 |
|
thread_lock_unlock (&port->lock); |
593 |
|
|
594 |
|
/* transfer send-once right and ref to entry */ |
595 |
|
entry->ie_bits = bits | (RTMK_PORT_TYPE_SEND_ONCE); |
596 |
|
entry->ie_urefs = 1; |
597 |
|
break; |
598 |
|
} |
599 |
|
|
600 |
|
case RTMK_MSG_TYPE_MOVE_RECEIVE: |
601 |
|
{ |
602 |
|
int bits = entry->ie_bits; |
603 |
|
|
604 |
|
assert (port->rcvname == RTMK_PORT_NULL); |
605 |
|
|
606 |
|
port->rcvname = name; |
607 |
|
port->rcvobject = object; |
608 |
|
|
609 |
|
assert ((bits & RTMK_PORT_TYPE_RECEIVE) == 0); |
610 |
|
|
611 |
|
if (bits & RTMK_PORT_TYPE_SEND) |
612 |
|
{ |
613 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_SEND); |
614 |
|
assert (entry->ie_urefs > 0); |
615 |
|
assert (port->srights > 0); |
616 |
|
|
617 |
|
thread_lock_unlock (&port->lock); |
618 |
|
ipc_port_release (port); |
619 |
|
ipc_reverse_remove (entry); |
620 |
|
} |
621 |
|
else |
622 |
|
{ |
623 |
|
assert (IE_BITS_RIGHTS (bits) == RTMK_PORT_TYPE_NONE); |
624 |
|
assert (entry->ie_urefs == 0); |
625 |
|
|
626 |
|
/* transfer ref to entry */ |
627 |
|
thread_lock_unlock (&port->lock); |
628 |
|
} |
629 |
|
entry->ie_bits = bits | RTMK_PORT_TYPE_RECEIVE; |
630 |
|
break; |
631 |
|
} |
632 |
} |
} |
633 |
|
return KERN_SUCCESS; |
634 |
|
} |
635 |
|
|
|
/* We look in the splay-tree instead. */ |
|
636 |
|
|
637 |
entry = (ipc_entry) ipc_splay_tree_lookup (&object->splay_tree, name); |
/* Inserts rights for PORT into OBJECT. MSGT determines |
638 |
if (entry == 0) |
what type of right we should insert. NAME is the right |
639 |
return KERN_INVALID_NAME; |
name in OBJECT. If there's already a right for PORT |
640 |
|
in OBJECT, NAME must match that rights name. */ |
641 |
|
kern_return_t |
642 |
|
ipc_object_copyout_name (struct ipc_object *object, |
643 |
|
struct ipc_port *port, int msgt, |
644 |
|
rtmk_port_t name) |
645 |
|
{ |
646 |
|
struct ipc_entry *entry, *oentry; |
647 |
|
kern_return_t kr; |
648 |
|
|
649 |
*entryp = entry; |
kr = ipc_object_lookup (object, name, &oentry); |
650 |
return KERN_SUCCESS; |
if (kr == KERN_SUCCESS) |
651 |
|
{ |
652 |
|
if (oentry->ie_port != port) |
653 |
|
return KERN_INVALID_NAME; |
654 |
|
entry = oentry; |
655 |
|
} |
656 |
|
else |
657 |
|
{ |
658 |
|
kr = ipc_entry_alloc_name (object, &entry, name); |
659 |
|
if (kr != KERN_SUCCESS) |
660 |
|
return kr; |
661 |
|
entry->ie_port = port; |
662 |
|
entry->ie_key = name; |
663 |
|
entry->ie_object = object; |
664 |
|
entry->ie_urefs = 0; |
665 |
|
entry->ie_bits = IE_BITS_VALID; |
666 |
|
} |
667 |
|
thread_lock_write (&port->lock); |
668 |
|
return right_copyout (object, port, msgt, entry, name); |
669 |
} |
} |
670 |
|
|
671 |
/* Insert rights for port PORT specified by MSGT into OBJECT. |
/* Create right for PORT in OBJECT. MSGT describes what right the |
672 |
NAMEP is the name that we should use. */ |
object should have to the port. Name is returned in NAMEP. */ |
673 |
kern_return_t |
kern_return_t |
674 |
ipc_object_insert (struct ipc_object *object, struct ipc_port *port, |
ipc_object_copyout (struct ipc_object *object, struct ipc_port *port, |
675 |
int msgt, rtmk_port_t name) |
int msgt, rtmk_port_t *namep) |
676 |
{ |
{ |
677 |
struct ipc_entry *entry; |
struct ipc_entry *entry; |
678 |
bool sonce = false; |
kern_return_t kr; |
|
int err, right; |
|
|
|
|
|
right = convert_name_to_right (msgt); |
|
|
|
|
|
/* SONCE is true if we should create send-once right. */ |
|
|
if (msgt == RTMK_MSG_TYPE_MAKE_SEND_ONCE |
|
|
|| msgt == RTMK_MSG_TYPE_MOVE_SEND_ONCE) |
|
|
sonce = true; |
|
679 |
|
|
680 |
/* If the target already holds send or receive rights for |
for (;;) |
|
the port, then name should denote those rights in the target. */ |
|
|
if (ipc_reverse_lookup (object, port, &entry) == KERN_SUCCESS) |
|
681 |
{ |
{ |
682 |
if (entry->ie_key != name) |
if ((msgt != RTMK_MSG_TYPE_MAKE_SEND_ONCE |
683 |
return KERN_RIGHT_EXISTS; |
&& msgt != RTMK_MSG_TYPE_MOVE_SEND_ONCE)) |
|
|
|
|
switch (right) |
|
684 |
{ |
{ |
685 |
case RTMK_PORT_TYPE_SEND: |
kr = ipc_reverse_lookup (object, port, &entry); |
686 |
port->srights++; |
if (kr == KERN_SUCCESS) |
687 |
break; |
{ |
688 |
case RTMK_PORT_TYPE_RECEIVE: |
thread_lock_write (&port->lock); |
689 |
assert (0); |
break; |
690 |
break; |
} |
|
|
|
|
case RTMK_PORT_TYPE_SEND_ONCE: |
|
|
port->sorights++; |
|
|
break; |
|
691 |
} |
} |
|
|
|
|
entry->ie_urefs++; |
|
|
entry->ie_bits = entry->ie_bits | right; |
|
|
return KERN_SUCCESS; |
|
|
} |
|
692 |
|
|
693 |
/* Allocate entry in OBJECT. This also checks if NAME already |
kr = ipc_entry_alloc (object, &entry, namep); |
694 |
exists. ENTRY contains no data (not even key). */ |
if (kr) |
695 |
err = ipc_entry_alloc_name (object, &entry, name); |
return kr; |
696 |
if (err) |
|
697 |
return err; |
thread_lock_write (&port->lock); |
698 |
|
entry->ie_port = port; |
699 |
|
entry->ie_key = *namep; |
700 |
|
entry->ie_urefs = 0; |
701 |
|
entry->ie_bits = IE_BITS_VALID; |
702 |
|
entry->ie_object = object; |
703 |
|
break; |
704 |
|
} |
705 |
|
*namep = entry->ie_key; |
706 |
|
|
707 |
|
/* This unlocks port. */ |
708 |
|
return right_copyout (object, port, msgt, entry, *namep); |
709 |
|
} |
710 |
|
|
711 |
/* Fill entry structure with needed information. */ |
|
712 |
entry->ie_key = name; |
/* Copyout right PORT. PORT is destination for a |
713 |
entry->ie_port = port; |
message. Name of right is returned in *NAMEP. */ |
714 |
entry->ie_object = object; |
kern_return_t |
715 |
|
ipc_object_copyout_dest (struct ipc_object *object, |
716 |
|
struct ipc_port *port, int msgt_name, |
717 |
|
rtmk_port_t *namep) |
718 |
|
{ |
719 |
|
rtmk_port_t name; |
720 |
|
|
721 |
|
/* If the space is the receiver/owner of the object, |
722 |
|
then we quietly consume the right and return |
723 |
|
the space's name for the object. Otherwise |
724 |
|
we destroy the right and return RTMK_PORT_NULL. */ |
725 |
|
switch (msgt_name) |
726 |
|
{ |
727 |
|
case RTMK_MSG_TYPE_COPY_SEND: |
728 |
|
case RTMK_MSG_TYPE_MOVE_SEND: |
729 |
|
case RTMK_MSG_TYPE_MAKE_SEND: |
730 |
|
{ |
731 |
|
thread_lock_write (&port->lock); |
732 |
|
assert (port->srights > 0); |
733 |
|
--port->srights; |
734 |
|
|
735 |
|
if (port->rcvobject == object) |
736 |
|
name = port->rcvname; |
737 |
|
else |
738 |
|
name = RTMK_PORT_NULL; |
739 |
|
thread_lock_unlock (&port->lock); |
740 |
|
break; |
741 |
|
} |
742 |
|
|
743 |
/* Set valid bit and right for port. */ |
case RTMK_MSG_TYPE_MAKE_SEND_ONCE: |
744 |
entry->ie_bits = IE_BITS_VALID | right; |
case RTMK_MSG_TYPE_MOVE_SEND_ONCE: |
745 |
|
{ |
746 |
|
thread_lock_write (&port->lock); |
747 |
|
assert (port->sorights > 0); |
748 |
|
|
749 |
|
if (port->rcvobject == object) |
750 |
|
{ |
751 |
|
/* quietly consume the send-once right */ |
752 |
|
port->sorights--; |
753 |
|
name = port->rcvname; |
754 |
|
thread_lock_unlock (&port->lock); |
755 |
|
} |
756 |
|
else |
757 |
|
{ |
758 |
|
/* A very bizarre case. The message |
759 |
|
was received, but before this copyout |
760 |
|
happened the space lost receive rights. |
761 |
|
We can't quietly consume the soright |
762 |
|
out from underneath some other task, |
763 |
|
so generate a send-once notification. */ |
764 |
|
port->ref_count++; |
765 |
|
thread_lock_unlock (&port->lock); |
766 |
|
|
767 |
|
name = RTMK_PORT_NULL; |
768 |
|
} |
769 |
|
break; |
770 |
|
} |
771 |
|
|
772 |
|
default: |
773 |
|
panic ("ipc_object_copyout_dest: strange rights"); |
774 |
|
} |
775 |
|
|
776 |
/* If SONCE is false, then we can insert it into the revese lookup |
*namep = name; |
|
hash table aswell. */ |
|
|
if (sonce == false) |
|
|
ipc_reverse_insert (object, entry); |
|
|
|
|
777 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
778 |
} |
} |
779 |
|
|
780 |
/* Remove NAME for OBJECT. Return IPC entry in *ENTRYP. */ |
/* Copyin a naked capability, PORT, from the kernel. |
781 |
|
PORT is the capability. MSGT_NAME is transit type. */ |
782 |
kern_return_t |
kern_return_t |
783 |
ipc_object_remove (struct ipc_object *object, |
ipc_object_copyin_from_kernel (struct ipc_port *port, |
784 |
struct ipc_entry **entryp, rtmk_port_t name) |
int msgt_name) |
785 |
{ |
{ |
786 |
kern_return_t kr; |
switch (msgt_name) |
787 |
|
{ |
788 |
kr = ipc_object_lookup (object, name, entryp); |
/* Transfering a receive right from the kernel. |
789 |
if (kr != KERN_SUCCESS) |
The receive object must be the kernel. */ |
790 |
return kr; |
case RTMK_MSG_TYPE_MOVE_RECEIVE: |
791 |
remove_entry (object, *entryp); |
{ |
792 |
|
thread_lock_write (&port->lock); |
793 |
|
assert (port->rcvobject == IPC_OBJECT_KERNEL ()); |
794 |
|
port->rcvobject = 0; |
795 |
|
port->rcvname = RTMK_PORT_NULL; |
796 |
|
port->msrights = 0; |
797 |
|
thread_lock_unlock (&port->lock); |
798 |
|
break; |
799 |
|
} |
800 |
|
|
801 |
|
/* Copy a send right from the kernel to a user |
802 |
|
IPC object. We just increase the send right count. */ |
803 |
|
case RTMK_MSG_TYPE_COPY_SEND: |
804 |
|
{ |
805 |
|
thread_lock_write (&port->lock); |
806 |
|
port->ref_count++; |
807 |
|
port->srights++; |
808 |
|
thread_lock_unlock (&port->lock); |
809 |
|
break; |
810 |
|
} |
811 |
|
|
812 |
|
/* Make a send right in a user IPC object. The |
813 |
|
kernel should hold the receive right. */ |
814 |
|
case RTMK_MSG_TYPE_MAKE_SEND: |
815 |
|
{ |
816 |
|
thread_lock_write (&port->lock); |
817 |
|
assert (port->rcvobject == IPC_OBJECT_KERNEL ()); |
818 |
|
port->ref_count++; |
819 |
|
port->srights++; |
820 |
|
port->msrights++; |
821 |
|
thread_lock_unlock (&port->lock); |
822 |
|
break; |
823 |
|
} |
824 |
|
|
825 |
|
/* Move send right into user IPC object. */ |
826 |
|
case RTMK_MSG_TYPE_MOVE_SEND: |
827 |
|
break; |
828 |
|
|
829 |
|
/* Move send-once right into user IPC object. */ |
830 |
|
case RTMK_MSG_TYPE_MOVE_SEND_ONCE: |
831 |
|
break; |
832 |
|
|
833 |
|
/* Make a send-once right user IPC object. */ |
834 |
|
case RTMK_MSG_TYPE_MAKE_SEND_ONCE: |
835 |
|
{ |
836 |
|
thread_lock_write (&port->lock); |
837 |
|
assert (port->rcvobject == IPC_OBJECT_KERNEL ()); |
838 |
|
port->ref_count++; |
839 |
|
port->sorights++; |
840 |
|
thread_lock_unlock (&port->lock); |
841 |
|
break; |
842 |
|
} |
843 |
|
} |
844 |
return KERN_SUCCESS; |
return KERN_SUCCESS; |
845 |
} |
} |