📄 su_devpoll_port.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005, 2006, 2007 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@ingroup su_wait * @CFILE su_devpoll_port.c * * Port implementation using devpoll(7) * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Kai Vehmanen <kai.vehmanen@nokia.com> * * @date Created: Fri Jan 26 20:44:14 2007 ppessi * @date Original: Tue Sep 14 15:51:04 1999 ppessi */#include "config.h"#define su_port_s su_devpoll_port_s#include "su_port.h"#if HAVE_SYS_DEVPOLL_H#include "sofia-sip/su.h"#include "sofia-sip/su_alloc.h"#include <stdlib.h>#include <assert.h>#include <stdarg.h>#include <stdio.h>#include <string.h>#include <limits.h>#include <errno.h>#include <sys/devpoll.h>#define POLL2EPOLL_NEEDED \ (POLLIN != EPOLLIN || POLLOUT != EPOLLOUT || POLLPRI != EPOLLPRI || \ POLLERR != EPOLLERR || POLLHUP != EPOLLHUP) #define POLL2EPOLL(e) (e & (POLLIN|POLLOUT|POLLPRI|POLLERR|POLLHUP))#define EPOLL2POLL(e) (e & (POLLIN|POLLOUT|POLLPRI|POLLERR|POLLHUP))/** Port based on /dev/poll. */struct su_devpoll_port_s { su_socket_port_t sup_base[1]; /** devpoll fd */ int sup_devpoll; unsigned sup_multishot; /**< Multishot operation? */ unsigned sup_registers; /** Counter incremented by su_port_register() or su_port_unregister() */ int sup_n_registrations; int sup_max_index; /**< Indexes are equal or smaller than this */ int sup_size_indices; /**< Size of allocated index table */ /** Structure containing registration data */ struct su_devpoll { struct su_devpoll *ser_next; /* Next in free list */ su_wakeup_f ser_cb; su_wakeup_arg_t*ser_arg; su_root_t *ser_root; int ser_id; /** registration identifier */ su_wait_t ser_wait[1]; } **sup_indices; /** Mapping from socket to struct su_devpoll */ struct su_devpoll **sup_devpoll_by_socket; int sup_max_socket; size_t sup_n_devpoll_by_socket;};static void su_devpoll_port_decref(su_port_t *self, int blocking, char const *who);static int su_devpoll_port_register(su_port_t *self, su_root_t *root, su_wait_t *wait, su_wakeup_f callback, su_wakeup_arg_t *arg, int priority);static int su_devpoll_port_unregister(su_port_t *port, su_root_t *root, su_wait_t *wait, su_wakeup_f callback, su_wakeup_arg_t *arg);static int su_devpoll_port_deregister(su_port_t *self, int i);static int su_devpoll_port_unregister_all(su_port_t *self, su_root_t *root);static int su_devpoll_port_eventmask(su_port_t *self, int index, int socket, int events);static int su_devpoll_port_multishot(su_port_t *self, int multishot);static int su_devpoll_port_wait_events(su_port_t *self, su_duration_t tout);static char const *su_devpoll_port_name(su_port_t const *self);su_port_vtable_t const su_devpoll_port_vtable[1] = {{ /* su_vtable_size: */ sizeof su_devpoll_port_vtable, su_pthread_port_lock, su_pthread_port_unlock, su_base_port_incref, su_devpoll_port_decref, su_base_port_gsource, su_socket_port_send, su_devpoll_port_register, su_devpoll_port_unregister, su_devpoll_port_deregister, su_devpoll_port_unregister_all, su_devpoll_port_eventmask, su_base_port_run, su_base_port_break, su_base_port_step, su_pthread_port_thread, su_base_port_add_prepoll, su_base_port_remove_prepoll, su_base_port_timers, su_devpoll_port_multishot, su_devpoll_port_wait_events, su_base_port_getmsgs, su_base_port_getmsgs_from, su_devpoll_port_name, su_base_port_start_shared, su_pthread_port_wait, su_pthread_port_execute, }};static char const *su_devpoll_port_name(su_port_t const *self){ return "devpoll";}static void su_devpoll_port_decref(su_port_t *self, int blocking, char const *who){ (void)su_base_port_decref(self, blocking, who);}static void su_devpoll_port_deinit(void *arg){ su_port_t *self = arg; SU_DEBUG_9(("%s(%p) called\n", "su_devpoll_port_deinit", (void* )self)); su_socket_port_deinit(self->sup_base); close(self->sup_devpoll), self->sup_devpoll = -1;}/** @internal * * Register a #su_wait_t object. The wait object, a callback function and * an argument pointer is stored in the port object. The callback function * will be called when the wait object is signaled. * * Please note if identical wait objects are inserted, only first one is * ever signalled. * * @param self pointer to port * @param root pointer to root object * @param waits pointer to wait object * @param callback callback function pointer * @param arg argument given to callback function when it is invoked * @param priority relative priority of the wait object * (0 is normal, 1 important, 2 realtime) * * @return * Positive index of the wait object, * or -1 upon an error. */int su_devpoll_port_register(su_port_t *self, su_root_t *root, su_wait_t *wait, su_wakeup_f callback, su_wakeup_arg_t *arg, int priority){ int i, j, n; struct su_devpoll *ser; struct su_devpoll **indices = self->sup_indices; struct su_devpoll **devpoll_by_socket = self->sup_devpoll_by_socket; su_home_t *h = su_port_home(self); struct pollfd pollfd[1]; assert(su_port_own_thread(self)); if (wait->fd < 0) return su_seterrno(EINVAL); n = self->sup_size_indices; if (n >= SU_WAIT_MAX) return su_seterrno(ENOMEM); ser = indices[0]; if (!ser) { i = self->sup_max_index, j = i == 0 ? 15 : i + 16; if (j >= self->sup_size_indices) { /* Reallocate index table */ n = n < 1024 ? 2 * n : n + 1024; indices = su_realloc(h, indices, n * sizeof(indices[0])); if (!indices) return -1; self->sup_indices = indices; self->sup_size_indices = n; } /* Allocate registrations */ ser = su_zalloc(h, (j - i) * (sizeof *ser)); if (!ser) return -1; indices[0] = ser; for (i++; i <= j; i++) { ser->ser_id = i; ser->ser_next = i < j ? ser + 1 : NULL; indices[i] = ser++; } self->sup_max_index = j; ser = indices[0]; } if ((size_t)wait->fd >= self->sup_n_devpoll_by_socket) { size_t n_devpoll_by_socket = ((size_t)wait->fd + 32) / 32 * 32; devpoll_by_socket = su_realloc(h, devpoll_by_socket, n_devpoll_by_socket * (sizeof devpoll_by_socket[0])); if (devpoll_by_socket == NULL) return -1; memset(&devpoll_by_socket[self->sup_n_devpoll_by_socket], 0, (char *)&devpoll_by_socket[n_devpoll_by_socket] - (char *)&devpoll_by_socket[self->sup_n_devpoll_by_socket]); self->sup_devpoll_by_socket = devpoll_by_socket; self->sup_n_devpoll_by_socket = n_devpoll_by_socket; } if (devpoll_by_socket[wait->fd]) /* XXX - we should lift this limitation with epoll, too */ return errno = EEXIST, -1; i = ser->ser_id; pollfd->fd = wait->fd; pollfd->events = wait->events & ~POLLREMOVE; pollfd->revents = 0; if (write(self->sup_devpoll, pollfd, (sizeof pollfd)) != (sizeof pollfd)) { return errno = EIO, -1; } indices[0] = ser->ser_next; devpoll_by_socket[wait->fd] = ser; ser->ser_next = NULL; *ser->ser_wait = *wait; ser->ser_cb = callback; ser->ser_arg = arg; ser->ser_root = root; self->sup_registers++; self->sup_n_registrations++; return i; /* return index */}/** Deregister a su_wait_t object. */static int su_devpoll_port_deregister0(su_port_t *self, int i, int destroy_wait){ struct su_devpoll **indices = self->sup_indices; struct su_devpoll *ser; struct pollfd pollfd[1]; ser = self->sup_indices[i]; if (ser == NULL || ser->ser_cb == NULL) { su_seterrno(ENOENT); return -1; } assert(ser->ser_id == i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -