102 |
|
|
103 |
if (thread->ipc_length < ikm->length) |
if (thread->ipc_length < ikm->length) |
104 |
{ |
{ |
105 |
thread->ipc_result = MSG_RCV_TOO_SMALL; |
thread->ipc_result = MSG_RECV_TOO_SMALL; |
106 |
thread_unlock (thread); |
thread_unlock (thread); |
107 |
SPLON (spl); |
SPLON (spl); |
108 |
|
|
110 |
goto retry_waiting_thread; |
goto retry_waiting_thread; |
111 |
} |
} |
112 |
|
|
113 |
thread->ipc_result = MSG_SUCCESS; |
thread->ipc_result = KERN_SUCCESS; |
114 |
thread->ipc_kmsg = ikm; |
thread->ipc_kmsg = ikm; |
115 |
thread_unlock (thread); |
thread_unlock (thread); |
116 |
SPLON (spl); |
SPLON (spl); |
127 |
/* Enqueue message on port message queue. Since we do not |
/* Enqueue message on port message queue. Since we do not |
128 |
want to block the kernel (??) we override message queue. */ |
want to block the kernel (??) we override message queue. */ |
129 |
|
|
130 |
result = ipc_mqueue_enqueue (send_port->mqueue, ikm, true); |
result = ipc_mqueue_enqueue (&send_port->mqueue, ikm, true); |
131 |
thread_lock_unlock (& send_port->lock); |
thread_lock_unlock (& send_port->lock); |
132 |
assert (result == false); |
assert (result == false); |
133 |
} |
} |
135 |
} |
} |
136 |
|
|
137 |
/* Message receive continuation point. */ |
/* Message receive continuation point. */ |
|
|
|
138 |
static void |
static void |
139 |
receive_continuation (void) |
receive_continuation (void) |
140 |
{ |
{ |
156 |
thread_syscall_return (kr); |
thread_syscall_return (kr); |
157 |
} |
} |
158 |
|
|
159 |
|
/* Timeout function for receving messages. This function is called |
160 |
|
when we timeout a receive operation. ??? lock thread? */ |
161 |
|
void |
162 |
|
timeout_receive (void *arg) |
163 |
|
{ |
164 |
|
struct thread *thread = (struct thread *) arg; |
165 |
|
struct ipc_port *port; |
166 |
|
|
167 |
|
trace_printf ("timeout receive"); |
168 |
|
|
169 |
|
port = thread->ipc_blocked_port; |
170 |
|
thread->ipc_blocked_port = 0; |
171 |
|
|
172 |
|
if (port) |
173 |
|
{ |
174 |
|
thread_lock_write (& port->lock); |
175 |
|
ipc_tqueue_remove (&port->waiting_threads, thread); |
176 |
|
thread_lock_unlock (& port->lock); |
177 |
|
} |
178 |
|
|
179 |
|
thread->ipc_result = MSG_RECV_TIMEOUT; |
180 |
|
thread_interrupt (thread); |
181 |
|
} |
182 |
|
|
183 |
|
/* Timeout function for sending messages. This function is called |
184 |
|
when we timeout a blocked thread waiting to send a message to a port. */ |
185 |
|
void |
186 |
|
timeout_send (void *arg) |
187 |
|
{ |
188 |
|
struct thread *thread = (struct thread *) arg; |
189 |
|
struct ipc_port *port; |
190 |
|
|
191 |
|
trace_printf ("timeout send"); |
192 |
|
|
193 |
|
port = thread->ipc_blocked_port; |
194 |
|
thread->ipc_blocked_port = 0; |
195 |
|
|
196 |
|
if (port) |
197 |
|
{ |
198 |
|
thread_lock_write (& port->lock); |
199 |
|
ipc_tqueue_remove (&port->blocked_threads, thread); |
200 |
|
thread_lock_unlock (& port->lock); |
201 |
|
} |
202 |
|
|
203 |
|
thread->ipc_result = MSG_SEND_TIMEOUT; |
204 |
|
thread_interrupt (thread); |
205 |
|
} |
206 |
|
|
207 |
|
|
208 |
/* User entry point for IPC send/receive. |
/* User entry point for IPC send/receive. |
209 |
|
|
219 |
internal_msg_trap (struct rtmk_msg_header *msgh, rtmk_msg_option_t options, |
internal_msg_trap (struct rtmk_msg_header *msgh, rtmk_msg_option_t options, |
220 |
rtmk_msg_size_t send_size, rtmk_port_t send_name, |
rtmk_msg_size_t send_size, rtmk_port_t send_name, |
221 |
rtmk_msg_size_t recv_size, rtmk_port_t recv_name, |
rtmk_msg_size_t recv_size, rtmk_port_t recv_name, |
222 |
rtmk_msg_timeout_t timeout) |
rtmk_msg_timeout_t timeout_value) |
223 |
{ |
{ |
224 |
struct thread *thread = THREAD_CURRENT (), *target; |
struct thread *thread = THREAD_CURRENT (), *target; |
225 |
struct ipc_object *object = THREAD_CURRENT()->task->ipc_object; |
struct ipc_object *object = THREAD_CURRENT()->task->ipc_object; |
239 |
|
|
240 |
if (options & RTMK_MSG_OPTION_RECEIVE) |
if (options & RTMK_MSG_OPTION_RECEIVE) |
241 |
{ |
{ |
242 |
ipc_object_lock (object); |
if (recv_name == RTMK_PORT_NULL || recv_name == RTMK_PORT_DEAD) |
243 |
|
return MSG_RECV_INVALID_SRC; |
244 |
|
|
245 |
|
ipc_object_lock (object); |
246 |
|
|
247 |
kr = ipc_object_lookup (object, recv_name, &entry); |
kr = ipc_object_lookup (object, recv_name, &entry); |
248 |
if (kr != KERN_SUCCESS) |
if (kr != KERN_SUCCESS) |
249 |
{ |
{ |
266 |
|
|
267 |
if (options & RTMK_MSG_OPTION_SEND) |
if (options & RTMK_MSG_OPTION_SEND) |
268 |
{ |
{ |
269 |
|
if (send_name == RTMK_PORT_NULL || send_name == RTMK_PORT_DEAD) |
270 |
|
return MSG_SEND_INVALID_DST; |
271 |
|
|
272 |
if (send_size < sizeof (struct rtmk_msg_header)) |
if (send_size < sizeof (struct rtmk_msg_header)) |
273 |
return MSG_SEND_TOO_SMALL; |
return MSG_SEND_TOO_SMALL; |
274 |
|
|
287 |
return KERN_INVALID_RIGHT; |
return KERN_INVALID_RIGHT; |
288 |
} |
} |
289 |
|
|
|
|
|
290 |
/* Obtain read lock to port. */ |
/* Obtain read lock to port. */ |
291 |
port = entry->ie_port; |
port = entry->ie_port; |
292 |
thread_lock_read (&port->lock); |
thread_lock_read (&port->lock); |
346 |
|
|
347 |
if (LIKELY (options & RTMK_MSG_OPTION_RECEIVE)) |
if (LIKELY (options & RTMK_MSG_OPTION_RECEIVE)) |
348 |
{ |
{ |
349 |
if (UNLIKELY (receive_port != reply_kmsg->remote_port)) |
if (UNLIKELY (receive_port != reply_kmsg->destination_port)) |
350 |
{ |
{ |
351 |
trace_printf ("rp %p kmsg rp %p %p esp %x", |
trace_printf ("rp %p kmsg rp %p %p esp %x", |
352 |
receive_port, reply_kmsg->remote_port, |
receive_port, reply_kmsg->destination_port, |
353 |
reply_kmsg->local_port, get_esp ()); |
reply_kmsg->reply_port, get_esp ()); |
354 |
trace_printf ("kmsg length %d", |
trace_printf ("kmsg length %d", |
355 |
reply_kmsg->header.msgh_length); |
reply_kmsg->header.msgh_length); |
356 |
goto enqueue_kernel_reply; |
goto enqueue_kernel_reply; |
425 |
next thread (reporting error to thread). */ |
next thread (reporting error to thread). */ |
426 |
if (target->ipc_length < kmsg->length) |
if (target->ipc_length < kmsg->length) |
427 |
{ |
{ |
428 |
target->ipc_result = MSG_RCV_TOO_SMALL; |
target->ipc_result = MSG_RECV_TOO_SMALL; |
429 |
|
|
430 |
thread_unlock (target); |
thread_unlock (target); |
431 |
SPLON (spl); |
SPLON (spl); |
438 |
|
|
439 |
/* TARGET is the thread that we can pass message to. */ |
/* TARGET is the thread that we can pass message to. */ |
440 |
|
|
441 |
|
/* We have to cancel any pending callout. */ |
442 |
|
untimeout (timeout_receive, target); |
443 |
|
|
444 |
target->ipc_result = KERN_SUCCESS; |
target->ipc_result = KERN_SUCCESS; |
445 |
target->ipc_kmsg = kmsg; |
target->ipc_kmsg = kmsg; |
446 |
target->ipc_blocked_port = 0; |
target->ipc_blocked_port = 0; |
464 |
assert (failed == false); |
assert (failed == false); |
465 |
|
|
466 |
enqueue_message_on_port: |
enqueue_message_on_port: |
467 |
|
result = ipc_mqueue_enqueue (&port->mqueue, kmsg, false); |
|
result = ipc_mqueue_enqueue (port->mqueue, kmsg, false); |
|
468 |
if (result == true |
if (result == true |
469 |
&& (options & RTMK_MSG_OPTION_NOBLOCK) == 0) |
&& (options & RTMK_MSG_OPTION_NOBLOCK) == 0) |
470 |
{ |
{ |
471 |
/* The port has reached its queue limit. What we have |
/* The port has reached its queue limit. What we have |
472 |
to do now is to put the thread to sleep until there's |
to do now is to put the thread to sleep until there's |
473 |
space available on the queue. */ |
space available on the queue. */ |
|
|
|
474 |
assert (0); |
assert (0); |
475 |
} |
} |
476 |
else if (result == true) |
else if (result == true) |
493 |
if (options & RTMK_MSG_OPTION_RECEIVE) |
if (options & RTMK_MSG_OPTION_RECEIVE) |
494 |
{ |
{ |
495 |
if (recv_size < sizeof (struct rtmk_msg_header)) |
if (recv_size < sizeof (struct rtmk_msg_header)) |
496 |
return MSG_RCV_TOO_SMALL; |
return MSG_RECV_TOO_SMALL; |
497 |
|
|
498 |
/* We get a read lock until we have to change anything in the port. */ |
/* We get a read lock until we have to change anything in the port. */ |
499 |
port = receive_port; |
port = receive_port; |
504 |
/* If we have message on queue we dequeue it and check size against |
/* If we have message on queue we dequeue it and check size against |
505 |
receive buffer. ??? dequeue first when size checked? */ |
receive buffer. ??? dequeue first when size checked? */ |
506 |
|
|
507 |
if (ipc_mqueue_empty (port->mqueue) == false) |
if (ipc_mqueue_empty (&port->mqueue) == false) |
508 |
{ |
{ |
509 |
kmsg = ipc_mqueue_first (port->mqueue); |
kmsg = ipc_mqueue_first (&port->mqueue); |
510 |
|
|
511 |
if (recv_size < kmsg->header.msgh_length) |
if (recv_size < kmsg->header.msgh_length) |
512 |
{ |
{ |
513 |
thread_lock_unlock (&port->lock); |
thread_lock_unlock (&port->lock); |
514 |
ipc_object_unlock (object); |
ipc_object_unlock (object); |
515 |
return MSG_RCV_TOO_SMALL; |
return MSG_RECV_TOO_SMALL; |
516 |
} |
} |
517 |
|
|
518 |
/* Upgrade to write lock for port. */ |
/* Upgrade to write lock for port. */ |
521 |
|
|
522 |
/* Remove message from port message queue and copy message into |
/* Remove message from port message queue and copy message into |
523 |
task address/ipc space. Discard message if we fail. */ |
task address/ipc space. Discard message if we fail. */ |
524 |
kmsg = ipc_mqueue_dequeue (port->mqueue); |
kmsg = ipc_mqueue_dequeue (& port->mqueue); |
525 |
|
|
526 |
kr = ipc_kmsg_copyout (thread->task, msgh, kmsg); |
kr = ipc_kmsg_copyout (thread->task, msgh, kmsg); |
527 |
if (kr != KERN_SUCCESS) |
if (kr != KERN_SUCCESS) |
556 |
/* Store pointer to user message buffer in threads scratch area. |
/* Store pointer to user message buffer in threads scratch area. |
557 |
Set maximum length of message. Unlock port when done. */ |
Set maximum length of message. Unlock port when done. */ |
558 |
|
|
559 |
|
/* ??? lock thread here? */ |
560 |
thread->scratch_area [0] = msgh; |
thread->scratch_area [0] = msgh; |
561 |
thread->ipc_length = recv_size; |
thread->ipc_length = recv_size; |
562 |
thread->ipc_blocked_port = port; |
thread->ipc_blocked_port = port; |
563 |
thread_lock_unlock (&port->lock); |
thread_lock_unlock (&port->lock); |
564 |
|
|
565 |
|
if (options & RTMK_MSG_OPTION_TIMEOUT) |
566 |
|
timeout (timeout_value, timeout_receive, thread); |
567 |
|
|
568 |
thread_wait ((int) port, &object->lock, receive_continuation); |
thread_wait ((int) port, &object->lock, receive_continuation); |
569 |
} |
} |
570 |
} |
} |