Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3022 → Rev 4055

/branches/dd/kernel/generic/src/ipc/ipc.c
43,6 → 43,7
#include <synch/waitq.h>
#include <synch/synch.h>
#include <ipc/ipc.h>
#include <ipc/kbox.h>
#include <errno.h>
#include <mm/slab.h>
#include <arch.h>
51,6 → 52,7
#include <debug.h>
 
#include <print.h>
#include <console/console.h>
#include <proc/thread.h>
#include <arch/interrupt.h>
#include <ipc/irq.h>
66,7 → 68,7
*/
static void _ipc_call_init(call_t *call)
{
memsetb((uintptr_t) call, sizeof(*call), 0);
memsetb(call, sizeof(*call), 0);
call->callerbox = &TASK->answerbox;
call->sender = TASK;
call->buffer = NULL;
87,7 → 89,8
call_t *call;
 
call = slab_alloc(ipc_call_slab, flags);
_ipc_call_init(call);
if (call)
_ipc_call_init(call);
 
return call;
}
160,7 → 163,7
*/
void ipc_phone_init(phone_t *phone)
{
mutex_initialize(&phone->lock);
mutex_initialize(&phone->lock, MUTEX_PASSIVE);
phone->callee = NULL;
phone->state = IPC_PHONE_FREE;
atomic_set(&phone->active_calls, 0);
170,8 → 173,10
*
* @param phone Destination kernel phone structure.
* @param request Call structure with request.
*
* @return EOK on success or EINTR if the sleep was interrupted.
*/
void ipc_call_sync(phone_t *phone, call_t *request)
int ipc_call_sync(phone_t *phone, call_t *request)
{
answerbox_t sync_box;
 
181,7 → 186,10
request->callerbox = &sync_box;
 
ipc_call(phone, request);
ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
if (!ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT,
SYNCH_FLAGS_INTERRUPTIBLE))
return EINTR;
return EOK;
}
 
/** Answer a message which was not dispatched and is not listed in any queue.
194,6 → 202,13
 
call->flags |= IPC_CALL_ANSWERED;
 
if (call->flags & IPC_CALL_FORWARDED) {
if (call->caller_phone) {
/* Demasquerade the caller phone. */
call->data.phone = call->caller_phone;
}
}
 
spinlock_lock(&callerbox->lock);
list_append(&call->link, &callerbox->answers);
spinlock_unlock(&callerbox->lock);
346,8 → 361,11
list_remove(&call->link);
spinlock_unlock(&oldbox->lock);
 
if (mode & IPC_FF_ROUTE_FROM_ME)
if (mode & IPC_FF_ROUTE_FROM_ME) {
if (!call->caller_phone)
call->caller_phone = call->data.phone;
call->data.phone = newphone;
}
 
return ipc_call(newphone, call);
}
411,7 → 429,7
*
* @param lst Head of the list to be cleaned up.
*/
static void ipc_cleanup_call_list(link_t *lst)
void ipc_cleanup_call_list(link_t *lst)
{
call_t *call;
 
426,33 → 444,31
}
}
 
/** Cleans up all IPC communication of the current task.
/** Disconnects all phones connected to an answerbox.
*
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
* have to change it as well if you want to cleanup other tasks than TASK.
* @param box Answerbox to disconnect phones from.
* @param notify_box If true, the answerbox will get a hangup message for
* each disconnected phone.
*/
void ipc_cleanup(void)
void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
{
int i;
call_t *call;
phone_t *phone;
DEADLOCK_PROBE_INIT(p_phonelck);
ipl_t ipl;
call_t *call;
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
call = notify_box ? ipc_call_alloc(0) : NULL;
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&TASK->answerbox);
 
