Subversion Repositories HelenOS-historic

Compare Revisions

Ignore whitespace Rev 1567 → Rev 1568

/kernel/trunk/generic/include/proc/task.h
51,7 → 51,9
/* IPC stuff */
answerbox_t answerbox; /**< Communication endpoint */
phone_t phones[IPC_MAX_PHONES];
atomic_t active_calls; /**< Active asynchronous messages */
atomic_t active_calls; /**< Active asynchronous messages.
* It is used for limiting uspace to
* certain extent. */
task_arch_t arch; /**< Architecture specific task data. */
/kernel/trunk/generic/include/ipc/ipc.h
178,16 → 178,18
};
 
typedef enum {
IPC_BUSY_FREE = 0,
IPC_BUSY_CONNECTING,
IPC_BUSY_CONNECTED
} ipc_busy_t;
IPC_PHONE_FREE = 0, /**< Phone is free and can be allocated */
IPC_PHONE_CONNECTING, /**< Phone is connecting somewhere */
IPC_PHONE_CONNECTED, /**< Phone is connected */
IPC_PHONE_HUNGUP, /**< Phone is hung up, waiting for answers to come */
IPC_PHONE_SLAMMED /**< Phone was hungup from server */
} ipc_phone_state_t;
 
struct phone_s {
SPINLOCK_DECLARE(lock);
link_t list;
answerbox_t *callee;
ipc_busy_t busy;
ipc_phone_state_t state;
atomic_t active_calls;
};
 
222,7 → 224,7
extern void task_print_list(void);
extern int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox);
extern void ipc_cleanup(task_t *task);
extern int ipc_phone_hangup(phone_t *phone);
extern int ipc_phone_hangup(phone_t *phone, int aggressive);
extern void ipc_backsend_err(phone_t *phone, call_t *call, __native err);
 
