Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4406 → Rev 4407

/trunk/kernel/generic/include/ipc/ipc.h
111,6 → 111,25
/* System-specific methods - only through special syscalls
* These methods have special behaviour
*/
/** Clone connection.
*
* The calling task clones one of its phones for the callee.
*
* - ARG1 - The caller sets ARG1 to the phone of the cloned connection.
* - The callee gets the new phone from ARG1.
* - on answer, the callee acknowledges the new connection by sending EOK back
* or the kernel closes it
*/
#define IPC_M_CONNECTION_CLONE 1
/** Protocol for CONNECT - ME
*
* Through this call, the recipient learns about the new cloned connection.
*
* - ARG5 - the kernel sets ARG5 to contain the hash of the used phone
* - on asnwer, the callee acknowledges the new connection by sending EOK back
* or the kernel closes it
*/
#define IPC_M_CONNECT_ME 2
/** Protocol for CONNECT - TO - ME
*
* Calling process asks the callee to create a callback connection,
127,7 → 146,7
* - the allocated phoneid is passed to userspace
* (on the receiving side) as ARG5 of the call.
*/
#define IPC_M_CONNECT_TO_ME 1
#define IPC_M_CONNECT_TO_ME 3
/** Protocol for CONNECT - ME - TO
*
* Calling process asks the callee to create for him a new connection.
145,11 → 164,11
* - recepient may forward message.
*
*/
#define IPC_M_CONNECT_ME_TO 2
#define IPC_M_CONNECT_ME_TO 4
/** This message is sent to answerbox when the phone
* is hung up
*/
#define IPC_M_PHONE_HUNGUP 3
#define IPC_M_PHONE_HUNGUP 5
 
/** Send as_area over IPC.
* - ARG1 - source as_area base address
159,7 → 178,7
* on answer, the recipient must set:
* - ARG1 - dst as_area base adress
*/
#define IPC_M_SHARE_OUT 4
#define IPC_M_SHARE_OUT 6
 
/** Receive as_area over IPC.
* - ARG1 - destination as_area base address
171,7 → 190,7
* - ARG1 - source as_area base address
* - ARG2 - flags that will be used for sharing
*/
#define IPC_M_SHARE_IN 5
#define IPC_M_SHARE_IN 7
 
/** Send data to another address space over IPC.
* - ARG1 - source address space virtual address
182,7 → 201,7
* - ARG1 - final destination address space virtual address
* - ARG2 - final size of data to be copied
*/
#define IPC_M_DATA_WRITE 6
#define IPC_M_DATA_WRITE 8
 
/** Receive data from another address space over IPC.
* - ARG1 - destination virtual address in the source address space
193,13 → 212,13
* - ARG1 - source virtual address in the destination address space
* - ARG2 - final size of data to be copied
*/
#define IPC_M_DATA_READ 7
#define IPC_M_DATA_READ 9
 
/** Debug the recipient.
* - ARG1 - specifies the debug method (from udebug_method_t)
* - other arguments are specific to the debug method
*/
#define IPC_M_DEBUG_ALL 8
#define IPC_M_DEBUG_ALL 10
 
/* Well-known methods */
#define IPC_M_LAST_SYSTEM 511
/trunk/kernel/generic/include/ipc/ipcrsc.h
35,8 → 35,11
#ifndef KERN_IPCRSC_H_
#define KERN_IPCRSC_H_
 
#include <proc/task.h>
#include <ipc/ipc.h>
 
extern call_t * get_call(unative_t callid);
extern int phone_alloc(void);
extern int phone_alloc(task_t *t);
extern void phone_connect(int phoneid, answerbox_t *box);
extern void phone_dealloc(int phoneid);
 
/trunk/kernel/generic/src/ipc/ipcrsc.c
160,27 → 160,29
return result;
}
 
/** Allocate new phone slot in the current TASK structure.
/** Allocate new phone slot in the specified task.
*
* @param t Task for which to allocate a new phone.
*
* @return New phone handle or -1 if the phone handle limit is
* exceeded.
*/
int phone_alloc(void)
int phone_alloc(task_t *t)
{
int i;
 
spinlock_lock(&TASK->lock);
spinlock_lock(&t->lock);
for (i = 0; i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
atomic_get(&TASK->phones[i].active_calls) == 0)
TASK->phones[i].state = IPC_PHONE_FREE;
if (t->phones[i].state == IPC_PHONE_HUNGUP &&
atomic_get(&t->phones[i].active_calls) == 0)
t->phones[i].state = IPC_PHONE_FREE;
 
if (TASK->phones[i].state == IPC_PHONE_FREE) {
TASK->phones[i].state = IPC_PHONE_CONNECTING;
if (t->phones[i].state == IPC_PHONE_FREE) {
t->phones[i].state = IPC_PHONE_CONNECTING;
break;
}
}
spinlock_unlock(&TASK->lock);
spinlock_unlock(&t->lock);
 
if (i == IPC_MAX_PHONES)
return -1;
/trunk/kernel/generic/src/ipc/kbox.c
248,7 → 248,7
return EINVAL;
}
 
