34,7 → 34,7 |
|
/* Lock ordering |
* |
* First the answerbox, then the phone |
* First the answerbox, then the phone. |
*/ |
|
#include <synch/spinlock.h> |
53,27 → 53,33 |
#include <arch/interrupt.h> |
#include <ipc/irq.h> |
|
/* Open channel that is assigned automatically to new tasks */ |
/** Open channel that is assigned automatically to new tasks */ |
answerbox_t *ipc_phone_0 = NULL; |
|
static slab_cache_t *ipc_call_slab; |
|
/* Initialize new call */ |
/** Initialize a call structure. |
* |
* @param call Call structure to be initialized. |
*/ |
static void _ipc_call_init(call_t *call) |
{ |
memsetb((uintptr_t)call, sizeof(*call), 0); |
memsetb((uintptr_t) call, sizeof(*call), 0); |
call->callerbox = &TASK->answerbox; |
call->sender = TASK; |
} |
|
/** Allocate & initialize call structure |
/** Allocate and initialize a call structure. |
* |
* The call is initialized, so that the reply will be directed |
* to TASK->answerbox |
* The call is initialized, so that the reply will be directed to |
* TASK->answerbox. |
* |
* @param flags Parameters for slab_alloc (ATOMIC, etc.) |
* @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC). |
* |
* @return If flags permit it, return NULL, or initialized kernel |
* call structure. |
*/ |
call_t * ipc_call_alloc(int flags) |
call_t *ipc_call_alloc(int flags) |
{ |
call_t *call; |
|
83,7 → 89,11 |
return call; |
} |
|
/** Initialize allocated call */ |
/** Initialize a statically allocated call structure. |
* |
* @param call Statically allocated kernel call structure to be |
* initialized. |
*/ |
void ipc_call_static_init(call_t *call) |
{ |
_ipc_call_init(call); |
90,13 → 100,19 |
call->flags |= IPC_CALL_STATIC_ALLOC; |
} |
|
/** Deallocate call stracuture */ |
/** Deallocate a call stracuture. |
* |
* @param call Call structure to be freed. |
*/ |
void ipc_call_free(call_t *call) |
{ |
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); |
slab_free(ipc_call_slab, call); |
} |
|
/** Initialize answerbox structure |
/** Initialize an answerbox structure. |
* |
* @param box Answerbox structure to be initialized. |
*/ |
void ipc_answerbox_init(answerbox_t *box) |
{ |
112,7 → 128,11 |
box->task = TASK; |
} |
|
/** Connect phone to answerbox */ |
/** Connect a phone to an answerbox. |
* |
* @param phone Initialized phone structure. |
* @param box Initialized answerbox structure. |
*/ |
void ipc_phone_connect(phone_t *phone, answerbox_t *box) |
{ |
spinlock_lock(&phone->lock); |
127,7 → 147,9 |
spinlock_unlock(&phone->lock); |
} |
|
/** Initialize phone structure and connect phone to answerbox |
/** Initialize a phone structure. |
* |
* @param phone Phone structure to be initialized. |
*/ |
void ipc_phone_init(phone_t *phone) |
{ |
137,7 → 159,11 |
atomic_set(&phone->active_calls, 0); |
} |
|
/** Helper function to facilitate synchronous calls */ |
/** Helper function to facilitate synchronous calls. |
* |
* @param phone Destination kernel phone structure. |
* @param request Call structure with request. |
*/ |
void ipc_call_sync(phone_t *phone, call_t *request) |
{ |
answerbox_t sync_box; |
144,7 → 170,7 |
|
ipc_answerbox_init(&sync_box); |
|
/* We will receive data on special box */ |
/* We will receive data in a special box. */ |
request->callerbox = &sync_box; |
|
ipc_call(phone, request); |
151,8 → 177,9 |
ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
} |
|
/** Answer message that was not dispatched and is not entered in |
* any queue |
/** Answer a message which was not dispatched and is not listed in any queue. |
* |
* @param call Call structure to be answered. |
*/ |
static void _ipc_answer_free_call(call_t *call) |
{ |
166,10 → 193,10 |
waitq_wakeup(&callerbox->wq, WAKEUP_FIRST); |
} |
|
/** Answer message, that is in callee queue |
/** Answer a message which is in a callee queue. |
* |
* @param box Answerbox that is answering the message |
* @param call Modified request that is being sent back |
* @param box Answerbox that is answering the message. |
* @param call Modified request that is being sent back. |
*/ |
void ipc_answer(answerbox_t *box, call_t *call) |
{ |
181,10 → 208,14 |
_ipc_answer_free_call(call); |
} |
|
/** Simulate sending back a message |
/** Simulate sending back a message. |
* |
* Most errors are better handled by forming a normal backward |
* message and sending it as a normal answer. |
* |
* @param phone Phone structure the call should appear to come from. |
* @param call Call structure to be answered. |
* @param err Return value to be used for the answer. |
*/ |
void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err) |
{ |
194,10 → 225,14 |
_ipc_answer_free_call(call); |
} |
|
/* Unsafe unchecking ipc_call */ |
/** Unsafe unchecking version of ipc_call. |
* |
* @param phone Phone structure the call comes from. |
* @param box Destination answerbox structure. |
*/ |
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) |
{ |
if (! (call->flags & IPC_CALL_FORWARDED)) { |
if (!(call->flags & IPC_CALL_FORWARDED)) { |
atomic_inc(&phone->active_calls); |
call->data.phone = phone; |
} |
208,10 → 243,13 |
waitq_wakeup(&box->wq, WAKEUP_FIRST); |
} |
|
/** Send a asynchronous request using phone to answerbox |
/** Send an asynchronous request using a phone to an answerbox. |
* |
* @param phone Phone connected to answerbox. |
* @param call Structure representing the call. |
* @param phone Phone structure the call comes from and which is |
* connected to the destination answerbox. |
* @param call Call structure with request. |
* |
* @return Return 0 on success, ENOENT on error. |
*/ |
int ipc_call(phone_t *phone, call_t *call) |
{ |
238,14 → 276,15 |
return 0; |
} |
|
/** Disconnect phone from answerbox |
/** Disconnect phone from answerbox. |
* |
* This call leaves the phone in HUNGUP state. The change to 'free' is done |
* This call leaves the phone in the HUNGUP state. The change to 'free' is done |
* lazily later. |
* |
* @param phone Phone to be hung up |
* @param phone Phone structure to be hung up. |
* |
* @return 0 - phone disconnected, -1 - the phone was already disconnected |
* @return Return 0 if the phone is disconnected. |
* Return -1 if the phone was already disconnected. |
*/ |
int ipc_phone_hangup(phone_t *phone) |
{ |
253,8 → 292,8 |
call_t *call; |
|
spinlock_lock(&phone->lock); |
if (phone->state == IPC_PHONE_FREE || phone->state ==IPC_PHONE_HUNGUP \ |
|| phone->state == IPC_PHONE_CONNECTING) { |
if (phone->state == IPC_PHONE_FREE || phone->state == IPC_PHONE_HUNGUP || |
phone->state == IPC_PHONE_CONNECTING) { |
spinlock_unlock(&phone->lock); |
return -1; |
} |
279,15 → 318,17 |
return 0; |
} |
|
/** Forwards call from one answerbox to a new one |
/** Forwards call from one answerbox to another one. |
* |
* @param call Call to be redirected. |
* @param newphone Phone to target answerbox. |
* @param oldbox Old answerbox |
* @return 0 on forward ok, error code, if there was error |
* @param call Call structure to be redirected. |
* @param newphone Phone structure to target answerbox. |
* @param oldbox Old answerbox structure. |
* |
* @return Return 0 if forwarding succeeded or an error code if |
* there was error. |
* |
* - the return value serves only as an information for the forwarder, |
* the original caller is notified automatically with EFORWARD |
* The return value serves only as an information for the forwarder, |
* the original caller is notified automatically with EFORWARD. |
*/ |
int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox) |
{ |
299,17 → 340,20 |
} |
|
|
/** Wait for phone call |
/** Wait for a phone call. |
* |
* @param box Answerbox expecting the call. |
* @param usec Timeout in microseconds. See documentation for waitq_sleep_timeout() for |
* decription of its special meaning. |
* @param flags Select mode of sleep operation. See documentation for waitq_sleep_timeout()i |
* for description of its special meaning. |
* @return Recived message address |
* - to distinguish between call and answer, look at call->flags |
* @param box Answerbox expecting the call. |
* @param usec Timeout in microseconds. See documentation for |
* waitq_sleep_timeout() for decription of its special |
* meaning. |
* @param flags Select mode of sleep operation. See documentation for |
* waitq_sleep_timeout() for description of its special |
* meaning. |
* @return Recived call structure or NULL. |
* |
* To distinguish between a call and an answer, have a look at call->flags. |
*/ |
call_t * ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) |
call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags) |
{ |
call_t *request; |
ipl_t ipl; |
350,7 → 394,10 |
return request; |
} |
|
/** Answer all calls from list with EHANGUP msg */ |
/** Answer all calls from list with EHANGUP answer. |
* |
* @param lst Head of the list to be cleaned up. |
*/ |
static void ipc_cleanup_call_list(link_t *lst) |
{ |
call_t *call; |
364,10 → 411,10 |
} |
} |
|
/** Cleans up all IPC communication of the current task |
/** 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 current then current. |
* have to change it as well if you want to cleanup other tasks than TASK. |
*/ |
void ipc_cleanup(void) |
{ |
377,7 → 424,7 |
DEADLOCK_PROBE_INIT(p_phonelck); |
|
/* Disconnect all our phones ('ipc_phone_hangup') */ |
for (i=0;i < IPC_MAX_PHONES; i++) |
for (i = 0; i < IPC_MAX_PHONES; i++) |
ipc_phone_hangup(&TASK->phones[i]); |
|
/* Disconnect all connected irqs */ |
413,8 → 460,8 |
/* Go through all phones, until all are FREE... */ |
/* Locking not needed, no one else should modify |
* it, when we are in cleanup */ |
for (i=0;i < IPC_MAX_PHONES; i++) { |
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \ |
for (i = 0; i < IPC_MAX_PHONES; i++) { |
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && |
atomic_get(&TASK->phones[i].active_calls) == 0) |
TASK->phones[i].state = IPC_PHONE_FREE; |
|
433,9 → 480,11 |
if (i == IPC_MAX_PHONES) |
break; |
|
call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF)); |
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC)); |
call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT, |
SYNCH_FLAGS_NONE); |
ASSERT((call->flags & IPC_CALL_ANSWERED) || |
(call->flags & IPC_CALL_NOTIF)); |
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC)); |
|
atomic_dec(&TASK->active_calls); |
ipc_call_free(call); |
446,11 → 495,15 |
/** Initilize IPC subsystem */ |
void ipc_init(void) |
{ |
ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, NULL, 0); |
ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL, |
NULL, 0); |
} |
|
|
/** Kconsole - list answerbox contents */ |
/** List answerbox contents. |
* |
* @param taskid Task ID. |
*/ |
void ipc_print_task(task_id_t taskid) |
{ |
task_t *task; |
468,10 → 521,10 |
|
/* Print opened phones & details */ |
printf("PHONE:\n"); |
for (i=0; i < IPC_MAX_PHONES;i++) { |
for (i = 0; i < IPC_MAX_PHONES; i++) { |
spinlock_lock(&task->phones[i].lock); |
if (task->phones[i].state != IPC_PHONE_FREE) { |
printf("%d: ",i); |
printf("%d: ", i); |
switch (task->phones[i].state) { |
case IPC_PHONE_CONNECTING: |
printf("connecting "); |