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), |