Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1087 → Rev 1088

/kernel/trunk/generic/src/ipc/ipcrsc.c
70,23 → 70,37
* IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async
* calls are answered, the phone is deallocated.
*
* *** The answerbox hangs up (ipc_answer(ESLAM))
* - The phone is disconnected. IPC_M_ANSWERBOX_HUNGUP notification
* is sent to source task, the calling process is expected to
* *** The answerbox hangs up (ipc_answer(EHANGUP))
* - The phone is disconnected. EHANGUP response code is sent
* to the calling process. All new calls through this phone
* get a EHUNGUP error code, the task is expected to
* send an sys_ipc_hangup after cleaning up it's internal structures.
*
* Call forwarding
*
* The call can be forwarded, so that the answer to call is passed directly
* to the original sender. However, this poses special problems regarding
* routing of hangup messages.
*
* sys_ipc_hangup -> IPC_M_PHONE_HUNGUP
* - this message CANNOT be forwarded
*
* EHANGUP during forward
* - The *forwarding* phone will be closed, EFORWARD is sent to receiver.
*
* EHANGUP, ENOENT during forward
* - EFORWARD is sent to the receiver, ipc_forward returns error code EFORWARD
*
* Cleanup strategy
*
* 1) Disconnect all our phones ('sys_ipc_hangup')
* 1) Disconnect all our phones ('ipc_phone_hangup').
*
* 2) Disconnect all phones connected to answerbox.
* * Send message 'PHONE_DISCONNECTED' to the target application
* - Once all phones are disconnected, no further calls can arrive
*
* 3) Answer all messages in 'calls' and 'dispatched_calls' queues with
* appropriate error code.
* appropriate error code (EHANGUP, EFORWARD).
*
* 4) Wait for all async answers to arrive
* 4) Wait for all async answers to arrive.
*
*/
 
116,8 → 130,8
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (!TASK->phones[i].busy && !atomic_get(&TASK->phones[i].active_calls)) {
TASK->phones[i].busy = 1;
if (TASK->phones[i].busy==IPC_BUSY_FREE && !atomic_get(&TASK->phones[i].active_calls)) {
TASK->phones[i].busy = IPC_BUSY_CONNECTING;
break;
}
}
136,10 → 150,10
{
spinlock_lock(&TASK->lock);
 
ASSERT(TASK->phones[phoneid].busy);
ASSERT(TASK->phones[phoneid].busy == IPC_BUSY_CONNECTING);
ASSERT(! TASK->phones[phoneid].callee);
 
TASK->phones[phoneid].busy = 0;
TASK->phones[phoneid].busy = IPC_BUSY_FREE;
spinlock_unlock(&TASK->lock);
}
 
155,6 → 169,6
{
phone_t *phone = &TASK->phones[phoneid];
ASSERT(phone->busy);
ASSERT(phone->busy == IPC_BUSY_CONNECTING);
ipc_phone_connect(phone, box);
}
/kernel/trunk/generic/src/ipc/sysipc.c
75,9 → 75,9
*/
 
/** Return true if the caller (ipc_answer) should save
* the old call contents and call answer_preprocess
* the old call contents for answer_preprocess
*/
static inline int answer_will_preprocess(call_t *call)
static inline int answer_need_old(call_t *call)
{
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
return 1;
91,6 → 91,14
{
int phoneid;
 
if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
/* Atomic operation */
answer->data.phone->callee = NULL;
}
 
if (!olddata)
return;
 
if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
phoneid = IPC_GET_ARG3(*olddata);
if (IPC_GET_RETVAL(answer->data)) {
97,7 → 105,7
/* The connection was not accepted */
phone_dealloc(phoneid);
} else {
/* The connection was accepted */
/* The connection was accepted */
phone_connect(phoneid,&answer->sender->answerbox);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
117,6 → 125,9
/** Do basic kernel processing of received call answer */
static int process_answer(answerbox_t *box,call_t *call)
{
if (IPC_GET_RETVAL(call->data) == EHANGUP && \
call->flags & IPC_CALL_FORWARDED)
IPC_SET_RETVAL(call->data, EFORWARD);
return 0;
}
 
275,6 → 286,8
if (!call)
return ENOENT;
 
call->flags |= IPC_CALL_FORWARDED;
 
GET_CHECK_PHONE(phone, phoneid, {
IPC_SET_RETVAL(call->data, EFORWARD);
ipc_answer(&TASK->answerbox, call);
298,9 → 311,7
IPC_SET_ARG1(call->data, arg1);
}
 
ipc_forward(call, phone, &TASK->answerbox);
 
return 0;
return ipc_forward(call, phone, &TASK->answerbox);
}
 
/** Send IPC answer */
309,24 → 320,22
{
call_t *call;
ipc_data_t saved_data;
int preprocess = 0;
int saveddata = 0;
 
call = get_call(callid);
if (!call)
return ENOENT;
 
if (answer_will_preprocess(call)) {
if (answer_need_old(call)) {
memcpy(&saved_data, &call->data, sizeof(call->data));
preprocess = 1;
saveddata = 1;
}
 
IPC_SET_RETVAL(call->data, retval);
IPC_SET_ARG1(call->data, arg1);
IPC_SET_ARG2(call->data, arg2);
answer_preprocess(call, saveddata ? &saved_data : NULL);
 
if (preprocess)
answer_preprocess(call, &saved_data);
 
ipc_answer(&TASK->answerbox, call);
return 0;
}
336,21 → 345,20
{
call_t *call;
ipc_data_t saved_data;
int preprocess = 0;
int saveddata = 0;
 
call = get_call(callid);
if (!call)
return ENOENT;
 
if (answer_will_preprocess(call)) {
if (answer_need_old(call)) {
memcpy(&saved_data, &call->data, sizeof(call->data));
preprocess = 1;
saveddata = 1;
}
copy_from_uspace(&call->data.args, &data->args,
sizeof(call->data.args));
 
if (preprocess)
answer_preprocess(call, &saved_data);
answer_preprocess(call, saveddata ? &saved_data : NULL);
ipc_answer(&TASK->answerbox, call);
 
448,6 → 456,8
 
restart:
call = ipc_wait_for_call(&TASK->answerbox, flags);
if (!call)
return 0;
 
if (call->flags & IPC_CALL_ANSWERED) {
if (process_answer(&TASK->answerbox, call))
/kernel/trunk/generic/src/ipc/ipc.c
104,7 → 104,7
spinlock_lock(&phone->lock);
 
ASSERT(!phone->callee);
phone->busy = 1;
phone->busy = IPC_BUSY_CONNECTED;
phone->callee = box;
 
spinlock_lock(&box->lock);
120,7 → 120,8
{
spinlock_initialize(&phone->lock, "phone_lock");
phone->callee = NULL;
phone->busy = 0;
phone->busy = IPC_BUSY_FREE;
atomic_set(&phone->active_calls, 0);
}
 
/** Helper function to facilitate synchronous calls */
171,8 → 172,10
/* Unsafe unchecking ipc_call */
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
{
atomic_inc(&phone->active_calls);
call->data.phone = phone;
if (! (call->flags & IPC_CALL_FORWARDED)) {
atomic_inc(&phone->active_calls);
call->data.phone = phone;
}
 
spinlock_lock(&box->lock);
list_append(&call->list, &box->calls);
185,7 → 188,7
* @param phone Phone connected to answerbox
* @param request Request to be sent
*/
void ipc_call(phone_t *phone, call_t *call)
int ipc_call(phone_t *phone, call_t *call)
{
answerbox_t *box;
 
195,15 → 198,24
if (!box) {
/* Trying to send over disconnected phone */
spinlock_unlock(&phone->lock);
if (call->flags & IPC_CALL_FORWARDED) {
IPC_SET_RETVAL(call->data, EFORWARD);
} else { /* Simulate sending a message */
call->data.phone = phone;
atomic_inc(&phone->active_calls);
if (phone->busy == IPC_BUSY_CONNECTED)
IPC_SET_RETVAL(call->data, EHANGUP);
else
IPC_SET_RETVAL(call->data, ENOENT);
}
 
call->data.phone = phone;
IPC_SET_RETVAL(call->data, ENOENT);
_ipc_answer_free_call(call);
return;
return ENOENT;
}
_ipc_call(phone, box, call);
spinlock_unlock(&phone->lock);
return 0;
}
 
/** Disconnect phone from answerbox
220,8 → 232,14
spinlock_lock(&phone->lock);
box = phone->callee;
if (!box) {
if (phone->busy == IPC_BUSY_CONNECTING) {
spinlock_unlock(&phone->lock);
return -1;
}
/* Already disconnected phone */
phone->busy = IPC_BUSY_FREE;
spinlock_unlock(&phone->lock);
return -1;
return 0;
}
 
spinlock_lock(&box->lock);
234,7 → 252,7
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
 
phone->busy = 0;
phone->busy = IPC_BUSY_FREE;
 
spinlock_unlock(&phone->lock);
 
246,15 → 264,18
* @param request Request to be forwarded
* @param newbox 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
*/
void ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox)
int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox)
{
spinlock_lock(&oldbox->lock);
atomic_dec(&call->data.phone->active_calls);
list_remove(&call->list);
spinlock_unlock(&oldbox->lock);
 
ipc_call(newphone, call);
return ipc_call(newphone, call);
}
 
 
279,8 → 300,6
/* Handle asynchronous answers */
request = list_get_instance(box->answers.next, call_t, list);
list_remove(&request->list);
printf("%d %P\n", IPC_GET_METHOD(request->data),
request->data.phone);
atomic_dec(&request->data.phone->active_calls);
} else if (!list_empty(&box->calls)) {
/* Handle requests */
313,6 → 332,15
*/
void ipc_cleanup(task_t *task)
{
/* Cancel all calls in my dispatch queue */
int i;
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i=0;i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&task->phones[i]);
 
/* Disconnect all phones connected to answerbox */
 
/* Answer all messages in 'calls' and 'dispatched_calls' queues */
/* Wait for all async answers to arrive */
}