summaryrefslogtreecommitdiff
path: root/concurrency.c
diff options
context:
space:
mode:
Diffstat (limited to 'concurrency.c')
-rw-r--r--concurrency.c68
1 files changed, 51 insertions, 17 deletions
diff --git a/concurrency.c b/concurrency.c
index 139883c..be1d62c 100644
--- a/concurrency.c
+++ b/concurrency.c
@@ -25,9 +25,9 @@ static ThreadData **threads;
int mainstacksize = STACKSIZE;
void
-recvtimeout(void *)
+recvtimeout(void *raw)
{
- ThreadData *td = getthreaddata();
+ ThreadData *td = (ThreadData *)raw;
if(0 == sleep(td->timeout)){
qlock(&td->lock);
td->timedout = 1;
@@ -107,37 +107,71 @@ messagesend(Array *a, int id)
Array *
messagerecv(Function match, int timeout)
{
- USED(match);
ThreadData *td = getthreaddata();
qlock(&td->lock);
+
+ /* Start a "timeout thread" if needed */
int timeoutid = 0;
+ td->timedout = 0; /* clear the timeout bit */
if(timeout > 0){
td->timeout = timeout;
- timeoutid = threadcreate(recvtimeout, nil, STACKSIZE);
+ timeoutid = proccreate(recvtimeout, td, STACKSIZE);
}
- td->timedout = 0; /* clear the timeout bit */
- while(td->mail == nil && !td->timedout){
+
+ /* Wait for a message, or timeout */
+ Mail *prev = nil;
+ Mail *m;
+Retry:
+ m = prev ? prev->next : td->mail;
+ while((td->mail == nil || (prev != nil && prev->next == nil)) && !td->timedout){
if(timeout == 0)
td->timedout = 1;
- else
+ else{
rsleep(&td->newmail);
+ if(prev == nil)
+ m = td->mail;
+ else
+ m = prev->next;
+ }
}
- if(timeout > 0)
- threadkill(timeoutid);
if(td->timedout){
qunlock(&td->lock);
throwerror(L"Message receive", ETimeout);
return nil; /* not reached */
- }else{
- Mail *m = td->mail;
+ }
+
+ /* Check if the new message is OK according to 'match' */
+ prev = m;
+ Array *matchres = runfunc(match, nil, m->contents);
+ if(GetRank(matchres) != 1 || GetSize(matchres) != 2){
+ freearray(matchres);
+ goto Retry;
+ }
+ Array *ok = arrayitem(matchres, 0);
+ if(GetType(ok) != AtypeInt || ok->intdata[0] != 1){
+ freearray(matchres);
+ freearray(ok);
+ goto Retry;
+ }
+
+ /* We found a match, remove the mail from the mailbox, and kill the timeout */
+ if(timeout > 0)
+ threadkill(timeoutid);
+ if(td->mail == m)
td->mail = m->next;
- if(td->mail == nil)
- td->lastmail = nil;
- qunlock(&td->lock);
- Array *a = m->contents;
- free(m);
- return a;
+ else{
+ Mail *tmp;
+ for(tmp = td->mail; tmp->next != m; tmp = tmp->next);
+ tmp->next = m->next;
}
+ if(td->mail == nil)
+ td->lastmail = nil;
+ qunlock(&td->lock);
+ Array *res = arrayitem(matchres, 1);
+ free(m);
+ freearray(matchres);
+ freearray(ok);
+ return res;
}