📄 gbx_watch.c
字号:
/*************************************************************************** watch.c Default event loop and file descriptor watch routines (c) 2000-2004 Beno� Minisini <gambas@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __GBX_WATCH_C#include "gb_common.h"#include "gb_error.h"#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include "gb_array.h"#include "gbx_exec.h"#include "gbx_event.h"#include "gbx_watch.h"PRIVATE fd_set read_fd;PRIVATE fd_set write_fd;PRIVATE WATCH_CALLBACK *watch_callback = NULL;PRIVATE long max_fd = 0;static int _do_not_really_delete_callback = 0;static bool _must_delete_callback;PUBLIC void WATCH_init(void){ FD_ZERO(&read_fd); FD_ZERO(&write_fd); ARRAY_create(&watch_callback);}PUBLIC void WATCH_exit(void){ ARRAY_delete(&watch_callback);}PRIVATE void watch_fd(int fd, int flag){ if (flag & WATCH_READ) FD_SET(fd, &read_fd); else FD_CLR(fd, &read_fd); if (flag & WATCH_WRITE) FD_SET(fd, &write_fd); else FD_CLR(fd, &write_fd);}static long watch_find_callback(long fd){ int i; for (i = 0; i < ARRAY_count(watch_callback); i++) { if (fd == watch_callback[i].fd) return i; } return (-1);}static long find_max_fd(void){ int i; int max = -1; for (i = 0; i < ARRAY_count(watch_callback); i++) { if (watch_callback[i].fd > max) max = watch_callback[i].fd; } return max;}static WATCH_CALLBACK *watch_create_callback(int fd){ long pos; WATCH_CALLBACK *wcb; //fprintf(stderr, "watch_create_callback: %d\n", fd); pos = watch_find_callback(fd); if (pos < 0) { wcb = ARRAY_add_void(&watch_callback); wcb->fd = fd; } else wcb = &watch_callback[pos]; if (fd > max_fd) max_fd = fd; return wcb;}static void watch_delete_callback(int fd){ int pos; pos = watch_find_callback(fd); if (pos < 0) return; watch_callback[pos].fd = -1; max_fd = find_max_fd(); if (_do_not_really_delete_callback) return; ARRAY_remove(&watch_callback, pos);}PUBLIC void WATCH_watch(int fd, int type, void *callback, long param){ WATCH_CALLBACK *wcb; if (fd < 0 || fd > FD_SETSIZE) { fprintf(stderr, "WARNING: trying to watch fd %d\n", fd); return; } watch_fd(fd, type); /*HOOK_DEFAULT(watch, watch_fd)(fd, type);*/ if (type == WATCH_NONE) watch_delete_callback(fd); else { wcb = watch_create_callback(fd); wcb->callback = callback; wcb->param = param; //fprintf(stderr, "add watch: %d\n", watch_find_callback(fd)); }}static void raise_callback(fd_set *rfd, fd_set *wfd){ int i; WATCH_CALLBACK wcb; _must_delete_callback = FALSE; _do_not_really_delete_callback++; //fprintf(stderr, "\nmax_fd = %d\n", max_fd); for (i = 0; i < ARRAY_count(watch_callback); i++) { // We copy the callback structure, because the watch_callback array can change during the // execution of the callbacks. wcb = watch_callback[i]; if (wcb.fd < 0) continue; if (FD_ISSET(wcb.fd, rfd)) (*(wcb.callback))(wcb.fd, WATCH_READ, wcb.param); if (FD_ISSET(wcb.fd, wfd)) (*(wcb.callback))(wcb.fd, WATCH_WRITE, wcb.param); } _do_not_really_delete_callback--; if (!_do_not_really_delete_callback && _must_delete_callback) { i = 0; while (i < ARRAY_count(watch_callback)) { if (watch_callback[i].fd < 0) { ARRAY_remove(&watch_callback, i); } else i++; } }}PRIVATE int do_select(fd_set *rfd, fd_set *wfd, struct timeval *timeout){ int fd; for (fd = max_fd; fd >= 0; fd--) { if (FD_ISSET(fd, &read_fd) || FD_ISSET(fd, &write_fd)) break; } if (fd < 0 && !timeout) return 0; max_fd = fd; *rfd = read_fd; *wfd = write_fd; return select(max_fd + 1, rfd, wfd, NULL, timeout);}PUBLIC int WATCH_loop(void){ int ret; fd_set rfd, wfd; for(;;) { ret = do_select(&rfd, &wfd, NULL); if (ret > 0) raise_callback(&rfd, &wfd); else if (ret < 0) { if (errno != EINTR) THROW_SYSTEM(errno, NULL); } if (EVENT_check_post()) continue; if (ret == 0) return 0; }}PUBLIC void WATCH_wait(long wait){ int ret; fd_set rfd, wfd; struct timeval tv; double current, end; if (gettimeofday(&tv, NULL) != 0) return; end = (double)tv.tv_sec + (double)tv.tv_usec / 1E6 + wait / 1E3; for(;;) { if (gettimeofday(&tv, NULL) != 0) return; current = (double)tv.tv_sec + (double)tv.tv_usec / 1E6; if (current >= end) break; wait = (long)((end - current) * 1E3); tv.tv_sec = (time_t)(wait / 1000); tv.tv_usec = (wait % 1000) * 1000; ret = do_select(&rfd, &wfd, &tv); if (ret > 0) raise_callback(&rfd, &wfd); else if (ret < 0) { if (errno != EINTR) THROW_SYSTEM(errno, NULL); } EVENT_check_post(); }}PUBLIC int WATCH_process(int fd_end, int fd_output){ fd_set rfd; int ret, fd_max; fd_max = fd_end > fd_output ? fd_end : fd_output; for(;;) { FD_ZERO(&rfd); FD_SET(fd_end, &rfd); if (fd_output >= 0) FD_SET(fd_output, &rfd); ret = select(fd_max + 1, &rfd, NULL, NULL, NULL); if (ret > 0) break; if (errno != EINTR) break; } if (FD_ISSET(fd_end, &rfd)) return fd_end; else if (FD_ISSET(fd_output, &rfd)) return fd_output; else return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -