⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 event.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1999 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission.  U.M. makes no representations about the * suitability of this software for any purpose.  It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team.  Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: event.c,v 1.24 2006/06/16 10:55:05 martinea Exp $ * * Event handler.  Serializes different kinds of events to allow for * a uniform interface, central state storage, and centralized * interdependency logic. */#include "amanda.h"#include "event.h"#include "queue.h"#include "conffile.h"#define event_debug(i, ...) do {	\       if ((i) <= debug_event) {	\           dbprintf(__VA_ARGS__);	\       }				\} while (0)/* * The opaque handle passed back to the caller.  This is typedefed to * event_handle_t in our header file. */struct event_handle {    event_fn_t fn;		/* function to call when this fires */    void *arg;			/* argument to pass to previous function */    event_type_t type;		/* type of event */    event_id_t data;		/* type data */    time_t lastfired;		/* timestamp of last fired (EV_TIME only) */    LIST_ENTRY(event_handle) le; /* queue handle */};/* * eventq is a queue of currently active events. * cache is a queue of unused handles.  We keep a few around to avoid * malloc overhead when doing a lot of register/releases. */static struct {    LIST_HEAD(, event_handle) listhead;    int qlength;} eventq = {    LIST_HEAD_INITIALIZER(eventq.listhead), 0}, cache = {    LIST_HEAD_INITIALIZER(eventq.listhead), 0};#define	eventq_first(q)		LIST_FIRST(&q.listhead)#define	eventq_next(eh)		LIST_NEXT(eh, le)#define	eventq_add(q, eh)	LIST_INSERT_HEAD(&q.listhead, eh, le);#define	eventq_remove(eh)	LIST_REMOVE(eh, le);/* * How many items we can have in the handle cache before we start * freeing. */#define	CACHEDEPTH	10/* * A table of currently set signal handlers. */static struct sigtabent {    event_handle_t *handle;	/* handle for this signal */    int score;			/* number of signals recvd since last checked */    void (*oldhandler)(int);/* old handler (for unsetting) */} sigtable[NSIG];static const char *event_type2str(event_type_t);#define	fire(eh)	(*(eh)->fn)((eh)->arg)static void signal_handler(int);static event_handle_t *gethandle(void);static void puthandle(event_handle_t *);static int event_loop_wait (event_handle_t *, const int);/* * Add a new event.  See the comment in event.h for what the arguments * mean. */event_handle_t *event_register(    event_id_t data,    event_type_t type,    event_fn_t fn,    void *arg){    event_handle_t *handle;    if ((type == EV_READFD) || (type == EV_WRITEFD)) {	/* make sure we aren't given a high fd that will overflow a fd_set */	if (data >= (int)FD_SETSIZE) {	    error(_("event_register: Invalid file descriptor %lu"), data);	    /*NOTREACHED*/	}#if !defined(__lint) /* Global checking knows that these are never called */    } else if (type == EV_SIG) {	/* make sure signals are within range */	if (data >= NSIG) {	    error(_("event_register: Invalid signal %lu"), data);	    /*NOTREACHED*/	}	if (sigtable[data].handle != NULL) { 	    error(_("event_register: signal %lu already registered"), data);	    /*NOTREACHED*/	}    } else if (type >= EV_DEAD) {	error(_("event_register: Invalid event type %d"), type);	/*NOTREACHED*/#endif    }    handle = gethandle();    handle->fn = fn;    handle->arg = arg;    handle->type = type;    handle->data = data;    handle->lastfired = -1;    eventq_add(eventq, handle);    eventq.qlength++;    event_debug(1, _("event: register: %p->data=%lu, type=%s\n"),		    handle, handle->data, event_type2str(handle->type));    return (handle);}/* * Mark an event to be released.  Because we may be traversing the queue * when this is called, we must wait until later to actually remove * the event. */voidevent_release(    event_handle_t *handle){    assert(handle != NULL);    event_debug(1, _("event: release (mark): %p data=%lu, type=%s\n"),		    handle, handle->data,		    event_type2str(handle->type));    assert(handle->type != EV_DEAD);    /*     * For signal events, we need to specially remove then from the     * signal event table.     */    if (handle->type == EV_SIG) {	struct sigtabent *se = &sigtable[handle->data];	assert(se->handle == handle);	signal((int)handle->data, se->oldhandler);	se->handle = NULL;	se->score = 0;    }    /*     * Decrement the qlength now since this is no longer a real     * event.     */    eventq.qlength--;    /*     * Mark it as dead and leave it for the loop to remove.     */    handle->type = EV_DEAD;}/* * Fire all EV_WAIT events waiting on the specified id. */intevent_wakeup(    event_id_t id){    event_handle_t *eh;    int nwaken = 0;    event_debug(1, _("event: wakeup: enter (%lu)\n"), id);    for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {	if (eh->type == EV_WAIT && eh->data == id) {	    event_debug(1, _("event: wakeup: %p id=%lu\n"), eh, id);	    fire(eh);	    nwaken++;	}    }    return (nwaken);}/* * The event loop.  We need to be specially careful here with adds and * deletes.  Since adds and deletes will often happen while this is running, * we need to make sure we don't end up referencing a dead event handle. */voidevent_loop(    const int dontblock){    event_loop_wait((event_handle_t *)NULL, dontblock);}intevent_wait(    event_handle_t *eh){    return event_loop_wait(eh, 0);}/* * The event loop.  We need to be specially careful here with adds and * deletes.  Since adds and deletes will often happen while this is running, * we need to make sure we don't end up referencing a dead event handle. */static intevent_loop_wait(    event_handle_t *wait_eh,    const int       dontblock){#ifdef ASSERTIONS    static int entry = 0;#endif    SELECT_ARG_TYPE readfds, writefds, errfds, werrfds;    struct timeval timeout, *tvptr;    int ntries, maxfd, rc;    long interval;    time_t curtime;    event_handle_t *eh, *nexteh;    struct sigtabent *se;    int event_wait_fired = 0;    int see_event;    event_debug(1, _("event: loop: enter: dontblock=%d, qlength=%d, eh=%p\n"),		    dontblock, eventq.qlength, wait_eh);    /*     * If we have no events, we have nothing to do     */    if (eventq.qlength == 0)	return 0;    /*     * We must not be entered twice     */    assert(++entry == 1);    ntries = 0;    /*     * Save a copy of the current time once, to reduce syscall load     * slightly.     */    curtime = time(NULL);    do {	if (debug_event >= 1) {	    event_debug(1, _("event: loop: dontblock=%d, qlength=%d eh=%p\n"),			    dontblock, eventq.qlength, wait_eh);	    for (eh = eventq_first(eventq); eh != NULL; eh = eventq_next(eh)) {		event_debug(1, _("%p): %s data=%lu fn=%p arg=%p\n"),				eh, event_type2str(eh->type), eh->data, eh->fn,				eh->arg);	    }	}	/*	 * Set ourselves up with no timeout initially.	 */	timeout.tv_sec = 0;	timeout.tv_usec = 0;	/*	 * If we can block, initially set the tvptr to NULL.  If	 * we come across timeout events in the loop below, they	 * will set it to an appropriate buffer.  If we don't	 * see any timeout events, then tvptr will remain NULL	 * and the select will properly block indefinately.	 *	 * If we can't block, set it to point to the timeout buf above.	 */	if (dontblock)	    tvptr = &timeout;	else	    tvptr = NULL;	/*	 * Rebuild the select bitmasks each time.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -