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

📄 select.c

📁 一个很有名的浏览器
💻 C
字号:
/* File descriptors managment and switching *//* $Id: select.c,v 1.48.6.3 2005/04/05 21:08:42 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <errno.h>#include <signal.h>#include <string.h> /* FreeBSD FD_ZERO() macro calls bzero() */#ifdef HAVE_SYS_SIGNAL_H#include <sys/signal.h>#endif#include <sys/types.h>#ifdef HAVE_SYS_WAIT_H#include <sys/wait.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif/* This must be here, thanks to BSD. */#ifdef HAVE_INTTYPES_H#include <inttypes.h> /* OMG */#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#include "elinks.h"#include "intl/gettext/libintl.h"#include "lowlevel/select.h"#include "lowlevel/signals.h"#include "main.h"#include "terminal/terminal.h"#include "util/error.h"#include "util/memory.h"#include "util/ttime.h"#ifndef FD_SETSIZE#define FD_SETSIZE 1024#endifstruct thread {	void (*read_func)(void *);	void (*write_func)(void *);	void (*error_func)(void *);	void *data;};struct timer {	LIST_HEAD(struct timer);	ttime interval;	void (*func)(void *);	void *data;	int id;};static INIT_LIST_HEAD(timers);static struct thread threads[FD_SETSIZE];static fd_set w_read;static fd_set w_write;static fd_set w_error;static fd_set x_read;static fd_set x_write;static fd_set x_error;static int w_max;static int timer_id = 0;longselect_info(int type){	int i = 0, j;	struct timer *timer;	switch (type) {		case INFO_FILES:			for (j = 0; j < FD_SETSIZE; j++)				if (threads[j].read_func				    || threads[j].write_func				    || threads[j].error_func)					i++;			return i;		case INFO_TIMERS:			foreach (timer, timers) i++;			return i;	}	return 0;}struct bottom_half {	LIST_HEAD(struct bottom_half);	void (*fn)(void *);	void *data;};INIT_LIST_HEAD(bottom_halves);intregister_bottom_half(void (*fn)(void *), void *data){	struct bottom_half *bh;	foreach (bh, bottom_halves)		if (bh->fn == fn && bh->data == data)			return 0;	bh = mem_alloc(sizeof(*bh));	if (!bh) return -1;	bh->fn = fn;	bh->data = data;	add_to_list(bottom_halves, bh);	return 0;}voiddo_check_bottom_halves(void){	do {		struct bottom_half *bh = bottom_halves.prev;		void (*fn)(void *) = bh->fn;		void *data = bh->data;		del_from_list(bh);		mem_free(bh);		fn(data);	} while (!list_empty(bottom_halves));}static ttime last_time;static voidcheck_timers(void){	ttime now = get_time();	ttime interval = now - last_time;	struct timer *timer;	foreach (timer, timers) timer->interval -= interval;	while (!list_empty(timers)) {		timer = timers.next;		if (timer->interval > 0) break;		del_from_list(timer);		timer->func(timer->data);		mem_free(timer);		check_bottom_halves();	}	last_time = now;}intinstall_timer(ttime t, void (*func)(void *), void *data){	struct timer *tm, *tt;	tm = mem_alloc(sizeof(*tm));	if (!tm) return -1;	tm->interval = t;	tm->func = func;	tm->data = data;	tm->id = timer_id++;	foreach (tt, timers)		if (tt->interval >= t)			break;	add_at_pos(tt->prev, tm);	return tm->id;}voidkill_timer(int id){	struct timer *tm;	int k = 0;	foreach (tm, timers) if (tm->id == id) {		struct timer *tt = tm;		tm = tm->prev;		del_from_list(tt);		mem_free(tt);		k++;	}	assertm(k, "trying to kill nonexisting timer");	assertm(k < 2, "more timers with same id");}void *get_handler(int fd, int tp){	assertm(fd >= 0 && fd < FD_SETSIZE,		"get_handler: handle %d >= FD_SETSIZE %d",		fd, FD_SETSIZE);	if_assert_failed return NULL;	switch (tp) {		case H_READ:	return threads[fd].read_func;		case H_WRITE:	return threads[fd].write_func;		case H_ERROR:	return threads[fd].error_func;		case H_DATA:	return threads[fd].data;	}	INTERNAL("get_handler: bad type %d", tp);	return NULL;}voidset_handlers(int fd, void (*read_func)(void *), void (*write_func)(void *),	     void (*error_func)(void *), void *data){	assertm(fd >= 0 && fd < FD_SETSIZE,		"set_handlers: handle %d >= FD_SETSIZE %d",		fd, FD_SETSIZE);	if_assert_failed return;	threads[fd].read_func = read_func;	threads[fd].write_func = write_func;	threads[fd].error_func = error_func;	threads[fd].data = data;	if (read_func) {		FD_SET(fd, &w_read);	} else {		FD_CLR(fd, &w_read);		FD_CLR(fd, &x_read);	}	if (write_func) {		FD_SET(fd, &w_write);	} else {		FD_CLR(fd, &w_write);		FD_CLR(fd, &x_write);	}	if (error_func) {		FD_SET(fd, &w_error);	} else {		FD_CLR(fd, &w_error);		FD_CLR(fd, &x_error);	}	if (read_func || write_func || error_func) {		if (fd >= w_max) w_max = fd + 1;	} else if (fd == w_max - 1) {		int i;		for (i = fd - 1; i >= 0; i--)			if (FD_ISSET(i, &w_read)			    || FD_ISSET(i, &w_write)			    || FD_ISSET(i, &w_error))				break;		w_max = i + 1;	}}voidselect_loop(void (*init)(void)){	int select_errors = 0;	clear_signal_mask_and_handlers();	FD_ZERO(&w_read);	FD_ZERO(&w_write);	FD_ZERO(&w_error);	w_max = 0;	last_time = get_time();#ifdef SIGPIPE	signal(SIGPIPE, SIG_IGN);#endif	init();	check_bottom_halves();	while (!terminate) {		int n, i;		struct timeval tv;		struct timeval *tm = NULL;		check_signals();		check_timers();		redraw_all_terminals();		if (!list_empty(timers)) {			ttime tt = ((struct timer *) &timers)->next->interval + 1;			if (tt < 0) tt = 0;			tv.tv_sec = tt / 1000;			tv.tv_usec = (tt % 1000) * 1000;			tm = &tv;		}		memcpy(&x_read, &w_read, sizeof(fd_set));		memcpy(&x_write, &w_write, sizeof(fd_set));		memcpy(&x_error, &w_error, sizeof(fd_set));		if (terminate) break;		if (!w_max && list_empty(timers)) break;		critical_section = 1;		if (check_signals()) {			critical_section = 0;			continue;		}#if 0		{			int i;			printf("\nR:");			for (i = 0; i < 256; i++)				if (FD_ISSET(i, &x_read)) printf("%d,", i);			printf("\nW:");			for (i = 0; i < 256; i++)				if (FD_ISSET(i, &x_write)) printf("%d,", i);			printf("\nE:");			for (i = 0; i < 256; i++)				if (FD_ISSET(i, &x_error)) printf("%d,", i);			fflush(stdout);		}#endif		n = select(w_max, &x_read, &x_write, &x_error, tm);		if (n < 0) {			critical_section = 0;			uninstall_alarm();			if (errno != EINTR) {				ERROR(gettext("The call to %s failed: %d (%s)"),				      "select()", errno, (unsigned char *) strerror(errno));				if (++select_errors > 10) /* Infinite loop prevention. */					INTERNAL(gettext("%d select() failures."),						 select_errors);			}			continue;		}		select_errors = 0;		critical_section = 0;		uninstall_alarm();		check_signals();		/*printf("sel: %d\n", n);*/		check_timers();		i = -1;		while (n > 0 && ++i < w_max) {			int k = 0;#if 0			printf("C %d : %d,%d,%d\n", i, FD_ISSET(i, &w_read),			       FD_ISSET(i, &w_write), FD_ISSET(i, &w_error));			printf("A %d : %d,%d,%d\n", i, FD_ISSET(i, &x_read),			       FD_ISSET(i, &x_write), FD_ISSET(i, &x_error));#endif			if (FD_ISSET(i, &x_read)) {				if (threads[i].read_func) {					threads[i].read_func(threads[i].data);					check_bottom_halves();				}				k = 1;			}			if (FD_ISSET(i, &x_write)) {				if (threads[i].write_func) {					threads[i].write_func(threads[i].data);					check_bottom_halves();				}				k = 1;			}			if (FD_ISSET(i, &x_error)) {				if (threads[i].error_func) {					threads[i].error_func(threads[i].data);					check_bottom_halves();				}				k = 1;			}			n -= k;		}	}}static intcan_read_or_write(int fd, int write){	struct timeval tv = {0, 0};	fd_set fds;	fd_set *rfds = NULL;	fd_set *wfds = NULL;	FD_ZERO(&fds);	FD_SET(fd, &fds);	if (write)		wfds = &fds;	else		rfds = &fds;	return select(fd + 1, rfds, wfds, NULL, &tv);}intcan_read(int fd){	return can_read_or_write(fd, 0);}intcan_write(int fd){	return can_read_or_write(fd, 1);}

⌨️ 快捷键说明

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