| /* |
| * Copyright (C) 2013 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <poll.h> |
| |
| #include "pollhandler.h" |
| |
| /* |
| * Code that allows to poll multiply file descriptors for events |
| * File descriptors can be added and removed at runtime |
| * |
| * Call poll_register_fd function first to add file descriptors to monitor |
| * Then call poll_dispatch_loop that will poll all registered file descriptors |
| * as long as they are not unregistered. |
| * |
| * When event happen on given fd appropriate user supplied handler is called |
| */ |
| |
| /* Maximum number of files to monitor */ |
| #define MAX_OPEN_FD 10 |
| |
| /* Storage for pollfd structures for monitored file descriptors */ |
| static struct pollfd fds[MAX_OPEN_FD]; |
| static poll_handler fds_handler[MAX_OPEN_FD]; |
| /* Number of registered file descriptors */ |
| static int fds_count = 0; |
| |
| /* |
| * Function polls file descriptor in loop and calls appropriate handler |
| * on event. Function returns when there is no more file descriptor to |
| * monitor |
| */ |
| void poll_dispatch_loop(void) |
| { |
| while (fds_count > 0) { |
| int i; |
| int cur_fds_count = fds_count; |
| int ready = poll(fds, fds_count, 1000); |
| |
| for (i = 0; i < fds_count && ready > 0; ++i) { |
| if (fds[i].revents == 0) |
| continue; |
| |
| fds_handler[i](fds + i); |
| ready--; |
| /* |
| * If handler was remove from table |
| * just skip the rest and poll again |
| * This is due to reordering of tables in |
| * register/unregister functions |
| */ |
| if (cur_fds_count != fds_count) |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Registers file descriptor to be monitored for events (see man poll(2)) |
| * for events. |
| * |
| * return non negative value on success |
| * -EMFILE when there are to much descriptors |
| */ |
| int poll_register_fd(int fd, short events, poll_handler ph) |
| { |
| if (fds_count >= MAX_OPEN_FD) |
| return -EMFILE; |
| |
| fds_handler[fds_count] = ph; |
| fds[fds_count].fd = fd; |
| fds[fds_count].events = events; |
| fds_count++; |
| |
| return fds_count; |
| } |
| |
| /* |
| * Unregisters file descriptor |
| * Both fd and ph must match previously registered data |
| * |
| * return 0 if unregister succeeded |
| * -EBADF if arguments do not match any register handler |
| */ |
| int poll_unregister_fd(int fd, poll_handler ph) |
| { |
| int i; |
| |
| for (i = 0; i < fds_count; ++i) { |
| if (fds_handler[i] == ph && fds[i].fd == fd) { |
| fds_count--; |
| if (i < fds_count) { |
| fds[i].fd = fds[fds_count].fd; |
| fds[i].events = fds[fds_count].events; |
| fds_handler[i] = fds_handler[fds_count]; |
| } |
| return 0; |
| } |
| } |
| return -EBADF; |
| } |