Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1039 → Rev 1040

/kernel/trunk/generic/src/ipc/sysipc.c
40,9 → 40,37
/* TODO: multi-threaded connect-to-me can cause race condition
* on phone, add counter + thread_kill??
*
* - don't allow userspace app to send system messages
*/
 
/** Return true if the method is a system method */
static inline int is_system_method(__native method)
{
if (method <= IPC_M_LAST_SYSTEM)
return 1;
return 0;
}
 
/** Return true if the message with this method is forwardable
*
* - some system messages may be forwarded, for some of them
* it is useless
*/
static inline int is_forwardable(__native method)
{
return 1;
}
 
/** Find call_t * in call table according to callid
*
* @return NULL on not found, otherwise pointer to call structure
*/
static inline call_t * get_call(__native callid)
{
/* TODO: Traverse list of dispatched calls and find one */
/* TODO: locking of call, ripping it from dispatched calls etc. */
return (call_t *) callid;
}
 
/** Return pointer to phone identified by phoneid or NULL if non-existent */
static phone_t * get_phone(__native phoneid)
{
58,7 → 86,7
}
 
/** Allocate new phone slot in current TASK structure */
static int phone_alloc(answerbox_t *callee)
static int phone_alloc(void)
{
int i;
 
65,8 → 93,8
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (!TASK->phones[i].callee) {
TASK->phones[i].callee = callee;
if (!TASK->phones[i].busy) {
TASK->phones[i].busy = 1;
break;
}
}
82,12 → 110,22
{
spinlock_lock(&TASK->lock);
 
ASSERT(TASK->phones[phoneid].callee);
ASSERT(TASK->phones[phoneid].busy);
 
TASK->phones[phoneid].callee = NULL;
if (TASK->phones[phoneid].callee)
ipc_phone_destroy(&TASK->phones[phoneid]);
 
TASK->phones[phoneid].busy = 0;
spinlock_unlock(&TASK->lock);
}
 
static void phone_connect(int phoneid, answerbox_t *box)
{
phone_t *phone = &TASK->phones[phoneid];
ipc_phone_connect(phone, box);
}
 
/****************************************************/
/* Functions that preprocess answer before sending
* it to the recepient
104,16 → 142,18
}
 
/** Interpret process answer as control information */
static inline void answer_preprocess(call_t *answer, call_t *call)
static inline void answer_preprocess(call_t *answer, ipc_data_t *olddata)
{
int phoneid;
 
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME) {
if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTTOME) {
phoneid = IPC_GET_ARG3(*olddata);
if (IPC_GET_RETVAL(answer->data)) {
/* The connection was not accepted */
/* TODO...race for multi-threaded process */
phoneid = IPC_GET_ARG3(call->data);
phone_dealloc(phoneid);
} else {
/* The connection was accepted */
phone_connect(phoneid,&answer->sender->answerbox);
}
}
}
138,7 → 178,7
int phoneid;
 
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECTTOME) {
phoneid = phone_alloc(&call->sender->answerbox);
phoneid = phone_alloc();
if (phoneid < 0) { /* Failed to allocate phone */
IPC_SET_RETVAL(call->data, ELIMIT);
ipc_answer(box,call);
162,8 → 202,11
 
phone = get_phone(phoneid);
if (!phone)
return IPC_CALLRET_FATAL;
return ENOENT;
 
if (is_system_method(method))
return EPERM;
 
ipc_call_init(&call);
IPC_SET_METHOD(call.data, method);
IPC_SET_ARG1(call.data, arg1);
184,10 → 227,13
 
phone = get_phone(phoneid);
if (!phone)
return IPC_CALLRET_FATAL;
return ENOENT;
 
ipc_call_init(&call);
copy_from_uspace(&call.data, question, sizeof(call.data));
 
if (is_system_method(IPC_GET_METHOD(call.data)))
return EPERM;
ipc_call_sync(phone, &call);
 
224,6 → 270,9
if (!phone)
return IPC_CALLRET_FATAL;
 
if (is_system_method(method))
return IPC_CALLRET_FATAL;
 
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
 
255,6 → 304,11
 
call = ipc_call_alloc();
copy_from_uspace(&call->data, data, sizeof(call->data));
 
if (is_system_method(IPC_GET_METHOD(call->data))) {
ipc_call_free(call);
return EPERM;
}
ipc_call(phone, call);
 
261,21 → 315,63
return (__native) call;
}
 
/** Forward received call to another destination
*
* The arg1 and arg2 are changed in the forwarded message
*/
__native sys_ipc_forward_fast(__native callid, __native phoneid,
__native method, __native arg1)
{
call_t *call;
phone_t *phone;
 
call = get_call(callid);
if (!call)
return ENOENT;
 
phone = get_phone(phoneid);
if (!phone) {
IPC_SET_RETVAL(call->data, EFORWARD);
ipc_answer(&TASK->answerbox, call);
return ENOENT;
}
 
if (!is_forwardable(IPC_GET_METHOD(call->data))) {
IPC_SET_RETVAL(call->data, EFORWARD);
ipc_answer(&TASK->answerbox, call);
return EPERM;
}
 
/* Userspace is not allowed to change method of system methods
* on forward, allow changing ARG1 and ARG2 by means of method and arg1
*/
if (is_system_method(IPC_GET_METHOD(call->data))) {
IPC_SET_ARG1(call->data, method);
IPC_SET_ARG2(call->data, arg1);
} else {
IPC_SET_METHOD(call->data, method);
IPC_SET_ARG1(call->data, arg1);
}
 
ipc_forward(call, phone->callee, &TASK->answerbox);
 
return 0;
}
 
/** Send IPC answer */
__native sys_ipc_answer_fast(__native callid, __native retval,
__native arg1, __native arg2)
{
call_t *call;
call_t saved_call;
ipc_data_t saved_data;
int preprocess = 0;
 
/* Check that the user is not sending us answer callid */
ASSERT(! (callid & 1));
/* TODO: Check that the callid is in the dispatch table */
call = (call_t *) callid;
call = get_call(callid);
if (!call)
return ENOENT;
 
if (answer_will_preprocess(call)) {
memcpy(&saved_call.data, &call->data, sizeof(call->data));
memcpy(&saved_data, &call->data, sizeof(call->data));
preprocess = 1;
}
 
282,8 → 378,9
IPC_SET_RETVAL(call->data, retval);
IPC_SET_ARG1(call->data, arg1);
IPC_SET_ARG2(call->data, arg2);
 
if (preprocess)
answer_preprocess(call, &saved_call);
answer_preprocess(call, &saved_data);
 
ipc_answer(&TASK->answerbox, call);
return 0;
293,22 → 390,21
inline __native sys_ipc_answer(__native callid, __native *data)
{
call_t *call;
call_t saved_call;
ipc_data_t saved_data;
int preprocess = 0;
 
/* Check that the user is not sending us answer callid */
ASSERT(! (callid & 1));
/* TODO: Check that the callid is in the dispatch table */
call = (call_t *) callid;
call = get_call(callid);
if (!call)
return ENOENT;
 
if (answer_will_preprocess(call)) {
memcpy(&saved_call.data, &call->data, sizeof(call->data));
memcpy(&saved_data, &call->data, sizeof(call->data));
preprocess = 1;
}
copy_from_uspace(&call->data, data, sizeof(call->data));
 
if (preprocess)
answer_preprocess(call, &saved_call);
answer_preprocess(call, &saved_data);
ipc_answer(&TASK->answerbox, call);
 
327,7 → 423,7
 
phone = get_phone(phoneid);
if (!phone)
return IPC_CALLRET_FATAL;
return ENOENT;
 
ipc_call_init(&call);
IPC_SET_METHOD(call.data, IPC_M_CONNECTTOME);
343,6 → 439,33
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;
 
phone = get_phone(phoneid);
if (!phone)
return ENOENT;
 
ipc_call_init(&call);
IPC_SET_METHOD(call.data, IPC_M_CONNECTMETO);
IPC_SET_ARG1(call.data, arg1);
IPC_SET_ARG2(call.data, arg2);
 
ipc_call_sync(phone, &call);
if (!IPC_GET_RETVAL(call.data)) {
/* Everybody accepted, we should be connected by now */
}
 
return 0;
}
 
/** Wait for incoming ipc call or answer
*
* Generic function - can serve either as inkernel or userspace call
362,6 → 485,7
 
restart:
call = ipc_wait_for_call(&TASK->answerbox, flags);
printf("Received call %P from sender: %P\n", call, call->sender);
 
if (call->flags & IPC_CALL_ANSWERED) {
if (process_answer(&TASK->answerbox, call))