#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); | |
} |