236 |
|
|
237 |
|
|
238 |
/* Obtain read lock to port. */ |
/* Obtain read lock to port. */ |
|
|
|
239 |
port = entry->ie_port; |
port = entry->ie_port; |
240 |
thread_lock_read (&port->lock); |
thread_lock_read (&port->lock); |
241 |
|
|
242 |
|
/* If port belongs to a port set -- use that message queue |
243 |
|
instead. For a short time we must hold both locks. */ |
244 |
|
if (port->pset) |
245 |
|
{ |
246 |
|
struct ipc_port *member = port; |
247 |
|
|
248 |
|
thread_lock_read (&port->pset->lock); |
249 |
|
port = port->pset; |
250 |
|
thread_lock_unlock (&member->lock); |
251 |
|
} |
252 |
|
|
253 |
/* Check if we are sending a intra task message. |
/* Check if we are sending a intra task message. |
254 |
If we are, we can optimize at some points. */ |
If we are, we can optimize at some points. */ |
|
|
|
255 |
intratask_p = (port->rcvobject == object); |
intratask_p = (port->rcvobject == object); |
256 |
|
|
257 |
/* Copy message into a kernel message buffer. */ |
/* Copy message into a kernel message buffer. */ |
275 |
|
|
276 |
reply_kmsg = ipc_kmsg_alloc (200); |
reply_kmsg = ipc_kmsg_alloc (200); |
277 |
memset (&reply_kmsg->header, 0, sizeof (struct rtmk_msg_header)); |
memset (&reply_kmsg->header, 0, sizeof (struct rtmk_msg_header)); |
278 |
|
|
279 |
|
/* We unlock the object before calling the kernel demuxer. |
280 |
|
Right after the demux, we acquire it again. */ |
281 |
|
ipc_object_unlock (object); |
282 |
kr = rtmk__demux (&kmsg->header, &reply_kmsg->header); |
kr = rtmk__demux (&kmsg->header, &reply_kmsg->header); |
283 |
|
ipc_object_lock (object); |
284 |
|
|
285 |
if (LIKELY (kr == RIG_RESULT_NOTIFY)) |
if (LIKELY (kr == RIG_RESULT_NOTIFY)) |
286 |
{ |
{ |
305 |
} |
} |
306 |
|
|
307 |
/* ??? check so that the message fits in the buffer. */ |
/* ??? check so that the message fits in the buffer. */ |
|
|
|
308 |
if (reply_kmsg->header.msgh_length > recv_size) |
if (reply_kmsg->header.msgh_length > recv_size) |
309 |
assert (0); |
assert (0); |
310 |
|
|
|
|
|
311 |
/* Copy kernel reply message into receiving task. */ |
/* Copy kernel reply message into receiving task. */ |
|
|
|
312 |
kr = ipc_kmsg_copyout (thread->task, msgh, reply_kmsg); |
kr = ipc_kmsg_copyout (thread->task, msgh, reply_kmsg); |
313 |
if (kr != KERN_SUCCESS) |
if (kr != KERN_SUCCESS) |
314 |
{ |
{ |
320 |
} |
} |
321 |
|
|
322 |
/* Free message and return as fast as possible. */ |
/* Free message and return as fast as possible. */ |
|
|
|
323 |
ipc_kmsg_free (reply_kmsg); |
ipc_kmsg_free (reply_kmsg); |
324 |
kr = KERN_SUCCESS; |
kr = KERN_SUCCESS; |
325 |
goto done_with_kernel_rpc; |
goto done_with_kernel_rpc; |
352 |
/* If sending to an ordinary port, check if theres any waiting |
/* If sending to an ordinary port, check if theres any waiting |
353 |
threads that we can pass the message to. Note that both port |
threads that we can pass the message to. Note that both port |
354 |
and IPC object is locked. */ |
and IPC object is locked. */ |
|
|
|
355 |
else if (ipc_tqueue_empty (&port->waiting_threads) == false) |
else if (ipc_tqueue_empty (&port->waiting_threads) == false) |
356 |
{ |
{ |
357 |
bool failed; |
bool failed; |
388 |
|
|
389 |
target->ipc_result = KERN_SUCCESS; |
target->ipc_result = KERN_SUCCESS; |
390 |
target->ipc_kmsg = kmsg; |
target->ipc_kmsg = kmsg; |
391 |
|
target->ipc_blocked_port = 0; |
392 |
thread_unlock (target); |
thread_unlock (target); |
393 |
SPLON (spl); |
SPLON (spl); |
394 |
|
|
399 |
} |
} |
400 |
|
|
401 |
/* We have to enqueue the message on the ports message queue. */ |
/* We have to enqueue the message on the ports message queue. */ |
|
|
|
402 |
else |
else |
403 |
{ |
{ |
404 |
bool failed, result; |
bool failed, result; |
463 |
} |
} |
464 |
|
|
465 |
/* Upgrade to write lock for port. */ |
/* Upgrade to write lock for port. */ |
|
|
|
466 |
while (thread_lock_read_to_write (&port->lock)) |
while (thread_lock_read_to_write (&port->lock)) |
467 |
assert (0); /* ??? block? */ |
assert (0); /* ??? block? */ |
468 |
|
|
469 |
/* Remove message from port message queue and copy message into |
/* Remove message from port message queue and copy message into |
470 |
task address/ipc space. Discard message if we fail. */ |
task address/ipc space. Discard message if we fail. */ |
|
|
|
471 |
kmsg = ipc_mqueue_dequeue (port->mqueue); |
kmsg = ipc_mqueue_dequeue (port->mqueue); |
472 |
|
|
473 |
kr = ipc_kmsg_copyout (thread->task, msgh, kmsg); |
kr = ipc_kmsg_copyout (thread->task, msgh, kmsg); |
496 |
|
|
497 |
/* If there is no message on the queue we have to wait for one |
/* If there is no message on the queue we have to wait for one |
498 |
to arrive. We block until someone else wakes us up. */ |
to arrive. We block until someone else wakes us up. */ |
|
|
|
499 |
else |
else |
500 |
{ |
{ |
501 |
ipc_tqueue_enqueue (&port->waiting_threads, thread); |
ipc_tqueue_enqueue (&port->waiting_threads, thread); |
505 |
|
|
506 |
thread->scratch_area [0] = msgh; |
thread->scratch_area [0] = msgh; |
507 |
thread->ipc_length = recv_size; |
thread->ipc_length = recv_size; |
508 |
|
thread->ipc_blocked_port = port; |
509 |
thread_lock_unlock (&port->lock); |
thread_lock_unlock (&port->lock); |
510 |
|
|
511 |
thread_wait ((int) port, &object->lock, receive_continuation); |
thread_wait ((int) port, &object->lock, receive_continuation); |