123,28 → 123,6 |
phone->busy = 0; |
} |
|
/** Disconnect phone from answerbox |
* |
* It is allowed to call disconnect on already disconnected phone\ |
*/ |
void ipc_phone_destroy(phone_t *phone) |
{ |
answerbox_t *box = phone->callee; |
|
ASSERT(box); |
|
spinlock_lock(&phone->lock); |
spinlock_lock(&box->lock); |
|
if (phone->callee) { |
list_remove(&phone->list); |
phone->callee = NULL; |
} |
|
spinlock_unlock(&box->lock); |
spinlock_unlock(&phone->lock); |
} |
|
/** Helper function to facilitate synchronous calls */ |
void ipc_call_sync(phone_t *phone, call_t *request) |
{ |
190,6 → 168,18 |
_ipc_answer_free_call(call); |
} |
|
/* Unsafe unchecking ipc_call */ |
static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call) |
{ |
atomic_inc(&phone->active_calls); |
call->data.phone = phone; |
|
spinlock_lock(&box->lock); |
list_append(&call->list, &box->calls); |
spinlock_unlock(&box->lock); |
waitq_wakeup(&box->wq, 0); |
} |
|
/** Send a asynchronous request using phone to answerbox |
* |
* @param phone Phone connected to answerbox |
200,20 → 190,55 |
answerbox_t *box; |
|
spinlock_lock(&phone->lock); |
|
box = phone->callee; |
if (!box) { |
/* Trying to send over disconnected phone */ |
spinlock_unlock(&phone->lock); |
|
call->data.phone = phone; |
IPC_SET_RETVAL(call->data, ENOENT); |
_ipc_answer_free_call(call); |
return; |
} |
_ipc_call(phone, box, call); |
|
spinlock_unlock(&phone->lock); |
} |
|
/** Disconnect phone from answerbox |
* |
* It is allowed to call disconnect on already disconnected phone |
* |
* @return 0 - phone disconnected, -1 - the phone was already disconnected |
*/ |
int ipc_phone_hangup(phone_t *phone) |
{ |
answerbox_t *box; |
call_t *call; |
|
spinlock_lock(&phone->lock); |
box = phone->callee; |
if (!box) { |
spinlock_unlock(&phone->lock); |
return -1; |
} |
|
spinlock_lock(&box->lock); |
list_append(&call->list, &box->calls); |
list_remove(&phone->list); |
phone->callee = NULL; |
spinlock_unlock(&box->lock); |
waitq_wakeup(&box->wq, 0); |
|
call = ipc_call_alloc(); |
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); |
call->flags |= IPC_CALL_DISCARD_ANSWER; |
_ipc_call(phone, box, call); |
|
phone->busy = 0; |
|
spinlock_unlock(&phone->lock); |
|
return 0; |
} |
|
/** Forwards call from one answerbox to a new one |
225,6 → 250,7 |
void ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox) |
{ |
spinlock_lock(&oldbox->lock); |
atomic_dec(&call->data.phone->active_calls); |
list_remove(&call->list); |
spinlock_unlock(&oldbox->lock); |
|
241,12 → 267,21 |
{ |
call_t *request; |
|
restart: |
if (flags & IPC_WAIT_NONBLOCKING) { |
if (waitq_sleep_timeout(&box->wq,0,1) == ESYNCH_WOULD_BLOCK) |
return NULL; |
} else |
waitq_sleep(&box->wq); |
|
spinlock_lock(&box->lock); |
while (1) { |
if (!list_empty(&box->answers)) { |
/* Handle asynchronous answers */ |
request = list_get_instance(box->answers.next, call_t, list); |
list_remove(&request->list); |
printf("%d %P\n", IPC_GET_METHOD(request->data), |
request->data.phone); |
atomic_dec(&request->data.phone->active_calls); |
} else if (!list_empty(&box->calls)) { |
/* Handle requests */ |
request = list_get_instance(box->calls.next, call_t, list); |
255,17 → 290,10 |
list_append(&request->list, &box->dispatched_calls); |
request->flags |= IPC_CALL_DISPATCHED; |
} else { |
if (!(flags & IPC_WAIT_NONBLOCKING)) { |
/* Wait for event to appear */ |
printf("WARNING: Spurious IPC wakeup.\n"); |
spinlock_unlock(&box->lock); |
waitq_sleep(&box->wq); |
spinlock_lock(&box->lock); |
continue; |
goto restart; |
} |
request = NULL; |
} |
break; |
} |
spinlock_unlock(&box->lock); |
return request; |
} |