diff --git a/src/backend.c b/src/backend.c index 607a58c7917fce353afedf2f3d9d04bb6bbb08af..510a80092d193ab437eb8cb5e4be929a089ccabf 100644 --- a/src/backend.c +++ b/src/backend.c @@ -4,7 +4,7 @@ ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" -RCSID("$Id: backend.c,v 1.21 1998/01/21 20:05:32 hubbe Exp $"); +RCSID("$Id: backend.c,v 1.22 1998/03/10 03:14:51 per Exp $"); #include "fdlib.h" #include "backend.h" #include <errno.h> @@ -33,6 +33,12 @@ RCSID("$Id: backend.c,v 1.21 1998/01/21 20:05:32 hubbe Exp $"); #define SELECT_READ 1 #define SELECT_WRITE 2 +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]; + +#ifndef HAVE_POLL struct selectors { my_fd_set read; @@ -41,10 +47,63 @@ struct selectors 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]; +#else +#include <poll.h> +struct pollfd *poll_fds, *active_poll_fds; +int num_in_poll=0; + +void POLL_FD_SET(int fd, short add) +{ + int i; + for(i=0; i<num_in_poll; i++) + if(poll_fds[i].fd == fd) + { + poll_fds[i].events |= add; + return; + } + num_in_poll++; + poll_fds = realloc(poll_fds, sizeof(struct pollfd)*num_in_poll); + poll_fds[num_in_poll-1].fd = fd; + poll_fds[num_in_poll-1].events = add; +} + +void POLL_FD_CLR(int fd, short sub) +{ + int i; + if(!poll_fds) return; + for(i=0; i<num_in_poll; i++) + if(poll_fds[i].fd == fd) + { + poll_fds[i].events &= ~sub; + if(!poll_fds[i].events) + { + if(i!=num_in_poll-1) + MEMCPY(poll_fds+i, poll_fds+i+1, + (num_in_poll-1-i)*sizeof(struct pollfd)); + num_in_poll--; + } + break; + } + return; +} + +int active_num_in_poll; +void switch_poll_set() +{ + struct pollfd *tmp = active_poll_fds; + + active_num_in_poll = num_in_poll; + + if(!num_in_poll) return; + + active_poll_fds = poll_fds; + + poll_fds = realloc(tmp, sizeof(struct pollfd)*num_in_poll); + + MEMCPY(poll_fds, active_poll_fds, sizeof(struct pollfd)*num_in_poll); +} +#endif + static int max_fd; struct timeval current_time; @@ -81,8 +140,10 @@ extern int pike_make_pipe(int *); void init_backend(void) { +#ifndef HAVE_POLL my_FD_ZERO(&selectors.read); my_FD_ZERO(&selectors.write); +#endif if(pike_make_pipe(wakeup_pipe) < 0) fatal("Couldn't create backend wakup pipe! errno=%d.\n",errno); set_nonblocking(wakeup_pipe[0],1); @@ -95,23 +156,31 @@ void init_backend(void) void set_read_callback(int fd,file_callback cb,void *data) { +#ifdef HAVE_POLL + int was_set = (read_callback[fd]!=0); +#endif #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) { +#ifdef HAVE_POLL + POLL_FD_SET(fd,POLLRDNORM); +#else my_FD_SET(fd, &selectors.read); +#endif if(max_fd < fd) max_fd = fd; wake_up_backend(); }else{ +#ifndef HAVE_POLL if(fd <= max_fd) { my_FD_CLR(fd, &selectors.read); + if(fd == max_fd) { while(max_fd >=0 && @@ -120,11 +189,18 @@ void set_read_callback(int fd,file_callback cb,void *data) max_fd--; } } +#else + if(was_set) + POLL_FD_CLR(fd,POLLRDNORM); +#endif } } void set_write_callback(int fd,file_callback cb,void *data) { +#ifdef HAVE_POLL + int was_set = (write_callback[fd]!=0); +#endif #ifdef DEBUG if(fd<0 || fd>=MAX_OPEN_FILEDESCRIPTORS) fatal("File descriptor out of range.\n %d",fd); @@ -135,10 +211,15 @@ void set_write_callback(int fd,file_callback cb,void *data) if(cb) { +#ifdef HAVE_POLL + POLL_FD_SET(fd,POLLOUT); +#else my_FD_SET(fd, &selectors.write); +#endif if(max_fd < fd) max_fd = fd; wake_up_backend(); }else{ +#ifndef HAVE_POLL if(fd <= max_fd) { my_FD_CLR(fd, &selectors.write); @@ -150,6 +231,10 @@ void set_write_callback(int fd,file_callback cb,void *data) max_fd--; } } +#else + if(was_set) + POLL_FD_CLR(fd,POLLOUT); +#endif } } @@ -217,6 +302,7 @@ void do_debug(void) call_callback(& do_debug_callbacks, 0); +#ifndef HAVE_POLL for(e=0;e<=max_fd;e++) { if(my_FD_ISSET(e,&selectors.read) || my_FD_ISSET(e,&selectors.write)) @@ -240,6 +326,28 @@ void do_debug(void) } } } +#else + for(e=0;e<num_in_poll;e++) + { + int ret; + do { + ret=fd_fstat(poll_fds[e].fd, &tmp); + }while(ret < 0 && errno == EINTR); + + if(ret<0) + { + switch(errno) + { + case EBADF: + fatal("Backend filedescriptor %d is bad.\n",poll_fds[e].fd); + break; + case ENOENT: + fatal("Backend filedescriptor %d is not.\n",poll_fds[e].fd); + break; + } + } + } +#endif } #endif @@ -271,8 +379,10 @@ void backend(void) check_threads_etc(); +#ifndef HAVE_POLL fd_copy_my_fd_set_to_fd_set(&rset, &selectors.read, max_fd+1); fd_copy_my_fd_set_to_fd_set(&wset, &selectors.write, max_fd+1); +#endif alloca(0); /* Do garbage collect */ #ifdef DEBUG @@ -288,15 +398,25 @@ void backend(void) next_timeout.tv_usec = 0; next_timeout.tv_sec = 0; } - +#ifdef HAVE_POLL + switch_poll_set(); +#endif THREADS_ALLOW(); +#ifdef HAVE_POLL + { + int msec = (next_timeout.tv_sec*1000) + next_timeout.tv_usec/1000; + i=poll(active_poll_fds, active_num_in_poll, msec); + } +#else i=fd_select(max_fd+1, &rset, &wset, 0, &next_timeout); +#endif GETTIMEOFDAY(¤t_time); THREADS_DISALLOW(); may_need_wakeup=0; if(i>=0) { +#ifndef HAVE_POLL for(i=0; i<max_fd+1; i++) { if(fd_FD_ISSET(i, &rset) && read_callback[i]) @@ -305,6 +425,28 @@ void backend(void) if(fd_FD_ISSET(i, &wset) && write_callback[i]) (*(write_callback[i]))(i,write_callback_data[i]); } +#else + for(i=0; i<active_num_in_poll; i++) + { + int fd = active_poll_fds[i].fd; + if(active_poll_fds[i].revents & POLLNVAL) + { + int j; + for(j=0;j<num_in_poll;j++) + if(poll_fds[j].fd == fd) /* It's still there... */ + fatal("Bad filedescriptor %d to select().\n", fd); + } + if((active_poll_fds[i].revents & POLLHUP) || + (active_poll_fds[i].revents & POLLERR)) + active_poll_fds[i].revents |= POLLRDNORM; + + if((active_poll_fds[i].revents & POLLRDNORM)&& read_callback[fd]) + (*(read_callback[fd]))(fd,read_callback_data[fd]); + + if((active_poll_fds[i].revents & POLLOUT)&& write_callback[fd]) + (*(write_callback[fd]))(fd,write_callback_data[fd]); + } +#endif }else{ switch(errno) { @@ -331,7 +473,8 @@ void backend(void) case WSAENOTSOCK: #endif case EBADF: - + /* TODO: Fix poll version! */ +#ifndef HAVE_POLL fd_copy_my_fd_set_to_fd_set(&rset, &selectors.read, max_fd+1); fd_copy_my_fd_set_to_fd_set(&wset, &selectors.write, max_fd+1); next_timeout.tv_usec=0; @@ -393,6 +536,7 @@ void backend(void) fatal("Bad filedescriptor to select().\n"); #endif /* _REENTRANT */ } +#endif break; } diff --git a/src/configure.in b/src/configure.in index cfd60e3266f1fca0baa9d852eee6fac851a7a04d..70a60f13bf4a72bfa546bfd6ab5382c3c59458e9 100644 --- a/src/configure.in +++ b/src/configure.in @@ -1,4 +1,4 @@ -AC_REVISION("$Id: configure.in,v 1.165 1998/03/06 17:34:39 grubba Exp $") +AC_REVISION("$Id: configure.in,v 1.166 1998/03/10 03:14:52 per Exp $") AC_INIT(interpret.c) AC_CONFIG_HEADER(machine.h) @@ -940,6 +940,7 @@ AC_FUNC_MMAP AC_CHECK_FUNCS( \ _crypt \ + poll \ bcopy \ bzero \ clock \ diff --git a/src/stralloc.c b/src/stralloc.c index 7175b9828ac6da9b484d2272dc69db5f0ba2c242..5759b88321c0314634b8a188c3b1b426c07469d8 100644 --- a/src/stralloc.c +++ b/src/stralloc.c @@ -17,7 +17,7 @@ #define BEGIN_HASH_SIZE 997 #define MAX_AVG_LINK_LENGTH 3 -#define HASH_PREFIX 20 +#define HASH_PREFIX 64 unsigned INT32 htable_size=0; static unsigned int hashprimes_entry=0; diff --git a/src/threads.c b/src/threads.c index ce12dfa49c8c6a731665cacd2731da1583f207f8..dca7e99a3d2fd567f44bd7ab62571fef40f1c033 100644 --- a/src/threads.c +++ b/src/threads.c @@ -1,5 +1,5 @@ #include "global.h" -RCSID("$Id: threads.c,v 1.58 1998/03/01 03:33:50 hubbe Exp $"); +RCSID("$Id: threads.c,v 1.59 1998/03/10 03:14:55 per Exp $"); int num_threads = 1; int threads_disabled = 0; @@ -152,6 +152,13 @@ struct thread_starter struct array *args; }; +int threads_denied; + +void f_thread_disallow(INT32 args) +{ + threads_denied = sp[-1].u.integer; + pop_n_elems(args); +} /* Thread hashtable */ @@ -272,11 +279,14 @@ static void check_threads(struct callback *cb, void *arg, void * arg2) static int div_; if(div_++ & 255) return; - THREADS_ALLOW(); + if(!threads_denied) + { + THREADS_ALLOW(); - /* Allow other threads to run */ + /* Allow other threads to run */ - THREADS_DISALLOW(); + THREADS_DISALLOW(); + } } void *new_thread_func(void * data) @@ -378,10 +388,6 @@ void f_thread_create(INT32 args) threads_evaluator_callback=add_to_callback(&evaluator_callbacks, check_threads, 0,0); } -#ifdef UNIX_THREADS - if((num_lwps==1) || num_threads/3 > num_lwps) - th_setconcurrency(++num_lwps); -#endif push_object(arg->id); arg->id->refs++; THREADS_FPRINTF((stderr,"THREAD_CREATE -> t:%08x\n",(unsigned int)arg->id)); @@ -735,6 +741,9 @@ void th_init(void) pthread_attr_setdetachstate(&small_pattr, PTHREAD_CREATE_DETACHED); #endif + + add_efun("thread_disallow", f_thread_disallow, "function(int:void)", + OPT_SIDE_EFFECT); add_efun("thread_create",f_thread_create,"function(mixed ...:object)", OPT_SIDE_EFFECT); @@ -822,4 +831,84 @@ void th_cleanup(void) } } +/* Thread farm code by Per + * + */ +static struct farmer { + struct farmer *neighbour; + void *field; + void (*harvest)(void *); + THREAD_T me; + COND_T harvest_moon; +} *farmers; + +static MUTEX_T rosie; + +static void *farm(void *_a) +{ + struct farmer *me = (struct farmer *)_a; + do + { +/* if(farmers == me) fatal("Ouch!\n"); */ +/* fprintf(stderr, "farm_begin %p\n",me ); */ + me->harvest( me->field ); +/* fprintf(stderr, "farm_end %p\n", me); */ + + me->harvest = 0; + mt_lock( &rosie ); + me->neighbour = farmers; + farmers = me; +/* fprintf(stderr, "farm_wait %p\n", me); */ + while(!me->harvest) co_wait( &me->harvest_moon, &rosie ); + mt_unlock( &rosie ); +/* fprintf(stderr, "farm_endwait %p\n", me); */ + } while(1); +} + +int th_num_idle_farmers() +{ + int q = 0; + struct farmer *f = farmers; + while(f) { f = f->neighbour; q++; } + return q; +} + +static int _num_farmers; +int th_num_farmers() +{ + return _num_farmers; +} + +static struct farmer *new_farmer(void (*fun)(void *), void *args) +{ + struct farmer *me = malloc(sizeof(struct farmer)); + _num_farmers++; + me->neighbour = 0; + me->field = args; + me->harvest = fun; + co_init( &me->harvest_moon ); +#ifdef UNIX_THREADS + thr_create(NULL,8192,farm,(void *)me,THR_DAEMON|THR_DETACHED|THR_BOUND,0); +#else + th_create_small(&me->me, farm, me); +#endif +} + +void th_farm(void (*fun)(void *), void *here) +{ + if(!fun) fatal("The farmers don't known how to handle empty fields\n"); + mt_lock( &rosie ); + if(farmers) + { + struct farmer *f = farmers; + farmers = f->neighbour; + mt_unlock( &rosie ); + f->field = here; + f->harvest = fun; + co_signal( &f->harvest_moon ); + return; + } + mt_unlock( &rosie ); + new_farmer( fun, here ); +} #endif