Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2471 → Rev 2470

/trunk/kernel/generic/src/ipc/ipc.c
34,7 → 34,7
 
/* Lock ordering
*
* First the answerbox, then the phone.
* First the answerbox, then the phone
*/
 
#include <synch/spinlock.h>
53,33 → 53,27
#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 a call structure.
*
* @param call Call structure to be initialized.
*/
/* Initialize new call */
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 and initialize a call structure.
/** Allocate & initialize 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 (e.g FRAME_ATOMIC).
*
* @return If flags permit it, return NULL, or initialized kernel
* call structure.
* @param flags Parameters for slab_alloc (ATOMIC, etc.)
*/
call_t *ipc_call_alloc(int flags)
call_t * ipc_call_alloc(int flags)
{
call_t *call;
 
89,11 → 83,7
return call;
}
 
/** Initialize a statically allocated call structure.
*
* @param call Statically allocated kernel call structure to be
* initialized.
*/
/** Initialize allocated call */
void ipc_call_static_init(call_t *call)
{
_ipc_call_init(call);
100,19 → 90,13
call->flags |= IPC_CALL_STATIC_ALLOC;
}
 
/** Deallocate a call stracuture.
*
* @param call Call structure to be freed.
*/
/** Deallocate call stracuture */
void ipc_call_free(call_t *call)
{
ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
slab_free(ipc_call_slab, call);
}
 
/** Initialize an answerbox structure.
*
* @param box Answerbox structure to be initialized.
/** Initialize answerbox structure
*/
void ipc_answerbox_init(answerbox_t *box)
{
128,11 → 112,7
box->task = TASK;
}
 
/** Connect a phone to an answerbox.
*
* @param phone Initialized phone structure.
* @param box Initialized answerbox structure.
*/
/** Connect phone to answerbox */
void ipc_phone_connect(phone_t *phone, answerbox_t *box)
{
spinlock_lock(&phone->lock);
147,9 → 127,7
spinlock_unlock(&phone->lock);
}
 
/** Initialize a phone structure.
*
* @param phone Phone structure to be initialized.
/** Initialize phone structure and connect phone to answerbox
*/
void ipc_phone_init(phone_t *phone)
{
159,11 → 137,7
atomic_set(&phone->active_calls, 0);
}
 
/** Helper function to facilitate synchronous calls.
*
* @param phone Destination kernel phone structure.
* @param request Call structure with request.
*/
/** Helper function to facilitate synchronous calls */
void ipc_call_sync(phone_t *phone, call_t *request)
{
answerbox_t sync_box;
170,7 → 144,7
 
ipc_answerbox_init(&sync_box);
 
/* We will receive data in a special box. */
/* We will receive data on special box */
request->callerbox = &sync_box;
 
ipc_call(phone, request);
177,9 → 151,8
ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
}
 
/** Answer a message which was not dispatched and is not listed in any queue.
*
* @param call Call structure to be answered.
/** Answer message that was not dispatched and is not entered in
* any queue
*/
static void _ipc_answer_free_call(call_t *call)
{
193,10 → 166,10
waitq_wakeup(&callerbox->wq, WAKEUP_FIRST);
}
 
/** Answer a message which is in a callee queue.
/** Answer message, that is in 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)
{
208,14 → 181,10
_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)
{
225,14 → 194,10
_ipc_answer_free_call(call);
}
 
/** Unsafe unchecking version of ipc_call.
*
* @param phone Phone structure the call comes from.
* @param box Destination answerbox structure.
*/
/* Unsafe unchecking ipc_call */
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;
}
243,13 → 208,10
waitq_wakeup(&box->wq, WAKEUP_FIRST);
}
 
/** Send an asynchronous request using a phone to an answerbox.
/** Send a asynchronous request using phone to answerbox
*
* @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.
* @param phone Phone connected to answerbox.
* @param call Structure representing the call.
*/
int ipc_call(phone_t *phone, call_t *call)
{
276,15 → 238,14
return 0;
}
 
/** Disconnect phone from answerbox.
/** Disconnect phone from answerbox
*
* This call leaves the phone in the HUNGUP state. The change to 'free' is done
* This call leaves the phone in HUNGUP state. The change to 'free' is done
* lazily later.
*
* @param phone Phone structure to be hung up.
* @param phone Phone to be hung up
*
* @return Return 0 if the phone is disconnected.
* Return -1 if the phone was already disconnected.
* @return 0 - phone disconnected, -1 - the phone was already disconnected
*/
int ipc_phone_hangup(phone_t *phone)
{
292,8 → 253,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;
}
318,17 → 279,15
return 0;
}
 
/** Forwards call from one answerbox to another one.
/** Forwards call from one answerbox to a new one
*
* @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.
* @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
*
* 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)
{
340,20 → 299,17
}
 
 
/** Wait for a phone call.
/** Wait for 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() 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.
* @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
*/
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;
394,10 → 350,7
return request;
}
 
/** Answer all calls from list with EHANGUP answer.
*
* @param lst Head of the list to be cleaned up.
*/
/** Answer all calls from list with EHANGUP msg */
static void ipc_cleanup_call_list(link_t *lst)
{
call_t *call;
411,10 → 364,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 tasks than TASK.
* have to change it as well if you want to cleanup other current then current.
*/
void ipc_cleanup(void)
{
424,7 → 377,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 */
460,8 → 413,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;
480,11 → 433,9
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);
495,15 → 446,11
/** 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);
}
 
 
/** List answerbox contents.
*
* @param taskid Task ID.
*/
/** Kconsole - list answerbox contents */
void ipc_print_task(task_id_t taskid)
{
task_t *task;
521,10 → 468,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 ");