Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2359 → Rev 2471

/trunk/kernel/generic/src/ipc/sysipc.c
49,14 → 49,23
#include <mm/as.h>
#include <print.h>
 
#define GET_CHECK_PHONE(phone, phoneid, err) { \
if (phoneid > IPC_MAX_PHONES) { err; } \
phone = &TASK->phones[phoneid]; \
#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 */
/** Decide if the method is a system method.
*
* @param method Method to be decided.
*
* @return Return 1 if the method is a system method.
* Otherwise return 0.
*/
static inline int is_system_method(unative_t method)
{
if (method <= IPC_M_LAST_SYSTEM)
64,10 → 73,15
return 0;
}
 
/** Return true if the message with this method is forwardable
/** Decide if the message with this method is forwardable.
*
* - some system messages may be forwarded, for some of them
* it is useless
*
* @param method Method to be decided.
*
* @return Return 1 if the method is forwardable.
* Otherwise return 0.
*/
static inline int is_forwardable(unative_t method)
{
77,13 → 91,18
return 1;
}
 
/****************************************************/
/* Functions that preprocess answer before sending
* it to the recepient
*/
 
/** Return true if the caller (ipc_answer) should save
* the old call contents for answer_preprocess
/***********************************************************************
* Functions that preprocess answer before sending it to the recepient.
***********************************************************************/
 
/** Decide if the caller (e.g. ipc_answer()) should save the old call contents
* for answer_preprocess().
*
* @param call Call structure to be decided.
*
* @return Return 1 if the old call contents should be saved.
* Return 0 otherwise.
*/
static inline int answer_need_old(call_t *call)
{
98,9 → 117,14
return 0;
}
 
/** Interpret process answer as control information
/** Interpret process answer as control information.
*
* This function is called directly after sys_ipc_answer
* This function is called directly after sys_ipc_answer().
*
* @param answer Call structure with the answer.
* @param olddata Saved data of the request.
*
* @return Return 0 on success or an error code.
*/
static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
{
131,7 → 155,7
} else {
/* The connection was accepted */
phone_connect(phoneid, &answer->sender->answerbox);
/* Set 'phone identification' as arg3 of response */
/* Set 'phone hash' as arg3 of response */
IPC_SET_ARG3(answer->data,
(unative_t) &TASK->phones[phoneid]);
}
181,9 → 205,11
return 0;
}
 
/** Called before the request is sent
/** Called before the request is sent.
*
* @return 0 - no error, -1 - report error to user
* @param call Call structure with the request.
*
* @return Return 0 on success, ELIMIT or EPERM on error.
*/
static int request_preprocess(call_t *call)
{
202,9 → 228,8
break;
case IPC_M_AS_AREA_SEND:
size = as_get_size(IPC_GET_ARG1(call->data));
if (!size) {
if (!size)
return EPERM;
}
IPC_SET_ARG2(call->data, size);
break;
default:
213,12 → 238,14
return 0;
}
 
/****************************************************/
/* Functions called to process received call/answer
* before passing to uspace
/*******************************************************************************
* Functions called to process received call/answer before passing it to uspace.
*******************************************************************************/
 
/** Do basic kernel processing of received call answer.
*
* @param call Call structure with the answer.
*/
 
/** Do basic kernel processing of received call answer */
static void process_answer(call_t *call)
{
if (IPC_GET_RETVAL(call->data) == EHANGUP &&
233,9 → 260,13
}
}
 
/** Do basic kernel processing of received call request
/** Do basic kernel processing of received call request.
*
* @return 0 - the call should be passed to userspace, 1 - ignore call
* @param box Destination answerbox structure.
* @param call Call structure with the request.
*
* @return Return 0 if the call should be passed to userspace.
* Return -1 if the call should be ignored.
*/
static int process_request(answerbox_t *box, call_t *call)
{
245,7 → 276,7
phoneid = phone_alloc();
if (phoneid < 0) { /* Failed to allocate phone */
IPC_SET_RETVAL(call->data, ELIMIT);
ipc_answer(box,call);
ipc_answer(box, call);
return -1;
}
IPC_SET_ARG3(call->data, phoneid);
253,10 → 284,19
return 0;
}
 
