Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2321 → Rev 2362

/trunk/kernel/generic/src/ipc/ipcrsc.c
34,8 → 34,8
 
/* IPC resources management
*
* The goal of this source code is to properly manage IPC resources
* and allow straight and clean clean-up procedure upon task termination.
* The goal of this source code is to properly manage IPC resources and allow
* straight and clean clean-up procedure upon task termination.
*
* The pattern of usage of the resources is:
* - allocate empty phone slot, connect | deallocate slot
47,24 → 47,24
*
* Locking strategy
*
* - To use a phone, disconnect a phone etc., the phone must be
* first locked and then checked that it is connected
* - To connect an allocated phone it need not be locked (assigning
* pointer is atomic on all platforms)
* - To use a phone, disconnect a phone etc., the phone must be first locked and
* then checked that it is connected
* - To connect an allocated phone it need not be locked (assigning pointer is
* atomic on all platforms)
*
* - To find an empty phone slot, the TASK must be locked
* - To answer a message, the answerbox must be locked
* - The locking of phone and answerbox is done at the ipc_ level.
* It is perfectly correct to pass unconnected phone to these functions
* and proper reply will be generated.
* It is perfectly correct to pass unconnected phone to these functions and
* proper reply will be generated.
*
* Locking order
*
* - first phone, then answerbox
* + Easy locking on calls
* - Very hard traversing list of phones when disconnecting because
* the phones may disconnect during traversal of list of connected phones.
* The only possibility is try_lock with restart of list traversal.
* - Very hard traversing list of phones when disconnecting because the phones
* may disconnect during traversal of list of connected phones. The only
* possibility is try_lock with restart of list traversal.
*
* Destroying is less frequent, this approach is taken.
*
71,24 → 71,23
* 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.
* 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.
* The caller sends IPC_M_CONNECT_TO_ME.
* 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) ***
* - The phone is disconnected (no more messages can be sent over this phone),
* all in-progress messages are correctly handled. The anwerbox receives
* all in-progress messages are correctly handled. The answerbox receives
* IPC_M_PHONE_HUNGUP call from the phone that hung up. When all async
* calls are answered, the phone is deallocated.
*
/trunk/kernel/generic/src/ipc/sysipc.c
49,12 → 49,12
#include <mm/as.h>
#include <print.h>
 
#define GET_CHECK_PHONE(phone,phoneid,err) { \
#define GET_CHECK_PHONE(phone, phoneid, err) { \
if (phoneid > IPC_MAX_PHONES) { err; } \
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(unative_t method)
71,8 → 71,8
*/
static inline int is_forwardable(unative_t method)
{
if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND \
|| method == IPC_M_AS_AREA_RECV)
if (method == IPC_M_PHONE_HUNGUP || method == IPC_M_AS_AREA_SEND ||
method == IPC_M_AS_AREA_RECV)
return 0; /* This message is meant only for the receiver */
return 1;
}
130,18 → 130,20
phone_dealloc(phoneid);
} else {
/* The connection was accepted */
phone_connect(phoneid,&answer->sender->answerbox);
phone_connect(phoneid, &answer->sender->answerbox);
/* Set 'phone identification' as arg3 of response */
IPC_SET_ARG3(answer->data, (unative_t)&TASK->phones[phoneid]);
IPC_SET_ARG3(answer->data,
(unative_t) &TASK->phones[phoneid]);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
/* If the users accepted call, connect */
if (!IPC_GET_RETVAL(answer->data)) {
ipc_phone_connect((phone_t *)IPC_GET_ARG3(*olddata),
&TASK->answerbox);
ipc_phone_connect((phone_t *) IPC_GET_ARG3(*olddata),
&TASK->answerbox);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_AS_AREA_SEND) {
if (!IPC_GET_RETVAL(answer->data)) { /* Accepted, handle as_area receipt */
if (!IPC_GET_RETVAL(answer->data)) {
/* Accepted, handle as_area receipt */
ipl_t ipl;
int rc;
as_t *as;
152,8 → 154,9
spinlock_unlock(&answer->sender->lock);
interrupts_restore(ipl);
rc = as_area_share(as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(*olddata),
AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
rc = as_area_share(as, IPC_GET_ARG1(*olddata),
IPC_GET_ARG2(*olddata), AS,
IPC_GET_ARG1(answer->data), IPC_GET_ARG3(*olddata));
IPC_SET_RETVAL(answer->data, rc);
return rc;
}
169,8 → 172,9
spinlock_unlock(&answer->sender->lock);
interrupts_restore(ipl);
rc = as_area_share(AS, IPC_GET_ARG1(answer->data), IPC_GET_ARG2(*olddata),
as, IPC_GET_ARG1(*olddata), IPC_GET_ARG2(answer->data));
rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
IPC_GET_ARG2(*olddata), as, IPC_GET_ARG1(*olddata),
IPC_GET_ARG2(answer->data));
IPC_SET_RETVAL(answer->data, rc);
}
}
192,7 → 196,7
if (newphid < 0)
return ELIMIT;
/* Set arg3 for server */
IPC_SET_ARG3(call->data, (unative_t)&TASK->phones[newphid]);
IPC_SET_ARG3(call->data, (unative_t) &TASK->phones[newphid]);
call->flags |= IPC_CALL_CONN_ME_TO;
call->priv = newphid;
break;
217,8 → 221,8
/** Do basic kernel processing of received call answer */
static void process_answer(call_t *call)
{
if (IPC_GET_RETVAL(call->data) == EHANGUP && \
call->flags & IPC_CALL_FORWARDED)
if (IPC_GET_RETVAL(call->data) == EHANGUP &&
(call->flags & IPC_CALL_FORWARDED))
IPC_SET_RETVAL(call->data, EFORWARD);
 
if (call->flags & IPC_CALL_CONN_ME_TO) {
233,7 → 237,7
*
* @return 0 - the call should be passed to userspace, 1 - ignore call
*/
static int process_request(answerbox_t *box,call_t *call)
static int process_request(answerbox_t *box, call_t *call)
{
int phoneid;
 
254,8 → 258,8
* @return Call identification, returns -1 on fatal error,
-2 on 'Too many async request, handle answers first
*/
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
unative_t arg1, ipc_data_t *data)
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
unative_t arg1, ipc_data_t *data)
{
call_t call;
phone_t *phone;
278,8 → 282,8
}
 
/** Synchronous IPC call allowing to send whole message */
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
ipc_data_t *reply)
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
ipc_data_t *reply)
{
call_t call;
phone_t *phone;
287,7 → 291,8
int rc;
 
ipc_call_static_init(&call);
rc = copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
rc = copy_from_uspace(&call.data.args, &question->args,
sizeof(call.data.args));
if (rc != 0)
return (unative_t) rc;
 
324,8 → 329,8
* @return Call identification, returns -1 on fatal error,
-2 on 'Too many async request, handle answers first
*/
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2)
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2)
{
call_t *call;
phone_t *phone;
342,7 → 347,7
IPC_SET_ARG2(call->data, arg2);
IPC_SET_ARG3(call->data, 0);
 
if (!(res=request_preprocess(call)))
if (!(res = request_preprocess(call)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
367,12 → 372,13
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
call = ipc_call_alloc(0);
rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
rc = copy_from_uspace(&call->data.args, &data->args,
sizeof(call->data.args));
if (rc != 0) {
ipc_call_free(call);
return (unative_t) rc;
}
if (!(res=request_preprocess(call)))
if (!(res = request_preprocess(call)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
388,7 → 394,7
* arg3 is not rewritten for certain system IPC
*/
unative_t sys_ipc_forward_fast(unative_t callid, unative_t phoneid,
unative_t method, unative_t arg1)
unative_t method, unative_t arg1)
{
call_t *call;
phone_t *phone;
429,8 → 435,8
}
 
/** Send IPC answer */
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
unative_t arg1, unative_t arg2)
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
unative_t arg1, unative_t arg2)
{
call_t *call;
ipc_data_t saved_data;
480,7 → 486,7
saveddata = 1;
}
rc = copy_from_uspace(&call->data.args, &data->args,
sizeof(call->data.args));
sizeof(call->data.args));
if (rc != 0)
return rc;
 
508,9 → 514,10
 
/** Wait for incoming ipc call or answer
*
* @param calldata Pointer to buffer where the call/answer data is stored
* @param usec Timeout. See waitq_sleep_timeout() for explanation.
* @param flags Select mode of sleep operation. See waitq_sleep_timeout() for explanation.
* @param calldata Pointer to buffer where the call/answer data is stored.
* @param usec Timeout. See waitq_sleep_timeout() for explanation.
* @param flags Select mode of sleep operation. See waitq_sleep_timeout()
* for explanation.
*
* @return Callid, if callid & 1, then the call is answer
*/
519,7 → 526,8
call_t *call;
 
restart:
call = ipc_wait_for_call(&TASK->answerbox, usec, flags | SYNCH_FLAGS_INTERRUPTIBLE);
call = ipc_wait_for_call(&TASK->answerbox, usec,
flags | SYNCH_FLAGS_INTERRUPTIBLE);
if (!call)
return 0;
 
574,7 → 582,8
*
* @return EPERM or a return code returned by ipc_irq_register().
*/
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, irq_code_t *ucode)
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
irq_code_t *ucode)
{
if (!(cap_get(TASK) & CAP_IRQ_REG))
return EPERM;
/trunk/uspace/libc/generic/ipc.c
417,19 → 417,29
return callid;
}
 
/** Ask destination to do a callback connection
/** Ask destination to do a callback connection.
*
* @return 0 - OK, error code
* @param phoneid Phone ID used for contacting the other side.
* @param arg1 User defined argument.
* @param arg2 User defined argument.
* @param phonehash Pointer to a place where the library will store an opaque
* identifier of the phone that will be used for incoming
* calls.
* @return Zero on success or a negative error code.
*/
int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone)
int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash)
{
return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1,
arg2, 0, 0, 0, phone);
return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0,
phonehash);
}
 
/** Ask through phone for a new connection to some service
/** Ask through phone for a new connection to some service.
*
* @return new phoneid - OK, error code
* @param phoneid Phone ID used for contacting the other side.
* @param arg1 User defined argument.
* @param arg2 User defined argument.
*
* @return New phone ID on success or a negative error code.
*/
int ipc_connect_me_to(int phoneid, int arg1, int arg2)
{
436,8 → 446,8
ipcarg_t newphid;
int res;
 
res = ipc_call_sync_3(phoneid, IPC_M_CONNECT_ME_TO, arg1,
arg2, 0, 0, 0, &newphid);
res = ipc_call_sync_3(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, 0, 0, 0,
&newphid);
if (res)
return res;
return newphid;