void mill_chclose(chan ch) { if(mill_slow(!ch)) mill_panic("null channel used"); assert(ch->refcount > 0); --ch->refcount; if(ch->refcount) return; if(!mill_list_empty(&ch->sender.clauses) || !mill_list_empty(&ch->receiver.clauses)) mill_panic("attempt to close a channel while it is still being used"); free(ch); }
void mill_choose_out(void *clause, chan ch, void *val, size_t sz, int idx) { if(mill_slow(!ch)) mill_panic("null channel used"); if(mill_slow(ch->done)) mill_panic("send to done-with channel"); if(mill_slow(ch->sz != sz)) mill_panic("send of a type not matching the channel"); /* Find out whether the clause is immediately available. */ int available = !mill_list_empty(&ch->receiver.clauses) || ch->items < ch->bufsz ? 1 : 0; if(available) ++mill_running->u_choose.available; /* If there are available clauses don't bother with non-available ones. */ if(!available && mill_running->u_choose.available) return; /* Fill in the clause entry. */ struct mill_clause *cl = (struct mill_clause*) clause; cl->cr = mill_running; cl->ep = &ch->sender; cl->val = val; cl->available = available; cl->idx = idx; cl->used = 1; mill_slist_push_back(&mill_running->u_choose.clauses, &cl->chitem); if(cl->ep->seqnum == mill_choose_seqnum) { ++cl->ep->refs; return; } cl->ep->seqnum = mill_choose_seqnum; cl->ep->refs = 1; cl->ep->tmp = -1; }
int mill_timer_next(void) { if(mill_list_empty(&mill_timers)) return -1; int64_t nw = now(); int64_t expiry = mill_cont(mill_list_begin(&mill_timers), struct mill_timer, item)->expiry; return (int) (nw >= expiry ? 0 : expiry - nw); }
int mill_timer_fire(void) { /* Avoid getting current time if there are no timers anyway. */ if(mill_list_empty(&mill_timers)) return 0; int64_t nw = now(); int fired = 0; while(!mill_list_empty(&mill_timers)) { struct mill_timer *tm = mill_cont( mill_list_begin(&mill_timers), struct mill_timer, item); if(tm->expiry > nw) break; mill_list_erase(&mill_timers, mill_list_begin(&mill_timers)); if(tm->callback) tm->callback(tm); fired = 1; } return fired; }
/* Push new item to the channel. */ static void mill_enqueue(chan ch, void *val) { /* If there's a receiver already waiting, let's resume it. */ if(!mill_list_empty(&ch->receiver.clauses)) { struct mill_clause *cl = mill_cont( mill_list_begin(&ch->receiver.clauses), struct mill_clause, epitem); memcpy(mill_valbuf(cl->cr, ch->sz), val, ch->sz); mill_choose_unblock(cl); return; } /* Write the value to the buffer. */ assert(ch->items < ch->bufsz); size_t pos = (ch->first + ch->items) % ch->bufsz; memcpy(((char*)(ch + 1)) + (pos * ch->sz) , val, ch->sz); ++ch->items; }
void goredump(void) { char buf[256]; char idbuf[10]; fprintf(stderr, "\nCOROUTINE state " "current created\n"); fprintf(stderr, "----------------------------------------------------------------------" "--------------------------------------------------\n"); struct mill_list_item *it; for(it = mill_list_begin(&mill_all_crs); it; it = mill_list_next(it)) { struct mill_cr *cr = mill_cont(it, struct mill_cr, debug.item); switch(cr->state) { case MILL_READY: sprintf(buf, "%s", mill_running == cr ? "RUNNING" : "ready"); break; case MILL_MSLEEP: sprintf(buf, "msleep()"); break; case MILL_FDWAIT: sprintf(buf, "fdwait(%d)", -1); break; case MILL_CHR: case MILL_CHS: case MILL_CHOOSE: { int pos = 0; if(cr->state == MILL_CHR) pos += sprintf(&buf[pos], "chr("); else if(cr->state == MILL_CHS) pos += sprintf(&buf[pos], "chs("); else pos += sprintf(&buf[pos], "choose("); int first = 1; struct mill_slist_item *it; for(it = mill_slist_begin(&cr->u_choose.clauses); it; it = mill_slist_next(it)) { if(first) first = 0; else pos += sprintf(&buf[pos], ","); pos += sprintf(&buf[pos], "<%d>", mill_getchan( mill_cont(it, struct mill_clause, chitem)->ep)->debug.id); } sprintf(&buf[pos], ")"); } break; default: assert(0); } snprintf(idbuf, sizeof(idbuf), "{%d}", (int)cr->debug.id); fprintf(stderr, "%-8s %-42s %-40s %s\n", idbuf, buf, cr == mill_running ? "---" : cr->debug.current, cr->debug.created ? cr->debug.created : "<main>"); } fprintf(stderr,"\n"); if(mill_list_empty(&mill_all_chans)) return; fprintf(stderr, "CHANNEL msgs/max senders/receivers " "refs done created\n"); fprintf(stderr, "----------------------------------------------------------------------" "--------------------------------------------------\n"); for(it = mill_list_begin(&mill_all_chans); it; it = mill_list_next(it)) { struct mill_chan *ch = mill_cont(it, struct mill_chan, debug.item); snprintf(idbuf, sizeof(idbuf), "<%d>", (int)ch->debug.id); sprintf(buf, "%d/%d", (int)ch->items, (int)ch->bufsz); fprintf(stderr, "%-8s %-11s ", idbuf, buf); int pos; struct mill_list *clauselist; if(!mill_list_empty(&ch->sender.clauses)) { pos = sprintf(buf, "s:"); clauselist = &ch->sender.clauses; } else if(!mill_list_empty(&ch->receiver.clauses)) { pos = sprintf(buf, "r:"); clauselist = &ch->receiver.clauses; } else { sprintf(buf, " "); clauselist = NULL; } struct mill_clause *cl = NULL; if(clauselist) cl = mill_cont(mill_list_begin(clauselist), struct mill_clause, epitem); int first = 1; while(cl) { if(first) first = 0; else pos += sprintf(&buf[pos], ","); pos += sprintf(&buf[pos], "{%d}", (int)cl->cr->debug.id); cl = mill_cont(mill_list_next(&cl->epitem), struct mill_clause, epitem); } fprintf(stderr, "%-42s %-5d %-5s %s\n", buf, (int)ch->refcount, ch->done ? "yes" : "no", ch->debug.created); } fprintf(stderr,"\n"); }