/** Send a call over IPC, wait for reply, return to user
/** Make a fast call over IPC, wait for reply and return to user.
*
* @return Call identification, returns -1 on fatal error,
-2 on 'Too many async request, handle answers first
* This function can handle only one argument of payload, but is faster than
* the generic function (i.e. sys_ipc_call_sync()).
*
* @param phoneid Phone handle for the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param data Address of userspace structure where the reply call will
* be stored.
*
* @return Returns 0 on success.
* Return ENOENT if there is no such phone handle.
*/
unative_t sys_ipc_call_sync_fast(unative_t phoneid, unative_t method,
unative_t arg1, ipc_data_t *data)
271,17 → 311,25
IPC_SET_METHOD(call.data, method);
IPC_SET_ARG1(call.data, arg1);
 
if (!(res=request_preprocess(&call))) {
if (!(res = request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
} else
} else {
IPC_SET_RETVAL(call.data, res);
}
STRUCT_TO_USPACE(&data->args, &call.data.args);
 
return 0;
}
 
/** Synchronous IPC call allowing to send whole message */
/** Make a synchronous IPC call allowing to transmit the entire payload.
*
* @param phoneid Phone handle for the call.
* @param question Userspace address of call data with the request.
* @param reply Userspace address of call data where to store the answer.
*
* @return Zero on success or an error code.
*/
unative_t sys_ipc_call_sync(unative_t phoneid, ipc_data_t *question,
ipc_data_t *reply)
{
298,7 → 346,7
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
if (!(res=request_preprocess(&call))) {
if (!(res = request_preprocess(&call))) {
ipc_call_sync(phone, &call);
process_answer(&call);
} else
311,9 → 359,9
return 0;
}
 
/** Check that the task did not exceed allowed limit
/** Check that the task did not exceed the allowed limit of asynchronous calls.
*
* @return 0 - Limit OK, -1 - limit exceeded
* @return Return 0 if limit not reached or -1 if limit exceeded.
*/
static int check_call_limit(void)
{
324,10 → 372,20
return 0;
}
 
/** Send an asynchronous call over ipc
/** Make a fast asynchronous call over IPC.
*
* @return Call identification, returns -1 on fatal error,
-2 on 'Too many async request, handle answers first
* This function can only handle two arguments of payload, but is faster than
* the generic function sys_ipc_call_async().
*
* @param phoneid Phone handle for the call.
* @param method Method of the call.
* @param arg1 Service-defined payload argument.
* @param arg2 Service-defined payload argument.
*
* @return Return call hash on success.
* Return IPC_CALLRET_FATAL in case of a fatal error and
* IPC_CALLRET_TEMPORARY if there are too many pending
* asynchronous requests; answers should be handled first.
*/
unative_t sys_ipc_call_async_fast(unative_t phoneid, unative_t method,
unative_t arg1, unative_t arg2)
355,9 → 413,12
return (unative_t) call;
}
 
/** Synchronous IPC call allowing to send whole message
/** Make an asynchronous IPC call allowing to transmit the entire payload.
*
* @return The same as sys_ipc_call_async
* @param phoneid Phone handle for the call.
* @param data Userspace address of call data with the request.
*
* @return See sys_ipc_call_async_fast().
*/
unative_t sys_ipc_call_async(unative_t phoneid, ipc_data_t *data)
{
386,12 → 447,22
return (unative_t) call;
}
 
