/* * Copyright (c) 2003-2004 MontaVista Software, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@mvista.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "aispoll.h" #include "../include/list.h" #include "hdb.h" #include "../include/ais_types.h" #include "tlist.h" typedef int (*dispatch_fn_t) (poll_handle poll_handle, int fd, int revents, void *data); struct poll_instance { struct pollfd *ufds; int nfds; dispatch_fn_t *dispatch_fns; void **data; struct timerlist timerlist; }; /* * All instances in one database */ static struct saHandleDatabase poll_instance_database = { .handleCount = 0, .handles = 0, .handleInstanceDestructor = 0 }; poll_handle poll_create (void) { poll_handle handle; struct poll_instance *poll_instance; SaErrorT error; error = saHandleCreate (&poll_instance_database, sizeof (struct poll_instance), &handle); if (error != SA_OK) { goto error_exit; } error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_destroy; } poll_instance->ufds = 0; poll_instance->nfds = 0; poll_instance->dispatch_fns = 0; poll_instance->data = 0; timerlist_init (&poll_instance->timerlist); return (handle); error_destroy: saHandleDestroy (&poll_instance_database, handle); error_exit: return (-1); } int poll_destroy (poll_handle handle) { struct poll_instance *poll_instance; SaErrorT error; error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } if (poll_instance->ufds) { free (poll_instance->ufds); } if (poll_instance->dispatch_fns) { free (poll_instance->dispatch_fns); } if (poll_instance->data) { free (poll_instance->data); } timerlist_free (&poll_instance->timerlist); saHandleDestroy (&poll_instance_database, handle); saHandleInstancePut (&poll_instance_database, handle); return (0); error_exit: return (-1); } int poll_dispatch_add ( poll_handle handle, int fd, int events, void *data, int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data)) { struct poll_instance *poll_instance; struct pollfd *ufds; dispatch_fn_t *dispatch_fns; void **data_list; int found = 0; int install_pos; SaErrorT error; error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } for (found = 0, install_pos = 0; install_pos < poll_instance->nfds; install_pos++) { if (poll_instance->ufds[install_pos].fd == -1) { found = 1; break; } } if (found == 0) { /* * Grow pollfd list */ ufds = (struct pollfd *)realloc (poll_instance->ufds, (poll_instance->nfds + 1) * sizeof (struct pollfd)); if (ufds == 0) { errno = ENOMEM; goto error_exit; } poll_instance->ufds = ufds; /* * Grow dispatch functions list */ dispatch_fns = (dispatch_fn_t *)realloc (poll_instance->dispatch_fns, (poll_instance->nfds + 1) * sizeof (dispatch_fn_t)); if (dispatch_fns == 0) { errno = ENOMEM; goto error_exit; } poll_instance->dispatch_fns = dispatch_fns; /* * Grow data list */ data_list = (void **)realloc (poll_instance->data, (poll_instance->nfds + 1) * sizeof (void *)); if (data_list == 0) { errno = ENOMEM; goto error_exit; } poll_instance->data = data_list; poll_instance->nfds += 1; install_pos = poll_instance->nfds - 1; } /* * Install new dispatch handler */ poll_instance->ufds[install_pos].fd = fd; poll_instance->ufds[install_pos].events = events; poll_instance->ufds[install_pos].revents = 0; poll_instance->dispatch_fns[install_pos] = dispatch_fn; poll_instance->data[install_pos] = data; saHandleInstancePut (&poll_instance_database, handle); return (0); error_exit: return (-1); } int poll_dispatch_modify ( poll_handle handle, int fd, int events, int (*dispatch_fn) (poll_handle poll_handle, int fd, int revents, void *data)) { struct poll_instance *poll_instance; int i; SaErrorT error; error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } /* * Find file descriptor to modify events and dispatch function */ for (i = 0; i < poll_instance->nfds; i++) { if (poll_instance->ufds[i].fd == fd) { poll_instance->ufds[i].events = events; poll_instance->dispatch_fns[i] = dispatch_fn; return (0); } } errno = EBADF; saHandleInstancePut (&poll_instance_database, handle); error_exit: return (-1); } int poll_dispatch_delete ( poll_handle handle, int fd) { struct poll_instance *poll_instance; int i; SaErrorT error; int found = 0; error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } /* * Find dispatch fd to delete */ for (i = 0; i < poll_instance->nfds; i++) { if (poll_instance->ufds[i].fd == fd) { found = 1; break; } } if (found) { poll_instance->ufds[i].fd = -1; saHandleInstancePut (&poll_instance_database, handle); return (0); } saHandleInstancePut (&poll_instance_database, handle); error_exit: errno = EBADF; return (-1); } int poll_timer_add ( poll_handle handle, int msec_in_future, void *data, void (*timer_fn) (void *data), poll_timer_handle *timer_handle_out) { struct poll_instance *poll_instance; poll_timer_handle timer_handle; int res = -1; SaErrorT error; error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } timer_handle = (poll_timer_handle)timerlist_add_future (&poll_instance->timerlist, timer_fn, data, msec_in_future); if (timer_handle != 0) { *timer_handle_out = timer_handle; res = 0; } saHandleInstancePut (&poll_instance_database, handle); error_exit: return (res); } int poll_timer_delete ( poll_handle handle, poll_timer_handle timer_handle) { struct poll_instance *poll_instance; SaErrorT error; if (timer_handle == 0) { return (0); } error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } timerlist_del (&poll_instance->timerlist, (void *)timer_handle); saHandleInstancePut (&poll_instance_database, handle); return (0); error_exit: return (-1); } int poll_run ( poll_handle handle) { struct poll_instance *poll_instance; int i; int timeout = -1; int res; SaErrorT error; error = saHandleInstanceGet (&poll_instance_database, handle, (void *)&poll_instance); if (error != SA_OK) { goto error_exit; } for (;;) { timeout = timerlist_timeout_msec (&poll_instance->timerlist); retry_poll: res = poll (poll_instance->ufds, poll_instance->nfds, timeout); if (errno == EINTR && res == -1) { goto retry_poll; } else if (res == -1) { goto error_exit; } for (i = 0; i < poll_instance->nfds; i++) { if (poll_instance->ufds[i].fd != -1 && poll_instance->ufds[i].revents) { res = poll_instance->dispatch_fns[i] (handle, poll_instance->ufds[i].fd, poll_instance->ufds[i].revents, poll_instance->data[i]); /* * Remove dispatch functions that return -1 */ if (res == -1) { poll_instance->ufds[i].fd = -1; /* empty entry */ } } } timerlist_expire (&poll_instance->timerlist); } /* for (;;) */ saHandleInstancePut (&poll_instance_database, handle); error_exit: return (-1); } int poll_stop ( poll_handle handle);