diff options
Diffstat (limited to 'concurrency.c')
-rw-r--r-- | concurrency.c | 68 |
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; } |