/* * Queue of void pointers. See queue.h for details. */ #include #include #include #include struct queue { int size; int nextwrite; // next element to write to (was head) int nextread; // next element to read from (was tail) void **data; }; static int q_grow(struct queue *q, int targetsize) { void **olddata = q->data; int onr = q->nextread; int onw = q->nextwrite; int osize = q->size; int nsize; void **ndata; int i, result; nsize = q->size; while (nsize < targetsize) { nsize *= 2; /* prevent infinite loop */ KASSERT(nsize > 0); } ndata = kmalloc(nsize * sizeof(void *)); if (ndata == NULL) { return ENOMEM; } q->size = nsize; q->data = ndata; q->nextread = q->nextwrite = 0; for (i=onr; i!=onw; i = (i+1)%osize) { result = q_addtail(q, olddata[i]); KASSERT(result==0); } kfree(olddata); return 0; } struct queue * q_create(int size) { struct queue *q = kmalloc(sizeof(struct queue)); if (q==NULL) { return NULL; } q->size = size; q->data = kmalloc(size * sizeof(void *)); if (q->data==NULL) { kfree(q); return NULL; } q->nextread = q->nextwrite = 0; return q; } int q_preallocate(struct queue *q, int size) { int result = 0; KASSERT(q->size > 0); if (size > q->size) { result = q_grow(q, size); } return result; } inline int q_empty(struct queue *q) { return q->nextwrite == q->nextread; } int q_addtail(struct queue *q, void *ptr) { int nextnext, result; KASSERT(q->size > 0); nextnext = (q->nextwrite+1) % q->size; if (nextnext==q->nextread) { result = q_grow(q, q->size+1); if (result) { return result; } nextnext = (q->nextwrite+1) % q->size; } q->data[q->nextwrite] = ptr; q->nextwrite = nextnext; return 0; } void * q_remhead(struct queue *q) { void *ret; KASSERT(q->size > 0); KASSERT(!q_empty(q)); ret = q->data[q->nextread]; q->nextread = (q->nextread+1)%q->size; return ret; } void q_destroy(struct queue *q) { KASSERT(q_empty(q)); kfree(q->data); kfree(q); } /* These are really intended only for debugging. */ int q_getstart(struct queue *q) { return q->nextread; } int q_getend(struct queue *q) { return q->nextwrite; } int q_getsize(struct queue *q) { return q->size; } void * q_getguy(struct queue *q, int index) { // note that we don't check to make sure the access isn't in the // unused part of the queue space. we probably should. KASSERT(index>=0 && indexsize); return q->data[index]; } void * q_peek(struct queue *q) { void *ret; KASSERT(q); KASSERT(q->size > 0); if (q_empty(q)) { ret = 0; } else { ret = q->data[q->nextread]; } return ret; } int q_len(struct queue *theq) { int count = 0; int tmp = theq->nextread; while (tmp != theq->nextwrite) { tmp = (tmp+1) % theq->size; count++; } return count; }