/* Disconnect all phones connected to our answerbox */
restart_phones:
spinlock_lock(&TASK->answerbox.lock);
while (!list_empty(&TASK->answerbox.connected_phones)) {
phone = list_get_instance(TASK->answerbox.connected_phones.next,
ipl = interrupts_disable();
spinlock_lock(&box->lock);
while (!list_empty(&box->connected_phones)) {
phone = list_get_instance(box->connected_phones.next,
phone_t, link);
if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
spinlock_unlock(&TASK->answerbox.lock);
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
goto restart_phones;
}
459,13 → 475,70
/* Disconnect phone */
ASSERT(phone->state == IPC_PHONE_CONNECTED);
 
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
list_remove(&phone->link);
 
if (notify_box) {
mutex_unlock(&phone->lock);
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
 
/*
* Send one message to the answerbox for each
* phone. Used to make sure the kbox thread
* wakes up after the last phone has been
* disconnected.
*/
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
 
/* Allocate another call in advance */
call = ipc_call_alloc(0);
 
/* Must start again */
goto restart_phones;
}
 
mutex_unlock(&phone->lock);
}
 
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
 
/* Free unused call */
if (call)
ipc_call_free(call);
}
 
/** Cleans up all IPC communication of the current task.
*
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
* have to change it as well if you want to cleanup other tasks than TASK.
*/
void ipc_cleanup(void)
{
int i;
call_t *call;
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&TASK->answerbox);
 
/* Disconnect all phones connected to our regular answerbox */
ipc_answerbox_slam_phones(&TASK->answerbox, false);
 
#ifdef CONFIG_UDEBUG
/* Clean up kbox thread and communications */
ipc_kbox_cleanup();
#endif
 
/* Answer all messages in 'calls' and 'dispatched_calls' queues */
spinlock_lock(&TASK->answerbox.lock);
ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
ipc_cleanup_call_list(&TASK->answerbox.calls);
spinlock_unlock(&TASK->answerbox.lock);
501,7 → 574,13
(call->flags & IPC_CALL_NOTIF));
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
atomic_dec(&TASK->active_calls);
/*
* Record the receipt of this call in the current task's counter
* of active calls. IPC_M_PHONE_HUNGUP calls do not contribute
* to this counter so do not record answers to them either.
*/
if (!(call->flags & IPC_CALL_DISCARD_ANSWER))
atomic_dec(&TASK->active_calls);
ipc_call_free(call);
}
}
562,7 → 641,7
default:
break;
}
printf("active: %d\n",
printf("active: %ld\n",
atomic_get(&task->phones[i].active_calls));
}
mutex_unlock(&task->phones[i].lock);
575,8 → 654,10
for (tmp = task->answerbox.calls.next; tmp != &task->answerbox.calls;
tmp = tmp->next) {
call = list_get_instance(tmp, call_t, link);
printf("Callid: %p Srctask:%llu M:%d A1:%d A2:%d A3:%d "
"A4:%d A5:%d Flags:%x\n", call, call->sender->taskid,
printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun
" A1:%" PRIun " A2:%" PRIun " A3:%" PRIun
" A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call,
call->sender->taskid,
IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
584,12 → 665,14
}
/* Print answerbox - calls */
printf("ABOX - DISPATCHED CALLS:\n");
for (tmp = task->answerbox.dispatched_calls.next;
tmp != &task->answerbox.dispatched_calls;
tmp = tmp->next) {
for (tmp = task->answerbox.dispatched_calls.next;
tmp != &task->answerbox.dispatched_calls;
tmp = tmp->next) {
call = list_get_instance(tmp, call_t, link);
printf("Callid: %p Srctask:%llu M:%d A1:%d A2:%d A3:%d "
"A4:%d A5:%d Flags:%x\n", call, call->sender->taskid,
printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun
" A1:%" PRIun " A2:%" PRIun " A3:%" PRIun
" A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call,
call->sender->taskid,
IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
597,10 → 680,12
}
/* Print answerbox - calls */
printf("ABOX - ANSWERS:\n");
for (tmp = task->answerbox.answers.next; tmp != &task->answerbox.answers;
for (tmp = task->answerbox.answers.next;
tmp != &task->answerbox.answers;
tmp = tmp->next) {
call = list_get_instance(tmp, call_t, link);
printf("Callid:%p M:%d A1:%d A2:%d A3:%d A4:%d A5:%d Flags:%x\n",
printf("Callid:%p M:%" PRIun " A1:%" PRIun " A2:%" PRIun
" A3:%" PRIun " A4:%" PRIun " A5:%" PRIun " Flags:%x\n",
call, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),