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

📄 selector.c

📁 This project provides a proxy that allows telnet/tcp connections to be made to serial ports on a mac
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * selector.c * * Code for abstracting select for files and timers. * * Author: MontaVista Software, Inc. *         Corey Minyard <minyard@mvista.com> *         source@mvista.com * * Copyright 2002 MontaVista Software Inc. * *  This program 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 of *  the License, or (at your option) any later version. * * *  THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. * *  You should have received a copy of the GNU Lesser General Public *  License along with this program; if not, write to the Free *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* This file holds code to abstract the "select" call and make it   easier to use.  The main thread lives here, the rest of the code   uses a callback interface.  Basically, other parts of the program   can register file descriptors with this code, when interesting   things happen on those file descriptors this code will call   routines registered with it. */#include "selector.h"#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <syslog.h>#include <signal.h>#include <string.h>#include <stdio.h>/* The control structure for each file descriptor. */typedef struct fd_control_s{    int              in_use;    void             *data;		/* Operation-specific data */    sel_fd_handler_t handle_read;    sel_fd_handler_t handle_write;    sel_fd_handler_t handle_except;} fd_control_t;struct sel_timer_s{    /* Set this to the function to call when the timeout occurs. */    sel_timeout_handler_t handler;    /* Set this to whatever you like.  You can use this to store your       own data. */    void *user_data;    /* Set this to the time when the timer will go off. */    struct timeval timeout;    /* Who owns me? */    selector_t *sel;    /* Am I currently running? */    int in_heap;    /* Links for the heap. */    sel_timer_t *left, *right, *up;};struct selector_s{    /* This is an array of all the file descriptors possible.  This is       moderately wasteful of space, but easy to do.  Hey, memory is       cheap. */    fd_control_t fds[FD_SETSIZE];        /* These are the offical fd_sets used to track what file descriptors       need to be monitored. */    fd_set read_set;    fd_set write_set;    fd_set except_set;    int maxfd; /* The largest file descriptor registered with this		  code. */    /* The timer heap. */    sel_timer_t *timer_top, *timer_last;};static t_sighup_handler user_sighup_handler = NULL;static int got_sighup = 0; /* Did I get a HUP signal? *//* Initialize a single file descriptor. */static voidinit_fd(fd_control_t *fd){    fd->in_use = 0;    fd->data = NULL;    fd->handle_read = NULL;    fd->handle_write = NULL;    fd->handle_except = NULL;}/* Set the handlers for a file descriptor. */voidsel_set_fd_handlers(selector_t       *sel,		    int              fd,		    void             *data,		    sel_fd_handler_t read_handler,		    sel_fd_handler_t write_handler,		    sel_fd_handler_t except_handler){    sel->fds[fd].in_use = 1;    sel->fds[fd].data = data;    sel->fds[fd].handle_read = read_handler;    sel->fds[fd].handle_write = write_handler;    sel->fds[fd].handle_except = except_handler;    /* Move maxfd up if necessary. */    if (fd > sel->maxfd) {	sel->maxfd = fd;    }}/* Clear the handlers for a file descriptor and remove it from   select's monitoring. */voidsel_clear_fd_handlers(selector_t   *sel,		      int          fd){    init_fd(&(sel->fds[fd]));    FD_CLR(fd, &sel->read_set);    FD_CLR(fd, &sel->write_set);    FD_CLR(fd, &sel->except_set);    /* Move maxfd down if necessary. */    if (fd == sel->maxfd) {	while ((sel->maxfd >= 0) && (! sel->fds[sel->maxfd].in_use)) {	    sel->maxfd--;	}    }}/* Set whether the file descriptor will be monitored for data ready to   read on the file descriptor. */voidsel_set_fd_read_handler(selector_t *sel, int fd, int state){    if (state == SEL_FD_HANDLER_ENABLED) {	FD_SET(fd, &sel->read_set);    } else if (state == SEL_FD_HANDLER_DISABLED) {	FD_CLR(fd, &sel->read_set);    }    /* FIXME - what to do on errors? */}/* Set whether the file descriptor will be monitored for when the file   descriptor can be written to. */voidsel_set_fd_write_handler(selector_t *sel, int fd, int state){    if (state == SEL_FD_HANDLER_ENABLED) {	FD_SET(fd, &sel->write_set);    } else if (state == SEL_FD_HANDLER_DISABLED) {	FD_CLR(fd, &sel->write_set);    }    /* FIXME - what to do on errors? */}/* Set whether the file descriptor will be monitored for exceptions   on the file descriptor. */voidsel_set_fd_except_handler(selector_t *sel, int fd, int state){    if (state == SEL_FD_HANDLER_ENABLED) {	FD_SET(fd, &sel->except_set);    } else if (state == SEL_FD_HANDLER_DISABLED) {	FD_CLR(fd, &sel->except_set);    }    /* FIXME - what to do on errors? */}static intcmp_timeval(struct timeval *tv1, struct timeval *tv2){    if (tv1->tv_sec < tv2->tv_sec)	return -1;    if (tv1->tv_sec > tv2->tv_sec)	return 1;    if (tv1->tv_usec < tv2->tv_usec)	return -1;    if (tv1->tv_usec > tv2->tv_usec)	return 1;    return 0;}static voiddiff_timeval(struct timeval *dest,	     struct timeval *left,	     struct timeval *right){    if (   (left->tv_sec < right->tv_sec)	|| (   (left->tv_sec == right->tv_sec)	    && (left->tv_usec < right->tv_usec)))    {	/* If left < right, just force to zero, don't allow negative           numbers. */	dest->tv_sec = 0;	dest->tv_usec = 0;	return;    }    dest->tv_sec = left->tv_sec - right->tv_sec;    dest->tv_usec = left->tv_usec - right->tv_usec;    while (dest->tv_usec < 0) {	dest->tv_usec += 1000000;	dest->tv_sec--;    }}#undef MASSIVE_DEBUG#ifdef MASSIVE_DEBUGFILE **debug_out = &stderr;static voidprint_tree_item(sel_timer_t *pos, int indent){    int i;    for (i=0; i<indent; i++)	fprintf(*debug_out, " ");    fprintf(*debug_out, "  %p: %p %p %p (%ld.%7.7ld)\n", pos, pos->left, pos->right,	   pos->up, pos->timeout.tv_sec, pos->timeout.tv_usec);    if (pos->left)	print_tree_item(pos->left, indent+1);    if (pos->right)	print_tree_item(pos->right, indent+1);}static voidprint_tree(sel_timer_t *top, sel_timer_t *last){    fprintf(*debug_out, "top=%p\n", top);    if (top)	print_tree_item(top, 0);    fprintf(*debug_out, "last=%p\n", last);    fflush(*debug_out);}static voidcheck_tree_item(sel_timer_t *curr,		int         *depth,		int         max_depth,		sel_timer_t **real_last,		int         *found_last){    if (! curr->left) {	if (curr->right) {	    fprintf(*debug_out, "Tree corrupt B\n");	    *((int *) NULL) = 0;	} else if (*depth > max_depth) {	    fprintf(*debug_out, "Tree corrupt C\n");	    *((int *) NULL) = 0;	} else if (*depth < (max_depth - 1)) {	    fprintf(*debug_out, "Tree corrupt D\n");	    *((int *) NULL) = 0;	} else if ((*found_last) && (*depth == max_depth)) {	    fprintf(*debug_out, "Tree corrupt E\n");	    *((int *) NULL) = 0;	} else if (*depth == max_depth) {	    *real_last = curr;	} else {	    *found_last = 1;	}    } else {	if (curr->left->up != curr) {	    fprintf(*debug_out, "Tree corrupt I\n");	    *((int *) NULL) = 0;	}	if (cmp_timeval(&(curr->left->timeout), &(curr->timeout)) < 0) {	    fprintf(*debug_out, "Tree corrupt K\n");	    *((int *) NULL) = 0;	}	(*depth)++;	check_tree_item(curr->left, depth, max_depth, real_last, found_last);	(*depth)--;	if (! curr->right) {	    if (*depth != (max_depth - 1)) {		fprintf(*debug_out, "Tree corrupt F\n");		*((int *) NULL) = 0;	    }	    if (*found_last) {		fprintf(*debug_out, "Tree corrupt G\n");		*((int *) NULL) = 0;	    }	    *found_last = 1;	} else {	    if (curr->right->up != curr) {		fprintf(*debug_out, "Tree corrupt H\n");		*((int *) NULL) = 0;	    }	    if (cmp_timeval(&(curr->right->timeout), &(curr->timeout)) < 0) {		fprintf(*debug_out, "Tree corrupt L\n");		*((int *) NULL) = 0;	    }	    (*depth)++;	    check_tree_item(curr->right, depth, max_depth, real_last, found_last);	    (*depth)--;	}    }}static voidcheck_tree(sel_timer_t *top, sel_timer_t *last){    unsigned int depth = 0, max_depth = 0;    int          found_last = 0;    sel_timer_t  *real_last;    if (!top) {	if (last) {	    fprintf(*debug_out, "Tree corrupt A\n");	    *((int *) NULL) = 0;	}	return;    }    real_last = top;    while (real_last->left) {	real_last = real_last->left;	max_depth++;    }    real_last = NULL;    check_tree_item(top, &depth, max_depth, &real_last, &found_last);    if (real_last != last) {	fprintf(*debug_out, "Tree corrupt J\n");	*((int *) NULL) = 0;    }    fflush(*debug_out);}#endifstatic voidfind_next_pos(sel_timer_t *curr, sel_timer_t ***next, sel_timer_t **parent){    unsigned int upcount = 0;    if (curr->up && (curr->up->left == curr)) {	/* We are a left node, the next node is just my right partner. */	*next = &(curr->up->right);	*parent = curr->up;	return;    }    /* While we are a right node, go up. */    while (curr->up && (curr->up->right == curr)) {	upcount++;	curr = curr->up;    }    if (curr->up) {	/* Now we are a left node, trace up then back down. */	curr = curr->up->right;	upcount--;    }    while (upcount) {	curr = curr->left;	upcount--;    }    *next = &(curr->left);    *parent = curr;}static voidfind_prev_elem(sel_timer_t *curr, sel_timer_t **prev){    unsigned int upcount = 0;    if (curr->up && (curr->up->right == curr)) {	/* We are a right node, the previous node is just my left partner. */	*prev = curr->up->left;	return;    }    /* While we are a left node, go up. */    while (curr->up && (curr->up->left == curr)) {	upcount++;	curr = curr->up;    }    if (curr->up) {	/* Now we are a right node, trace up then back down. */	curr = curr->up->left;    } else {	/* We are going to the previous "row". */	upcount--;    }    while (upcount) {	curr = curr->right;	upcount--;    }    *prev = curr;}static voidsend_up(sel_timer_t *elem, sel_timer_t **top, sel_timer_t **last){    sel_timer_t *tmp1, *tmp2, *parent;    parent = elem->up;    while (parent && (cmp_timeval(&elem->timeout, &parent->timeout) < 0)) {	tmp1 = elem->left;	tmp2 = elem->right;	if (parent->left == elem) {	    elem->left = parent;	    elem->right = parent->right;	    if (elem->right)		elem->right->up = elem;	} else {	    elem->right = parent;	    elem->left = parent->left;	    if (elem->left)		elem->left->up = elem;	}	elem->up = parent->up;	if (parent->up) {	    if (parent->up->left == parent) {		parent->up->left = elem;	    } else {		parent->up->right = elem;	    }	} else {	    *top = elem;	}

⌨️ 快捷键说明

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