mirror of
				https://gitee.com/jiuyilian/embedded-framework.git
				synced 2025-10-24 18:20:15 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			170 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "iowatcher.h"
 | |
| 
 | |
| #ifdef EVENT_SELECT
 | |
| #include "hplatform.h"
 | |
| #include "hdef.h"
 | |
| #include "hevent.h"
 | |
| #include "hsocket.h"
 | |
| 
 | |
| typedef struct select_ctx_s {
 | |
|     int max_fd;
 | |
|     fd_set readfds;
 | |
|     fd_set writefds;
 | |
|     int nread;
 | |
|     int nwrite;
 | |
| } select_ctx_t;
 | |
| 
 | |
| int iowatcher_init(hloop_t* loop) {
 | |
|     if (loop->iowatcher) return 0;
 | |
|     select_ctx_t* select_ctx;
 | |
|     HV_ALLOC_SIZEOF(select_ctx);
 | |
|     select_ctx->max_fd = -1;
 | |
|     FD_ZERO(&select_ctx->readfds);
 | |
|     FD_ZERO(&select_ctx->writefds);
 | |
|     select_ctx->nread = 0;
 | |
|     select_ctx->nwrite = 0;
 | |
|     loop->iowatcher = select_ctx;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int iowatcher_cleanup(hloop_t* loop) {
 | |
|     HV_FREE(loop->iowatcher);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int iowatcher_add_event(hloop_t* loop, int fd, int events) {
 | |
|     if (loop->iowatcher == NULL) {
 | |
|         iowatcher_init(loop);
 | |
|     }
 | |
|     select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
 | |
|     if (fd > select_ctx->max_fd) {
 | |
|         select_ctx->max_fd = fd;
 | |
|     }
 | |
|     if (events & HV_READ) {
 | |
|         if (!FD_ISSET(fd, &select_ctx->readfds)) {
 | |
|             FD_SET(fd, &select_ctx->readfds);
 | |
|             select_ctx->nread++;
 | |
|         }
 | |
|     }
 | |
|     if (events & HV_WRITE) {
 | |
|         if (!FD_ISSET(fd, &select_ctx->writefds)) {
 | |
|             FD_SET(fd, &select_ctx->writefds);
 | |
|             select_ctx->nwrite++;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int iowatcher_del_event(hloop_t* loop, int fd, int events) {
 | |
|     select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
 | |
|     if (select_ctx == NULL)    return 0;
 | |
|     if (fd == select_ctx->max_fd) {
 | |
|         select_ctx->max_fd = -1;
 | |
|     }
 | |
|     if (events & HV_READ) {
 | |
|         if (FD_ISSET(fd, &select_ctx->readfds)) {
 | |
|             FD_CLR(fd, &select_ctx->readfds);
 | |
|             select_ctx->nread--;
 | |
|         }
 | |
|     }
 | |
|     if (events & HV_WRITE) {
 | |
|         if (FD_ISSET(fd, &select_ctx->writefds)) {
 | |
|             FD_CLR(fd, &select_ctx->writefds);
 | |
|             select_ctx->nwrite--;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int find_max_active_fd(hloop_t* loop) {
 | |
|     hio_t* io = NULL;
 | |
|     for (int i = loop->ios.maxsize-1; i >= 0; --i) {
 | |
|         io = loop->ios.ptr[i];
 | |
|         if (io && io->active && io->events) return i;
 | |
|     }
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| static int remove_bad_fds(hloop_t* loop) {
 | |
|     select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
 | |
|     if (select_ctx == NULL)    return 0;
 | |
|     int badfds = 0;
 | |
|     int error = 0;
 | |
|     socklen_t optlen = sizeof(error);
 | |
|     for (int fd = 0; fd <= select_ctx->max_fd; ++fd) {
 | |
|         if (FD_ISSET(fd, &select_ctx->readfds) ||
 | |
|             FD_ISSET(fd, &select_ctx->writefds)) {
 | |
|             error = 0;
 | |
|             optlen = sizeof(int);
 | |
|             if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&error, &optlen) < 0 || error != 0) {
 | |
|                 ++badfds;
 | |
|                 hio_t* io = loop->ios.ptr[fd];
 | |
|                 if (io) {
 | |
|                     hio_del(io, HV_RDWR);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return badfds;
 | |
| }
 | |
| 
 | |
| int iowatcher_poll_events(hloop_t* loop, int timeout) {
 | |
|     select_ctx_t* select_ctx = (select_ctx_t*)loop->iowatcher;
 | |
|     if (select_ctx == NULL)    return 0;
 | |
|     if (select_ctx->nread == 0 && select_ctx->nwrite == 0) {
 | |
|         return 0;
 | |
|     }
 | |
|     int     max_fd = select_ctx->max_fd;
 | |
|     fd_set  readfds = select_ctx->readfds;
 | |
|     fd_set  writefds = select_ctx->writefds;
 | |
|     if (max_fd == -1) {
 | |
|         select_ctx->max_fd = max_fd = find_max_active_fd(loop);
 | |
|     }
 | |
|     struct timeval tv, *tp;
 | |
|     if (timeout == INFINITE) {
 | |
|         tp = NULL;
 | |
|     }
 | |
|     else {
 | |
|         tv.tv_sec = timeout / 1000;
 | |
|         tv.tv_usec = (timeout % 1000) * 1000;
 | |
|         tp = &tv;
 | |
|     }
 | |
|     int nselect = select(max_fd+1, &readfds, &writefds, NULL, tp);
 | |
|     if (nselect < 0) {
 | |
| #ifdef OS_WIN
 | |
|         if (WSAGetLastError() == WSAENOTSOCK) {
 | |
| #else
 | |
|         if (errno == EBADF) {
 | |
|             perror("select");
 | |
| #endif
 | |
|             remove_bad_fds(loop);
 | |
|             return -EBADF;
 | |
|         }
 | |
|         return nselect;
 | |
|     }
 | |
|     if (nselect == 0)   return 0;
 | |
|     int nevents = 0;
 | |
|     int revents = 0;
 | |
|     for (int fd = 0; fd <= max_fd; ++fd) {
 | |
|         revents = 0;
 | |
|         if (FD_ISSET(fd, &readfds)) {
 | |
|             ++nevents;
 | |
|             revents |= HV_READ;
 | |
|         }
 | |
|         if (FD_ISSET(fd, &writefds)) {
 | |
|             ++nevents;
 | |
|             revents |= HV_WRITE;
 | |
|         }
 | |
|         if (revents) {
 | |
|             hio_t* io = loop->ios.ptr[fd];
 | |
|             if (io) {
 | |
|                 io->revents = revents;
 | |
|                 EVENT_PENDING(io);
 | |
|             }
 | |
|         }
 | |
|         if (nevents == nselect) break;
 | |
|     }
 | |
|     return nevents;
 | |
| }
 | |
| #endif
 | 
