Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1039 → Rev 1040

/kernel/trunk/generic/include/syscall/syscall.h
40,8 → 40,10
SYS_IPC_CALL_ASYNC,
SYS_IPC_ANSWER_FAST,
SYS_IPC_ANSWER,
SYS_IPC_FORWARD_FAST,
SYS_IPC_WAIT,
SYS_IPC_CONNECT_TO_ME,
SYS_IPC_CONNECT_ME_TO,
SYSCALL_END
} syscall_t;
 
/kernel/trunk/generic/include/errno.h
35,5 → 35,7
#define ENOMEM -2 /* Not enough memory */
#define ELIMIT -3 /* Limit exceeded */
#define EREFUSED -4 /* Connection refused */
#define EFORWARD -5 /* Forward error */
#define EPERM -6 /* Permission denied */
 
#endif
/kernel/trunk/generic/include/ipc/sysipc.h
43,5 → 43,10
__native arg2, task_id_t *taskid);
__native sys_ipc_wait_for_call(ipc_data_t *calldata, task_id_t *taskid,
__native flags);
__native sys_ipc_connect_me_to(__native phoneid, __native arg1,
__native arg2);
__native sys_ipc_forward_fast(__native callid, __native phoneid,
__native method, __native arg1);
 
 
#endif
/kernel/trunk/generic/include/ipc/ipc.h
71,13 → 71,12
/* System-specific methods - only through special syscalls
* These methods have special behaviour
*/
#define IPC_M_IAMCONNECTING 0
/** Protocol for CONNECT - TO - ME
*
* Calling process asks the callee to create a callback connection,
* so that it can start initiating new messages.
*
* The protocol for negotiating is as follows:
* The protocol for negotiating is:
* - sys_connecttome - sends a message IPC_M_CONNECTTOME
* - sys_wait_for_call - upon receipt tries to allocate new phone
* - if it fails, responds with ELIMIT
85,16 → 84,34
* responds with error, phone is deallocated and
* error is sent back to caller. Otherwise
* the call is accepted and the response is sent back.
* - the allocated phoneid is passed to userspace as
* ARG3 of the call.
* - the allocated phoneid is passed to userspace
* (on the receiving sid) as ARG3 of the call.
* - the caller obtains taskid of the called thread
*/
#define IPC_M_CONNECTTOME 1
/** Protocol for CONNECT - ME - TO
*
* Calling process asks the callee to create for him a new connection.
* E.g. the caller wants a name server to connect him to print server.
*
* The protocol for negotiating is:
* - sys_connect_me_to - send a synchronous message to name server
* indicating that it wants to be connected to some
* service
* recepient - if ipc_answer == 0, then accept connection
* - otherwise connection refused
* - recepient may forward message. Forwarding
* system message
*
*/
#define IPC_M_CONNECTMETO 2
/* Control messages that the server sends to the processes
* about their connections.
*/
 
 
/* Well-known methods */
#define IPC_M_FIRST_USER 512
#define IPC_M_LAST_SYSTEM 511
#define IPC_M_PING 512
/* User methods */
#define FIRST_USER_METHOD 1024
123,8 → 140,7
 
task_t *task;
 
mutex_t mutex;
condvar_t cv;
waitq_t wq;
 
link_t connected_phones; /**< Phones connected to this answerbox */
link_t calls; /**< Received calls */
137,6 → 153,7
SPINLOCK_DECLARE(lock);
link_t list;
answerbox_t *callee;
int busy;
} phone_t;
 
extern void ipc_init(void);
145,12 → 162,13
extern void ipc_call(phone_t *phone, call_t *request);
extern void ipc_call_sync(phone_t *phone, call_t *request);
extern void ipc_phone_destroy(phone_t *phone);
extern void ipc_phone_init(phone_t *phone, answerbox_t *box);
extern void ipc_phone_init(phone_t *phone);
extern void ipc_phone_connect(phone_t *phone, answerbox_t *box);
extern void ipc_call_free(call_t *call);
extern call_t * ipc_call_alloc(void);
extern void ipc_answerbox_init(answerbox_t *box);
extern void ipc_phone_init(phone_t *phone, answerbox_t *box);
extern void ipc_call_init(call_t *call);
extern void ipc_forward(call_t *call, answerbox_t *newbox,answerbox_t *oldbox);
 
extern answerbox_t *ipc_phone_0;
 
/kernel/trunk/generic/src/proc/task.c
69,6 → 69,7
{
ipl_t ipl;
task_t *ta;
int i;
ta = (task_t *) malloc(sizeof(task_t), 0);
 
77,10 → 78,12
list_initialize(&ta->tasks_link);
ta->as = as;
 
ipc_answerbox_init(&ta->answerbox);
memsetb((__address)&ta->phones, sizeof(ta->phones[0])*IPC_MAX_PHONES, 0);
for (i=0; i < IPC_MAX_PHONES;i++)
ipc_phone_init(&ta->phones[i]);
if (ipc_phone_0)
ipc_phone_init(&ta->phones[0], ipc_phone_0);
ipc_phone_connect(&ta->phones[0], ipc_phone_0);
atomic_set(&ta->active_calls, 0);
ipl = interrupts_disable();
/kernel/trunk/generic/src/main/kinit.c
143,9 → 143,10
panic("init[%d].addr is not frame aligned", i);
 
utask = task_run_program((void *) init.tasks[i].addr);
if (utask)
ipc_phone_0 = &utask->answerbox;
else
if (utask) {
if (!ipc_phone_0)
ipc_phone_0 = &utask->answerbox;
} else
printf("Userspace not started.\n");
}
 
/kernel/trunk/generic/src/syscall/syscall.c
81,6 → 81,8
sys_ipc_call_async,
sys_ipc_answer_fast,
sys_ipc_answer,
sys_ipc_forward_fast,
sys_ipc_wait_for_call,
sys_ipc_connect_to_me
sys_ipc_connect_to_me,
sys_ipc_connect_me_to
};
/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;
}