ref: cb091e75393b176ccb02c68f0ecfcfbb8bc49376
dir: /sys/src/games/music/playlistfs/boilerplate.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <fcall.h> #include "playlist.h" static Channel *reqs; Req* reqalloc(void) { Req *r; if(reqs == nil) reqs = chancreate(sizeof(Req*), 256); if(r = nbrecvp(reqs)) return r; r = malloc(sizeof(Req)); return r; } void reqfree(Req *r) { if(!nbsendp(reqs, r)) free(r); } Wmsg waitmsg(Worker *w, Channel *q) { Wmsg m; sendp(q, w); recv(w->eventc, &m); return m; } int sendmsg(Channel *q, Wmsg *m) { Worker *w; while(w = nbrecvp(q)){ /* Test for markerdom (see bcastmsg) */ if(w->eventc){ send(w->eventc, m); return 1; } sendp(q, w); /* put back */ } return 0; } void bcastmsg(Channel *q, Wmsg *m) { Worker *w, marker; void *a; a = m->arg; /* * Use a marker to mark the end of the queue. * This prevents workers from getting the * broadcast and putting themselves back on the * queue before the broadcast has finished */ marker.eventc = nil; /* Only markers have eventc == nil */ sendp(q, &marker); while((w = recvp(q)) != &marker){ if(w->eventc == nil){ /* somebody else's marker, put it back */ sendp(q, w); }else{ if(a) m->arg = strdup(a); send(w->eventc, m); } } free(a); m->arg = nil; } void readbuf(Req *r, void *s, long n) { r->ofcall.count = r->ifcall.count; if(r->ifcall.offset >= n){ r->ofcall.count = 0; return; } if(r->ifcall.offset+r->ofcall.count > n) r->ofcall.count = n - r->ifcall.offset; memmove(r->ofcall.data, (char*)s+r->ifcall.offset, r->ofcall.count); } void readstr(Req *r, char *s) { readbuf(r, s, strlen(s)); }