31,7 → 31,8 |
* First the answerbox, then the phone |
*/ |
|
#include <synch/waitq.h> |
#include <synch/condvar.h> |
#include <synch/mutex.h> |
#include <ipc/ipc.h> |
#include <errno.h> |
#include <mm/slab.h> |
43,7 → 44,8 |
#include <print.h> |
#include <proc/thread.h> |
|
answerbox_t *ipc_central_box; |
/* Open channel that is assigned automatically to new tasks */ |
answerbox_t *ipc_phone_0 = NULL; |
|
static slab_cache_t *ipc_call_slab; |
|
63,6 → 65,13 |
return call; |
} |
|
/** Initialize allocated call */ |
void ipc_call_init(call_t *call) |
{ |
call->callerbox = &TASK->answerbox; |
call->flags = IPC_CALL_STATIC_ALLOC; |
} |
|
/** Deallocate call stracuture */ |
void ipc_call_free(call_t *call) |
{ |
73,8 → 82,8 |
*/ |
void ipc_answerbox_init(answerbox_t *box) |
{ |
spinlock_initialize(&box->lock, "abox_lock"); |
waitq_initialize(&box->wq); |
mutex_initialize(&box->mutex); |
condvar_initialize(&box->cv); |
list_initialize(&box->connected_phones); |
list_initialize(&box->calls); |
list_initialize(&box->dispatched_calls); |
88,9 → 97,10 |
spinlock_initialize(&phone->lock, "phone_lock"); |
|
phone->callee = box; |
spinlock_lock(&box->lock); |
|
mutex_lock(&box->mutex); |
list_append(&phone->list, &box->connected_phones); |
spinlock_unlock(&box->lock); |
mutex_unlock(&box->mutex); |
} |
|
/** Disconnect phone from answerbox */ |
100,9 → 110,9 |
|
ASSERT(box); |
|
spinlock_lock(&box->lock); |
mutex_lock(&box->mutex); |
list_remove(&phone->list); |
spinlock_unlock(&box->lock); |
mutex_unlock(&box->mutex); |
} |
|
/** Helper function to facilitate synchronous calls */ |
130,10 → 140,10 |
|
ASSERT(box); |
|
spinlock_lock(&box->lock); |
mutex_lock(&box->mutex); |
list_append(&request->list, &box->calls); |
spinlock_unlock(&box->lock); |
waitq_wakeup(&box->wq, 0); |
mutex_unlock(&box->mutex); |
condvar_signal(&box->cv); |
} |
|
/** Answer message back to phone |
147,15 → 157,14 |
|
request->flags |= IPC_CALL_ANSWERED; |
|
spinlock_lock(&box->lock); |
spinlock_lock(&callerbox->lock); |
mutex_lock(&box->mutex); |
list_remove(&request->list); |
mutex_unlock(&box->mutex); |
|
list_remove(&request->list); |
mutex_lock(&callerbox->mutex); |
list_append(&request->list, &callerbox->answers); |
waitq_wakeup(&callerbox->wq, 0); |
|
spinlock_unlock(&callerbox->lock); |
spinlock_unlock(&box->lock); |
mutex_unlock(&callerbox->mutex); |
condvar_signal(&callerbox->cv); |
} |
|
/** Wait for phone call |
167,30 → 176,30 |
{ |
call_t *request; |
|
if ((flags & IPC_WAIT_NONBLOCKING)) { |
if (waitq_sleep_timeout(&box->wq,SYNCH_NO_TIMEOUT,SYNCH_NON_BLOCKING) == ESYNCH_WOULD_BLOCK) |
return 0; |
} else { |
waitq_sleep(&box->wq); |
mutex_lock(&box->mutex); |
while (1) { |
if (!list_empty(&box->answers)) { |
/* Handle asynchronous answers */ |
request = list_get_instance(box->answers.next, call_t, list); |
list_remove(&request->list); |
} else if (!list_empty(&box->calls)) { |
/* Handle requests */ |
request = list_get_instance(box->calls.next, call_t, list); |
list_remove(&request->list); |
/* Append request to dispatch queue */ |
list_append(&request->list, &box->dispatched_calls); |
} else { |
if (!(flags & IPC_WAIT_NONBLOCKING)) { |
condvar_wait(&box->cv, &box->mutex); |
continue; |
} |
if (condvar_trywait(&box->cv, &box->mutex) != ESYNCH_WOULD_BLOCK) |
continue; |
request = NULL; |
} |
break; |
} |
|
|
// TODO - might need condition variable+mutex if we want to support |
// removing of requests from queue before dispatch |
spinlock_lock(&box->lock); |
/* Handle answers first */ |
if (!list_empty(&box->answers)) { |
request = list_get_instance(box->answers.next, call_t, list); |
list_remove(&request->list); |
} else { |
ASSERT (! list_empty(&box->calls)); |
request = list_get_instance(box->calls.next, call_t, list); |
list_remove(&request->list); |
/* Append request to dispatch queue */ |
list_append(&request->list, &box->dispatched_calls); |
} |
spinlock_unlock(&box->lock); |
|
mutex_unlock(&box->mutex); |
return request; |
} |
|
202,32 → 211,3 |
0, |
NULL, NULL, 0); |
} |
|
static void ipc_phonecompany_thread(void *data) |
{ |
call_t *call; |
|
printf("Phone company started.\n"); |
while (1) { |
call = ipc_wait_for_call(&TASK->answerbox, 0); |
printf("Received phone call - %P %P\n", |
call->data[0], call->data[1]); |
call->data[0] = 0xbabaaaee;; |
call->data[1] = 0xaaaaeeee; |
ipc_answer(&TASK->answerbox, call); |
printf("Call answered.\n"); |
} |
} |
|
void ipc_create_phonecompany(void) |
{ |
thread_t *t; |
|
if ((t = thread_create(ipc_phonecompany_thread, "phonecompany", |
TASK, 0))) |
thread_ready(t); |
else |
panic("thread_create/phonecompany"); |
|
ipc_central_box = &TASK->answerbox; |
} |