/*\ ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License) ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" #include "backend.h" #include <errno.h> #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #include <sys/param.h> #include <string.h> #include "interpret.h" #include "object.h" #include "types.h" #include "error.h" #include "fd_control.h" #include "main.h" #include "callback.h" #include "threads.h" #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> #endif #define SELECT_READ 1 #define SELECT_WRITE 2 struct selectors { fd_set read; fd_set write; }; static struct selectors selectors; file_callback read_callback[MAX_OPEN_FILEDESCRIPTORS]; void *read_callback_data[MAX_OPEN_FILEDESCRIPTORS]; file_callback write_callback[MAX_OPEN_FILEDESCRIPTORS]; void *write_callback_data[MAX_OPEN_FILEDESCRIPTORS]; static int max_fd; struct timeval current_time; struct timeval next_timeout; static struct callback *backend_callbacks = 0; struct callback *add_backend_callback(callback_func call, void *arg, callback_func free_func) { return add_to_callback(&backend_callbacks, call, arg, free_func); } void init_backend() { FD_ZERO(&selectors.read); FD_ZERO(&selectors.write); } void set_read_callback(int fd,file_callback cb,void *data) { #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); #endif read_callback[fd]=cb; read_callback_data[fd]=data; if(cb) { FD_SET(fd, &selectors.read); if(max_fd < fd) max_fd = fd; }else{ if(fd <= max_fd) { FD_CLR(fd, &selectors.read); if(fd == max_fd) { while(max_fd >=0 && !FD_ISSET(max_fd, &selectors.read) && !FD_ISSET(max_fd, &selectors.write)) max_fd--; } } } } void set_write_callback(int fd,file_callback cb,void *data) { #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); #endif write_callback[fd]=cb; write_callback_data[fd]=data; if(cb) { FD_SET(fd, &selectors.write); if(max_fd < fd) max_fd = fd; }else{ if(fd <= max_fd) { FD_CLR(fd, &selectors.write); if(fd == max_fd) { while(max_fd >=0 && !FD_ISSET(max_fd, &selectors.read) && !FD_ISSET(max_fd, &selectors.write)) max_fd--; } } } } file_callback query_read_callback(int fd) { #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); #endif return read_callback[fd]; } file_callback query_write_callback(int fd) { #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); #endif return write_callback[fd]; } void *query_read_callback_data(int fd) { #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); #endif return read_callback_data[fd]; } void *query_write_callback_data(int fd) { #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); #endif return write_callback_data[fd]; } #ifdef DEBUG void do_debug() { extern void check_all_arrays(); extern void check_all_mappings(); extern void check_all_programs(); extern void check_all_objects(); extern void verify_shared_strings_tables(); extern void slow_check_stack(); slow_check_stack(); check_all_arrays(); check_all_mappings(); check_all_programs(); verify_all_objects(); verify_shared_strings_tables(); } #endif void backend() { JMP_BUF back; int i, delay; struct selectors sets; if(SETJMP(back)) { exit_on_error="Error in handle_error in master object!\nPrevious error:"; assign_svalue_no_free(sp++, & throw_value); APPLY_MASTER("handle_error", 1); pop_stack(); automatic_fatal=0; } while(first_object) { next_timeout.tv_usec = 0; next_timeout.tv_sec = 7 * 24 * 60 * 60; /* See you in a week */ my_add_timeval(&next_timeout, ¤t_time); call_callback(& backend_callbacks, (void *)0); sets=selectors; alloca(0); /* Do garbage collect */ #ifdef DEBUG if(d_flag > 1) do_debug(); #endif GETTIMEOFDAY(¤t_time); if(my_timercmp(&next_timeout, > , ¤t_time)) { my_subtract_timeval(&next_timeout, ¤t_time); }else{ next_timeout.tv_usec = 0; next_timeout.tv_sec = 0; } THREADS_ALLOW(); i=select(max_fd+1, &sets.read, &sets.write, 0, &next_timeout); GETTIMEOFDAY(¤t_time); THREADS_DISALLOW(); check_threads_etc(); if(i>=0) { for(i=0; i<max_fd+1; i++) { if(FD_ISSET(i, &sets.read) && read_callback[i]) (*(read_callback[i]))(i,read_callback_data[i]); if(FD_ISSET(i, &sets.write) && write_callback[i]) (*(write_callback[i]))(i,write_callback_data[i]); } }else{ switch(errno) { case EINVAL: fatal("Invalid timeout to select().\n"); break; case EINTR: /* ignore */ break; case EBADF: fatal("Bad filedescriptor to select().\n"); break; } } call_callback(& backend_callbacks, (void *)1); } UNSETJMP(back); } int write_to_stderr(char *a, INT32 len) { int nonblock; INT32 pos, tmp; if((nonblock=query_nonblocking(2))) set_nonblocking(2,0); for(pos=0;pos<len;pos+=tmp) { tmp=write(2,a+pos,len-pos); if(tmp<0) break; } if(nonblock) set_nonblocking(2,1); return 1; }