📄 fdset.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. 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. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 KANNEL GROUP OR ITS 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * fdset.c - module for managing a large collection of file descriptors */#include <stdlib.h>#include <unistd.h>#include <errno.h>#include "gwlib/gwlib.h"struct FDSet{ /* Thread ID of the set's internal thread, which will spend most * of its time blocking on poll(). This is set when the thread * is created, and not changed after that. It's not protected * by any lock. */ long poll_thread; /* The following fields are for use by the polling thread only. * No-one else may touch them. It's not protected by any lock. */ /* Array for use with poll(). Elements 0 through size-1 are allocated. * Elements 0 through entries-1 are in use. */ struct pollfd *pollinfo; int size; int entries; /* Arrays of callback and data fields. They are kept in sync with * the pollinfo array, and are basically extra fields that we couldn't * put in struct pollfd because that structure is defined externally. */ fdset_callback_t **callbacks; void **datafields; /* The poller function loops over the table after poll() returns, * and calls callback functions that may modify the table that is * being scanned. We can't just copy the table to avoid interference, * because fdset_unregister and fdset_listen guarantee that their * operations are complete when they return -- that does not work * if poller() is scanning an outdated copy of the table. * To solve this, we have a field that marks when the table is * being scanned. If this field is true, fdset_unregister merely * sets the fd to -1 instead of deleting the whole entry. * fdset_listen will takes care to modify revents as well as * events. fdset_register always adds to the end of the table, * so it does not have to do anything special. */ int scanning; /* This field keeps track of how many fds were set to -1 by * fdset_unregister while "scanning" is true. That way we can * efficiently check if we need to scan the table to really * delete those entries. */ int deleted_entries; /* The following fields are for general use, and are of types that * have internal locks. */ /* List of struct action. Used by other threads to make requests * of the polling thread. */ List *actions;};/* Datatype to describe changes to the fdset fields that only the polling * thread may touch. Other threads use this type to submit requests to * change those fields. *//* Action life cycle: Created, then pushed on set->actions list by * action_submit. Poller thread wakes up and takes it from the list, * then calls handle_action, which performs the action and pushes it * on the action's done list. action_submit then takes it back and * destroys it. *//* If no synchronization is needed, action_submit_nosync can be used. * In that case handle_action will destroy the action itself instead * of putting it on any list. */struct action{ enum { REGISTER, LISTEN, UNREGISTER, DESTROY } type; int fd; /* Used by REGISTER, LISTEN, and UNREGISTER */ int mask; /* Used by LISTEN */ int events; /* Used by REGISTER and LISTEN */ fdset_callback_t *callback; /* Used by REGISTER */ void *data; /* Used by REGISTER */ /* When the request has been handled, an element is produced on this * list, so that the submitter can synchronize. Can be left NULL. */ List *done; /* Used by LISTEN, UNREGISTER, and DESTROY */};/* Return a new action structure of the given type, with all fields empty. */static struct action *action_create(int type){ struct action *new; new = gw_malloc(sizeof(*new)); new->type = type; new->fd = -1; new->mask = 0; new->events = 0; new->callback = NULL; new->data = NULL; new->done = NULL; return new;}static void action_destroy(struct action *action){ if (action == NULL) return; list_destroy(action->done, NULL); gw_free(action);}/* For use with list_destroy */static void action_destroy_item(void *action){ action_destroy(action);}/* * Submit an action for this set, and wait for the polling thread to * confirm that it's been done, by pushing the action on its done list. */static void submit_action(FDSet *set, struct action *action){ List *done; void *sync; gw_assert(set != NULL); gw_assert(action != NULL); done = list_create(); list_add_producer(done); action->done = done; list_append(set->actions, action); gwthread_wakeup(set->poll_thread); sync = list_consume(done); gw_assert(sync == action); action_destroy(action);}/* * As above, but don't wait for confirmation. */static void submit_action_nosync(FDSet *set, struct action *action){ list_append(set->actions, action); gwthread_wakeup(set->poll_thread);}/* Do one action for this thread and confirm that it's been done by * appending the action to its done list. May only be called by * the polling thread. Returns 0 normally, and returns -1 if the * action destroyed the set. */static int handle_action(FDSet *set, struct action *action){ int result; gw_assert(set != NULL); gw_assert(set->poll_thread == gwthread_self()); gw_assert(action != NULL); result = 0; switch (action->type) { case REGISTER: fdset_register(set, action->fd, action->events, action->callback, action->data); break; case LISTEN: fdset_listen(set, action->fd, action->mask, action->events); break; case UNREGISTER: fdset_unregister(set, action->fd); break; case DESTROY: fdset_destroy(set); result = -1; break; default: panic(0, "fdset: handle_action got unknown action type %d.", action->type); } if (action->done == NULL) action_destroy(action); else list_produce(action->done, action); return result;}/* Look up the entry number in the pollinfo array for this fd. * Right now it's a linear search, this may have to be improved. */static int find_entry(FDSet *set, int fd){ int i; gw_assert(set != NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -