Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1089 → Rev 1090

/kernel/trunk/generic/src/ipc/ipcrsc.c
62,6 → 62,22
*
* Destroying is less frequent, this approach is taken.
*
* Phone call
*
* *** Connect_me_to ***
* The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server
* receives 'phoneid' of the connecting phone as an ARG3. If it answers
* with RETVAL=0, the phonecall is accepted, otherwise it is refused.
*
* *** Connect_to_me ***
* The caller sends IPC_M_CONNECT_TO_ME, with special
* The server receives an automatically
* opened phoneid. If it accepts (RETVAL=0), it can use the phoneid
* immediately.
* Possible race condition can arise, when the client receives messages
* from new connection before getting response for connect_to_me message.
* Userspace should implement handshake protocol that would control it.
*
* Phone hangup
*
* *** The caller hangs up (sys_ipc_hangup) ***
100,7 → 116,7
* 3) Answer all messages in 'calls' and 'dispatched_calls' queues with
* appropriate error code (EHANGUP, EFORWARD).
*
* 4) Wait for all async answers to arrive.
* 4) Wait for all async answers to arrive and dispose of them.
*
*/
 
142,19 → 158,22
return i;
}
 
/** Disconnect phone a free the slot
static void phone_deallocp(phone_t *phone)
{
ASSERT(phone->busy == IPC_BUSY_CONNECTING);
ASSERT(! phone->callee);
/* atomic operation */
phone->busy = IPC_BUSY_FREE;
}
 
/** Free slot from a disconnected phone
*
* All already sent messages will be correctly processed
*/
void phone_dealloc(int phoneid)
{
spinlock_lock(&TASK->lock);
 
ASSERT(TASK->phones[phoneid].busy == IPC_BUSY_CONNECTING);
ASSERT(! TASK->phones[phoneid].callee);
 
TASK->phones[phoneid].busy = IPC_BUSY_FREE;
spinlock_unlock(&TASK->lock);
phone_deallocp(&TASK->phones[phoneid]);
}
 
/** Connect phone to a given answerbox
/kernel/trunk/generic/src/ipc/sysipc.c
47,7 → 47,7
phone = &TASK->phones[phoneid]; \
}
 
#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*src))
#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*(src)))
 
/** Return true if the method is a system method */
static inline int is_system_method(__native method)
105,8 → 105,10
/* The connection was not accepted */
phone_dealloc(phoneid);
} else {
/* The connection was accepted */
/* The connection was accepted */
phone_connect(phoneid,&answer->sender->answerbox);
/* Set 'phone identification' as arg3 of response */
IPC_SET_ARG3(answer->data, (__native)&TASK->phones[phoneid]);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
/* If the users accepted call, connect */
117,6 → 119,30
}
}
 
/** Called before the request is sent
*
* @return 0 - no error, -1 - report error to user
*/
static int request_preprocess(call_t *call)
{
int newphid;
 
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_CONNECT_ME_TO:
newphid = phone_alloc();
if (newphid < 0)
return ELIMIT;
/* Set arg3 for server */
IPC_SET_ARG3(call->data, (__native)&TASK->phones[newphid]);
call->flags |= IPC_CALL_CONN_ME_TO;
call->private = newphid;
break;
default:
break;
}
return 0;
}
 
/****************************************************/
/* Functions called to process received call/answer
* before passing to uspace
123,12 → 149,18
*/
 
/** Do basic kernel processing of received call answer */
static int process_answer(answerbox_t *box,call_t *call)
static void process_answer(call_t *call)
{
if (IPC_GET_RETVAL(call->data) == EHANGUP && \
call->flags & IPC_CALL_FORWARDED)
IPC_SET_RETVAL(call->data, EFORWARD);
return 0;
 
if (call->flags & IPC_CALL_CONN_ME_TO) {
if (IPC_GET_RETVAL(call->data))
phone_dealloc(call->private);
else
IPC_SET_ARG3(call->data, call->private);
}
}
 
/** Do basic kernel processing of received call request
161,18 → 193,19
{
call_t call;
phone_t *phone;
int res;
 
if (is_system_method(method))
return EPERM;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
ipc_call_static_init(&call);
IPC_SET_METHOD(call.data, method);
IPC_SET_ARG1(call.data, arg1);
ipc_call_sync(phone, &call);
 
if (!(res=request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
} else
IPC_SET_RETVAL(call.data, res);
STRUCT_TO_USPACE(&data->args, &call.data.args);
 
return 0;
184,16 → 217,18
{
call_t call;
phone_t *phone;
int res;
 
ipc_call_static_init(&call);
copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
 
if (is_system_method(IPC_GET_METHOD(call.data)))
return EPERM;
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
ipc_call_sync(phone, &call);
if (!(res=request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
} else
IPC_SET_RETVAL(call.data, res);
 
STRUCT_TO_USPACE(&reply->args, &call.data.args);
 
223,14 → 258,12
{
call_t *call;
phone_t *phone;
int res;
 
if (is_system_method(method))
return IPC_CALLRET_FATAL;
 
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
call = ipc_call_alloc();
IPC_SET_METHOD(call->data, method);
237,7 → 270,10
IPC_SET_ARG1(call->data, arg1);
IPC_SET_ARG2(call->data, arg2);
 
ipc_call(phone, call);
if (!(res=request_preprocess(call)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
 
return (__native) call;
}
250,22 → 286,20
{
call_t *call;
phone_t *phone;
int res;
 
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
call = ipc_call_alloc();
copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
if (!(res=request_preprocess(call)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
 
if (is_system_method(IPC_GET_METHOD(call->data))) {
ipc_call_free(call);
return EPERM;
}
ipc_call(phone, call);
 
return (__native) call;
}
 
304,6 → 338,9
* on forward, allow changing ARG1 and ARG2 by means of method and arg1
*/
if (is_system_method(IPC_GET_METHOD(call->data))) {
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
phone_dealloc(IPC_GET_ARG3(call->data));
 
IPC_SET_ARG1(call->data, method);
IPC_SET_ARG2(call->data, arg1);
} else {
365,68 → 402,8
return 0;
}
 
/** Ask the other side of connection to do 'callback' connection
*
* @return 0 if no error, error otherwise
*/
__native sys_ipc_connect_to_me(__native phoneid, __native arg1,
__native arg2, task_id_t *taskid)
{
call_t call;
phone_t *phone;
 
ipc_call_static_init(&call);
IPC_SET_METHOD(call.data, IPC_M_CONNECT_TO_ME);
IPC_SET_ARG1(call.data, arg1);
IPC_SET_ARG2(call.data, arg2);
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
ipc_call_sync(phone, &call);
 
if (!IPC_GET_RETVAL(call.data) && taskid)
STRUCT_TO_USPACE(taskid, &phone->callee->task->taskid);
 
return IPC_GET_RETVAL(call.data);
}
 
/** Ask target process to connect me somewhere
*
* @return phoneid - on success, error otherwise
*/
__native sys_ipc_connect_me_to(__native phoneid, __native arg1,
__native arg2)
{
call_t call;
phone_t *phone;
int newphid;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
newphid = phone_alloc();
if (newphid < 0)
return ELIMIT;
 
ipc_call_static_init(&call);
IPC_SET_METHOD(call.data, IPC_M_CONNECT_ME_TO);
IPC_SET_ARG1(call.data, arg1);
IPC_SET_ARG2(call.data, arg2);
IPC_SET_ARG3(call.data, (__native)&TASK->phones[newphid]);
 
ipc_call_sync(phone, &call);
 
if (IPC_GET_RETVAL(call.data)) { /* Connection failed */
phone_dealloc(newphid);
return IPC_GET_RETVAL(call.data);
}
 
return newphid;
}
 
/** Hang up the phone
*
*
*
*/
__native sys_ipc_hangup(int phoneid)
{
448,9 → 425,7
* @param flags
* @return Callid, if callid & 1, then the call is answer
*/
__native sys_ipc_wait_for_call(ipc_data_t *calldata, task_id_t *taskid,
__native flags)
__native sys_ipc_wait_for_call(ipc_data_t *calldata, __native flags)
{
call_t *call;
 
460,8 → 435,7
return 0;
 
if (call->flags & IPC_CALL_ANSWERED) {
if (process_answer(&TASK->answerbox, call))
goto restart;
process_answer(call);
 
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
 
481,9 → 455,8
if (process_request(&TASK->answerbox, call))
goto restart;
 
/* Include phone address('id') of the caller in the request */
/* Include phone address('id') of the caller in the request,
* copy whole call->data, not only call->data.args */
STRUCT_TO_USPACE(calldata, &call->data);
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
STRUCT_TO_USPACE(taskid, &TASK->taskid);
return (__native)call;
}
/kernel/trunk/generic/src/ipc/ipc.c
145,7 → 145,6
{
answerbox_t *callerbox = call->callerbox;
 
call->flags &= ~IPC_CALL_DISPATCHED;
call->flags |= IPC_CALL_ANSWERED;
 
spinlock_lock(&callerbox->lock);
169,6 → 168,23
_ipc_answer_free_call(call);
}
 
/** Simulate sending back a message
*
* Most errors are better handled by forming a normal backward
* message and sending it as a normal answer.
*/
void ipc_backsend_err(phone_t *phone, call_t *call, __native err)
{
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);
 
_ipc_answer_free_call(call);
}
 
/* Unsafe unchecking ipc_call */
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
{
200,16 → 216,14
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);
_ipc_answer_free_call(call);
} else { /* Simulate sending back a message */
if (phone->busy == IPC_BUSY_CONNECTED)
IPC_SET_RETVAL(call->data, EHANGUP);
ipc_backsend_err(phone, call, EHANGUP);
else
IPC_SET_RETVAL(call->data, ENOENT);
ipc_backsend_err(phone, call, ENOENT);
}
 
_ipc_answer_free_call(call);
return ENOENT;
}
_ipc_call(phone, box, call);
307,7 → 321,6
list_remove(&request->list);
/* Append request to dispatch queue */
list_append(&request->list, &box->dispatched_calls);
request->flags |= IPC_CALL_DISPATCHED;
} else {
printf("WARNING: Spurious IPC wakeup.\n");
spinlock_unlock(&box->lock);