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(&current_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