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))
/kernel/trunk/generic/src/ipc/ipc.c
31,8 → 31,8
* First the answerbox, then the phone
*/
 
#include <synch/condvar.h>
#include <synch/mutex.h>
#include <synch/spinlock.h>
#include <synch/waitq.h>
#include <ipc/ipc.h>
#include <errno.h>
#include <mm/slab.h>
84,8 → 84,8
*/
void ipc_answerbox_init(answerbox_t *box)
{
mutex_initialize(&box->mutex);
condvar_initialize(&box->cv);
spinlock_initialize(&box->lock, "ipc_box_lock");
waitq_initialize(&box->wq);
list_initialize(&box->connected_phones);
list_initialize(&box->calls);
list_initialize(&box->dispatched_calls);
93,19 → 93,27
box->task = TASK;
}
 
/** Initialize phone structure and connect phone to naswerbox
*/
void ipc_phone_init(phone_t *phone, answerbox_t *box)
/** Connect phone to answerbox */
void ipc_phone_connect(phone_t *phone, answerbox_t *box)
{
spinlock_initialize(&phone->lock, "phone_lock");
ASSERT(!phone->callee);
phone->busy = 1;
phone->callee = box;
 
mutex_lock(&box->mutex);
spinlock_lock(&box->lock);
list_append(&phone->list, &box->connected_phones);
mutex_unlock(&box->mutex);
spinlock_unlock(&box->lock);
}
 
/** Initialize phone structure and connect phone to naswerbox
*/
void ipc_phone_init(phone_t *phone)
{
spinlock_initialize(&phone->lock, "phone_lock");
phone->callee = NULL;
phone->busy = 0;
}
 
/** Disconnect phone from answerbox */
void ipc_phone_destroy(phone_t *phone)
{
113,9 → 121,9
ASSERT(box);
 
mutex_lock(&box->mutex);
spinlock_lock(&box->lock);
list_remove(&phone->list);
mutex_unlock(&box->mutex);
spinlock_unlock(&box->lock);
}
 
/** Helper function to facilitate synchronous calls */
137,18 → 145,36
* @param phone Phone connected to answerbox
* @param request Request to be sent
*/
void ipc_call(phone_t *phone, call_t *request)
void ipc_call(phone_t *phone, call_t *call)
{
answerbox_t *box = phone->callee;
 
ASSERT(box);
 
mutex_lock(&box->mutex);
list_append(&request->list, &box->calls);
mutex_unlock(&box->mutex);
condvar_signal(&box->cv);
spinlock_lock(&box->lock);
list_append(&call->list, &box->calls);
spinlock_unlock(&box->lock);
waitq_wakeup(&box->wq, 0);
}
 
/** Forwards call from one answerbox to a new one
*
* @param request Request to be forwarded
* @param newbox Target answerbox
* @param oldbox Old answerbox
*/
void ipc_forward(call_t *call, answerbox_t *newbox, answerbox_t *oldbox)
{
spinlock_lock(&oldbox->lock);
list_remove(&call->list);
spinlock_unlock(&oldbox->lock);
 
spinlock_lock(&newbox->lock);
list_append(&call->list, &newbox->calls);
spinlock_lock(&newbox->lock);
waitq_wakeup(&newbox->wq, 0);
}
 
/** Answer message back to phone
*
* @param box Answerbox that is answering the message
160,14 → 186,14
 
request->flags |= IPC_CALL_ANSWERED;
 
mutex_lock(&box->mutex);
spinlock_lock(&box->lock);
list_remove(&request->list);
mutex_unlock(&box->mutex);
spinlock_unlock(&box->lock);
 
mutex_lock(&callerbox->mutex);
spinlock_lock(&callerbox->lock);
list_append(&request->list, &callerbox->answers);
mutex_unlock(&callerbox->mutex);
condvar_signal(&callerbox->cv);
spinlock_unlock(&callerbox->lock);
waitq_wakeup(&callerbox->wq, 0);
}
 
/** Wait for phone call
179,7 → 205,7
{
call_t *request;
 
mutex_lock(&box->mutex);
spinlock_lock(&box->lock);
while (1) {
if (!list_empty(&box->answers)) {
/* Handle asynchronous answers */
194,7 → 220,9
} else {
if (!(flags & IPC_WAIT_NONBLOCKING)) {
/* Wait for event to appear */
condvar_wait(&box->cv, &box->mutex);
spinlock_unlock(&box->lock);
waitq_sleep(&box->wq);
spinlock_lock(&box->lock);
continue;
}
request = NULL;
201,7 → 229,7
}
break;
}
mutex_unlock(&box->mutex);
spinlock_unlock(&box->lock);
return request;
}