diff options
-rw-r--r-- | main.c | 12 | ||||
-rw-r--r-- | runloop.c | 55 | ||||
-rw-r--r-- | runloop.h | 4 |
3 files changed, 64 insertions, 7 deletions
@@ -10,6 +10,7 @@ #include "command.h" #include "conn_data.h" #include "db.h" +#include "net.h" #include "runloop.h" #include "user_data.h" @@ -111,7 +112,7 @@ static bool server_socket_callback(int fd){ do sock=accept(fd,NULL,NULL); while(sock<0&&errno==EINTR); if(sock<0)die_perror("accept"); - runloop_add_fd(sock,client_socket_callback); + runloop_add_fd(sock,client_socket_callback,true); struct hash_item *item=malloc(1,struct hash_item); conn_data_init(&item->cd,sock); @@ -121,6 +122,11 @@ static bool server_socket_callback(int fd){ return false; } +static bool timeout_callback(int fd){ + net_send_raw_text(fd,"_push ping\n",11); + return false; // We aren't going to get closure info from a send() +} + #ifndef __APPLE__ void srandomdev(void){ FILE *f=fopen("/dev/urandom","r"); @@ -139,7 +145,9 @@ int main(void){ db_init(); int sock=create_server_socket(); printf("Listening on port %d\n",PORT); - runloop_add_fd(sock,server_socket_callback); + runloop_set_timeout(60*1000000,timeout_callback); + runloop_add_fd(sock,server_socket_callback,false); runloop_run(); + printf("Runloop empty, shutting down\n"); db_close(); } @@ -1,17 +1,22 @@ #include <string.h> #include <errno.h> #include <sys/select.h> +#include <sys/time.h> #include "runloop.h" struct fd_list_item{ int fd; runloop_callback *func; + i64 last_activity; // -1 if timeout is not enabled }; static struct fd_list_item *fd_list; static size_t fd_list_len,fd_list_cap; +static i64 timeout_usecs=0; +static runloop_callback *timeout_callback=NULL; + __attribute__((constructor)) static void constructor(void){ fd_list_cap=16; @@ -20,32 +25,74 @@ static void constructor(void){ } -void runloop_add_fd(int fd,runloop_callback *func){ +static i64 make_timestamp(void){ + struct timeval tv; + gettimeofday(&tv,NULL); + return (i64)tv.tv_sec*1000000+tv.tv_usec; +} + +void runloop_set_timeout(i64 usecs,runloop_callback *cb){ + timeout_usecs=usecs; + timeout_callback=cb; +} + +void runloop_add_fd(int fd,runloop_callback *func,bool use_timeout){ if(fd_list_len==fd_list_cap){ fd_list_cap*=2; fd_list=realloc(fd_list,fd_list_cap,struct fd_list_item); } fd_list[fd_list_len].fd=fd; fd_list[fd_list_len].func=func; + fd_list[fd_list_len].last_activity=use_timeout ? make_timestamp() : -1; fd_list_len++; } void runloop_run(void){ - while(true){ + while(fd_list_len>0){ fd_set inset; FD_ZERO(&inset); int maxfd=-1; + i64 oldest_timestamp=-1; + int oldest_at=-1; for(size_t i=0;i<fd_list_len;i++){ FD_SET(fd_list[i].fd,&inset); if(fd_list[i].fd>maxfd)maxfd=fd_list[i].fd; + if(fd_list[i].last_activity!=-1&& + (oldest_timestamp==-1||fd_list[i].last_activity<oldest_timestamp)){ + oldest_timestamp=fd_list[i].last_activity; + oldest_at=i; + } } - int ret=select(maxfd+1,&inset,NULL,NULL,NULL); - if(ret<=0){ + + struct timeval tv={.tv_sec=0,.tv_usec=0}; + struct timeval *tv_ptr=NULL; + if(timeout_usecs>0&&timeout_callback!=NULL&&oldest_timestamp!=-1){ + i64 chosen_timeout=timeout_usecs-(make_timestamp()-oldest_timestamp); + if(chosen_timeout<0)chosen_timeout=0; + tv.tv_sec=chosen_timeout/1000000; + tv.tv_usec=chosen_timeout%1000000; + tv_ptr=&tv; + } + int ret=select(maxfd+1,&inset,NULL,NULL,tv_ptr); + if(ret==0){ + fd_list[oldest_at].last_activity=make_timestamp(); + if(timeout_callback(fd_list[oldest_at].fd)){ + memmove(fd_list+oldest_at,fd_list+oldest_at+1, + (fd_list_len-oldest_at-1)*sizeof(struct fd_list_item)); + fd_list_len--; + } + continue; + } + if(ret<0){ if(errno==EINTR)continue; die_perror("select"); } + for(size_t i=0;i<fd_list_len;i++){ if(FD_ISSET(fd_list[i].fd,&inset)){ + if(fd_list[i].last_activity!=-1){ + fd_list[i].last_activity=make_timestamp(); + } if(fd_list[i].func(fd_list[i].fd)){ memmove(fd_list+i,fd_list+i+1,(fd_list_len-i-1)*sizeof(struct fd_list_item)); i--; @@ -6,5 +6,7 @@ // Return true to remove fd from runloop typedef bool runloop_callback(int fd); -void runloop_add_fd(int fd,runloop_callback *func); +void runloop_set_timeout(i64 usecs,runloop_callback *timeout_callback); + +void runloop_add_fd(int fd,runloop_callback *func,bool use_timeout); void runloop_run(void); // Returns when empty |