/** Forward received call to another destination
/** Forward a received call to another destination.
*
* The arg1 and arg2 are changed in the forwarded message
* @param callid Hash of the call to forward.
* @param phoneid Phone handle to use for forwarding.
* @param method New method to use for the forwarded call.
* @param arg1 New value of the first argument for the forwarded call.
*
* @return Return 0 on succes, otherwise return an error code.
*
* In case the original method is a system method, ARG1 and ARG2 are overwritten
* in the forwarded message with the new method and the new arg1, respectively.
* Otherwise the METHOD and ARG1 are rewritten with the new method and arg1,
* respectively.
*
* Warning: If implementing non-fast version, make sure that
* arg3 is not rewritten for certain system IPC
* 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)
434,7 → 505,18
return ipc_forward(call, phone, &TASK->answerbox);
}
 
/** Send IPC answer */
/** Answer an IPC call - fast version.
*
* This function can handle only two return arguments of payload, but is faster
* than the generic sys_ipc_answer().
*
* @param callid Hash of the call to be answered.
* @param retval Return value of the answer.
* @param arg1 Service-defined return value.
* @param arg2 Service-defined return value.
*
* @return Return 0 on success, otherwise return an error code.
*/
unative_t sys_ipc_answer_fast(unative_t callid, unative_t retval,
unative_t arg1, unative_t arg2)
{
465,7 → 547,13
return rc;
}
 
/** Send IPC answer */
/** Answer an IPC call.
*
* @param callid Hash of the call to be answered.
* @param data Userspace address of call data with the answer.
*
* @return Return 0 on success, otherwise return an error code.
*/
unative_t sys_ipc_answer(unative_t callid, ipc_data_t *data)
{
call_t *call;
497,8 → 585,11
return rc;
}
 
/** Hang up the phone
/** Hang up a phone.
*
* @param Phone handle of the phone to be hung up.
*
* @return Return 0 on success or an error code.
*/
unative_t sys_ipc_hangup(int phoneid)
{
512,7 → 603,7
return 0;
}
 
/** Wait for incoming ipc call or answer
/** Wait for an incoming IPC call or an answer.
*
* @param calldata Pointer to buffer where the call/answer data is stored.
* @param usec Timeout. See waitq_sleep_timeout() for explanation.
519,7 → 610,10
* @param flags Select mode of sleep operation. See waitq_sleep_timeout()
* for explanation.
*
* @return Callid, if callid & 1, then the call is answer
* @return Hash of the call.
* If IPC_CALLID_NOTIFICATION bit is set in the hash, the
* call is a notification. IPC_CALLID_ANSWERED denotes an
* answer.
*/
unative_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec, int flags)
{
541,7 → 635,7
 
ipc_call_free(call);
return ((unative_t)call) | IPC_CALLID_NOTIFICATION;
return ((unative_t) call) | IPC_CALLID_NOTIFICATION;
}
 
if (call->flags & IPC_CALL_ANSWERED) {
559,7 → 653,7
STRUCT_TO_USPACE(&calldata->args, &call->data.args);
ipc_call_free(call);
 
return ((unative_t)call) | IPC_CALLID_ANSWERED;
return ((unative_t) call) | IPC_CALLID_ANSWERED;
}
 
if (process_request(&TASK->answerbox, call))
573,14 → 667,14
return (unative_t)call;
}
 
/** Connect irq handler to task.
/** Connect an IRQ handler to a task.
*
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to the top-half pseudocode.
* @param inr IRQ number.
* @param devno Device number.
* @param method Method to be associated with the notification.
* @param ucode Uspace pointer to the top-half pseudocode.
*
* @return EPERM or a return code returned by ipc_irq_register().
* @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)
591,10 → 685,12
return ipc_irq_register(&TASK->answerbox, inr, devno, method, ucode);
}
 
/** Disconnect irq handler from task.
/** Disconnect an IRQ handler from a task.
*
* @param inr IRQ number.
* @param devno Device number.
* @param inr IRQ number.
* @param devno Device number.
*
* @return Zero on success or EPERM on error..
*/
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno)
{