newphid = phone_alloc();
newphid = phone_alloc(TASK);
if (newphid < 0) {
mutex_unlock(&ta->kb.cleanup_lock);
return ELIMIT;
/trunk/kernel/generic/src/ipc/sysipc.c
93,6 → 93,8
static inline int method_is_forwardable(unative_t method)
{
switch (method) {
case IPC_M_CONNECTION_CLONE:
case IPC_M_CONNECT_ME:
case IPC_M_PHONE_HUNGUP:
/* This message is meant only for the original recipient. */
return 0;
140,6 → 142,8
static inline int answer_need_old(call_t *call)
{
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_CONNECTION_CLONE:
case IPC_M_CONNECT_ME:
case IPC_M_CONNECT_TO_ME:
case IPC_M_CONNECT_ME_TO:
case IPC_M_SHARE_OUT:
182,9 → 186,48
if (!olddata)
return 0;
 
if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
phoneid = IPC_GET_ARG1(*olddata);
phone_t *phone = &TASK->phones[phoneid];
if (IPC_GET_RETVAL(answer->data) != EOK) {
/*
* The recipient of the cloned phone rejected the offer.
* In this case, the connection was established at the
* request time and therefore we need to slam the phone.
* We don't merely hangup as that would result in
* sending IPC_M_HUNGUP to the third party on the
* other side of the cloned phone.
*/
mutex_lock(&phone->lock);
if (phone->state == IPC_PHONE_CONNECTED) {
spinlock_lock(&phone->callee->lock);
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
spinlock_unlock(&phone->callee->lock);
}
mutex_unlock(&phone->lock);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME) {
phone_t *phone = (phone_t *)IPC_GET_ARG5(*olddata);
if (IPC_GET_RETVAL(answer->data) != EOK) {
/*
* The other party on the cloned phoned rejected our
* request for connection on the protocol level.
* We need to break the connection without sending
* IPC_M_HUNGUP back.
*/
mutex_lock(&phone->lock);
if (phone->state == IPC_PHONE_CONNECTED) {
spinlock_lock(&phone->callee->lock);
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
spinlock_unlock(&phone->callee->lock);
}
mutex_unlock(&phone->lock);
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
phoneid = IPC_GET_ARG5(*olddata);
if (IPC_GET_RETVAL(answer->data)) {
if (IPC_GET_RETVAL(answer->data) != EOK) {
/* The connection was not accepted */
phone_dealloc(phoneid);
} else {
196,7 → 239,7
}
} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
/* If the users accepted call, connect */
if (!IPC_GET_RETVAL(answer->data)) {
if (IPC_GET_RETVAL(answer->data) == EOK) {
ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
&TASK->answerbox);
}
308,8 → 351,48
int rc;
 
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_CONNECTION_CLONE: {
phone_t *cloned_phone;
GET_CHECK_PHONE(cloned_phone, IPC_GET_ARG1(call->data),
return ENOENT);
if (cloned_phone < phone) {
mutex_lock(&cloned_phone->lock);
mutex_lock(&phone->lock);
} else {
mutex_lock(&phone->lock);
mutex_lock(&cloned_phone->lock);
}
if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
phone->state != IPC_PHONE_CONNECTED) {
mutex_unlock(&cloned_phone->lock);
mutex_unlock(&phone->lock);
return EINVAL;
}
/*
* We can be pretty sure now that both tasks exist and we are
* connected to them. As we continue to hold the phone locks,
* we are effectively preventing them from finishing their
* potential cleanup.
*/
newphid = phone_alloc(phone->callee->task);
if (newphid < 0) {
mutex_unlock(&cloned_phone->lock);
mutex_unlock(&phone->lock);
return ELIMIT;
}
ipc_phone_connect(&phone->callee->task->phones[newphid],
cloned_phone->callee);
mutex_unlock(&cloned_phone->lock);
mutex_unlock(&phone->lock);
/* Set the new phone for the callee. */
IPC_SET_ARG1(call->data, newphid);
break;
}
case IPC_M_CONNECT_ME:
IPC_SET_ARG5(call->data, (unative_t) phone);
break;
case IPC_M_CONNECT_ME_TO:
newphid = phone_alloc();
newphid = phone_alloc(TASK);
if (newphid < 0)
return ELIMIT;
/* Set arg5 for server */
399,7 → 482,7
int phoneid;
 
if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
phoneid = phone_alloc();
phoneid = phone_alloc(TASK);
if (phoneid < 0) { /* Failed to allocate phone */
IPC_SET_RETVAL(call->data, ELIMIT);
ipc_answer(box, call);