/* ARISA - simple pointer queue implementation, which got complex... * Copyright (C) 2003, 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include #include pqueue_t *pqueue_init(pqueue_t *q, int lockable) { if(q == NULL) q = xalloc(sizeof(pqueue_t)); if(lockable > 0) { q->lock = xalloc(sizeof(lock_t)); LOCK_INIT(q->lock); } else q->lock = NULL; q->front = NULL; q->back = NULL; q->length = 0; q->fd = -1; return q; } static pqueueb_t *pqueue_bucket_init(void *ptr) { pqueueb_t *b = xalloc(sizeof(pqueueb_t)); b->ptr = ptr; b->next = NULL; return b; } static void pqueue_bucket_free(pqueueb_t *b) { xfree(b); } /* clear, but don't free, for non-malloc'ed pqueues */ void pqueue_clear(pqueue_t *q, void (*ptrfree)(void *), int doclose) { pqueueb_t *p,*b; if(q->lock != NULL) LOCKR(q->lock); b = q->front; while(b != NULL) { p = b; b = b->next; if(ptrfree != NULL) ptrfree(p->ptr); pqueue_bucket_free(p); } q->front = NULL; q->back = NULL; q->length = 0; if(q->fd != -1 && doclose) { //D("close: %d",q->fd); close(q->fd); q->fd = -1; } if(q->lock != NULL) UNLOCKR(q->lock); } void pqueue_deinit(pqueue_t *q, void (*ptrfree)(void *), int doclose) { pqueue_clear(q,ptrfree,doclose); if(q->lock != NULL) { LOCK_FREE(q->lock); xfree(q->lock); } } void pqueue_free(pqueue_t *q, void (*ptrfree)(void *)) { pqueue_deinit(q,ptrfree,1); xfree(q); } /* internal notification function * - this could block if someone didn't their signal_fd non-blocking */ static void q_notify(pqueue_t *q) { ssize_t ret; if(q->fd != -1) { ret = write(q->fd,"\0",1); if(ret == -1 && !(errno == EAGAIN)) { if(errno == EINTR) { /* try again and don't care about the return value */ write(q->fd,"\0",1); } else { /* self error correcting */ D("close: %d",q->fd); close(q->fd); q->fd = -1; } } } } void pqueue_push_front(pqueue_t *q, void *ptr) { pqueueb_t *p; if(q == NULL || ptr == NULL) return; if(q->lock != NULL) LOCKR(q->lock); p = q->front; q->front = pqueue_bucket_init(ptr); q->front->next = p; if(q->length == 0) q->back = q->front; q->length++; q_notify(q); if(q->lock != NULL) UNLOCKR(q->lock); } void pqueue_push_back(pqueue_t *q, void *ptr) { if(q == NULL || ptr == NULL) return; if(q->lock != NULL) LOCKR(q->lock); if(q->back != NULL) { q->back->next = pqueue_bucket_init(ptr); q->back = q->back->next; } else { q->back = pqueue_bucket_init(ptr); q->front = q->back; } q->length++; q_notify(q); if(q->lock != NULL) UNLOCKR(q->lock); } void *pqueue_pop_front(pqueue_t *q) { pqueueb_t *p; void *ret = NULL; if(q == NULL) return NULL; if(q->lock != NULL) LOCKR(q->lock); if(q->length > 0) { p = q->front; ret = q->front->ptr; q->front= q->front->next; pqueue_bucket_free(p); q->length--; if(q->length == 0) q->back = NULL; } if(q->lock != NULL) UNLOCKR(q->lock); return ret; } void *pqueue_pop_back(pqueue_t *q) { pqueueb_t *p; void *ret = NULL; if(q == NULL) return NULL; if(q->lock != NULL) LOCKR(q->lock); if(q->length > 0) { ret = q->back->ptr; pqueue_bucket_free(q->back); if(q->length != 1) { for(p = q->front; p->next != q->back; p = p->next) ; q->back = p; } else { q->front = NULL; q->back = NULL; } q->length--; } if(q->lock != NULL) UNLOCKR(q->lock); return ret; } unsigned int pqueue_length(pqueue_t *q) { unsigned int ret = 0; if(q != NULL) { if(q->lock != NULL) LOCKR(q->lock); ret = q->length; if(q->lock != NULL) UNLOCKR(q->lock); } return ret; } void pqueue_set_notification_fd(pqueue_t *q, int fd) { if(q->lock != NULL) LOCKR(q->lock); q->fd = fd; if(q->lock != NULL) UNLOCKR(q->lock); }