extern answerbox_t *ipc_phone_0;
/kernel/trunk/generic/src/mm/frame.c
134,6 → 134,7
/**
* Insert-sort zone into zones list
*
* @param newzone New zone to be inserted into zone list
* @return zone number on success, -1 on error
*/
static int zones_add_zone(zone_t *newzone)
172,8 → 173,10
/**
* Try to find a zone where can we find the frame
*
* @param hint Start searching in zone 'hint'
* @param lock Lock zone if true
* @param frame Frame number contained in zone
* @param pzone If not null, it is used as zone hint. Zone index
* is filled into the variable on success.
* @return Pointer to LOCKED zone containing frame
*
* Assume interrupts disable
*/
220,6 → 223,7
*
* Assume interrupts are disabled!!
*
* @param order Size (2^order) of free space we are trying to find
* @param pzone Pointer to preferred zone or NULL, on return contains zone number
*/
static zone_t * find_free_zone_lock(__u8 order, int *pzone)
468,6 → 472,9
/** Free frame from zone
*
* Assume zone is locked
*
* @param zone Pointer to zone from which the frame is to be freed
* @param frame_idx Frame index relative to zone
*/
static void zone_frame_free(zone_t *zone, index_t frame_idx)
{
518,6 → 525,10
* Expect zone_t *z to point to space at least zone_conf_size large
*
* Assume z1 & z2 are locked
*
* @param z Target zone structure pointer
* @param z1 Zone to merge
* @param z2 Zone to merge
*/
 
static void _zone_merge(zone_t *z, zone_t *z1, zone_t *z2)
627,8 → 638,9
/** Reduce allocated block to count of order 0 frames
*
* The allocated block need 2^order frames of space. Reduce all frames
* in block to order 0 and free the unneded frames. This means, that
* when freeing the block, you have to free every frame from block.
* in block to order 0 and free the unneeded frames. This means, that
* when freeing the previously allocated block starting with frame_idx,
* you have to free every frame.
*
* @param zone
* @param frame_idx Index to block
751,8 → 763,8
* Create new frame zone.
*
* @param start Physical address of the first frame within the zone.
* @param size Size of the zone. Must be a multiple of FRAME_SIZE.
* @param conffram Address of configuration frame
* @param count Count of frames in zone
* @param z Address of configuration information of zone
* @param flags Zone flags.
*
* @return Initialized zone.
793,7 → 805,11
}
}
 
/** Compute configuration data size for zone */
/** Compute configuration data size for zone
*
* @param count Size of zone in frames
* @return Size of zone configuration info (in bytes)
*/
__address zone_conf_size(count_t count)
{
int size = sizeof(zone_t) + count*sizeof(frame_t);
806,11 → 822,16
 
/** Create and add zone to system
*
* @param confframe Where configuration frame is supposed to be.
* Always check, that we will not disturb the kernel and possibly init.
* @param start First frame number (absolute)
* @param count Size of zone in frames
* @param confframe Where configuration frames are supposed to be.
* Automatically checks, that we will not disturb the
* kernel and possibly init.
* If confframe is given _outside_ this zone, it is expected,
* that the area is already marked BUSY and big enough
* to contain zone_conf_size() amount of data
* to contain zone_conf_size() amount of data.
* If the confframe is inside the area, the zone free frame
* information is modified not to include it.
*
* @return Zone number or -1 on error
*/
/kernel/trunk/generic/src/ipc/ipcrsc.c
158,8 → 158,12
spinlock_lock(&TASK->lock);
for (i=0; i < IPC_MAX_PHONES; i++) {
if (TASK->phones[i].busy==IPC_BUSY_FREE && !atomic_get(&TASK->phones[i].active_calls)) {
TASK->phones[i].busy = IPC_BUSY_CONNECTING;
if (TASK->phones[i].state == IPC_PHONE_HUNGUP && \
atomic_get(&TASK->phones[i].active_calls) == 0)
TASK->phones[i].state = IPC_PHONE_FREE;
 
if (TASK->phones[i].state == IPC_PHONE_FREE) {
TASK->phones[i].state = IPC_PHONE_CONNECTING;
break;
}
}
172,11 → 176,11
 
static void phone_deallocp(phone_t *phone)
{
ASSERT(phone->busy == IPC_BUSY_CONNECTING);
ASSERT(phone->state == IPC_PHONE_CONNECTING);
ASSERT(! phone->callee);
/* atomic operation */
phone->busy = IPC_BUSY_FREE;
phone->state = IPC_PHONE_FREE;
}
 
/** Free slot from a disconnected phone
200,6 → 204,6
{
phone_t *phone = &TASK->phones[phoneid];
ASSERT(phone->busy == IPC_BUSY_CONNECTING);
ASSERT(phone->state == IPC_PHONE_CONNECTING);
ipc_phone_connect(phone, box);
}
/kernel/trunk/generic/src/ipc/sysipc.c
105,9 → 105,9
*/
spinlock_lock(&answer->data.phone->lock);
spinlock_lock(&TASK->answerbox.lock);
if (answer->data.phone->callee) {
if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
list_remove(&answer->data.phone->list);
answer->data.phone->callee = 0;
answer->data.phone->state = IPC_PHONE_SLAMMED;
}
spinlock_unlock(&TASK->answerbox.lock);
spinlock_unlock(&answer->data.phone->lock);
492,7 → 492,7
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
if (ipc_phone_hangup(phone))
if (ipc_phone_hangup(phone, 0))
return -1;
 
return 0;
/kernel/trunk/generic/src/ipc/ipc.c
111,7 → 111,7
spinlock_lock(&phone->lock);
 
ASSERT(!phone->callee);
phone->busy = IPC_BUSY_CONNECTED;
phone->state = IPC_PHONE_CONNECTED;
phone->callee = box;
 
spinlock_lock(&box->lock);
127,7 → 127,7
{
spinlock_initialize(&phone->lock, "phone_lock");
phone->callee = NULL;
phone->busy = IPC_BUSY_FREE;
phone->state = IPC_PHONE_FREE;
atomic_set(&phone->active_calls, 0);
}
 
184,11 → 184,7
{
call->data.phone = phone;
atomic_inc(&phone->active_calls);
if (phone->busy == IPC_BUSY_CONNECTED)
IPC_SET_RETVAL(call->data, EHANGUP);
else
IPC_SET_RETVAL(call->data, ENOENT);
 
IPC_SET_RETVAL(call->data, err);
_ipc_answer_free_call(call);
}
 
216,23 → 212,20
answerbox_t *box;
 
spinlock_lock(&phone->lock);
 
box = phone->callee;
if (!box) {
/* Trying to send over disconnected phone */
if (phone->state != IPC_PHONE_CONNECTED) {
spinlock_unlock(&phone->lock);
if (call->flags & IPC_CALL_FORWARDED) {
IPC_SET_RETVAL(call->data, EFORWARD);
_ipc_answer_free_call(call);
} else { /* Simulate sending back a message */
if (phone->busy == IPC_BUSY_CONNECTED)
} else {
if (phone->state == IPC_PHONE_HUNGUP)
ipc_backsend_err(phone, call, EHANGUP);
else
ipc_backsend_err(phone, call, ENOENT);
}
 
return ENOENT;
}
box = phone->callee;
_ipc_call(phone, box, call);
spinlock_unlock(&phone->lock);
241,40 → 234,51
 
/** Disconnect phone from answerbox
*
* It is allowed to call disconnect on already disconnected phone
* This call leaves the phone in HUNGUP state. The change to 'free' is done
* lazily later.
*
* @param phone Phone to be hung up
* @param aggressive If false, the phone is only marked hungup, and all
* messages are allowed to complete.
* If true, all messages in all queues are discarded. There
* may still be some messages that will be 'in-transit' on
* other CPU.
*
* @return 0 - phone disconnected, -1 - the phone was already disconnected
*/
int ipc_phone_hangup(phone_t *phone)
int ipc_phone_hangup(phone_t *phone, int aggressive)
{
answerbox_t *box;
call_t *call;
spinlock_lock(&phone->lock);
if (phone->state == IPC_PHONE_FREE || phone->state ==IPC_PHONE_HUNGUP \
|| phone->state == IPC_PHONE_CONNECTING) {
spinlock_unlock(&phone->lock);
return -1;
}
box = phone->callee;
if (!box) {
if (phone->busy == IPC_BUSY_CONNECTING) {
spinlock_unlock(&phone->lock);
return -1;
if (phone->state != IPC_PHONE_SLAMMED) {
/* Remove myself from answerbox */
spinlock_lock(&box->lock);
list_remove(&phone->list);
spinlock_unlock(&box->lock);
 
if (phone->state != IPC_PHONE_SLAMMED) {
call = ipc_call_alloc(0);
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
}
/* Already disconnected phone */
phone->busy = IPC_BUSY_FREE;
spinlock_unlock(&phone->lock);
return 0;
}
 
spinlock_lock(&box->lock);
list_remove(&phone->list);
phone->callee = NULL;
spinlock_unlock(&box->lock);
if (aggressive && atomic_get(&phone->active_calls) > 0) {
/* TODO: Do some stuff be VERY aggressive */
}
 
call = ipc_call_alloc(0);
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
 
phone->busy = IPC_BUSY_FREE;
 
phone->callee = 0;
phone->state = IPC_PHONE_HUNGUP;
spinlock_unlock(&phone->lock);
 
return 0;
380,7 → 384,7
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i=0;i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&task->phones[i]);
ipc_phone_hangup(&task->phones[i], 1);
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&task->answerbox);
398,7 → 402,8
}
/* Disconnect phone */
phone->callee = NULL;
ASSERT(phone->state == IPC_PHONE_CONNECTED);
phone->state = IPC_PHONE_SLAMMED;
list_remove(&phone->list);
 
spinlock_unlock(&phone->lock);
411,7 → 416,21
spinlock_unlock(&task->answerbox.lock);
/* Wait for all async answers to arrive */
while (atomic_get(&task->active_calls)) {
while (1) {
/* Go through all phones, until all are FREE... */
/* Locking not needed, no one else should modify
* it, when we are in cleanup */
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 (task->phones[i].state != IPC_PHONE_FREE)
break;
}
/* Voila, got into cleanup */
if (i == IPC_MAX_PHONES)
break;
call = ipc_wait_for_call(&task->answerbox, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
ASSERT((call->flags & IPC_CALL_ANSWERED) || (call->flags & IPC_CALL_NOTIF));
ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));