/* * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "logging.h" #include "link_mon.h" #include #include #include struct link_callback { int fd; const char *name; void *data; int (*callback)(void *data); struct link_callback *next; }; static unsigned used_pfds = 0; static unsigned free_pfds = 0; static struct pollfd *pfds = NULL; static struct link_callback *callbacks = NULL; int links_register(int fd, const char *name, int (*callback)(void *data), void *data) { unsigned i; struct link_callback *lc; for (i = 0; i < used_pfds; i++) { if (fd == pfds[i].fd) { LOG_ERROR("links_register: Duplicate file descriptor"); return -EINVAL; } } lc = malloc(sizeof(*lc)); if (!lc) return -ENOMEM; lc->fd = fd; lc->name = name; lc->data = data; lc->callback = callback; if (!free_pfds) { struct pollfd *tmp; tmp = realloc(pfds, sizeof(struct pollfd) * ((used_pfds*2) + 1)); if (!tmp) { free(lc); return -ENOMEM; } pfds = tmp; free_pfds = used_pfds + 1; } free_pfds--; pfds[used_pfds].fd = fd; pfds[used_pfds].events = POLLIN; pfds[used_pfds].revents = 0; used_pfds++; lc->next = callbacks; callbacks = lc; LOG_DBG("Adding %s/%d", lc->name, lc->fd); LOG_DBG(" used_pfds = %u, free_pfds = %u", used_pfds, free_pfds); return 0; } int links_unregister(int fd) { unsigned i; struct link_callback *p, *c; for (i = 0; i < used_pfds; i++) if (fd == pfds[i].fd) { /* entire struct is copied (overwritten) */ pfds[i] = pfds[used_pfds - 1]; used_pfds--; free_pfds++; } for (p = NULL, c = callbacks; c; p = c, c = c->next) if (fd == c->fd) { LOG_DBG("Freeing up %s/%d", c->name, c->fd); LOG_DBG(" used_pfds = %u, free_pfds = %u", used_pfds, free_pfds); if (p) p->next = c->next; else callbacks = c->next; free(c); break; } return 0; } int links_monitor(void) { unsigned i; int r; for (i = 0; i < used_pfds; i++) { pfds[i].revents = 0; } r = poll(pfds, used_pfds, -1); if (r <= 0) return r; r = 0; /* FIXME: handle POLLHUP */ for (i = 0; i < used_pfds; i++) if (pfds[i].revents & POLLIN) { LOG_DBG("Data ready on %d", pfds[i].fd); /* FIXME: Add this back return 1;*/ r++; } return r; } int links_issue_callbacks(void) { unsigned i; struct link_callback *lc; for (i = 0; i < used_pfds; i++) if (pfds[i].revents & POLLIN) for (lc = callbacks; lc; lc = lc->next) if (pfds[i].fd == lc->fd) { LOG_DBG("Issuing callback on %s/%d", lc->name, lc->fd); lc->callback(lc->data); break; } return 0; }