|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <venti.h> | 
|  | #include "queue.h" | 
|  |  | 
|  | typedef struct Qel Qel; | 
|  | struct Qel | 
|  | { | 
|  | Qel *next; | 
|  | void *p; | 
|  | }; | 
|  |  | 
|  | struct Queue | 
|  | { | 
|  | int ref; | 
|  | int hungup; | 
|  | QLock lk; | 
|  | Rendez r; | 
|  | Qel *head; | 
|  | Qel *tail; | 
|  | }; | 
|  |  | 
|  | Queue* | 
|  | _vtqalloc(void) | 
|  | { | 
|  | Queue *q; | 
|  |  | 
|  | q = vtmallocz(sizeof(Queue)); | 
|  | q->r.l = &q->lk; | 
|  | q->ref = 1; | 
|  | return q; | 
|  | } | 
|  |  | 
|  | Queue* | 
|  | _vtqincref(Queue *q) | 
|  | { | 
|  | qlock(&q->lk); | 
|  | q->ref++; | 
|  | qunlock(&q->lk); | 
|  | return q; | 
|  | } | 
|  |  | 
|  | void | 
|  | _vtqdecref(Queue *q) | 
|  | { | 
|  | Qel *e; | 
|  |  | 
|  | qlock(&q->lk); | 
|  | if(--q->ref > 0){ | 
|  | qunlock(&q->lk); | 
|  | return; | 
|  | } | 
|  | assert(q->ref == 0); | 
|  | qunlock(&q->lk); | 
|  |  | 
|  | /* Leaks the pointers e->p! */ | 
|  | while(q->head){ | 
|  | e = q->head; | 
|  | q->head = e->next; | 
|  | free(e); | 
|  | } | 
|  | free(q); | 
|  | } | 
|  |  | 
|  | int | 
|  | _vtqsend(Queue *q, void *p) | 
|  | { | 
|  | Qel *e; | 
|  |  | 
|  | e = vtmalloc(sizeof(Qel)); | 
|  | qlock(&q->lk); | 
|  | if(q->hungup){ | 
|  | werrstr("hungup queue"); | 
|  | qunlock(&q->lk); | 
|  | return -1; | 
|  | } | 
|  | e->p = p; | 
|  | e->next = nil; | 
|  | if(q->head == nil) | 
|  | q->head = e; | 
|  | else | 
|  | q->tail->next = e; | 
|  | q->tail = e; | 
|  | rwakeup(&q->r); | 
|  | qunlock(&q->lk); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void* | 
|  | _vtqrecv(Queue *q) | 
|  | { | 
|  | void *p; | 
|  | Qel *e; | 
|  |  | 
|  | qlock(&q->lk); | 
|  | while(q->head == nil && !q->hungup) | 
|  | rsleep(&q->r); | 
|  | if(q->hungup){ | 
|  | qunlock(&q->lk); | 
|  | return nil; | 
|  | } | 
|  | e = q->head; | 
|  | q->head = e->next; | 
|  | qunlock(&q->lk); | 
|  | p = e->p; | 
|  | vtfree(e); | 
|  | return p; | 
|  | } | 
|  |  | 
|  | void* | 
|  | _vtnbqrecv(Queue *q) | 
|  | { | 
|  | void *p; | 
|  | Qel *e; | 
|  |  | 
|  | qlock(&q->lk); | 
|  | if(q->head == nil){ | 
|  | qunlock(&q->lk); | 
|  | return nil; | 
|  | } | 
|  | e = q->head; | 
|  | q->head = e->next; | 
|  | qunlock(&q->lk); | 
|  | p = e->p; | 
|  | vtfree(e); | 
|  | return p; | 
|  | } | 
|  |  | 
|  | void | 
|  | _vtqhangup(Queue *q) | 
|  | { | 
|  | qlock(&q->lk); | 
|  | q->hungup = 1; | 
|  | rwakeupall(&q->r); | 
|  | qunlock(&q->lk); | 
|  | } |