List:Commits« Previous MessageNext Message »
From:monty Date:March 14 2007 11:48am
Subject:bk commit into 5.0 tree (monty:1.2387)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of monty. When monty does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-03-14 12:47:58+02:00, monty@stripped +52 -0
  WL#441: A new thread design
  Added scheduler interface to allow different ways to schedule
  threads.
  Initially we have implementations for Solaris
  (using port_create, from the event completion framework) and windows (using IOCP)
  The Solaris framework is tested (passes test suite) while the windows code is yet
untested (passes compiler but not tested at all)

  BUILD/compile-solaris-sparc@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +5 -2
    Update scripts

  BUILD/compile-solaris-sparc-debug@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +2 -2
    Update scripts

  BUILD/compile-solaris-sparc-forte@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +7 -7
    Update scripts

  BUILD/compile-solaris-sparc-purify@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +5
-5
    Update scripts

  BitKeeper/etc/ignore@stripped, 2007-02-20 17:47:23+02:00, monty@stripped +2 -0
    added libmysqld/scheduler.cc libmysqld/sql_connect.cc

  client/mysqltest.c@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +16 -14
    Free warning and query memory no abort.
    (Removes strange warnings on screen if mysql-test-run fails)
    Removed compiler warnings

  configure.in@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +4 -3
    Added detection of port_create and port.h

  extra/yassl/src/ssl.cpp@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +4 -0
    Portability fix

  include/config-win.h@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +1 -0
    Portability fix

  include/my_pthread.h@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +5 -4
    Added my_thread_id typedef
    Renamed 'my_thread_id()' function to my_thead_dbug_id()

  include/thr_alarm.h@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +2 -1
    Make thr_alarm_kill() to depend on thread_id instead of thread

  include/thr_lock.h@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +2 -2
    Make thr_abort_locks_for_thread() depend on thread_id instead of thread

  libmysqld/Makefile.am@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +2 -1
    Added new files

  libmysqld/lib_sql.cc@stripped, 2007-03-14 12:47:54+02:00, monty@stripped +0 -9
    Remove not needed code (store_globals() now takes care of things)

  myisam/mi_log.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -1
    my_thread_id() -> my_thread_debug_id()

  mysql-test/include/one_thread_per_connection.inc@stripped, 2007-03-14 12:47:56+02:00,
monty@stripped +5 -0
    New BitKeeper file ``mysql-test/include/one_thread_per_connection.inc''

  mysql-test/include/one_thread_per_connection.inc@stripped, 2007-03-14 12:47:56+02:00,
monty@stripped +0 -0

  mysql-test/mysql-test-run.pl@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -1
    Fixed typo that caused mysql-test-run.pl to fail on Solaris

  mysql-test/r/no-threads.result@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +6 -0
    New BitKeeper file ``mysql-test/r/no-threads.result''

  mysql-test/r/no-threads.result@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -0

  mysql-test/r/one_thread_per_connection.require@stripped, 2007-03-14 12:47:56+02:00,
monty@stripped +2 -0
    New BitKeeper file ``mysql-test/r/one_thread_per_connection.require''

  mysql-test/r/one_thread_per_connection.require@stripped, 2007-03-14 12:47:56+02:00,
monty@stripped +0 -0

  mysql-test/t/no-threads-master.opt@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +1 -0
    New BitKeeper file ``mysql-test/t/no-threads-master.opt''

  mysql-test/t/no-threads-master.opt@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -0

  mysql-test/t/no-threads.test@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +5 -0
    New BitKeeper file ``mysql-test/t/no-threads.test''

  mysql-test/t/no-threads.test@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -0

  mysql-test/t/wait_timeout.test@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -0
     Don't run this if we are not using a thread per connection (as other thread_h

  mysys/my_bitmap.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +6 -5
    Fixed alignment bug

  mysys/my_getopt.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -1
    Fixed compiler warning

  mysys/my_init.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +9 -7
    Indentation fixes

  mysys/my_thr_init.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +40 -37
    Always use mysys_var->id to generate thread name (makes things uniform accross
thread implementations and thread usage)
    Always generate my_thread_name() when using DBUG
    Ensure mysys_var->pthread_self is set
    Fixed compiler warnings

  mysys/thr_alarm.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +5 -4
    Change thr_alarm_kill() to use mysys_var->id instead of thread id

  mysys/thr_lock.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +22 -13
    Change thr_abort_locks_for_thread() to use mysys_var->id instead of thread id
    Fixed compiler warnings

  mysys/thr_mutex.c@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +2 -2
    my_thread_id() -> my_thread_dbug_id()

  sql/Makefile.am@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +3 -2
    Added new files

  sql/handler.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +3 -3
    Avoid warnings on KILL_CONNECTION
    Don't print out null pointer with printf()  (Causes crashes on Solaris)

  sql/item_func.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +3 -10
    GET_LOCK, RELEASE_LOCK now works on my_thread_id instead of pthread_t

  sql/lock.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -1
    Use (new) parameter to thr_abort_locks_for_thread()

  sql/mysql_priv.h@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +27 -5
    Remove TEST_NO_THREADS (not needed with new scheduler interface)
    Added functions from sql_connect.cc and new functions from sql_parse.cc

  sql/mysqld.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +218 -105
    Use thread_scheduler structure to dispatch calls (make code more dynamic)
    Change --one-thread option to use thread_scheduler interface
    Made ONE_THREAD option independent of DBUG_BUILD
    --one-thread is now depricated. One should instead use '--thread-handling=no-threads'
    Remove not used uname() function.
    Split create_new_thread() into reusable sub functions.
    Use new scheduler interface.
    Fixed compiler warnings

  sql/parse_file.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -1
    Don't send zero pointer to fn_format() (Causes crashes when using --debug)

  sql/repl_failsafe.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +4 -8
    Setup pseudo_thread_id same way as other code

  sql/scheduler.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +1252 -0
    New BitKeeper file ``sql/scheduler.cc''

  sql/scheduler.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -0

  sql/scheduler.h@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +115 -0
    New BitKeeper file ``sql/scheduler.h''

  sql/scheduler.h@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -0

  sql/set_var.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +12 -0
    Added variables 'thread_handling' and 'thread_pool_size'

  sql/slave.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -8
    Setup pseudo_thread_id same way as other code
    Removed not used signal mask

  sql/sql_base.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +43 -19
    Fixed long comments
    Normalized variable setup
    Don't destroy value of thd->variables.pseduo_thread_id
    More DBUG_PRINT()'s
    More DBUG_ASSERT()'s
    Don't send zero pointers to printf()

  sql/sql_class.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +12 -11
    Remove thd->real_id and thd->dbug_thread_id
    Added DBUG_ASSERT()
    Use thread_scheduler to signal threads to be killed.
    In THD::store_globals(), set my_thread_var->id to be thd->thread_id.
    Fixed compiler warnings

  sql/sql_class.h@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +8 -5
    Use 'my_thread_id' for internal thread id's
    Remove not needed THD elements: block_signals and dbug_thread_id
    Added 'thread_scheduler' scheduling extension element to THD

  sql/sql_connect.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +1097 -0
    New BitKeeper file ``sql/sql_connect.cc''

  sql/sql_connect.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -0

  sql/sql_insert.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +1 -7
    Removed not used signal mask
     

  sql/sql_parse.cc@stripped, 2007-03-14 12:47:55+02:00, monty@stripped +10 -987
    Move connection related code to sql_connect.cc
    Remove setting of signal mask (not needed)
    Ensure TABLE_LIST->alias is set for generated TABLE_LIST elements (fixed core dumps
when running with --debug)
    Added previous 'optional' element to reset_mgh()
    Removed not needed DBUG_PRINT call

  sql/sql_show.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +0 -4
    Don't send pthread_kill() to threads to detect if they exists.
    (Not that useful and causes problems with future thread_handling code)

  sql/sql_table.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +8 -13
    Simplify code 

  sql/sql_test.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +6 -4
    Remove dbug_thread_id from test output

  sql/sql_view.cc@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +1 -1
    Don't send zero pointer to fn_format()

  vio/viosslfactories.c@stripped, 2007-03-14 12:47:56+02:00, monty@stripped +8 -0
    More debugging

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	monty
# Host:	narttu.mysql.fi
# Root:	/home/my/mysql-5.0-ebay

--- 1.15/BUILD/compile-solaris-sparc-purify	2005-05-18 14:23:13 +03:00
+++ 1.16/BUILD/compile-solaris-sparc-purify	2007-03-14 12:47:54 +02:00
@@ -31,7 +31,7 @@
   shift
 done
 
-gmake -k clean || true 
+make -k clean || true 
 /bin/rm -f */.deps/*.P config.cache
  
 path=`dirname $0`
@@ -39,7 +39,7 @@
 
 CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts
-Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused 
-DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type
-Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare
-Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy
-Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti  -DHAVE_purify
-DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler
--with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db
--with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS
 
-gmake -j 4
+make -j 4
 
 # ----------------------------------------------------------------------
 
@@ -75,17 +75,17 @@
     fi
 
     if [ -n "$mode" -a $mode = purify ] ; then
-      gmake CCLD="purify   $opts gcc"  CXXLD="purify   $opts g++"  $target
+      make CCLD="purify   $opts gcc"  CXXLD="purify   $opts g++"  $target
       mv $binary $binary-purify
     fi
 
     if [ -n "$mode" -a $mode = quantify ] ; then
-      gmake CCLD="quantify $opts gcc"  CXXLD="quantify $opts g++"  $target
+      make CCLD="quantify $opts gcc"  CXXLD="quantify $opts g++"  $target
       mv $binary $binary-quantify
     fi
 
     if [ -n "$mode" -a $mode = purecov ] ; then
-      gmake CCLD="purecov  $opts gcc"  CXXLD="purecov  $opts g++"  $target
+      make CCLD="purecov  $opts gcc"  CXXLD="purecov  $opts g++"  $target
       mv $binary $binary-purecov
     fi
 

--- 1.9/BUILD/compile-solaris-sparc	2005-05-18 14:23:13 +03:00
+++ 1.10/BUILD/compile-solaris-sparc	2007-03-14 12:47:54 +02:00
@@ -1,11 +1,14 @@
 #! /bin/sh
 
-gmake -k clean || true
+make -k clean || true
 /bin/rm -f */.deps/*.P config.cache
  
+# gcc is often in /usr/ccs/bin or /usr/local/bin
+PATH=$PATH:/usr/ccs/bin:/usr/local/bin
+
 path=`dirname $0`
 . "$path/autorun.sh"
 
 CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts
-Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused  -O3
-fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa" CXX=gcc CXXFLAGS="-Wimplicit
-Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses
-Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder
-Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti 
-O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g" ./configure
--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex
--enable-thread-safe-client
 
-gmake -j 4
+make -j 4

--- 1.422/configure.in	2007-01-23 16:41:58 +02:00
+++ 1.423/configure.in	2007-03-14 12:47:54 +02:00
@@ -748,7 +748,7 @@
  sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
  unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \
  sys/ioctl.h malloc.h sys/malloc.h sys/ipc.h sys/shm.h linux/config.h \
- sys/resource.h sys/param.h)
+ sys/resource.h sys/param.h port.h)
 
 #--------------------------------------------------------------------
 # Check for system libraries. Adds the library to $LIBS
@@ -1959,8 +1959,9 @@
   pthread_setprio_np pthread_setschedparam pthread_sigmask readlink \
   realpath rename rint rwlock_init setupterm \
   shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \
-  sighold sigset sigthreadmask \
-  snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr strtol \
+  sighold port_create sigset sigthreadmask \
+  snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \
+  strtol \
   strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr)
 
 #

--- 1.83/include/config-win.h	2006-12-27 07:28:19 +02:00
+++ 1.84/include/config-win.h	2007-03-14 12:47:54 +02:00
@@ -338,6 +338,7 @@
 #define HAVE_SETFILEPOINTER
 #define HAVE_VIO_READ_BUFF
 #define HAVE_STRNLEN
+#define HAVE_WINSOCK2
 
 #ifndef __NT__
 #undef FILE_SHARE_DELETE

--- 1.97/include/my_pthread.h	2007-01-22 14:10:36 +02:00
+++ 1.98/include/my_pthread.h	2007-03-14 12:47:54 +02:00
@@ -18,7 +18,6 @@
 #ifndef _my_pthread_h
 #define _my_pthread_h
 
-#include <errno.h>
 #ifndef ETIME
 #define ETIME ETIMEDOUT				/* For FreeBSD */
 #endif
@@ -90,6 +89,7 @@
 
 typedef int pthread_mutexattr_t;
 #define win_pthread_self my_thread_var->pthread_self
+#define pthread_self() win_pthread_self
 #ifdef OS2
 #define pthread_handler_t EXTERNC void * _Optlink
 typedef void * (_Optlink *pthread_handler)(void *);
@@ -152,7 +152,6 @@
 #define ETIMEDOUT 145		    /* Win32 doesn't have this */
 #define getpid() GetCurrentThreadId()
 #endif
-#define pthread_self() win_pthread_self
 #define HAVE_LOCALTIME_R		1
 #define _REENTRANT			1
 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE	1
@@ -712,12 +711,14 @@
 #define MY_MUTEX_INIT_ERRCHK   NULL
 #endif
 
+typedef ulong my_thread_id;
+
 extern my_bool my_thread_global_init(void);
 extern void my_thread_global_end(void);
 extern my_bool my_thread_init(void);
 extern void my_thread_end(void);
 extern const char *my_thread_name(void);
-extern long my_thread_id(void);
+extern my_thread_id my_thread_dbug_id(void);
 extern int pthread_no_free(void *);
 extern int pthread_dummy(int);
 
@@ -744,7 +745,7 @@
   pthread_mutex_t * volatile current_mutex;
   pthread_cond_t * volatile current_cond;
   pthread_t pthread_self;
-  long id;
+  my_thread_id id;
   int cmp_length;
   int volatile abort;
   my_bool init;

--- 1.18/include/thr_alarm.h	2006-12-23 21:04:05 +02:00
+++ 1.19/include/thr_alarm.h	2007-03-14 12:47:54 +02:00
@@ -94,6 +94,7 @@
   ulong expire_time;
   thr_alarm_entry alarmed;		/* set when alarm is due */
   pthread_t thread;
+  my_thread_id thread_id;
   my_bool malloced;
 } ALARM;
 
@@ -102,7 +103,7 @@
 void init_thr_alarm(uint max_alarm);
 void resize_thr_alarm(uint max_alarms);
 my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff);
-void thr_alarm_kill(pthread_t thread_id);
+void thr_alarm_kill(my_thread_id thread_id);
 void thr_end_alarm(thr_alarm_t *alarmed);
 void end_thr_alarm(my_bool free_structures);
 sig_handler process_alarm(int);

--- 1.18/include/thr_lock.h	2006-12-23 21:04:05 +02:00
+++ 1.19/include/thr_lock.h	2007-03-14 12:47:54 +02:00
@@ -78,7 +78,7 @@
 typedef struct st_thr_lock_info
 {
   pthread_t thread;
-  ulong thread_id;
+  my_thread_id thread_id;
   ulong n_cursors;
 } THR_LOCK_INFO;
 
@@ -143,7 +143,7 @@
                                          uint count, THR_LOCK_OWNER *owner);
 void thr_multi_unlock(THR_LOCK_DATA **data,uint count);
 void thr_abort_locks(THR_LOCK *lock);
-my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread);
+my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread);
 void thr_print_locks(void);		/* For debugging */
 my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data);
 my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data);

--- 1.13/myisam/mi_log.c	2006-12-30 22:02:05 +02:00
+++ 1.14/myisam/mi_log.c	2007-03-14 12:47:55 +02:00
@@ -31,7 +31,7 @@
 
 #undef GETPID					/* For HPUX */
 #ifdef THREAD
-#define GETPID() (log_type == 1 ? (long) myisam_pid : (long) my_thread_id());
+#define GETPID() (log_type == 1 ? (long) myisam_pid : (long) my_thread_var->id);
 #else
 #define GETPID() myisam_pid
 #endif

--- 1.47/mysys/my_init.c	2006-12-23 21:04:07 +02:00
+++ 1.48/mysys/my_init.c	2007-03-14 12:47:55 +02:00
@@ -245,14 +245,16 @@
 }
 
 /*
-  my_paramter_handler
-  Invalid paramter handler we will use instead of the one "baked" into the CRT
-  for MSC v8.  This one just prints out what invalid parameter was encountered.
-  By providing this routine, routines like lseek will return -1 when we expect them 
-  to instead of crash.
+  my_parameter_handler
+  
+  Invalid parameter handler we will use instead of the one "baked"
+  into the CRT for MSC v8.  This one just prints out what invalid
+  parameter was encountered.  By providing this routine, routines like
+  lseek will return -1 when we expect them to instead of crash.
 */
-void my_parameter_handler(const wchar_t * expression, const wchar_t * function, 
-                          const wchar_t * file, unsigned int line, 
+
+void my_parameter_handler(const wchar_t * expression, const wchar_t * function,
+                          const wchar_t * file, unsigned int line,
                           uintptr_t pReserved)
 {
   DBUG_PRINT("my",("Expression: %s  function: %s  file: %s, line: %d",

--- 1.36/mysys/my_thr_init.c	2007-01-12 13:22:48 +02:00
+++ 1.37/mysys/my_thr_init.c	2007-03-14 12:47:55 +02:00
@@ -46,23 +46,23 @@
 pthread_mutexattr_t my_errorcheck_mutexattr;
 #endif
 
-#ifdef NPTL_PTHREAD_EXIT_BUG /* see my_pthread.h */
+#ifdef NPTL_PTHREAD_EXIT_BUG                    /* see my_pthread.h */
 
 /*
  Dummy thread spawned in my_thread_global_init() below to avoid
  race conditions in NPTL pthread_exit code.
 */
 
-static
-pthread_handler_t nptl_pthread_exit_hack_handler(void *arg)
+static pthread_handler_t
+nptl_pthread_exit_hack_handler(void *arg __attribute((unused)))
 {
   /* Do nothing! */
   pthread_exit(0);
   return 0;
 }
-
 #endif
 
+
 /*
   initialize thread environment
 
@@ -83,25 +83,28 @@
   }
   
 #ifdef NPTL_PTHREAD_EXIT_BUG
+  /*
+    BUG#24507: Race conditions inside current NPTL pthread_exit() 
+    implementation.
 
-/*
-  BUG#24507: Race conditions inside current NPTL pthread_exit() implementation.
-
-  To avoid a possible segmentation fault during concurrent executions of 
-  pthread_exit(), a dummy thread is spawned which initializes internal variables
-  of pthread lib. See bug description for thoroughfull explanation. 
+    To avoid a possible segmentation fault during concurrent
+    executions of pthread_exit(), a dummy thread is spawned which
+    initializes internal variables of pthread lib. See bug description
+    for a full explanation.
   
-  TODO: Remove this code when fixed versions of glibc6 are in common use. 
-*/
-
-  pthread_t       dummy_thread;
-  pthread_attr_t  dummy_thread_attr;
-
-  pthread_attr_init(&dummy_thread_attr);
-  pthread_attr_setdetachstate(&dummy_thread_attr,PTHREAD_CREATE_DETACHED);
+    TODO: Remove this code when fixed versions of glibc6 are in common
+    use.
+  */
+  {
+    pthread_t       dummy_thread;
+    pthread_attr_t  dummy_thread_attr;
 
- 
pthread_create(&dummy_thread,&dummy_thread_attr,nptl_pthread_exit_hack_handler,NULL);
+    pthread_attr_init(&dummy_thread_attr);
+    pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED);
 
+    pthread_create(&dummy_thread,&dummy_thread_attr,
+                   nptl_pthread_exit_hack_handler, NULL);
+  }
 #endif
 
 #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
@@ -206,7 +209,7 @@
 #endif
 }
 
-static long thread_id=0;
+static my_thread_id thread_id= 0;
 
 /*
   Allocate thread specific memory for the thread, used by mysys and dbug
@@ -234,15 +237,16 @@
   my_bool error=0;
 
 #ifdef EXTRA_DEBUG_THREADS
-  fprintf(stderr,"my_thread_init(): thread_id=%ld\n",pthread_self());
+  fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
+          (ulong) pthread_self());
 #endif  
 
 #if !defined(__WIN__) || defined(USE_TLS)
   if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
   {
 #ifdef EXTRA_DEBUG_THREADS
-    fprintf(stderr,"my_thread_init() called more than once in thread %ld\n",
-	        pthread_self());
+    fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
+            (long) pthread_self());
 #endif    
     goto end;
   }
@@ -262,7 +266,9 @@
   tmp= &THR_KEY_mysys;
 #endif
 #if defined(__WIN__) && defined(EMBEDDED_LIBRARY)
-  tmp->thread_self= (pthread_t)getpid();
+  tmp->pthread_self= (pthread_t) getpid();
+#else
+  tmp->pthread_self= pthread_self();
 #endif
   pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
   pthread_cond_init(&tmp->suspend, NULL);
@@ -272,6 +278,11 @@
   tmp->id= ++thread_id;
   ++THR_thread_count;
   pthread_mutex_unlock(&THR_LOCK_threads);
+#ifndef DBUG_OFF
+  /* Generate unique name for thread */
+  (void) my_thread_name();
+#endif
+
 end:
   return error;
 }
@@ -295,8 +306,8 @@
   tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
 
 #ifdef EXTRA_DEBUG_THREADS
-  fprintf(stderr,"my_thread_end(): tmp: 0x%lx  thread_id=%ld\n",
-	  (long) tmp, pthread_self());
+  fprintf(stderr,"my_thread_end(): tmp: 0x%lx  pthread_self: 0x%lx  thread_id: %ld\n",
+	  (long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
 #endif  
   if (tmp && tmp->init)
   {
@@ -357,17 +368,9 @@
   Get name of current thread.
 ****************************************************************************/
 
-#define UNKNOWN_THREAD -1
-
-long my_thread_id()
+my_thread_id my_thread_dbug_id()
 {
-#if defined(HAVE_PTHREAD_GETSEQUENCE_NP)
-  return pthread_getsequence_np(pthread_self());
-#elif (defined(__sun) || defined(__sgi) || defined(__linux__)) &&
!defined(HAVE_mit_thread)
-  return pthread_self();
-#else
   return my_thread_var->id;
-#endif
 }
 
 #ifdef DBUG_OFF
@@ -384,8 +387,8 @@
   struct st_my_thread_var *tmp=my_thread_var;
   if (!tmp->name[0])
   {
-    long id=my_thread_id();
-    sprintf(name_buff,"T@%ld", id);
+    my_thread_id id= my_thread_dbug_id();
+    sprintf(name_buff,"T@%lu", (ulong) id);
     strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
   }
   return tmp->name;

--- 1.50/mysys/thr_alarm.c	2006-12-23 21:04:08 +02:00
+++ 1.51/mysys/thr_alarm.c	2007-03-14 12:47:55 +02:00
@@ -147,6 +147,7 @@
   ulong now;
   sigset_t old_mask;
   my_bool reschedule;
+  struct st_my_thread_var *current_my_thread_var= my_thread_var;
   DBUG_ENTER("thr_alarm");
   DBUG_PRINT("enter",("thread: %s  sec: %d",my_thread_name(),sec));
 
@@ -196,7 +197,8 @@
     alarm_data->malloced=0;
   alarm_data->expire_time=now+sec;
   alarm_data->alarmed=0;
-  alarm_data->thread=pthread_self();
+  alarm_data->thread=    current_my_thread_var->pthread_self;
+  alarm_data->thread_id= current_my_thread_var->id;
   queue_insert(&alarm_queue,(byte*) alarm_data);
 
   /* Reschedule alarm if the current one has more than sec left */
@@ -445,7 +447,7 @@
   Remove another thread from the alarm
 */
 
-void thr_alarm_kill(pthread_t thread_id)
+void thr_alarm_kill(my_thread_id thread_id)
 {
   uint i;
   if (alarm_aborted)
@@ -453,8 +455,7 @@
   pthread_mutex_lock(&LOCK_alarm);
   for (i=0 ; i < alarm_queue.elements ; i++)
   {
-    if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
-		      thread_id))
+    if (((ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id)
     {
       ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
       tmp->expire_time=0;

--- 1.52/mysys/thr_lock.c	2006-12-23 21:04:08 +02:00
+++ 1.53/mysys/thr_lock.c	2007-03-14 12:47:55 +02:00
@@ -343,8 +343,9 @@
 
 void thr_lock_info_init(THR_LOCK_INFO *info)
 {
-  info->thread= pthread_self();
-  info->thread_id= my_thread_id();              /* for debugging */
+  struct st_my_thread_var *tmp= my_thread_var;
+  info->thread=    tmp->pthread_self;
+  info->thread_id= tmp->id;
   info->n_cursors= 0;
 }
 
@@ -481,7 +482,7 @@
   data->type=lock_type;
   data->owner= owner;                           /* Must be reset ! */
   VOID(pthread_mutex_lock(&lock->mutex));
-  DBUG_PRINT("lock",("data: 0x%lx  thread: %ld  lock: 0x%lx  type: %d",
+  DBUG_PRINT("lock",("data: 0x%lx  thread: %lu  lock: 0x%lx  type: %d",
                      (long) data, data->owner->info->thread_id,
                      (long) lock, (int) lock_type));
   check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
@@ -500,7 +501,7 @@
 	   and the read lock is not TL_READ_NO_INSERT
       */
 
-      DBUG_PRINT("lock",("write locked by thread: %ld",
+      DBUG_PRINT("lock",("write locked by thread: %lu",
 			 lock->write.data->owner->info->thread_id));
       if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
 	  (lock->write.data->type <= TL_WRITE_DELAYED &&
@@ -622,8 +623,10 @@
 	statistic_increment(locks_immediate,&THR_LOCK_lock);
 	goto end;
       }
-      DBUG_PRINT("lock",("write locked by thread: %ld",
+      /* purecov: begin inspected */
+      DBUG_PRINT("lock",("write locked by thread: %lu",
 			 lock->write.data->owner->info->thread_id));
+      /* purecov: end */
     }
     else
     {
@@ -658,8 +661,10 @@
 	  goto end;
 	}
       }
-      DBUG_PRINT("lock",("write locked by thread: %ld, type: %d",
+      /* purecov: begin inspected */
+      DBUG_PRINT("lock",("write locked by thread: %lu  type: %d",
 			 lock->read.data->owner->info->thread_id, data->type));
+      /* purecov: end */
     }
     wait_queue= &lock->write_wait;
   }
@@ -720,8 +725,10 @@
       }
       lock->read_no_write_count++;
     }      
-    DBUG_PRINT("lock",("giving read lock to thread: %ld",
+    /* purecov: begin inspected */
+    DBUG_PRINT("lock",("giving read lock to thread: %lu",
 		       data->owner->info->thread_id));
+    /* purecov: end */
     data->cond=0;				/* Mark thread free */
     VOID(pthread_cond_signal(cond));
   } while ((data=data->next));
@@ -738,7 +745,7 @@
   THR_LOCK *lock=data->lock;
   enum thr_lock_type lock_type=data->type;
   DBUG_ENTER("thr_unlock");
-  DBUG_PRINT("lock",("data: 0x%lx  thread: %ld  lock: 0x%lx",
+  DBUG_PRINT("lock",("data: 0x%lx  thread: %lu  lock: 0x%lx",
                      (long) data, data->owner->info->thread_id, (long) lock));
   pthread_mutex_lock(&lock->mutex);
   check_locks(lock,"start of release lock",0);
@@ -798,8 +805,10 @@
 	  if (data->type == TL_WRITE_CONCURRENT_INSERT &&
 	      (*lock->check_status)(data->status_param))
 	    data->type=TL_WRITE;			/* Upgrade lock */
-	  DBUG_PRINT("lock",("giving write lock of type %d to thread: %ld",
+          /* purecov: begin inspected */
+	  DBUG_PRINT("lock",("giving write lock of type %d to thread: %lu",
 			     data->type, data->owner->info->thread_id));
+          /* purecov: end */
 	  {
 	    pthread_cond_t *cond=data->cond;
 	    data->cond=0;				/* Mark thread free */
@@ -998,7 +1007,7 @@
       thr_unlock(*pos);
     else
     {
-      DBUG_PRINT("lock",("Free lock: data: 0x%lx  thread: %ld  lock: 0x%lx",
+      DBUG_PRINT("lock",("Free lock: data: 0x%lx  thread: %lu  lock: 0x%lx",
                          (long) *pos, (*pos)->owner->info->thread_id,
                          (long) (*pos)->lock));
     }
@@ -1046,7 +1055,7 @@
   This is used to abort all locks for a specific thread
 */
 
-my_bool thr_abort_locks_for_thread(THR_LOCK *lock, pthread_t thread)
+my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id)
 {
   THR_LOCK_DATA *data;
   my_bool found= FALSE;
@@ -1055,7 +1064,7 @@
   pthread_mutex_lock(&lock->mutex);
   for (data= lock->read_wait.data; data ; data= data->next)
   {
-    if (pthread_equal(thread, data->owner->info->thread))
+    if (data->owner->info->thread_id == thread_id)    /* purecov: tested */
     {
       DBUG_PRINT("info",("Aborting read-wait lock"));
       data->type= TL_UNLOCK;			/* Mark killed */
@@ -1072,7 +1081,7 @@
   }
   for (data= lock->write_wait.data; data ; data= data->next)
   {
-    if (pthread_equal(thread, data->owner->info->thread))
+    if (data->owner->info->thread_id == thread_id) /* purecov: tested */
     {
       DBUG_PRINT("info",("Aborting write-wait lock"));
       data->type= TL_UNLOCK;

--- 1.29/mysys/thr_mutex.c	2006-12-23 21:04:08 +02:00
+++ 1.30/mysys/thr_mutex.c	2007-03-14 12:47:55 +02:00
@@ -212,7 +212,7 @@
   {
     fprintf(stderr,
 	    "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d\n",
-	    mp->count-1, my_thread_id(), file, line);
+	    mp->count-1, my_thread_dbug_id(), file, line);
     fflush(stderr);
     abort();
   }
@@ -250,7 +250,7 @@
   {
     fprintf(stderr,
 	    "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d (error:
%d (%d))\n",
-	    mp->count-1, my_thread_id(), file, line, error, error);
+	    mp->count-1, my_thread_dbug_id(), file, line, error, error);
     fflush(stderr);
     abort();
   }

--- 1.130/sql/Makefile.am	2006-12-30 22:02:06 +02:00
+++ 1.131/sql/Makefile.am	2007-03-14 12:47:55 +02:00
@@ -62,7 +62,7 @@
                         tztime.h my_decimal.h\
 			sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
 			parse_file.h sql_view.h	sql_trigger.h \
-			sql_array.h sql_cursor.h \
+			sql_array.h sql_cursor.h scheduler.h \
 			examples/ha_example.h ha_archive.h \
 			examples/ha_tina.h ha_blackhole.h  \
 			ha_federated.h
@@ -76,7 +76,8 @@
 			lock.cc my_lock.c \
 			sql_string.cc sql_manager.cc sql_map.cc \
 			mysqld.cc password.c hash_filo.cc hostname.cc \
-			set_var.cc sql_parse.cc sql_yacc.yy \
+			sql_connect.cc scheduler.cc sql_parse.cc \
+			set_var.cc sql_yacc.yy \
 			sql_base.cc table.cc sql_select.cc sql_insert.cc \
                         sql_prepare.cc sql_error.cc sql_locale.cc \
 			sql_update.cc sql_delete.cc uniques.cc sql_do.cc \

--- 1.227/sql/handler.cc	2007-01-22 14:10:39 +02:00
+++ 1.228/sql/handler.cc	2007-03-14 12:47:55 +02:00
@@ -831,7 +831,7 @@
     message in the error log, so we don't send it.
   */
   if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
&&
-      !thd->slave_thread)
+      !thd->slave_thread && thd->killed != THD::KILL_CONNECTION)
     push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                  ER_WARNING_NOT_COMPLETE_ROLLBACK,
                  ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
@@ -2428,8 +2428,8 @@
 {
   int error= 0;
   DBUG_ENTER("ha_find_files");
-  DBUG_PRINT("enter", ("db: %s, path: %s, wild: %s, dir: %d",
-		       db, path, wild, dir));
+  DBUG_PRINT("enter", ("db: '%s'  path: '%s'  wild: '%s'  dir: %d",
+                       db, path, wild ? wild : "NULL", dir));
 #ifdef HAVE_NDBCLUSTER_DB
   if (have_ndbcluster == SHOW_OPTION_YES)
     error= ndbcluster_find_files(thd, db, path, wild, dir, files);

--- 1.321/sql/item_func.cc	2007-01-22 14:10:39 +02:00
+++ 1.322/sql/item_func.cc	2007-03-14 12:47:55 +02:00
@@ -3070,8 +3070,7 @@
   int count;
   bool locked;
   pthread_cond_t cond;
-  pthread_t thread;
-  ulong thread_id;
+  my_thread_id thread_id;
 
   User_level_lock(const char *key_arg,uint length, ulong id) 
     :key_length(length),count(1),locked(1), thread_id(id)
@@ -3224,7 +3223,7 @@
   else
   {
     ull->locked=1;
-    ull->thread=thd->real_id;
+    ull->thread_id= thd->thread_id;             /* purecov: inspected */
     thd->ull=ull;
   }
   pthread_mutex_unlock(&LOCK_user_locks);
@@ -3299,7 +3298,6 @@
       null_value=1;				// Probably out of memory
       return 0;
     }
-    ull->thread=thd->real_id;
     thd->ull=ull;
     pthread_mutex_unlock(&LOCK_user_locks);
     return 1;					// Got new lock
@@ -3340,7 +3338,6 @@
   else                                          // We got the lock
   {
     ull->locked=1;
-    ull->thread=thd->real_id;
     ull->thread_id= thd->thread_id;
     thd->ull=ull;
     error=0;
@@ -3388,11 +3385,7 @@
   }
   else
   {
-#ifdef EMBEDDED_LIBRARY
-    if (ull->locked && pthread_equal(current_thd->real_id,ull->thread))
-#else
-    if (ull->locked && pthread_equal(pthread_self(),ull->thread))
-#endif
+    if (ull->locked && current_thd->thread_id == ull->thread_id)
     {
       result=1;					// Release is ok
       item_user_lock_release(ull);

--- 1.92/sql/lock.cc	2006-12-30 22:02:07 +02:00
+++ 1.93/sql/lock.cc	2007-03-14 12:47:55 +02:00
@@ -447,7 +447,7 @@
     for (uint i=0; i < locked->lock_count; i++)
     {
       if (thr_abort_locks_for_thread(locked->locks[i]->lock,
-                                     table->in_use->real_id))
+                                     table->in_use->thread_id))
         result= TRUE;
     }
     my_free((gptr) locked,MYF(0));

--- 1.431/sql/mysql_priv.h	2007-01-22 14:10:40 +02:00
+++ 1.432/sql/mysql_priv.h	2007-03-14 12:47:55 +02:00
@@ -34,6 +34,7 @@
 #include <my_base.h>			/* Needed by field.h */
 #include "sql_bitmap.h"
 #include "sql_array.h"
+#include "scheduler.h"
 
 #ifdef __EMX__
 #undef write  /* remove pthread.h macro definition for EMX */
@@ -272,7 +273,6 @@
 #define TEST_MIT_THREAD		4
 #define TEST_BLOCKING		8
 #define TEST_KEEP_TMP_TABLES	16
-#define TEST_NO_THREADS		32	/* For debugging under Linux */
 #define TEST_READCHECK		64	/* Force use of readcheck */
 #define TEST_NO_EXTRA		128
 #define TEST_CORE_ON_SIGNAL	256	/* Give core if signal */
@@ -654,6 +654,23 @@
 #define query_cache_invalidate_by_MyISAM_filename_ref NULL
 #endif /*HAVE_QUERY_CACHE*/
 
+/* sql_connect.cc */
+int check_user(THD *thd, enum enum_server_command command, 
+	       const char *passwd, uint passwd_len, const char *db,
+	       bool check_count);
+pthread_handler_t handle_one_connection(void *arg);
+bool init_new_connection_handler_thread();
+void reset_mqh(LEX_USER *lu, bool get_them);
+bool check_mqh(THD *thd, uint check_command);
+void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
+int check_for_max_user_connections(THD *thd, USER_CONN *uc);
+void decrease_user_connections(USER_CONN *uc);
+void thd_init_client_charset(THD *thd, uint cs_number);
+bool setup_connection_thread_globals(THD *thd);
+bool login_connection(THD *thd);
+void prepare_new_connection_state(THD* thd);
+void end_connection(THD *thd);
+
 bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
 bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
 bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -687,10 +704,7 @@
 void init_max_user_conn(void);
 void init_update_queries(void);
 void free_max_user_conn(void);
-pthread_handler_t handle_one_connection(void *arg);
 pthread_handler_t handle_bootstrap(void *arg);
-void end_thread(THD *thd,bool put_in_cache);
-void flush_thread_cache();
 bool mysql_execute_command(THD *thd);
 bool do_command(THD *thd);
 bool dispatch_command(enum enum_server_command command, THD *thd,
@@ -1158,6 +1172,11 @@
 extern void MYSQLerror(const char*);
 void refresh_status(THD *thd);
 my_bool mysql_rm_tmp_tables(void);
+void handle_connection_in_main_thread(THD *thd);
+void create_thread_to_handle_connection(THD *thd);
+void unlink_thd(THD *thd);
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
+void flush_thread_cache();
 
 /* item_func.cc */
 extern bool check_reserved_words(LEX_STRING *name);
@@ -1233,7 +1252,7 @@
 extern ulong max_prepared_stmt_count, prepared_stmt_count;
 extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
 extern ulong max_binlog_size, max_relay_log_size;
-extern ulong rpl_recovery_rank, thread_cache_size;
+extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
 extern ulong back_log;
 extern ulong specialflag, current_pid;
 extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
@@ -1310,6 +1329,9 @@
 extern const char* any_db;
 extern struct my_option my_long_options[];
 extern const LEX_STRING view_type;
+extern scheduler_functions thread_scheduler;
+extern TYPELIB thread_handling_typelib;
+extern uint8 uc_update_queries[SQLCOM_END+1];
 
 /* optional things, have_* variables */
 

--- 1.587/sql/mysqld.cc	2007-01-23 16:42:00 +02:00
+++ 1.588/sql/mysqld.cc	2007-03-14 12:47:55 +02:00
@@ -63,10 +63,6 @@
 
 #define mysqld_charset &my_charset_latin1
 
-#ifndef DBUG_OFF
-#define ONE_THREAD
-#endif
-
 #ifdef HAVE_purify
 #define IF_PURIFY(A,B) (A)
 #else
@@ -281,6 +277,17 @@
   array_elements(tc_heuristic_recover_names)-1,"",
   tc_heuristic_recover_names, NULL
 };
+
+static const char *thread_handling_names[]=
+{ "one-thread-per-connection", "no-threads", "pool-of-threads", NullS};
+
+TYPELIB thread_handling_typelib=
+{
+  array_elements(thread_handling_names) - 1, "",
+  thread_handling_names, NULL
+};
+
+
 const char *first_keyword= "first", *binary_keyword= "BINARY";
 const char *my_localhost= "localhost", *delayed_user= "DELAYED";
 #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
@@ -402,7 +409,8 @@
 ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
 ulong open_files_limit, max_binlog_size, max_relay_log_size;
 ulong slave_net_timeout, slave_trans_retries;
-ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
+ulong thread_cache_size=0, thread_pool_size= 0;
+ulong binlog_cache_size=0, max_binlog_cache_size=0;
 ulong query_cache_size=0;
 ulong refresh_version, flush_version;	/* Increments on each reload */
 query_id_t global_query_id;
@@ -609,6 +617,8 @@
 HANDLE smem_event_connect_request= 0;
 #endif
 
+scheduler_functions thread_scheduler;
+
 #define SSL_VARS_NOT_STATIC
 #include "sslopt-vars.h"
 #ifdef HAVE_OPENSSL
@@ -788,6 +798,7 @@
       continue;
 
     tmp->killed= THD::KILL_CONNECTION;
+    thread_scheduler.post_kill_notification(tmp);
     if (tmp->mysys_var)
     {
       tmp->mysys_var->abort=1;
@@ -1182,6 +1193,8 @@
   if (!opt_bootstrap)
     (void) my_delete(pidfile_name,MYF(0));	// This may not always exist
 #endif
+  if (thread_scheduler.end)
+    thread_scheduler.end();
   finish_client_errs();
   my_free((gptr) my_error_unregister(ER_ERROR_FIRST, ER_ERROR_LAST),
           MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
@@ -1440,6 +1453,9 @@
   DBUG_ENTER("network_init");
   LINT_INIT(ret);
 
+  if (thread_scheduler.init())
+    unireg_abort(1);			/* purecov: inspected */
+
   set_ports();
 
   if (mysqld_port != 0 && !opt_disable_networking && !opt_bootstrap)
@@ -1658,26 +1674,60 @@
   if (thd && ! thd->bootstrap)
   {
     statistic_increment(killed_threads, &LOCK_status);
-    end_thread(thd,0);
+    thread_scheduler.end_thread(thd,0);		/* purecov: inspected */
   }
   DBUG_VOID_RETURN;				/* purecov: deadcode */
 }
 
 
-void end_thread(THD *thd, bool put_in_cache)
+/*
+  Unlink thd from global list of available connections and free thd
+
+  SYNOPSIS
+    unlink_thd()
+    thd		 Thread handler
+
+  NOTES
+    LOCK_thread_count is locked and left locked
+*/
+
+void unlink_thd(THD *thd)
 {
-  DBUG_ENTER("end_thread");
+  DBUG_ENTER("unlink_thd");
+  DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
   thd->cleanup();
   (void) pthread_mutex_lock(&LOCK_thread_count);
   thread_count--;
   delete thd;
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Store thread in cache for reuse by new connections
+
+  SYNOPSIS
+    cache_thread()
 
-  if (put_in_cache && cached_thread_count < thread_cache_size &&
+  NOTES
+    LOCK_thread_count has to be locked
+
+  RETURN
+    0  Thread was not put in cache
+    1  Thread is to be reused by new connection.
+       (ie, caller should return, not abort with pthread_exit())
+*/
+
+
+static bool cache_thread()
+{
+  safe_mutex_assert_owner(&LOCK_thread_count);
+  if (cached_thread_count < thread_cache_size &&
       ! abort_loop && !kill_cached_threads)
   {
     /* Don't kill the thread, just put it in cache for reuse */
     DBUG_PRINT("info", ("Adding thread to cache"))
-    cached_thread_count++;
+      cached_thread_count++;
     while (!abort_loop && ! wake_thread && ! kill_cached_threads)
       (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count);
     cached_thread_count--;
@@ -1685,31 +1735,55 @@
       pthread_cond_signal(&COND_flush_thread_cache);
     if (wake_thread)
     {
+      THD *thd; 
       wake_thread--;
-      thd=thread_cache.get();
-      thd->real_id=pthread_self();
+      thd= thread_cache.get();
       thd->thread_stack= (char*) &thd;          // For store_globals
       (void) thd->store_globals();
       thd->thr_create_time= time(NULL);
       threads.append(thd);
-      pthread_mutex_unlock(&LOCK_thread_count);
-      DBUG_VOID_RETURN;
+      return(1);
     }
   }
+  return(0);
+}
+
+
+/*
+  End thread for the current connection
+
+  SYNOPSIS
+    one_thread_per_connection_end()
+    thd		  Thread handler
+    put_in_cache  Store thread in cache, if there is room in it
+                  Normally this is true in all cases except when we got
+                  out of resources initializing the current thread
+
+  NOTES
+    If thread is cached, we will wait until thread is scheduled to be
+    reused and then we will return.
+    If thread is not cached, we end the thread.
+
+  RETURN
+    0    Signal to handle_one_connection to reuse connection
+*/
+
+bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
+{
+  DBUG_ENTER("one_thread_per_connection_end");
+  unlink_thd(thd);
+  if (put_in_cache)
+    put_in_cache= cache_thread();
+  pthread_mutex_unlock(&LOCK_thread_count);
+  if (put_in_cache)
+    DBUG_RETURN(0);                             // Thread is reused
 
-  /* Tell main we are ready */
-  (void) pthread_mutex_unlock(&LOCK_thread_count);
   /* It's safe to broadcast outside a lock (COND... is not deleted here) */
   DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
   (void) pthread_cond_broadcast(&COND_thread_count);
-#ifdef ONE_THREAD
-  if (!(test_flags & TEST_NO_THREADS))	// For debugging under Linux
-#endif
-  {
-    my_thread_end();
-    pthread_exit(0);
-  }
-  DBUG_VOID_RETURN;
+
+  my_thread_end();
+  pthread_exit(0);
 }
 
 
@@ -2086,10 +2160,10 @@
           (ulong) dflt_key_cache->key_cache_mem_size);
   fprintf(stderr, "read_buffer_size=%ld\n", (long)
global_system_variables.read_buff_size);
   fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
-  fprintf(stderr, "max_connections=%lu\n", max_connections);
+  fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads);
   fprintf(stderr, "threads_connected=%u\n", thread_count);
   fprintf(stderr, "It is possible that mysqld could use up to \n\
-key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %lu K\n\
+key_buffer_size + (read_buffer_size + sort_buffer_size)*thread_scheduler.max_threads =
%lu K\n\
 bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
 		     (global_system_variables.read_buff_size +
 		      global_system_variables.sortbuff_size) *
@@ -2294,7 +2368,7 @@
     This should actually be '+ max_number_of_slaves' instead of +10,
     but the +10 should be quite safe.
   */
-  init_thr_alarm(max_connections +
+  init_thr_alarm(thread_scheduler.max_threads +
 		 global_system_variables.max_insert_delayed_threads + 10);
 #if SIGINT != THR_KILL_SIGNAL
   if (test_flags & TEST_SIGINT)
@@ -2490,18 +2564,6 @@
 
 #ifdef __WIN__
 
-struct utsname
-{
-  char nodename[FN_REFLEN];
-};
-
-
-int uname(struct utsname *a)
-{
-  return -1;
-}
-
-
 pthread_handler_t handle_shutdown(void *arg)
 {
   MSG msg;
@@ -3850,7 +3912,7 @@
   my_net_init(&thd->net,(st_vio*) 0);
   thd->max_client_packet_length= thd->net.max_packet;
   thd->security_ctx->master_access= ~(ulong)0;
-  thd->thread_id=thread_id++;
+  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
   thread_count++;
 
   bootstrap_file=file;
@@ -3893,6 +3955,74 @@
 
 
 #ifndef EMBEDDED_LIBRARY
+
+/*
+   Simple scheduler that use the main thread to handle the request
+
+   NOTES
+     This is only used for debugging, when starting mysqld with
+     --thread-handling=no-threads or --one-thread
+
+     When we enter this function, LOCK_thread_count is hold!
+*/
+   
+void handle_connection_in_main_thread(THD *thd)
+{
+  safe_mutex_assert_owner(&LOCK_thread_count);
+  thread_cache_size=0;			// Safety
+  threads.append(thd);
+  (void) pthread_mutex_unlock(&LOCK_thread_count);
+  handle_one_connection((void*) thd);
+}
+
+
+/*
+  Scheduler that uses one thread per connection
+*/
+
+void create_thread_to_handle_connection(THD *thd)
+{
+  if (cached_thread_count > wake_thread)
+  {
+    /* Get thread from cache */
+    thread_cache.append(thd);
+    wake_thread++;
+    pthread_cond_signal(&COND_thread_cache);
+  }
+  else
+  {
+    /* Create new thread to handle connection */
+    int error;
+    thread_created++;
+    threads.append(thd);
+    DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
+    thd->connect_time = time(NULL);
+    if ((error=pthread_create(&thd->real_id,&connection_attrib,
+                              handle_one_connection,
+                              (void*) thd)))
+    {
+      /* purify: begin inspected */
+      DBUG_PRINT("error",
+                 ("Can't create thread to handle request (error %d)",
+                  error));
+      thread_count--;
+      thd->killed= THD::KILL_CONNECTION;			// Safety
+      (void) pthread_mutex_unlock(&LOCK_thread_count);
+      statistic_increment(aborted_connects,&LOCK_status);
+      net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
+      (void) pthread_mutex_lock(&LOCK_thread_count);
+      close_connection(thd,0,0);
+      delete thd;
+      (void) pthread_mutex_unlock(&LOCK_thread_count);
+      return;
+      /* purecov: end */
+    }
+  }
+  (void) pthread_mutex_unlock(&LOCK_thread_count);
+  DBUG_PRINT("info",("Thread created"));
+}
+
+
 /*
   Create new thread to handle incoming connection.
 
@@ -3914,9 +4044,9 @@
 
 static void create_new_thread(THD *thd)
 {
+  NET *net=&thd->net;				// For easy ref
   DBUG_ENTER("create_new_thread");
 
-  NET *net=&thd->net;				// For easy ref
   net->read_timeout = (uint) connect_timeout;
   if (protocol_version > 9)
     net->return_errno=1;
@@ -3930,64 +4060,15 @@
     DBUG_VOID_RETURN;
   }
   pthread_mutex_lock(&LOCK_thread_count);
-  thd->thread_id=thread_id++;
-
-  thd->real_id=pthread_self();			// Keep purify happy
+  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
 
   /* Start a new thread to handle connection */
   thread_count++;
 
-#ifdef ONE_THREAD
-  if (test_flags & TEST_NO_THREADS)		// For debugging under Linux
-  {
-    thread_cache_size=0;			// Safety
-    threads.append(thd);
-    thd->real_id=pthread_self();
-    (void) pthread_mutex_unlock(&LOCK_thread_count);
-    handle_one_connection((void*) thd);
-  }
-  else
-#endif
-  {
-    if (thread_count-delayed_insert_threads > max_used_connections)
-      max_used_connections=thread_count-delayed_insert_threads;
-
-    if (cached_thread_count > wake_thread)
-    {
-      thread_cache.append(thd);
-      wake_thread++;
-      pthread_cond_signal(&COND_thread_cache);
-    }
-    else
-    {
-      int error;
-      thread_created++;
-      threads.append(thd);
-      DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
-      thd->connect_time = time(NULL);
-      if ((error=pthread_create(&thd->real_id,&connection_attrib,
-				handle_one_connection,
-				(void*) thd)))
-      {
-	DBUG_PRINT("error",
-		   ("Can't create thread to handle request (error %d)",
-		    error));
-	thread_count--;
-	thd->killed= THD::KILL_CONNECTION;			// Safety
-	(void) pthread_mutex_unlock(&LOCK_thread_count);
-	statistic_increment(aborted_connects,&LOCK_status);
-	net_printf_error(thd, ER_CANT_CREATE_THREAD, error);
-	(void) pthread_mutex_lock(&LOCK_thread_count);
-	close_connection(thd,0,0);
-	delete thd;
-	(void) pthread_mutex_unlock(&LOCK_thread_count);
-	DBUG_VOID_RETURN;
-      }
-    }
-    (void) pthread_mutex_unlock(&LOCK_thread_count);
+  if (thread_count-delayed_insert_threads > max_used_connections)
+    max_used_connections=thread_count-delayed_insert_threads;
 
-  }
-  DBUG_PRINT("info",("Thread created"));
+  thread_scheduler.add_connection(thd);
   DBUG_VOID_RETURN;
 }
 #endif /* EMBEDDED_LIBRARY */
@@ -4726,6 +4807,7 @@
   OPT_TABLE_LOCK_WAIT_TIMEOUT,
   OPT_PORT_OPEN_TIMEOUT,
   OPT_MERGE,
+  OPT_THREAD_HANDLING,
   OPT_INNODB_ROLLBACK_ON_TIMEOUT
 };
 
@@ -5269,11 +5351,9 @@
    (gptr*) &global_system_variables.old_passwords,
    (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
    0, 0, 0, 0, 0, 0},
-#ifdef ONE_THREAD
   {"one-thread", OPT_ONE_THREAD,
-   "Only use one thread (for debugging under Linux).", 0, 0, 0, GET_NO_ARG,
-   NO_ARG, 0, 0, 0, 0, 0, 0},
-#endif
+   "(deprecated): Only use one thread (for debugging under Linux). Use
thread-handling=no-threads instead",
+   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
   {"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS,
    "Enable old-style user limits (before 5.0.3 user resources were counted per each
user+host vs. per account)",
    (gptr*) &opt_old_style_user_limits, (gptr*) &opt_old_style_user_limits,
@@ -5769,7 +5849,7 @@
     REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0},
   {"max_connections", OPT_MAX_CONNECTIONS,
    "The number of simultaneous clients allowed.", (gptr*) &max_connections,
-   (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 0, 1,
+   (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 50000, 0, 1,
    0},
   {"max_delayed_threads", OPT_MAX_DELAYED_THREADS,
    "Don't start more than this number of threads to handle INSERT DELAYED statements. If
set to zero, which means INSERT DELAYED is not used.",
@@ -6049,6 +6129,12 @@
    "Permits the application to give the threads system a hint for the desired number of
threads that should be run at the same time.",
    (gptr*) &concurrency, (gptr*) &concurrency, 0, GET_ULONG, REQUIRED_ARG,
    DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0},
+#ifdef HAVE_POOL_OF_THREADS
+  {"thread_pool_size", OPT_THREAD_CACHE_SIZE,
+   "How many threads we should create to handle query requests in case of
'thread_handling=pool-of-threads'",
+   (gptr*) &thread_pool_size, (gptr*) &thread_pool_size, 0, GET_ULONG,
+   REQUIRED_ARG, 20, 1, 16384, 0, 1, 0},
+#endif
   {"thread_stack", OPT_THREAD_STACK,
    "The stack size for each thread.", (gptr*) &thread_stack,
    (gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
@@ -6073,6 +6159,10 @@
    (gptr*) &global_system_variables.trans_prealloc_size,
    (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
    REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0},
+  {"thread_handling", OPT_THREAD_HANDLING,
+   "Define threads usage for handling queries:  "
+   "one-thread-per-connection, no-threads or pool-of-threads", 0, 0,
+   0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
   {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT,
    "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a
key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO =
Prohibit update of a VIEW, which does not contain a key of the underlying table and the
query uses a LIMIT clause (usually get from GUI tools).",
    (gptr*) &global_system_variables.updatable_views_with_limit,
@@ -6693,7 +6783,6 @@
     break;
   case 'T':
     test_flags= argument ? (uint) atoi(argument) : 0;
-    test_flags&= ~TEST_NO_THREADS;
     opt_endinfo=1;
     break;
   case (int) OPT_BIG_TABLES:
@@ -6878,11 +6967,6 @@
     opt_skip_show_db=1;
     opt_specialflag|=SPECIAL_SKIP_SHOW_DB;
     break;
-#ifdef ONE_THREAD
-  case (int) OPT_ONE_THREAD:
-    test_flags |= TEST_NO_THREADS;
-#endif
-    break;
   case (int) OPT_WANT_CORE:
     test_flags |= TEST_CORE_ON_SIGNAL;
     break;
@@ -7167,6 +7251,23 @@
 						   sql_mode);
     break;
   }
+  case OPT_ONE_THREAD:
+    global_system_variables.thread_handling= 2;
+    break;
+  case OPT_THREAD_HANDLING:
+  {
+    if ((global_system_variables.thread_handling=
+         find_type(argument, &thread_handling_typelib, 2)) <= 0 ||
+        (global_system_variables.thread_handling == SCHEDULER_POOL_OF_THREADS
+         && !HAVE_POOL_OF_THREADS))
+    {
+      /* purecov: begin tested */
+      fprintf(stderr,"Unknown/unsupported thread-handling: %s\n",argument);
+      exit(1);
+      /* purecov: end */
+    }
+    break;
+  }
   case OPT_FT_BOOLEAN_SYNTAX:
     if (ft_boolean_check_syntax_string((byte*) argument))
     {
@@ -7295,6 +7396,7 @@
   if (mysqld_chroot)
     set_root(mysqld_chroot);
 #else
+  global_system_variables.thread_handling = SCHEDULER_NO_THREADS;
   max_allowed_packet= global_system_variables.max_allowed_packet;
   net_buffer_length= global_system_variables.net_buffer_length;
 #endif
@@ -7324,6 +7426,17 @@
       init_global_datetime_format(MYSQL_TIMESTAMP_DATETIME,
 				  &global_system_variables.datetime_format))
     exit(1);
+#ifdef EMBEDDED_LIBRARY
+    one_thread_scheduler(&thread_scheduler);
+#else
+  if (global_system_variables.thread_handling <=
+      SCHEDULER_ONE_THREAD_PER_CONNECTION)
+    one_thread_per_connection_scheduler(&thread_scheduler);
+  else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)
+    one_thread_scheduler(&thread_scheduler);
+  else
+    pool_of_threads_scheduler(&thread_scheduler);  /* purecov: tested */
+#endif
 }
 
 

--- 1.290/sql/slave.cc	2007-01-22 14:10:40 +02:00
+++ 1.291/sql/slave.cc	2007-03-14 12:47:55 +02:00
@@ -2905,9 +2905,8 @@
   thd->slave_thread = 1;
   set_slave_thread_options(thd);
   thd->client_capabilities = CLIENT_LOCAL_FILES;
-  thd->real_id=pthread_self();
   pthread_mutex_lock(&LOCK_thread_count);
-  thd->thread_id = thread_id++;
+  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
   pthread_mutex_unlock(&LOCK_thread_count);
 
   if (init_thr_lock() || thd->store_globals())
@@ -2916,12 +2915,6 @@
     delete thd;
     DBUG_RETURN(-1);
   }
-
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
-  sigset_t set;
-  VOID(sigemptyset(&set));			// Get mask in use
-  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
 
   if (thd_type == SLAVE_THD_SQL)
     thd->proc_info= "Waiting for the next event in relay log";

--- 1.363/sql/sql_base.cc	2007-01-11 19:13:00 +02:00
+++ 1.364/sql/sql_base.cc	2007-03-14 12:47:55 +02:00
@@ -509,7 +509,6 @@
   if (!thd->active_transaction())
     thd->transaction.xid_state.xid.null();
 
-  /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
   if (!lock_in_use)
     VOID(pthread_mutex_lock(&LOCK_open));
   safe_mutex_assert_owner(&LOCK_open);
@@ -640,18 +639,21 @@
     return;
   }
 
-  TABLE *next,
-    *prev_table /* prev link is not maintained in TABLE's double-linked list */;
-  bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */
-  // Better add "if exists", in case a RESET MASTER has been done
+  TABLE *next;
+  /* prev link is not maintained in TABLE's double-linked list */
+  TABLE *prev_table;
+  /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */
+  bool was_quote_show= TRUE;
+  /* Better to use "IF EXISTS", in case a RESET MASTER has been done */
   const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
   uint stub_len= sizeof(stub) - 1;
   char buf[256];
-  memcpy(buf, stub, stub_len);
   String s_query= String(buf, sizeof(buf), system_charset_info);
-  bool found_user_tables= false;
+  bool found_user_tables= FALSE;
   LINT_INIT(next);
 
+  memcpy(buf, stub, stub_len);
+
   /*
      insertion sort of temp tables by pseudo_thread_id to build ordered list
      of sublists of equal pseudo_thread_id
@@ -701,10 +703,13 @@
   {
     if (is_user_table(table))
     {
+      my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
       /* Set pseudo_thread_id to be that of the processed table */
       thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
-      /* Loop forward through all tables within the sublist of
-         common pseudo_thread_id to create single DROP query */
+      /*
+        Loop forward through all tables within the sublist of
+        common pseudo_thread_id to create single DROP query.
+      */
       for (s_query.length(stub_len);
            table && is_user_table(table) &&
              tmpkeyval(thd, table) == thd->variables.pseudo_thread_id;
@@ -730,16 +735,18 @@
                             0, FALSE);
       thd->variables.character_set_client= cs_save;
       /*
-        Imagine the thread had created a temp table, then was doing a SELECT, and
-        the SELECT was killed. Then it's not clever to mark the statement above as
-        "killed", because it's not really a statement updating data, and there
-        are 99.99% chances it will succeed on slave.
-        If a real update (one updating a persistent table) was killed on the
-        master, then this real update will be logged with error_code=killed,
-        rightfully causing the slave to stop.
+        Imagine the thread had created a temp table, then was doing a
+        SELECT, and the SELECT was killed. Then it's not clever to
+        mark the statement above as "killed", because it's not really
+        a statement updating data, and there are 99.99% chances it
+        will succeed on slave.  If a real update (one updating a
+        persistent table) was killed on the master, then this real
+        update will be logged with error_code=killed, rightfully
+        causing the slave to stop.
       */
       qinfo.error_code= 0;
       mysql_bin_log.write(&qinfo);
+      thd->variables.pseudo_thread_id= save_pseudo_thread_id;
     }
     else
     {
@@ -939,6 +946,7 @@
   char	key[MAX_DBKEY_LENGTH];
   uint	key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
   TABLE *table,**prev;
+  DBUG_ENTER("find_temporary_table");
 
   int4store(key+key_length,thd->server_id);
   key_length += 4;
@@ -950,12 +958,19 @@
   {
     if (table->s->key_length == key_length &&
 	!memcmp(table->s->table_cache_key,key,key_length))
-      return prev;
+    {
+      DBUG_PRINT("info",
+                     ("Found table. server_id: %u  pseudo_thread_id: %lu",
+                      (uint) thd->server_id,
+                      (ulong) thd->variables.pseudo_thread_id));
+      DBUG_RETURN(prev);
+    }
     prev= &table->next;
   }
-  return 0;					// Not a temporary table
+  DBUG_RETURN(0);                               // Not a temporary table
 }
 
+
 bool close_temporary_table(THD *thd, const char *db, const char *table_name)
 {
   TABLE *table,**prev;
@@ -1221,6 +1236,10 @@
 	if (table->query_id == thd->query_id ||
             thd->prelocked_mode && table->query_id)
 	{
+          DBUG_PRINT("error",
+                     ("query_id: %lu  server_id: %u  pseudo_thread_id: %lu",
+                      (ulong) table->query_id, (uint) thd->server_id,
+                      (ulong) thd->variables.pseudo_thread_id));
 	  my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
 	  DBUG_RETURN(0);
 	}
@@ -1906,7 +1925,7 @@
                       (flags & OPEN_VIEW_NO_PARSE),
 		      thd->open_options, entry)) &&
       (error != 5 ||
-       (fn_format(path, path, 0, reg_ext, MY_UNPACK_FILENAME),
+       (fn_format(path, path, "", reg_ext, MY_UNPACK_FILENAME),
         open_new_frm(thd, path, alias, db, name,
                      (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
                              HA_GET_INDEX | HA_TRY_READ_ONLY),
@@ -2726,6 +2745,8 @@
   TABLE *tmp_table;
   TABLE_SHARE *share;
   DBUG_ENTER("open_temporary_table");
+  DBUG_PRINT("enter", ("server_id: %u  pseudo_thread_id: %lu",
+                       thd->server_id, thd->variables.pseudo_thread_id));
 
   /*
     The extra size in my_malloc() is for table_cache_key
@@ -3140,6 +3161,9 @@
 {
   Field *fld;
   DBUG_ENTER("find_field_in_table_ref");
+  DBUG_ASSERT(table_list->alias);
+  DBUG_ASSERT(name);
+  DBUG_ASSERT(item_name);
   DBUG_PRINT("enter",
              ("table: '%s'  field name: '%s'  item name: '%s'  ref 0x%lx",
               table_list->alias, name, item_name, (ulong) ref));

--- 1.258/sql/sql_class.cc	2007-01-22 14:10:40 +02:00
+++ 1.259/sql/sql_class.cc	2007-03-14 12:47:55 +02:00
@@ -209,7 +209,7 @@
   time_after_lock=(time_t) 0;
   current_linfo =  0;
   slave_thread = 0;
-  variables.pseudo_thread_id= 0;
+  thread_id= variables.pseudo_thread_id= 0;
   one_shot_set= 0;
   file_id = 0;
   query_id= 0;
@@ -230,9 +230,6 @@
   ull=0;
   system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
   peer_port= 0;					// For SHOW PROCESSLIST
-#ifdef	__WIN__
-  real_id = 0;
-#endif
 #ifdef SIGNAL_WITH_VIO_CLOSE
   active_vio = 0;
 #endif
@@ -366,6 +363,8 @@
 void THD::cleanup(void)
 {
   DBUG_ENTER("THD::cleanup");
+  DBUG_ASSERT(cleanup_done == 0);
+
 #ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
   if (transaction.xid_state.xa_state == XA_PREPARED)
   {
@@ -401,7 +400,6 @@
     pthread_mutex_lock(&LOCK_user_locks);
     item_user_lock_release(ull);
     pthread_mutex_unlock(&LOCK_user_locks);
-    ull= 0;
   }
 
   cleanup_done=1;
@@ -483,7 +481,9 @@
   killed= state_to_set;
   if (state_to_set != THD::KILL_QUERY)
   {
-    thr_alarm_kill(real_id);
+    thr_alarm_kill(thread_id);
+    if (!slave_thread)
+      thread_scheduler.post_kill_notification(this);
 #ifdef SIGNAL_WITH_VIO_CLOSE
     close_active_vio();
 #endif    
@@ -533,18 +533,19 @@
     Assert that thread_stack is initialized: it's necessary to be able
     to track stack overrun.
   */
-  DBUG_ASSERT(this->thread_stack);
+  DBUG_ASSERT(thread_stack);
 
   if (my_pthread_setspecific_ptr(THR_THD,  this) ||
       my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
     return 1;
   mysys_var=my_thread_var;
-  dbug_thread_id=my_thread_id();
   /*
-    By default 'slave_proxy_id' is 'thread_id'. They may later become different
-    if this is the slave SQL thread.
+    Let mysqld define the thread id (not mysys)
+    This allows us to move THD to different threads if needed.
   */
-  variables.pseudo_thread_id= thread_id;
+  mysys_var->id= thread_id;
+  real_id= pthread_self();                      // For debugging
+
   /*
     We have to call thr_lock_info_init() again here as THD may have been
     created in another thread

--- 1.319/sql/sql_class.h	2007-01-22 14:10:41 +02:00
+++ 1.320/sql/sql_class.h	2007-03-14 12:47:55 +02:00
@@ -527,6 +527,7 @@
   ulong div_precincrement;
   ulong sortbuff_size;
   ulong table_type;
+  ulong thread_handling;
   ulong tx_isolation;
   ulong completion_type;
   /* Determines which non-standard SQL behaviour should be enabled */
@@ -547,7 +548,7 @@
     In slave thread we need to know in behalf of which
     thread the query is being run to replicate temp tables properly
   */
-  ulong pseudo_thread_id;
+  my_thread_id pseudo_thread_id;
 
   my_bool low_priority_updates;
   my_bool new_mode;
@@ -1228,7 +1229,7 @@
   } transaction;
   Field      *dupp_field;
 #ifndef __WIN__
-  sigset_t signals,block_signals;
+  sigset_t signals;
 #endif
 #ifdef SIGNAL_WITH_VIO_CLOSE
   Vio* active_vio;
@@ -1317,14 +1318,15 @@
     update auto-updatable fields (like auto_increment and timestamp).
   */
   query_id_t query_id, warn_id;
-  ulong      thread_id, col_access;
+  ulong         col_access;
 
   /* Statement id is thread-wide. This counter is used to generate ids */
   ulong      statement_id_counter;
   ulong	     rand_saved_seed1, rand_saved_seed2;
   ulong      row_count;  // Row counter, mainly for errors and warnings
-  long	     dbug_thread_id;
-  pthread_t  real_id;
+
+  pthread_t  real_id;                           /* For debugging */
+  my_thread_id  thread_id;
   uint	     tmp_table, global_read_lock;
   uint	     server_status,open_options,system_thread;
   uint       db_length;
@@ -1659,6 +1661,7 @@
       *p_db_length= db_length;
     return FALSE;
   }
+  thd_scheduler scheduler;
 };
 
 

--- 1.213/sql/sql_insert.cc	2007-01-22 14:10:41 +02:00
+++ 1.214/sql/sql_insert.cc	2007-03-14 12:47:55 +02:00
@@ -1777,7 +1777,7 @@
   pthread_detach_this_thread();
   /* Add thread to THD list so that's it's visible in 'show processlist' */
   pthread_mutex_lock(&LOCK_thread_count);
-  thd->thread_id=thread_id++;
+  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
   thd->end_time();
   threads.append(thd);
   thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED;
@@ -1808,14 +1808,8 @@
     strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
     goto end;
   }
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
-  sigset_t set;
-  VOID(sigemptyset(&set));			// Get mask in use
-  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
 
   /* open table */
-
   if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED)))
   {
     thd->fatal_error();				// Abort waiting inserts

--- 1.603/sql/sql_parse.cc	2007-01-22 14:10:41 +02:00
+++ 1.604/sql/sql_parse.cc	2007-03-14 12:47:55 +02:00
@@ -33,23 +33,6 @@
 #include "sp.h"
 #include "sp_cache.h"
 
-#ifdef HAVE_OPENSSL
-/*
-  Without SSL the handshake consists of one packet. This packet
-  has both client capabilites and scrambled password.
-  With SSL the handshake might consist of two packets. If the first
-  packet (client capabilities) has CLIENT_SSL flag set, we have to
-  switch to SSL and read the second packet. The scrambled password
-  is in the second packet and client_capabilites field will be ignored.
-  Maybe it is better to accept flags other than CLIENT_SSL from the
-  second packet?
-*/
-#define SSL_HANDSHAKE_SIZE      2
-#define NORMAL_HANDSHAKE_SIZE   6
-#define MIN_HANDSHAKE_SIZE      2
-#else
-#define MIN_HANDSHAKE_SIZE      6
-#endif /* HAVE_OPENSSL */
 
 /* Used in error handling only */
 #define SP_TYPE_STRING(LP) \
@@ -61,15 +44,6 @@
    (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
    "FUNCTION" : "PROCEDURE")
 
-#ifdef SOLARIS
-extern "C" int gethostname(char *name, int namelen);
-#endif
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
-static void decrease_user_connections(USER_CONN *uc);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
 static bool check_db_used(THD *thd,TABLE_LIST *tables);
 static void remove_escape(char *name);
 static bool append_file_to_dir(THD *thd, const char **filename_ptr,
@@ -91,24 +65,6 @@
   "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
 };
 
-#ifdef __WIN__
-static void  test_signal(int sig_ptr)
-{
-#if !defined( DBUG_OFF)
-  MessageBox(NULL,"Test signal","DBUG",MB_OK);
-#endif
-#if defined(OS2)
-  fprintf(stderr, "Test signal %d\n", sig_ptr);
-  fflush(stderr);
-#endif
-}
-static void init_signals(void)
-{
-  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
-  for (int i=0 ; i < 7 ; i++)
-    signal( signals[i], test_signal) ;
-}
-#endif
 
 static void unlock_locked_tables(THD *thd)
 {
@@ -151,6 +107,7 @@
   DBUG_RETURN(error);
 }
 
+
 static bool begin_trans(THD *thd)
 {
   int error=0;
@@ -202,409 +159,6 @@
   return 0;
 }
 
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-static HASH hash_user_connections;
-
-static int get_or_create_user_conn(THD *thd, const char *user,
-				   const char *host,
-				   USER_RESOURCES *mqh)
-{
-  int return_val= 0;
-  uint temp_len, user_len;
-  char temp_user[USER_HOST_BUFF_SIZE];
-  struct  user_conn *uc;
-
-  DBUG_ASSERT(user != 0);
-  DBUG_ASSERT(host != 0);
-
-  user_len= strlen(user);
-  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
-  (void) pthread_mutex_lock(&LOCK_user_conn);
-  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
-					       (byte*) temp_user, temp_len)))
-  {
-    /* First connection for user; Create a user connection object */
-    if (!(uc= ((struct user_conn*)
-	       my_malloc(sizeof(struct user_conn) + temp_len+1,
-			 MYF(MY_WME)))))
-    {
-      net_send_error(thd, 0, NullS);		// Out of memory
-      return_val= 1;
-      goto end;
-    }
-    uc->user=(char*) (uc+1);
-    memcpy(uc->user,temp_user,temp_len+1);
-    uc->host= uc->user + user_len +  1;
-    uc->len= temp_len;
-    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
-    uc->user_resources= *mqh;
-    uc->intime= thd->thr_create_time;
-    if (my_hash_insert(&hash_user_connections, (byte*) uc))
-    {
-      my_free((char*) uc,0);
-      net_send_error(thd, 0, NullS);		// Out of memory
-      return_val= 1;
-      goto end;
-    }
-  }
-  thd->user_connect=uc;
-  uc->connections++;
-end:
-  (void) pthread_mutex_unlock(&LOCK_user_conn);
-  return return_val;
-
-}
-#endif /* !NO_EMBEDDED_ACCESS_CHECKS */
-
-
-/*
-  Check if user exist and password supplied is correct. 
-
-  SYNOPSIS
-    check_user()
-    thd          thread handle, thd->security_ctx->{host,user,ip} are used
-    command      originator of the check: now check_user is called
-                 during connect and change user procedures; used for 
-                 logging.
-    passwd       scrambled password received from client
-    passwd_len   length of scrambled password
-    db           database name to connect to, may be NULL
-    check_count  dont know exactly
-
-    Note, that host, user and passwd may point to communication buffer.
-    Current implementation does not depend on that, but future changes
-    should be done with this in mind; 'thd' is INOUT, all other params
-    are 'IN'.
-
-  RETURN VALUE
-    0  OK; thd->security_ctx->user/master_access/priv_user/db_access and
-       thd->db are updated; OK is sent to client;
-   -1  access denied or handshake error; error is sent to client;
-   >0  error, not sent to client
-*/
-
-int check_user(THD *thd, enum enum_server_command command, 
-	       const char *passwd, uint passwd_len, const char *db,
-	       bool check_count)
-{
-  DBUG_ENTER("check_user");
-  
-#ifdef NO_EMBEDDED_ACCESS_CHECKS
-  thd->main_security_ctx.master_access= GLOBAL_ACLS;       // Full rights
-  /* Change database if necessary */
-  if (db && db[0])
-  {
-    /*
-      thd->db is saved in caller and needs to be freed by caller if this
-      function returns 0
-    */
-    thd->reset_db(NULL, 0);
-    if (mysql_change_db(thd, db, FALSE))
-    {
-      /* Send the error to the client */
-      net_send_error(thd);
-      DBUG_RETURN(-1);
-    }
-  }
-  send_ok(thd);
-  DBUG_RETURN(0);
-#else
-
-  my_bool opt_secure_auth_local;
-  pthread_mutex_lock(&LOCK_global_system_variables);
-  opt_secure_auth_local= opt_secure_auth;
-  pthread_mutex_unlock(&LOCK_global_system_variables);
-  
-  /*
-    If the server is running in secure auth mode, short scrambles are 
-    forbidden.
-  */
-  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
-  {
-    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
-    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
-    DBUG_RETURN(-1);
-  }
-  if (passwd_len != 0 &&
-      passwd_len != SCRAMBLE_LENGTH &&
-      passwd_len != SCRAMBLE_LENGTH_323)
-    DBUG_RETURN(ER_HANDSHAKE_ERROR);
-
-  /*
-    Clear thd->db as it points to something, that will be freed when 
-    connection is closed. We don't want to accidentally free a wrong pointer
-    if connect failed. Also in case of 'CHANGE USER' failure, current
-    database will be switched to 'no database selected'.
-  */
-  thd->reset_db(NULL, 0);
-
-  USER_RESOURCES ur;
-  int res= acl_getroot(thd, &ur, passwd, passwd_len);
-#ifndef EMBEDDED_LIBRARY
-  if (res == -1)
-  {
-    /*
-      This happens when client (new) sends password scrambled with
-      scramble(), but database holds old value (scrambled with
-      scramble_323()). Here we please client to send scrambled_password
-      in old format.
-    */
-    NET *net= &thd->net;
-    if (opt_secure_auth_local)
-    {
-      net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
-                       thd->main_security_ctx.user,
-                       thd->main_security_ctx.host_or_ip);
-      mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
-                      thd->main_security_ctx.user,
-                      thd->main_security_ctx.host_or_ip);
-      DBUG_RETURN(-1);
-    }
-    /* We have to read very specific packet size */
-    if (send_old_password_request(thd) ||
-        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
-    {
-      inc_host_errors(&thd->remote.sin_addr);
-      DBUG_RETURN(ER_HANDSHAKE_ERROR);
-    }
-    /* Final attempt to check the user based on reply */
-    /* So as passwd is short, errcode is always >= 0 */
-    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
-  }
-#endif /*EMBEDDED_LIBRARY*/
-  /* here res is always >= 0 */
-  if (res == 0)
-  {
-    if (!(thd->main_security_ctx.master_access &
-          NO_ACCESS)) // authentication is OK
-    {
-      DBUG_PRINT("info",
-                 ("Capabilities: %lu  packet_length: %ld  Host: '%s'  "
-                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
-                  "Access: %lu  db: '%s'",
-                  thd->client_capabilities,
-                  thd->max_client_packet_length,
-                  thd->main_security_ctx.host_or_ip,
-                  thd->main_security_ctx.user,
-                  thd->main_security_ctx.priv_user,
-                  passwd_len ? "yes": "no",
-                  thd->main_security_ctx.master_access,
-                  (thd->db ? thd->db : "*none*")));
-
-      if (check_count)
-      {
-        VOID(pthread_mutex_lock(&LOCK_thread_count));
-        bool count_ok= thread_count <= max_connections + delayed_insert_threads
-                       || (thd->main_security_ctx.master_access & SUPER_ACL);
-        VOID(pthread_mutex_unlock(&LOCK_thread_count));
-        if (!count_ok)
-        {                                         // too many connections
-          net_send_error(thd, ER_CON_COUNT_ERROR);
-          DBUG_RETURN(-1);
-        }
-      }
-
-      /* Why logging is performed before all checks've passed? */
-      mysql_log.write(thd, command,
-                      (thd->main_security_ctx.priv_user ==
-                       thd->main_security_ctx.user ?
-                       (char*) "%s@%s on %s" :
-                       (char*) "%s@%s as anonymous on %s"),
-                      thd->main_security_ctx.user,
-                      thd->main_security_ctx.host_or_ip,
-                      db ? db : (char*) "");
-
-      /*
-        This is the default access rights for the current database.  It's
-        set to 0 here because we don't have an active database yet (and we
-        may not have an active database to set.
-      */
-      thd->main_security_ctx.db_access=0;
-
-      /* Don't allow user to connect if he has done too many queries */
-      if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
-	   max_user_connections) &&
-	  get_or_create_user_conn(thd,
-            (opt_old_style_user_limits ? thd->main_security_ctx.user :
-             thd->main_security_ctx.priv_user),
-            (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
-             thd->main_security_ctx.priv_host),
-            &ur))
-	DBUG_RETURN(-1);
-      if (thd->user_connect &&
-	  (thd->user_connect->user_resources.conn_per_hour ||
-	   thd->user_connect->user_resources.user_conn ||
-	   max_user_connections) &&
-	  check_for_max_user_connections(thd, thd->user_connect))
-	DBUG_RETURN(-1);
-
-      /* Change database if necessary */
-      if (db && db[0])
-      {
-        if (mysql_change_db(thd, db, FALSE))
-        {
-          /* Send error to the client */
-          net_send_error(thd);
-          if (thd->user_connect)
-            decrease_user_connections(thd->user_connect);
-          DBUG_RETURN(-1);
-        }
-      }
-      send_ok(thd);
-      thd->password= test(passwd_len);          // remember for error messages 
-      /* Ready to handle queries */
-      DBUG_RETURN(0);
-    }
-  }
-  else if (res == 2) // client gave short hash, server has long hash
-  {
-    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
-    mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
-    DBUG_RETURN(-1);
-  }
-  net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
-                   thd->main_security_ctx.user,
-                   thd->main_security_ctx.host_or_ip,
-                   passwd_len ? ER(ER_YES) : ER(ER_NO));
-  mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
-                  thd->main_security_ctx.user,
-                  thd->main_security_ctx.host_or_ip,
-                  passwd_len ? ER(ER_YES) : ER(ER_NO));
-  DBUG_RETURN(-1);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-/*
-  Check for maximum allowable user connections, if the mysqld server is
-  started with corresponding variable that is greater then 0.
-*/
-
-extern "C" byte *get_key_conn(user_conn *buff, uint *length,
-			      my_bool not_used __attribute__((unused)))
-{
-  *length=buff->len;
-  return (byte*) buff->user;
-}
-
-extern "C" void free_user(struct user_conn *uc)
-{
-  my_free((char*) uc,MYF(0));
-}
-
-void init_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
-		   0,0,
-		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
-		   0);
-#endif
-}
-
-
-/*
-  check if user has already too many connections
-  
-  SYNOPSIS
-  check_for_max_user_connections()
-  thd			Thread handle
-  uc			User connect object
-
-  NOTES
-    If check fails, we decrease user connection count, which means one
-    shouldn't call decrease_user_connections() after this function.
-
-  RETURN
-    0	ok
-    1	error
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
-{
-  int error=0;
-  DBUG_ENTER("check_for_max_user_connections");
-
-  (void) pthread_mutex_lock(&LOCK_user_conn);
-  if (max_user_connections && !uc->user_resources.user_conn &&
-      max_user_connections < (uint) uc->connections)
-  {
-    net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
-    error=1;
-    goto end;
-  }
-  time_out_user_resource_limits(thd, uc);
-  if (uc->user_resources.user_conn &&
-      uc->user_resources.user_conn < uc->connections)
-  {
-    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
-                     "max_user_connections",
-                     (long) uc->user_resources.user_conn);
-    error= 1;
-    goto end;
-  }
-  if (uc->user_resources.conn_per_hour &&
-      uc->user_resources.conn_per_hour <= uc->conn_per_hour)
-  {
-    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
-                     "max_connections_per_hour",
-                     (long) uc->user_resources.conn_per_hour);
-    error=1;
-    goto end;
-  }
-  uc->conn_per_hour++;
-
-  end:
-  if (error)
-    uc->connections--; // no need for decrease_user_connections() here
-  (void) pthread_mutex_unlock(&LOCK_user_conn);
-  DBUG_RETURN(error);
-}
-
-/*
-  Decrease user connection count
-
-  SYNOPSIS
-    decrease_user_connections()
-    uc			User connection object
-
-  NOTES
-    If there is a n user connection object for a connection
-    (which only happens if 'max_user_connections' is defined or
-    if someone has created a resource grant for a user), then
-    the connection count is always incremented on connect.
-
-    The user connect object is not freed if some users has
-    'max connections per hour' defined as we need to be able to hold
-    count over the lifetime of the connection.
-*/
-
-static void decrease_user_connections(USER_CONN *uc)
-{
-  DBUG_ENTER("decrease_user_connections");
-  (void) pthread_mutex_lock(&LOCK_user_conn);
-  DBUG_ASSERT(uc->connections);
-  if (!--uc->connections && !mqh_used)
-  {
-    /* Last connection for user; Delete it */
-    (void) hash_delete(&hash_user_connections,(byte*) uc);
-  }
-  (void) pthread_mutex_unlock(&LOCK_user_conn);
-  DBUG_VOID_RETURN;
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-
-void free_max_user_conn(void)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-  hash_free(&hash_user_connections);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-
 
 /*
   Mark all commands that somehow changes a table
@@ -620,7 +174,7 @@
           a number of modified rows
 */
 
-char  uc_update_queries[SQLCOM_END+1];
+uint8 uc_update_queries[SQLCOM_END+1];
 
 void init_update_queries(void)
 {
@@ -656,399 +210,6 @@
   return uc_update_queries[command] != 0;
 }
 
-/*
-  Reset per-hour user resource limits when it has been more than
-  an hour since they were last checked
-
-  SYNOPSIS:
-    time_out_user_resource_limits()
-    thd			Thread handler
-    uc			User connection details
-
-  NOTE:
-    This assumes that the LOCK_user_conn mutex has been acquired, so it is
-    safe to test and modify members of the USER_CONN structure.
-*/
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
-static void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
-{
-  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
-  DBUG_ENTER("time_out_user_resource_limits");
-
-  /* If more than a hour since last check, reset resource checking */
-  if (check_time  - uc->intime >= 3600)
-  {
-    uc->questions=1;
-    uc->updates=0;
-    uc->conn_per_hour=0;
-    uc->intime=check_time;
-  }
-
-  DBUG_VOID_RETURN;
-}
-
-/*
-  Check if maximum queries per hour limit has been reached
-  returns 0 if OK.
-*/
-
-static bool check_mqh(THD *thd, uint check_command)
-{
-  bool error= 0;
-  USER_CONN *uc=thd->user_connect;
-  DBUG_ENTER("check_mqh");
-  DBUG_ASSERT(uc != 0);
-
-  (void) pthread_mutex_lock(&LOCK_user_conn);
-
-  time_out_user_resource_limits(thd, uc);
-
-  /* Check that we have not done too many questions / hour */
-  if (uc->user_resources.questions &&
-      uc->questions++ >= uc->user_resources.questions)
-  {
-    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
-                     (long) uc->user_resources.questions);
-    error=1;
-    goto end;
-  }
-  if (check_command < (uint) SQLCOM_END)
-  {
-    /* Check that we have not done too many updates / hour */
-    if (uc->user_resources.updates && uc_update_queries[check_command]
&&
-	uc->updates++ >= uc->user_resources.updates)
-    {
-      net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
-                       (long) uc->user_resources.updates);
-      error=1;
-      goto end;
-    }
-  }
-end:
-  (void) pthread_mutex_unlock(&LOCK_user_conn);
-  DBUG_RETURN(error);
-}
-
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-
-
-static void reset_mqh(LEX_USER *lu, bool get_them= 0)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-  (void) pthread_mutex_lock(&LOCK_user_conn);
-  if (lu)  // for GRANT
-  {
-    USER_CONN *uc;
-    uint temp_len=lu->user.length+lu->host.length+2;
-    char temp_user[USER_HOST_BUFF_SIZE];
-
-    memcpy(temp_user,lu->user.str,lu->user.length);
-    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
-    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
-    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
-						(byte*) temp_user, temp_len)))
-    {
-      uc->questions=0;
-      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
-      uc->updates=0;
-      uc->conn_per_hour=0;
-    }
-  }
-  else
-  {
-    /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
-    for (uint idx=0;idx < hash_user_connections.records; idx++)
-    {
-      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
-						      idx);
-      if (get_them)
-	get_mqh(uc->user,uc->host,uc);
-      uc->questions=0;
-      uc->updates=0;
-      uc->conn_per_hour=0;
-    }
-  }
-  (void) pthread_mutex_unlock(&LOCK_user_conn);
-#endif /* NO_EMBEDDED_ACCESS_CHECKS */
-}
-
-void thd_init_client_charset(THD *thd, uint cs_number)
-{
-  /*
-   Use server character set and collation if
-   - opt_character_set_client_handshake is not set
-   - client has not specified a character set
-   - client character set is the same as the servers
-   - client character set doesn't exists in server
-  */
-  if (!opt_character_set_client_handshake ||
-      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
-      !my_strcasecmp(&my_charset_latin1,
-                     global_system_variables.character_set_client->name,
-                     thd->variables.character_set_client->name))
-  {
-    thd->variables.character_set_client=
-      global_system_variables.character_set_client;
-    thd->variables.collation_connection=
-      global_system_variables.collation_connection;
-    thd->variables.character_set_results=
-      global_system_variables.character_set_results;
-  }
-  else
-  {
-    thd->variables.character_set_results=
-      thd->variables.collation_connection= 
-      thd->variables.character_set_client;
-  }
-}
-
-
-/*
-    Perform handshake, authorize client and update thd ACL variables.
-  SYNOPSIS
-    check_connection()
-    thd  thread handle
-
-  RETURN
-     0  success, OK is sent to user, thd is updated.
-    -1  error, which is sent to user
-   > 0  error code (not sent to user)
-*/
-
-#ifndef EMBEDDED_LIBRARY
-static int check_connection(THD *thd)
-{
-  uint connect_errors= 0;
-  NET *net= &thd->net;
-  ulong pkt_len= 0;
-  char *end;
-
-  DBUG_PRINT("info",
-             ("New connection received on %s", vio_description(net->vio)));
-#ifdef SIGNAL_WITH_VIO_CLOSE
-  thd->set_active_vio(net->vio);
-#endif
-
-  if (!thd->main_security_ctx.host)         // If TCP/IP connection
-  {
-    char ip[30];
-
-    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
-      return (ER_BAD_HOST_ERROR);
-    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
-      return (ER_OUT_OF_RESOURCES);
-    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
-    vio_in_addr(net->vio,&thd->remote.sin_addr);
-    if (!(specialflag & SPECIAL_NO_RESOLVE))
-    {
-      vio_in_addr(net->vio,&thd->remote.sin_addr);
-      thd->main_security_ctx.host=
-        ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
-      /* Cut very long hostnames to avoid possible overflows */
-      if (thd->main_security_ctx.host)
-      {
-        if (thd->main_security_ctx.host != my_localhost)
-          thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
-                                          HOSTNAME_LENGTH)]= 0;
-        thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
-      }
-      if (connect_errors > max_connect_errors)
-        return(ER_HOST_IS_BLOCKED);
-    }
-    DBUG_PRINT("info",("Host: %s  ip: %s",
-		       (thd->main_security_ctx.host ?
-                        thd->main_security_ctx.host : "unknown host"),
-		       (thd->main_security_ctx.ip ?
-                        thd->main_security_ctx.ip : "unknown ip")));
-    if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
-      return(ER_HOST_NOT_PRIVILEGED);
-  }
-  else /* Hostname given means that the connection was on a socket */
-  {
-    DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
-    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
-    thd->main_security_ctx.ip= 0;
-    /* Reset sin_addr */
-    bzero((char*) &thd->remote, sizeof(thd->remote));
-  }
-  vio_keepalive(net->vio, TRUE);
-  {
-    /* buff[] needs to big enough to hold the server_version variable */
-    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
-    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
-			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
-
-    if (opt_using_transactions)
-      client_flags|=CLIENT_TRANSACTIONS;
-#ifdef HAVE_COMPRESS
-    client_flags |= CLIENT_COMPRESS;
-#endif /* HAVE_COMPRESS */
-#ifdef HAVE_OPENSSL
-    if (ssl_acceptor_fd)
-      client_flags |= CLIENT_SSL;       /* Wow, SSL is available! */
-#endif /* HAVE_OPENSSL */
-
-    end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
-    int4store((uchar*) end, thd->thread_id);
-    end+= 4;
-    /*
-      So as check_connection is the only entry point to authorization
-      procedure, scramble is set here. This gives us new scramble for
-      each handshake.
-    */
-    create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
-    /*
-      Old clients does not understand long scrambles, but can ignore packet
-      tail: that's why first part of the scramble is placed here, and second
-      part at the end of packet.
-    */
-    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
-   
-    int2store(end, client_flags);
-    /* write server characteristics: up to 16 bytes allowed */
-    end[2]=(char) default_charset_info->number;
-    int2store(end+3, thd->server_status);
-    bzero(end+5, 13);
-    end+= 18;
-    /* write scramble tail */
-    end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, 
-                 SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
-
-    /* At this point we write connection message and read reply */
-    if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
-			  (uint) (end-buff)) ||
-	(pkt_len= my_net_read(net)) == packet_error ||
-	pkt_len < MIN_HANDSHAKE_SIZE)
-    {
-      inc_host_errors(&thd->remote.sin_addr);
-      return(ER_HANDSHAKE_ERROR);
-    }
-  }
-#ifdef _CUSTOMCONFIG_
-#include "_cust_sql_parse.h"
-#endif
-  if (connect_errors)
-    reset_host_errors(&thd->remote.sin_addr);
-  if (thd->packet.alloc(thd->variables.net_buffer_length))
-    return(ER_OUT_OF_RESOURCES);
-
-  thd->client_capabilities=uint2korr(net->read_pos);
-  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
-  {
-    thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
-    thd->max_client_packet_length= uint4korr(net->read_pos+4);
-    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
-    thd_init_client_charset(thd, (uint) net->read_pos[8]);
-    thd->update_charset();
-    end= (char*) net->read_pos+32;
-  }
-  else
-  {
-    thd->max_client_packet_length= uint3korr(net->read_pos+2);
-    end= (char*) net->read_pos+5;
-  }
-
-  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
-    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-#ifdef HAVE_OPENSSL
-  DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
-  if (thd->client_capabilities & CLIENT_SSL)
-  {
-    /* Do the SSL layering. */
-    if (!ssl_acceptor_fd)
-    {
-      inc_host_errors(&thd->remote.sin_addr);
-      return(ER_HANDSHAKE_ERROR);
-    }
-    DBUG_PRINT("info", ("IO layer change in progress..."));
-    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
-    {
-      DBUG_PRINT("error", ("Failed to accept new SSL connection"));
-      inc_host_errors(&thd->remote.sin_addr);
-      return(ER_HANDSHAKE_ERROR);
-    }
-    DBUG_PRINT("info", ("Reading user information over SSL layer"));
-    if ((pkt_len= my_net_read(net)) == packet_error ||
-	pkt_len < NORMAL_HANDSHAKE_SIZE)
-    {
-      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
-			   pkt_len));
-      inc_host_errors(&thd->remote.sin_addr);
-      return(ER_HANDSHAKE_ERROR);
-    }
-  }
-#endif
-
-  if (end >= (char*) net->read_pos+ pkt_len +2)
-  {
-    inc_host_errors(&thd->remote.sin_addr);
-    return(ER_HANDSHAKE_ERROR);
-  }
-
-  if (thd->client_capabilities & CLIENT_INTERACTIVE)
-    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
-  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
-      opt_using_transactions)
-    net->return_status= &thd->server_status;
-  net->read_timeout=(uint) thd->variables.net_read_timeout;
-
-  char *user= end;
-  char *passwd= strend(user)+1;
-  uint user_len= passwd - user - 1;
-  char *db= passwd;
-  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
-  char user_buff[USERNAME_LENGTH + 1];	// buffer to store user in utf8
-  uint dummy_errors;
-
-  /*
-    Old clients send null-terminated string as password; new clients send
-    the size (1 byte) + string (not null-terminated). Hence in case of empty
-    password both send '\0'.
-  */
-  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
-    *passwd++ : strlen(passwd);
-  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
-    db + passwd_len + 1 : 0;
-  uint db_len= db ? strlen(db) : 0;
-
-  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
-  {
-    inc_host_errors(&thd->remote.sin_addr);
-    return ER_HANDSHAKE_ERROR;
-  }
-
-  /* Since 4.1 all database names are stored in utf8 */
-  if (db)
-  {
-    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
-                             system_charset_info,
-                             db, db_len,
-                             thd->charset(), &dummy_errors)]= 0;
-    db= db_buff;
-  }
-
-  user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
-                                       system_charset_info, user, user_len,
-                                       thd->charset(), &dummy_errors)]= '\0';
-  user= user_buff;
-
-  /* If username starts and ends in "'", chop them off */
-  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
-  {
-    user[user_len-1]= 0;
-    user++;
-    user_len-= 2;
-  }
-
-  if (thd->main_security_ctx.user)
-    x_free(thd->main_security_ctx.user);
-  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
-    return (ER_OUT_OF_RESOURCES);
-  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
-}
-
 
 void execute_init_command(THD *thd, sys_var_str *init_command_var,
 			  rw_lock_t *var_mutex)
@@ -1081,145 +242,6 @@
 }
 
 
-pthread_handler_t handle_one_connection(void *arg)
-{
-  THD *thd=(THD*) arg;
-  uint launch_time  =
-    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);
-  if (launch_time >= slow_launch_time)
-    statistic_increment(slow_launch_threads,&LOCK_status );
-
-  pthread_detach_this_thread();
-
-#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
-  /* The following calls needs to be done before we call DBUG_ macros */
-  if (!(test_flags & TEST_NO_THREADS) & my_thread_init())
-  {
-    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
-    statistic_increment(aborted_connects,&LOCK_status);
-    end_thread(thd,0);
-    return 0;
-  }
-#endif
-
-  /*
-    handle_one_connection() is the only way a thread would start
-    and would always be on top of the stack, therefore, the thread
-    stack always starts at the address of the first local variable
-    of handle_one_connection, which is thd. We need to know the
-    start of the stack so that we could check for stack overruns.
-  */
-  DBUG_PRINT("info", ("handle_one_connection called by thread %lu\n",
-		      thd->thread_id));
-  /* now that we've called my_thread_init(), it is safe to call DBUG_* */
-
-#if defined(__WIN__)
-  init_signals();
-#elif !defined(OS2) && !defined(__NETWARE__)
-  sigset_t set;
-  VOID(sigemptyset(&set));			// Get mask in use
-  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-  thd->thread_stack= (char*) &thd;
-  if (thd->store_globals())
-  {
-    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
-    statistic_increment(aborted_connects,&LOCK_status);
-    end_thread(thd,0);
-    return 0;
-  }
-
-  do
-  {
-    int error;
-    NET *net= &thd->net;
-    Security_context *sctx= thd->security_ctx;
-    net->no_send_error= 0;
-
-    if ((error=check_connection(thd)))
-    {						// Wrong permissions
-      if (error > 0)
-	net_printf_error(thd, error, sctx->host_or_ip);
-#ifdef __NT__
-      if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
-	my_sleep(1000);				/* must wait after eof() */
-#endif
-      statistic_increment(aborted_connects,&LOCK_status);
-      goto end_thread;
-    }
-#ifdef __NETWARE__
-    netware_reg_user(sctx->ip, sctx->user, "MySQL");
-#endif
-    if (thd->variables.max_join_size == HA_POS_ERROR)
-      thd->options |= OPTION_BIG_SELECTS;
-    if (thd->client_capabilities & CLIENT_COMPRESS)
-      net->compress=1;				// Use compression
-
-    thd->version= refresh_version;
-    thd->proc_info= 0;
-    thd->command= COM_SLEEP;
-    thd->set_time();
-    thd->init_for_queries();
-
-    if (sys_init_connect.value_length && !(sctx->master_access &
SUPER_ACL))
-    {
-      execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
-      if (thd->query_error)
-      {
-	thd->killed= THD::KILL_CONNECTION;
-        sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
-                          thd->thread_id,(thd->db ? thd->db : "unconnected"),
-                          sctx->user ? sctx->user : "unauthenticated",
-                          sctx->host_or_ip, "init_connect command failed");
-        sql_print_warning("%s", net->last_error);
-      }
-      thd->proc_info=0;
-      thd->set_time();
-      thd->init_for_queries();
-    }
-
-    while (!net->error && net->vio != 0 &&
-           !(thd->killed == THD::KILL_CONNECTION))
-    {
-      net->no_send_error= 0;
-      if (do_command(thd))
-	break;
-    }
-    if (thd->user_connect)
-      decrease_user_connections(thd->user_connect);
-    if (net->error && net->vio != 0 && net->report_error)
-    {
-      if (!thd->killed && thd->variables.log_warnings > 1)
-	sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
-                          thd->thread_id,(thd->db ? thd->db : "unconnected"),
-                          sctx->user ? sctx->user : "unauthenticated",
-                          sctx->host_or_ip,
-                          (net->last_errno ? ER(net->last_errno) :
-                           ER(ER_UNKNOWN_ERROR)));
-      net_send_error(thd, net->last_errno, NullS);
-      statistic_increment(aborted_threads,&LOCK_status);
-    }
-    else if (thd->killed)
-    {
-      statistic_increment(aborted_threads,&LOCK_status);
-    }
-    
-end_thread:
-    close_connection(thd, 0, 1);
-    end_thread(thd,1);
-    /*
-      If end_thread returns, we are either running with --one-thread
-      or this thread has been schedule to handle the next query
-    */
-    thd= current_thd;
-    thd->thread_stack= (char*) &thd;
-  } while (!(test_flags & TEST_NO_THREADS));
-  /* The following is only executed if we are not using --one-thread */
-  return(0);					/* purecov: deadcode */
-}
-
-#endif /* EMBEDDED_LIBRARY */
-
 /*
   Execute commands from bootstrap_file.
   Used when creating the initial grant tables
@@ -1246,11 +268,6 @@
 #ifndef EMBEDDED_LIBRARY
   pthread_detach_this_thread();
   thd->thread_stack= (char*) &thd;
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
-  sigset_t set;
-  VOID(sigemptyset(&set));			// Get mask in use
-  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
 #endif /* EMBEDDED_LIBRARY */
 
   if (thd->variables.max_join_size == HA_POS_ERROR)
@@ -4085,7 +3102,7 @@
           {
             if (!(user= get_current_user(thd, tmp_user)))
               goto error;
-	    reset_mqh(user);
+	    reset_mqh(user, 0);
           }
 	}
       }
@@ -6330,6 +5347,7 @@
   join_list->push_front(ptr);
   ptr->embedding= embedding;
   ptr->join_list= join_list;
+  ptr->alias= (char*) "(nested_join)";
   embedding= ptr;
   join_list= &nested_join->join_list;
   join_list->empty();
@@ -6414,6 +5432,7 @@
 
   ptr->embedding= embedding;
   ptr->join_list= join_list;
+  ptr->alias= (char*) "(nest_last_join)";
   embedded_list= &nested_join->join_list;
   embedded_list->empty();
 
@@ -6906,7 +5925,7 @@
  }
 #endif
  if (options & REFRESH_USER_RESOURCES)
-   reset_mqh((LEX_USER *) NULL);
+   reset_mqh((LEX_USER *) NULL, 0);		/* purecov: inspected */
  *write_to_binlog= tmp_write_to_binlog;
  return result;
 }
@@ -6927,7 +5946,10 @@
 {
   THD *tmp;
   uint error=ER_NO_SUCH_THREAD;
+  DBUG_ENTER("kill_one_thread");
+  DBUG_PRINT("enter", ("id: %lu  only_kill: %d", id, only_kill_query));
   VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+
   I_List_iterator<THD> it(threads);
   while ((tmp=it++))
   {
@@ -6955,6 +5977,7 @@
     send_ok(thd);
   else
     my_error(error, MYF(0), id);
+  DBUG_VOID_RETURN;
 }
 
 

--- 1.339/sql/sql_show.cc	2007-01-22 14:10:41 +02:00
+++ 1.340/sql/sql_show.cc	2007-03-14 12:47:56 +02:00
@@ -1351,10 +1351,6 @@
         if (mysys_var)
           pthread_mutex_unlock(&mysys_var->mutex);
 
-#if !defined(DONT_USE_THR_ALARM) && ! defined(SCO)
-        if (pthread_kill(tmp->real_id,0))
-          tmp->proc_info="*** DEAD ***";        // This shouldn't happen
-#endif
 #ifdef EXTRA_DEBUG
         thd_info->start_time= tmp->time_after_lock;
 #else

--- 1.332/sql/sql_table.cc	2007-01-22 14:10:42 +02:00
+++ 1.333/sql/sql_table.cc	2007-03-14 12:47:56 +02:00
@@ -1668,19 +1668,14 @@
   }
   else  
   {
-	#ifdef FN_DEVCHAR
-	  /* check if the table name contains FN_DEVCHAR when defined */
-	  const char *start= alias;
-	  while (*start != '\0')
-	  {
-		  if (*start == FN_DEVCHAR)
-		  {
-			  my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
-			  DBUG_RETURN(TRUE);
-		  }
-		  start++;
-	  }	  
-	#endif
+#ifdef FN_DEVCHAR
+    /* check if the table name contains FN_DEVCHAR when defined */
+    if (strchr(alias, FN_DEVCHAR))
+    {
+      my_error(ER_WRONG_TABLE_NAME, MYF(0), alias);
+      DBUG_RETURN(TRUE);
+    }
+#endif
     build_table_path(path, sizeof(path), db, alias, reg_ext);
   }
 

--- 1.48/sql/sql_test.cc	2006-12-30 22:02:07 +02:00
+++ 1.49/sql/sql_test.cc	2007-03-14 12:47:56 +02:00
@@ -71,17 +71,18 @@
   uint idx,count,unused;
   TABLE *start_link,*lnk;
 
+  /* purecov: begin tested */
   VOID(pthread_mutex_lock(&LOCK_open));
-  puts("DB             Table                            Version  Thread  L.thread  Open 
Lock");
+  puts("DB             Table                            Version  Thread  Open  Lock");
 
   for (idx=unused=0 ; idx < open_cache.records ; idx++)
   {
     TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
-    printf("%-14.14s %-32s%6ld%8ld%10ld%6d  %s\n",
+    printf("%-14.14s %-32s%6ld%8ld%6d  %s\n",
 	   entry->s->db, entry->s->table_name, entry->s->version,
 	   entry->in_use ? entry->in_use->thread_id : 0L,
-	   entry->in_use ? entry->in_use->dbug_thread_id : 0L,
-	   entry->db_stat ? 1 : 0, entry->in_use ?
lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
+	   entry->db_stat ? 1 : 0, 
+           entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not
in use");
     if (!entry->in_use)
       unused++;
   }
@@ -108,6 +109,7 @@
     printf("Error: File hash table is corrupted\n");
   fflush(stdout);
   VOID(pthread_mutex_unlock(&LOCK_open));
+  /* purecov: end */
   return;
 }
 

--- 1.21/sql/parse_file.cc	2006-12-23 21:04:25 +02:00
+++ 1.22/sql/parse_file.cc	2007-03-14 12:47:55 +02:00
@@ -225,7 +225,7 @@
   DBUG_PRINT("enter", ("Dir: %s, file: %s, base 0x%lx",
 		       dir->str, file_name->str, (ulong) base));
 
-  fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME);
+  fn_format(path, file_name->str, dir->str, "", MY_UNPACK_FILENAME);
   path_end= strlen(path);
 
   // temporary file name

--- 1.104/sql/sql_view.cc	2007-01-22 14:10:42 +02:00
+++ 1.105/sql/sql_view.cc	2007-03-14 12:47:56 +02:00
@@ -711,7 +711,7 @@
     File_parser *parser;
 
     path.str= path_buff;
-    fn_format(path_buff, file.str, dir.str, 0, MY_UNPACK_FILENAME);
+    fn_format(path_buff, file.str, dir.str, "", MY_UNPACK_FILENAME);
     path.length= strlen(path_buff);
 
     if (!access(path.str, F_OK))

--- 1.59/mysys/my_getopt.c	2006-12-30 22:02:05 +02:00
+++ 1.60/mysys/my_getopt.c	2007-03-14 12:47:55 +02:00
@@ -960,7 +960,7 @@
 	printf("%d\n", *((uint*) value));
 	break;
       case GET_LONG:
-	printf("%lu\n", *((long*) value));
+	printf("%ld\n", *((long*) value));
 	break;
       case GET_ULONG:
 	printf("%lu\n", *((ulong*) value));

--- 1.37/mysys/my_bitmap.c	2007-01-22 14:10:37 +02:00
+++ 1.38/mysys/my_bitmap.c	2007-03-14 12:47:55 +02:00
@@ -59,21 +59,22 @@
 my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size,
 		    my_bool thread_safe)
 {
+  uint alloc_size;
   DBUG_ENTER("bitmap_init");
 
-  DBUG_ASSERT((bitmap_size & 7) == 0);
-  bitmap_size/=8;
+  bitmap_size= MY_ALIGN(bitmap_size, 8) / 8;
+  alloc_size= ALIGN_SIZE(bitmap_size);
   if (!(map->bitmap=buf) &&
-      !(map->bitmap= (uchar*) my_malloc(bitmap_size +
+      !(map->bitmap= (uchar*) my_malloc(alloc_size +
 					(thread_safe ?
 					 sizeof(pthread_mutex_t) : 0),
 					MYF(MY_WME | MY_ZEROFILL))))
     DBUG_RETURN(1);
-  map->bitmap_size=bitmap_size;
+  map->bitmap_size= bitmap_size;
 #ifdef THREAD
   if (thread_safe)
   {
-    map->mutex=(pthread_mutex_t *)(map->bitmap+bitmap_size);
+    map->mutex=(pthread_mutex_t *)(map->bitmap+alloc_size);
     pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST);
   }
   else

--- 1.9/mysql-test/t/wait_timeout.test	2007-01-10 16:55:50 +02:00
+++ 1.10/mysql-test/t/wait_timeout.test	2007-03-14 12:47:55 +02:00
@@ -1,5 +1,6 @@
 # This tests not performed with embedded server
 -- source include/not_embedded.inc
+-- source include/one_thread_per_connection.inc
 
 #
 # Bug #8731: wait_timeout does not work on Mac OS X

--- 1.190/mysql-test/mysql-test-run.pl	2007-01-11 16:40:01 +02:00
+++ 1.191/mysql-test/mysql-test-run.pl	2007-03-14 12:47:55 +02:00
@@ -1701,7 +1701,7 @@
   }
 
   $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths,
-				$ENV{'LD_LIBRARY_PATHS'} ?
+				$ENV{'LD_LIBRARY_PATH'} ?
 				split(':', $ENV{'LD_LIBRARY_PATH'}) : ());
   mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}");
 

--- 1.3/BUILD/compile-solaris-sparc-debug	2005-05-18 14:23:13 +03:00
+++ 1.4/BUILD/compile-solaris-sparc-debug	2007-03-14 12:47:54 +02:00
@@ -1,6 +1,6 @@
 #! /bin/sh
 
-gmake -k clean || true
+make -k clean || true
 /bin/rm -f */.deps/*.P config.cache
  
 path=`dirname $0`
@@ -8,4 +8,4 @@
  
 CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts
-Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Wunused  -O3
-fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa" CXX=gcc CXXFLAGS="-Wimplicit
-Wreturn-type -Wid-clash-51 -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat
-Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder
-Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti 
-O3 -fno-omit-frame-pointer -mcpu=v8 -Wa,-xarch=v8plusa -g" ./configure
--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex
--enable-thread-safe-client --with-debug
 
-gmake -j 4
+make -j 4

--- 1.4/BUILD/compile-solaris-sparc-forte	2005-05-18 14:23:13 +03:00
+++ 1.5/BUILD/compile-solaris-sparc-forte	2007-03-14 12:47:54 +02:00
@@ -1,16 +1,16 @@
 #! /bin/sh
 
-gmake -k clean || true
+# Assume Forte is installed in /opt/SUNWSpro and ld is installed in
+# /usr/ccs/bin
+
+PATH=/opt/SUNWspro/bin/:/usr/ccs/bin:$PATH
+
+make -k clean || true
 /bin/rm -f */.deps/*.P config.cache
  
 path=`dirname $0`
 . "$path/autorun.sh"
 
-
-# Assume Forte is installed in /opt/SUNWSpro
-
-PATH=/opt/SUNWspro/bin/:$PATH
-
 # For "optimal" code for this computer add -fast to EXTRA
 # To compile 64 bit, add -xarch=v9 to EXTRA_64_BIT
 
@@ -27,7 +27,7 @@
 CXX=CC CXXFLAGS="-noex $STD" \
 ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex
--enable-thread-safe-client
 
-gmake -j 4
+make -j 4
 if [ $? = 0 ]
 then
   make test

--- 1.178/sql/set_var.cc	2007-01-22 14:10:40 +02:00
+++ 1.179/sql/set_var.cc	2007-03-14 12:47:55 +02:00
@@ -340,6 +340,10 @@
 sys_var_thd_ulong	sys_trans_prealloc_size("transaction_prealloc_size",
 						&SV::trans_prealloc_size,
 						0, fix_trans_mem_root);
+sys_var_thd_enum        sys_thread_handling("thread_handling",
+                                            &SV::thread_handling,
+                                            &thread_handling_typelib,
+                                            NULL);
 
 #ifdef HAVE_QUERY_CACHE
 sys_var_long_ptr	sys_query_cache_limit("query_cache_limit",
@@ -406,6 +410,8 @@
                                                     &table_lock_wait_timeout);
 sys_var_long_ptr	sys_thread_cache_size("thread_cache_size",
 					      &thread_cache_size);
+sys_var_long_ptr	sys_thread_pool_size("thread_pool_size",
+					      &thread_pool_size);
 sys_var_thd_enum	sys_tx_isolation("tx_isolation",
 					 &SV::tx_isolation,
 					 &tx_isolation_typelib,
@@ -747,6 +753,8 @@
   &sys_table_lock_wait_timeout,
   &sys_table_type,
   &sys_thread_cache_size,
+  &sys_thread_handling,
+  &sys_thread_pool_size,
   &sys_time_format,
   &sys_timed_mutexes,
   &sys_timestamp,
@@ -1068,6 +1076,10 @@
   {sys_thread_cache_size.name,(char*) &sys_thread_cache_size,       SHOW_SYS},
 #ifdef HAVE_THR_SETCONCURRENCY
   {"thread_concurrency",      (char*) &concurrency,                 SHOW_LONG},
+#endif
+  {sys_thread_handling.name,  (char*) &sys_thread_handling,         SHOW_SYS},
+#ifdef HAVE_POOL_OF_THREADS
+  {sys_thread_pool_size.name, (char*) &sys_thread_pool_size,       SHOW_SYS},
 #endif
   {"thread_stack",            (char*) &thread_stack,                SHOW_LONG},
   {sys_time_format.name,      (char*) &sys_time_format,		    SHOW_SYS},
--- New file ---
+++ mysql-test/include/one_thread_per_connection.inc	07/03/14 12:47:56
-- require r/one_thread_per_connection.require
disable_query_log;
select @@thread_handling;
enable_query_log;


--- New file ---
+++ mysql-test/r/no-threads.result	07/03/14 12:47:56
select 1+1;
1+1
2
select 1+2;
1+2
3

--- New file ---
+++ mysql-test/r/one_thread_per_connection.require	07/03/14 12:47:56
@@thread_handling
one-thread-per-connection

--- New file ---
+++ mysql-test/t/no-threads-master.opt	07/03/14 12:47:56
--one-thread --thread-handling=no-threads

--- New file ---
+++ mysql-test/t/no-threads.test	07/03/14 12:47:56
#
# Test the --thread-handler=no-threads option
#
select 1+1;
select 1+2;

--- New file ---
+++ sql/scheduler.cc	07/03/14 12:47:56
/* Copyright (C) 2007 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Implementation for the thread scheduler
*/

#ifdef USE_PRAGMA_INTERFACE
#pragma implementation
#endif

#include <mysql_priv.h>

/*
  'Dummy' functions to be used when we don't need any handling for a scheduler
  event
 */

static bool init_dummy(void) {return 0;}
static void post_kill_dummy(THD* thd) {}  
static void end_dummy(void) {}
static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; }

/*
  Initialize default scheduler with dummy functions so that setup functions
  only need to declare those that are relvant for their usage
*/

scheduler_functions::scheduler_functions()
  :init(init_dummy),
   init_new_connection_thread(init_new_connection_handler_thread),
   add_connection(0),                           // Must be defined
   post_kill_notification(post_kill_dummy),
   end_thread(end_thread_dummy), end(end_dummy)
{}


/*
  End connection, in case when we are using 'no-threads'
*/

static bool no_threads_end(THD *thd, bool put_in_cache)
{
  unlink_thd(thd);
  pthread_mutex_unlock(&LOCK_thread_count);
  return 1;                                     // Abort handle_one_connection
}


/*
  Initailize scheduler for --thread-handling=no-threads
*/

void one_thread_scheduler(scheduler_functions* func)
{
  func->max_threads= 1;
#ifndef EMBEDDED_LIBRARY
  func->add_connection= handle_connection_in_main_thread;
#endif
  func->init_new_connection_thread= init_dummy;
  func->end_thread= no_threads_end;
}


/*
  Initialize scheduler for --thread-handling=one-thread-per-connection
*/

#ifndef EMBEDDED_LIBRARY
void one_thread_per_connection_scheduler(scheduler_functions* func)
{
  func->max_threads= max_connections;
  func->add_connection= create_thread_to_handle_connection;
  func->end_thread= one_thread_per_connection_end;
}
#endif /* EMBEDDED_LIBRARY */


/****************************************************************************
  Schudule threads with even_ports (Solaris)

  Limitations in this implemention:
  - Connect timeout doesn't work (as we can't have a timeout for
    port_associate())
  - Slaves connection to the master should preferably have a thread of
    their own. Now each slave thread will take up a connection pool thread,
    even if it's mainly waiting for binlog change events in
    mysql_binlog_send().

****************************************************************************/

#ifndef EMBEDDED_LIBRARY
#if defined(HAVE_PORT_CREATE)

#include <port.h>

/* Reserve one connection for root user (as in mysqld.cc) */
#define EXTRA_CONNECTIONS 1

/*
  EP_FILE_INFO is used to hold the link between event_completion ports
  and THD's.  We can't use THD's directly because port_dissociate()
  doesn't tell us if a port_associate() was was deleted or not and we
  would be left with a dangling pointer to a THD if a port event and a
  connection killed happened at the same time.
  We solve this by allocate enough EP_FILE_INFO structures at start
  (solves the dangling pointer problem) and having code to detect delayed
  file-events events.  We also use a bitmap to tell us which elements
  are in use to not have to allocate more EP_FILE_INFO elements than
  we have connections.
  (A better solution would be to use patch the port_dissociate() code
  to inform us if an active port_associate() was deleted and use
  THD directly)
*/

struct EP_FILE_INFO
{
  pthread_mutex_t LOCK_port;
  THD *thd;
  uint in_use;                      // Counter
  pool_command_op key;              // Key for last generated operation
  bool killed;
};


static int port_fd;
static uint created_threads, killed_threads;
static EP_FILE_INFO *ep_file_info;
static MY_BITMAP port_map;

#define file_info_id(A) ((uint) ((A) - ep_file_info))

pthread_handler_t ep_thread_proc(void *);
static bool ep_post_notification(EP_FILE_INFO *file_info, pool_command_op key);
static void ep_abort_threads();

/*
  thd_scheduler keeps the connection between THD and EP_FILE_INFO.
  It's embedded in the THD class.
*/

thd_scheduler::thd_scheduler()
  :id((uint) -1)                                // Set to catch errors
{}


thd_scheduler::~thd_scheduler()
{}


/* Wrapper for port_associate */

static int my_port_associate(int port, int source, uintptr_t object,
                             int events, void *user)
{
  int ret;
  DBUG_ENTER("my_port_associate");
  DBUG_PRINT("enter",
             ("port: %d  source: %d  object: %ld  events: %d  file_info: %u",
              port, source, (long) object, events,
              file_info_id(((EP_FILE_INFO*) user))));
  ret= port_associate(port, source, object, events, user);
  DBUG_PRINT("exit", ("ret: %d", ret));
  DBUG_RETURN(ret);
}


/* Wrapper for port_dissociate */

static int my_port_dissociate(int port, int source, uintptr_t object)
{
  int ret;
  DBUG_ENTER("my_port_dissociate");
  DBUG_PRINT("enter", ("port: %d  source: %d  object: %ld",
                       port, source, (long) object));
  ret= port_dissociate(port, source, object);
  DBUG_PRINT("exit", ("ret: %d", ret));
  DBUG_RETURN(ret);
}


/* Wrapper for port_get */

static int my_port_get(int port, port_event_t *pe, timespec_t *timeout)
{
  int ret;
  DBUG_ENTER("my_port_get");
  ret= port_get(port, pe, timeout);
#ifndef DBUG_OFF
  {
    EP_FILE_INFO *file_info;
    file_info= (EP_FILE_INFO*) pe->portev_user;
    DBUG_PRINT("exit",
               ("ret: %d  source: %d  events: %d  file_info: %u  in_use: %d",
                ret, pe->portev_source, pe->portev_events,
                file_info ? file_info_id(file_info) : (uint) -1,
                file_info ? file_info->in_use : 0));
  }
#endif
  DBUG_RETURN(ret);
}


/* Wrapper for port_send */

static int my_port_send(int port, int events, void *user)
{
  int ret;
  DBUG_ENTER("my_port_send");
  DBUG_PRINT("enter", ("events: %d  file_info: %u", events,
                       file_info_id(((EP_FILE_INFO*) user))));
  ret= port_send(port, events, user);
  DBUG_PRINT("exit", ("ret: %d", ret));
  DBUG_RETURN(ret);
}


/* End connection */

static bool ep_threads_end(THD *thd)
{
  ep_file_info[thd->scheduler.id].thd= 0;       // Safety
  bitmap_clear_bit(&port_map, thd->scheduler.id);
  return no_threads_end(thd, 0);
}

/*
  Create all threads for the thread pool

  NOTES
    After threads are created we wait until all threads has signaled that
    they have started before we return

  RETURN
    0  ok
    1  We got an error creating the thread pool
       In this case we will abort all created threads
*/

static bool ep_init(void)
{
  uint i, max_ports= max_connections + EXTRA_CONNECTIONS;
  DBUG_ENTER("ep_init");

  /*
    Create memory to hold context
  */
  if (bitmap_init(&port_map, 0, max_ports, 1))
    DBUG_RETURN(TRUE);

  if (!(ep_file_info= (EP_FILE_INFO*) my_malloc(max_ports *
                                                sizeof(ep_file_info[0]),
                                                MYF(MY_WME | MY_ZEROFILL))))
    DBUG_RETURN(TRUE);

  /* Create port to use for event completion */
  if (!(port_fd= port_create()))
  {
    sql_print_error("port_create failed with %d", (int) errno);
    my_free((gptr) ep_file_info, MYF(0));
    bitmap_free(&port_map);
    DBUG_RETURN(TRUE);
  }

  for (i= 0 ; i < max_ports ; i++)
    pthread_mutex_init(&ep_file_info[i].LOCK_port, MY_MUTEX_INIT_FAST);

  /* Set up the thread pool */
  created_threads= killed_threads= 0;
  pthread_mutex_lock(&LOCK_thread_count);

  for (i= 0; i < thread_pool_size; i++)
  {
    pthread_t thread;
    int error= pthread_create(&thread, &connection_attrib,
                              ep_thread_proc, 0);
    if (error)
    {
      sql_print_error("Can't create completion port thread "
                      "(error %d, errno: %d)",
                      error, errno);
      ep_abort_threads();                       // Cleanup
      DBUG_RETURN(TRUE);
    }
  }

  /* Wait until all threads are created */
  while (created_threads != thread_pool_size)
    (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  DBUG_PRINT("info", ("%u threads created", (uint) thread_pool_size));
  DBUG_RETURN(FALSE);
}


/*
  Notify the thread pool about a new connection

  NOTES
    LOCK_thread_count is locked on entry. This function MUST unlock it!
*/

static void ep_add_connection(THD *thd)
{
  EP_FILE_INFO *file_info;
  DBUG_ENTER("ep_add_connection");

  threads.append(thd);
  (void) pthread_mutex_unlock(&LOCK_thread_count);

  thd->scheduler.id= bitmap_set_next(&port_map);
  DBUG_ASSERT(thd->scheduler.id != MY_BIT_NONE);

  file_info= ep_file_info + thd->scheduler.id;
  file_info->thd= thd;
  file_info->in_use= 0;
  file_info->killed= 0;
  file_info->key= CONNECT_OP;             // Protect against sporadic read

  DBUG_PRINT("info", ("thd: 0x%lx  thread_id: %lu  file_info: %u",
                      (long) thd, thd->thread_id, (uint) thd->scheduler.id));
  if (ep_post_notification(file_info, CONNECT_OP))
    ep_threads_end(thd);
  DBUG_VOID_RETURN;
}


/*
  Signal a connection it's time to die

  NOTES
    On entry we have a lock on LOCK_thread_cont
*/

static void ep_post_kill_notification(THD *thd)
{
  if (thd->scheduler.id != (uint) -1)
    (void) ep_post_notification(ep_file_info + thd->scheduler.id, KILL_OP);
}


/*
  Post notification for thread to handle request

  SYNOPSIS
    ep_post_notification()
    file_info	connection object
    key		Operation

  RETURN
    0   ok     ; Notification will be sent
    1   error  ; Connection was already killed or could not send notification
*/

static bool ep_post_notification(EP_FILE_INFO *file_info, pool_command_op key)
{
  DBUG_ENTER("ep_post_notification");
  DBUG_PRINT("enter", ("key: %d  file_info: %u  in_use: %u  killed: %d",
                       (int) key, file_info_id(file_info),
                       file_info->in_use, (int) file_info->killed));

  pthread_mutex_lock(&file_info->LOCK_port);
  if (file_info->killed)
  {
    /* THD has already got a kill signal, ignore this one */
    pthread_mutex_unlock(&file_info->LOCK_port);
    DBUG_RETURN(TRUE);
  }

  if (key == KILL_OP)
  {
    Vio *vio= file_info->thd->net.vio;
    file_info->killed= TRUE;
    (void) my_port_dissociate(port_fd, PORT_SOURCE_FD, vio->sd);
    if (file_info->key != NOT_IN_USE_OP || file_info->in_use > 0)
    {
      /*
        We don't have to send a notification because either:
        a) A thread is working on the connection and it will kill
           the connection after usage
        b) There is already an existing event that will handle the kill
      */
      pthread_mutex_unlock(&file_info->LOCK_port);
      DBUG_RETURN(TRUE);
    }
  }

  /* One thread will be started to take care of this notification */
  file_info->in_use++;

  if (my_port_send(port_fd, (int) key, (void *) file_info) < 0)
  {
    sql_print_error("port_send failed with error: %d", (int) errno);
    if (key == CONNECT_OP || key == NORMAL_OP)
    {
      THD *thd= file_info->thd;
      file_info->killed= TRUE;
      end_connection(thd);
      close_connection(thd, ER_ERROR_ON_READ, 1);
      ep_threads_end(thd);
    }
    pthread_mutex_unlock(&file_info->LOCK_port);
    DBUG_RETURN(TRUE);
  }
  pthread_mutex_unlock(&file_info->LOCK_port);
  DBUG_RETURN(FALSE);
}


/*
  Register that we want to have an event if there is data on file descriptor

  SYNOPSIS
    ep_start_waiting_for_data()
    file_info		File handler

  RETURN
    0    ok    (Event was registered)
    1    error (Could not register event or connection is killed)
*/


static bool ep_start_waiting_for_data(EP_FILE_INFO *file_info)
{
  Vio *vio;
  DBUG_ENTER("ep_start_waiting_for_data");

  pthread_mutex_lock(&file_info->LOCK_port);
  if (file_info->killed)
  {
    /*
      THD was killed between ep_unregister and ep_start_waiting for data.
      In this case the kill event will take care of killing the
      connection and we can safely ignore this event.
    */
    pthread_mutex_unlock(&file_info->LOCK_port);
    DBUG_RETURN(TRUE);
  }

  /* Mark that we can receive new events on the port */
  file_info->key= NOT_IN_USE_OP;

  vio= file_info->thd->net.vio;
  if (vio->read_pos < vio->read_end)
  {
    /*
      We have still data in buffer, so it won't trigger an event.
      Post a message so that a thread can take care of this event.
    */
    pthread_mutex_unlock(&file_info->LOCK_port);
    DBUG_RETURN(ep_post_notification(file_info, NORMAL_OP));
  }

  if (my_port_associate(port_fd, PORT_SOURCE_FD, vio->sd, POLLIN,
                        (void *) file_info) < 0)
  {
    THD *thd= file_info->thd;
    sql_print_error("port_associate failed: error %d", (int) errno);
    file_info->killed= 1;
    end_connection(thd);
    close_connection(thd, ER_ERROR_ON_READ, 1);
    ep_threads_end(thd);
    pthread_mutex_unlock(&file_info->LOCK_port);
    DBUG_RETURN(TRUE);
  }

  /* We are now about to start waiting for data to work on */
  file_info->thd->net.reading_or_writing= 1;
  pthread_mutex_unlock(&file_info->LOCK_port);
  DBUG_RETURN(FALSE);
}


static void ep_unregister(EP_FILE_INFO *file_info)
{
  THD *thd= file_info->thd;
  DBUG_ENTER("ep_unregister");
  pthread_mutex_lock(&file_info->LOCK_port);
  DBUG_PRINT("enter", ("file_info: %u  in_use: %u  killed: %d",
                       file_info_id(file_info), file_info->in_use,
                       file_info->killed));
  DBUG_ASSERT(file_info->in_use >= 0);

  /* Inform notification that it can create a kill event */
  file_info->key= NOT_IN_USE_OP;
  if (file_info->killed && file_info->in_use == 0)
  {
    thd->killed= THD::KILL_CONNECTION;          // Avoid error messages
    if (thd->net.vio->sd >= 0)                   // not already closed
    {
      end_connection(thd);
      close_connection(thd, 0, 1);
    }
    ep_threads_end(thd);
  }
  pthread_mutex_unlock(&file_info->LOCK_port);
  DBUG_VOID_RETURN;
}


pthread_handler_t ep_thread_proc(void *arg)
{
  port_event_t ev;

  if (init_new_connection_handler_thread())
  {
    my_thread_global_end();
    sql_print_error("ep_thread_proc: my_thread_init() failed\n");
    exit(1);
  }
  DBUG_ENTER("ep_thread_proc");

  /*
    Signal ep_init() when all threads has been created and are ready to
    receive events.
  */
  pthread_mutex_lock(&LOCK_thread_count);
  created_threads++;
  if (created_threads == thread_pool_size)
    pthread_cond_signal(&COND_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  
  for (;;)
  {
    THD* thd;
    EP_FILE_INFO *file_info;
    bool terminate;

    if (my_port_get(port_fd, &ev, NULL) < 0)
    {
      switch (errno) {
      case EINTR:
      case ETIME:
        break;
      default:
        sql_print_error("port_get: error %d", errno);
        DBUG_ASSERT(0);
        break;
      }
      continue;
    }

    if (ev.portev_source == PORT_SOURCE_ALERT)
      break;                                    // mysqld is shutting down

    file_info= (EP_FILE_INFO*) ev.portev_user;
    thd= file_info->thd;

    /*
      Check if we should ignore the event
      
      Here we block the freeing of THD by ensuring that file_info->key is set
      to the operation that we are handling.  The key is reset in
      ep_unregister().

      We are ensuring that we have at most one thread working on the
      same ep_file_info (and thus THD) at the same time.
    */
    pthread_mutex_lock(&file_info->LOCK_port);
    if (file_info->killed)
    {
      if (ev.portev_source == PORT_SOURCE_FD)
      {
        /* Ignore FD event, as the KILL_OP event will free THD */
        DBUG_PRINT("warning", ("read event ignored becasue thread is killed"));
        pthread_mutex_unlock(&file_info->LOCK_port);
        continue;
      }
      file_info->in_use--;
      pthread_mutex_unlock(&file_info->LOCK_port);
      /*
        Here we have either only a kill event or a more-data + kill event.
        The last event will delete the THD
      */
      thd->thread_stack= (char*) &thd;
      (void) setup_connection_thread_globals(thd);
      ep_unregister(file_info);
      continue;
    }
    else
    {
      if (ev.portev_source == PORT_SOURCE_FD)
      {
        if (file_info->key != NOT_IN_USE_OP)
        {
          /*
            Must be a PORT_SOURCE_FD for a previous version of file_info;
            ignore it.
          */
          DBUG_PRINT("warning", ("Old read event ignored"));
          pthread_mutex_unlock(&file_info->LOCK_port);
          continue;
        }
        file_info->key= NORMAL_OP;
      }
      else
      {
        DBUG_ASSERT(ev.portev_source == PORT_SOURCE_USER);
        file_info->in_use--;
        /*
          Mark that we are doing something
          This will stop all KILL events until event is handled.
        */
        file_info->key= (pool_command_op) ev.portev_events;
      }
      pthread_mutex_unlock(&file_info->LOCK_port);
    }

    thd->thread_stack= (char*) &thd;
    if (setup_connection_thread_globals(thd))
    {
      file_info->killed= 1;
      ep_unregister(file_info);
      continue;
    }

    if (ev.portev_source == PORT_SOURCE_USER)
    {
      if (ev.portev_events == CONNECT_OP)
      {
        DBUG_PRINT("info", ("init new connection.  sd: %d",
                            thd->net.vio->sd));
        if (login_connection(thd))
        {
          /*
            ep_unregister() below will delete thd
            close_connection() here to avoid calling end_connection() later
            in ep_unregister()
          */
          close_connection(thd, 0, 1);
          file_info->killed= 1;
          ep_unregister(file_info);
        }
        else
        {
          prepare_new_connection_state(thd);
          if (ep_start_waiting_for_data(file_info))
            ep_unregister(file_info);
        }
        continue;
      }
    }

    /* Process one query (if connection is not killed) */
    terminate= TRUE;
    if (thd->net.vio != 0 && thd->killed != THD::KILL_CONNECTION)
    {
      thd->net.no_send_error= 0;
      if (do_command(thd))
        file_info->killed= TRUE;
    }
    else
      file_info->killed= TRUE;
    if (ep_start_waiting_for_data(file_info))
      ep_unregister(file_info);
  }

  DBUG_PRINT("exit", ("ending thread"));
  pthread_mutex_lock(&LOCK_thread_count);
  killed_threads++;
  pthread_cond_signal(&COND_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);                               /* purify: deadcode */
}


/*
  Wait until all pool threads has been deleted for clean shutdown
*/

static void ep_abort_threads()
{
  DBUG_ENTER("ep_abort_threads");
  DBUG_PRINT("enter", ("created_threads: %d  killed_threads: %u",
                       created_threads, killed_threads));

  if (port_fd)
  {
    uint i;
    port_alert(port_fd, PORT_ALERT_SET, 1, NULL);
    pthread_mutex_lock(&LOCK_thread_count);
    while (killed_threads != created_threads)
      (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
    pthread_mutex_unlock(&LOCK_thread_count);

    for (i= 0 ; i < max_connections + EXTRA_CONNECTIONS ; i++)
      pthread_mutex_destroy(&ep_file_info[i].LOCK_port);
    my_free((gptr) ep_file_info, MYF(0));
    bitmap_free(&port_map);

    close(port_fd);
    port_fd= 0;                                   // Safety
  }
  DBUG_VOID_RETURN;
}


/*
  Initialize scheduler for --thread-handling=pool-of-threads
*/

void pool_of_threads_scheduler(scheduler_functions* func)
{
  func->max_threads= thread_pool_size;
  func->init= ep_init;
  func->end=  ep_abort_threads;
  func->post_kill_notification= ep_post_kill_notification;
  func->add_connection= ep_add_connection;
}


/****************************************************************************
 Schudule threads with IOCP (Windows XP)
****************************************************************************/

#elif defined(HAVE_WINSOCK2) && HAVE_POOL_OF_THREADS == 1

static HANDLE completion_port;
static uint created_threads, killed_threads;

pthread_handler_t iocp_thread_proc(void *arg);
static bool iocp_post_notification(THD *thd, pool_command_op key,
                                   MY_WSAOVERLAPPED *overlapped);
static void iocp_abort_threads();


static void iocp_init_overlapped(THD *thd, MY_WSAOVERLAPPED* overlapped)
{
  WSABUF *bufRef= &overlapped->ref;
  bufRef->buf=    overlapped->data;
  bufRef->len=    0;
  overlapped->thd= thd;
}

/*
  thd_scheduler keeps the connection between THD and EP_FILE_INFO.
  It's embedded in the THD class.
*/

thd_scheduler::thd_scheduler()
  :in_use(0), context(0), killed(FALSE), key(CONNECT_OP)
{
  pthread_mutex_init(&LOCK_port, MY_MUTEX_INIT_FAST);
}


thd_scheduler::~thd_scheduler()
{
  pthread_mutex_destroy(&LOCK_port);
}

/* End connection */

static void iocp_threads_end(THD *thd)
{
  no_threads_end(thd, 0);
}


/*
  Create all threads for the thread pool

  NOTES
    After threads are created we wait until all threads has signaled that
    they have started before we return

  RETURN
    0  ok
    1  We got an error creating the thread pool
       In this case we will abort all created threads
*/

static bool iocp_init(void)
{
  uint i;
  DBUG_ENTER("iocp_init");

  /* Create port to use for event completion */
  if (!(completion_port= CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
                                                NORMAL_OP, thread_pool_size)))
  {
    int err= GetLastError();
    sql_print_error("CreateIoCompletionPort failed with %d", err);
    DBUG_RETURN(TRUE);
  }

  /* Set up the thread pool */
  created_threads= killed_threads= 0;
  pthread_mutex_lock(&LOCK_thread_count);

  for (i= 0; i < thread_pool_size; i++)
  {
    pthread_t thread;
    int error= pthread_create(&thread, &connection_attrib,
                              iocp_thread_proc, 0);
    if (error)
    {
      sql_print_error("Can't create completion port thread (error %d)",
                      error);
      iocp_abort_threads();                       // Cleanup
      DBUG_RETURN(TRUE);
    }
  }

  /* Wait until all threads are created */
  while (created_threads != thread_pool_size)
    (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  DBUG_PRINT("info", ("%u threads created", (uint) thread_pool_size));
  DBUG_RETURN(FALSE);
}


/*
  Notify the thread pool about a new connection

  NOTES
    LOCK_thread_count is locked on entry. This function MUST unlock it!
*/

static void iocp_add_connection(THD *thd)
{
  HANDLE socket;
  DBUG_ENTER("iocp_add_connection");
  DBUG_PRINT("enter", ("thd: 0x%lx  thread_id: %lu",
                       (long) thd, thd->thread_id));

  threads.append(thd);
  (void) pthread_mutex_unlock(&LOCK_thread_count);

  /* We don't have to close 'socket' as we are using 'completion_port' */
  socket= CreateIoCompletionPort((HANDLE) thd->net.vio->sd,
                                 completion_port, NORMAL_OP, 0);
  if (socket == NULL)
  {
    int err= GetLastError();
    sql_print_error("Failed to associate socket with completion port %d", err);
    iocp_threads_end(thd);
    DBUG_VOID_RETURN;
  }
  thd->scheduler.context= socket;               // Only for asserts
  iocp_init_overlapped(thd, &thd->scheduler.notification);
  iocp_init_overlapped(thd, &thd->scheduler.port_wait);
  iocp_init_overlapped(thd, &thd->scheduler.extra_read);

  if (iocp_post_notification(thd, CONNECT_OP, &thd->scheduler.notification))
    iocp_threads_end(thd);
  DBUG_VOID_RETURN;
}


/*
  Signal a connection it's time to die

  NOTES
    On entry we have a lock on LOCK_thread_cont
*/

static void iocp_post_kill_notification(THD *thd)
{
  if (thd->scheduler.context)
    (void) iocp_post_notification(thd, KILL_OP, &thd->scheduler.notification);
}

/*
  Post notification for thread to handle request

  SYNOPSIS
    iocp_post_notification()
    thd		connection object
    key		Operation
    overlapped  Buffer to use for overlapped notification

  RETURN
    0   ok     ; Notification will be sent
    1   error  ; Connection was already killed or could not send notification
*/

static bool iocp_post_notification(THD *thd, pool_command_op key,
                                   MY_WSAOVERLAPPED *overlapped)
{
  DBUG_ENTER("iocp_post_notification");
  DBUG_PRINT("enter", ("key: %d  thd: 0x%lx  in_use: %u  killed: %d",
                       (int) key, (long) thd, thd->scheduler.in_use,
                       thd->scheduler.killed));
  DBUG_ASSERT(thd->scheduler.context);

  pthread_mutex_lock(&thd->scheduler.LOCK_port);
  if (thd->scheduler.killed)
  {
    /* THD has already got a kill signal, ignore this one */
    pthread_mutex_unlock(&thd->scheduler.LOCK_port);
    DBUG_RETURN(TRUE);
  }

  if (key == KILL_OP)
  {
    thd->scheduler.killed= TRUE;
    if (thd->scheduler.key != NOT_IN_USE_OP || thd->scheduler.in_use > 0)
    {
      /*
        We don't have to send a notification because either:
        a) A thread is working on the connection and it will kill
           the connection after usage
        b) There is already an existing event that will handle the kill
      */
      pthread_mutex_unlock(&thd->scheduler.LOCK_port);
      DBUG_RETURN(TRUE);
    }
  }

  /* One thread will be started to take care of this notification */
  thd->scheduler.in_use++;
  if (!PostQueuedCompletionStatus(completion_port, 0, key,
                                 (LPWSAOVERLAPPED) overlapped))
  {
    int err= GetLastError();
    sql_print_error("PostNotification for connect failed with %d", (int) err);
    if (key == CONNECT_OP || key == NORMAL_OP)
    {
      thd->scheduler.killed= TRUE;
      end_connection(thd);
      close_connection(thd, ER_ERROR_ON_READ, 1);
      pthread_mutex_unlock(&thd->scheduler.LOCK_port);
      iocp_threads_end(thd);
      DBUG_RETURN(TRUE);
    }
    pthread_mutex_unlock(&thd->scheduler.LOCK_port);
    DBUG_RETURN(TRUE);
  }
  pthread_mutex_unlock(&thd->scheduler.LOCK_port);
  DBUG_RETURN(FALSE);
}


/*
  Register that we want to have an event if there is data on file descriptor

  SYNOPSIS
    iocp_start_waiting_for_data()
    thd 	Connection handler

  RETURN
    0    ok    (Event was registered)
    1    error (Could not register event or connection is killed)
*/


static bool iocp_start_waiting_for_data(THD *thd)
{
  Vio *vio;
  DWORD bytes_read, flags;
  DBUG_ENTER("iocp_start_waiting_for_data");

  pthread_mutex_lock(&thd->scheduler.LOCK_port);
  if (thd->scheduler.killed)
  {
    /*
      THD was killed between iocp_unregister and iocp_start_waiting for data.
      In this case the kill event will take care of killing the
      connection and we can safely ignore this event.
    */
    pthread_mutex_unlock(&thd->scheduler.LOCK_port);
    DBUG_RETURN(TRUE);
  }

  /* Mark that we can receive new events on the port */
  thd->scheduler.key= NOT_IN_USE_OP;

  vio= thd->net.vio;
  if (vio->read_pos < vio->read_end)
  {
    /*
      We have still data in buffer, so it won't trigger an event.
      Post a message so that a thread can take care of this event.
    */
    pthread_mutex_unlock(&thd->scheduler.LOCK_port);
    DBUG_RETURN(iocp_post_notification(thd, NORMAL_OP,
                                       &thd->scheduler.extra_read));
  }

  if (WSARecv(vio->sd, &thd->scheduler.extra_read.ref, 1,
              &bytes_read, &flags,
              (LPWSAOVERLAPPED) &thd->scheduler.extra_read,
              NULL))
  {
    DWORD err = WSAGetLastError();
    if (err != ERROR_IO_PENDING)
    {
      sql_print_error("WSARecv failed with %d", (int) err);
      thd->scheduler.killed= 1;
      end_connection(thd);
      close_connection(thd, ER_ERROR_ON_READ, 1);
      pthread_mutex_unlock(&thd->scheduler.LOCK_port);
      iocp_threads_end(thd);
      DBUG_RETURN(TRUE);
    }
  }

  /*
    Both zero return code and ERROR_IO_PENDING mean that
    GetQueuedCompletionStatus() will receive a notification.
  */
  thd->scheduler.in_use++;
  /* We are now about to start waiting for data to work on */
  thd->net.reading_or_writing= 1;
  pthread_mutex_unlock(&thd->scheduler.LOCK_port);
  DBUG_RETURN(FALSE);
}


static void iocp_unregister(THD *thd)
{
  DBUG_ENTER("iocp_unregister");
  pthread_mutex_lock(&thd->scheduler.LOCK_port);
  DBUG_PRINT("enter", ("thd: 0x%lx in_use: %u  killed: %d",
                       (long) thd, thd->scheduler.in_use,
                       thd->scheduler.killed));
  DBUG_ASSERT(thd->scheduler.in_use >= 0);

  /* Inform notification that it can create a kill event */
  thd->scheduler.key= NOT_IN_USE_OP;
  if (thd->scheduler.killed && thd->scheduler.in_use == 0)
  {
    thd->killed= THD::KILL_CONNECTION;          // Avoid error messages
    if (thd->net.vio->sd >= 0)                   // not already closed
    {
      end_connection(thd);
      close_connection(thd, 0, 1);
    }
    iocp_threads_end(thd);
  }
  pthread_mutex_unlock(&thd->scheduler.LOCK_port);
  DBUG_VOID_RETURN;
}


pthread_handler_t iocp_thread_proc(void *arg)
{
  if (init_new_connection_handler_thread())
  {
    my_thread_global_end();
    sql_print_error("iocp_thread_proc: my_thread_init() failed\n");
    exit(1);
  }
  DBUG_ENTER("iocp_thread_proc");

  /*
    Signal iocp_init() when all threads has been created and are ready to
    receive events.
  */
  pthread_mutex_lock(&LOCK_thread_count);
  created_threads++;
  if (created_threads == thread_pool_size)
    pthread_cond_signal(&COND_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  
  for (;;)
  {
    THD* thd;
    bool terminate;
    DWORD num_bytes, completion_key= 0;
    BOOL res;
    MY_WSAOVERLAPPED *overlapped= NULL;
    res= GetQueuedCompletionStatus(completion_port, &num_bytes,
                                   (PULONG_PTR) &completion_key,
                                   (LPOVERLAPPED*) &overlapped, 45000);
    if (!overlapped)
    {
      if ((pool_command_op) completion_key == DIE_OP)
        break;                                  // Shutdown
      /* Probably timeout from GetQueuedCompletionStatus(); Continue */
      continue;
    }

    thd= overlapped->thd;
    thd->thread_stack= (char*) &thd;

    if (!res)
    {
      int err= GetLastError();
      switch (err) {
      case WAIT_TIMEOUT:
      {
        DBUG_ASSERT(0);
	// Unexpected timeout, just continue
	break;
      }
      case ERROR_OPERATION_ABORTED:
      {
	/*
          This happens after 1 minute of connection inactivity
          reason is unknown so far, but reposting connection helps

          We have to call setup_connection_thread_globals() to ensure
          the close_connection() works in case of iocp_start_waiting_for_data()
          fails.
        */
        (void) setup_connection_thread_globals(thd);
	(void) iocp_start_waiting_for_data(thd);
        iocp_unregister(thd);
        break;
      }
      case ERROR_NETNAME_DELETED:
        iocp_unregister(thd);
        break;
      default:
	close_connection(thd, ER_ERROR_ON_READ, 1);
	sql_print_error("GetQueuedCompletionStatus returned unexpected error "
                        "%d", err);
        iocp_unregister(thd);
      }
      continue;
    }

    if (setup_connection_thread_globals(thd))
    {
      /* Fatal, unlikely error; Kill connection */
      thd->scheduler.killed= 1;
      thd->scheduler.in_use--;
      iocp_unregister(thd);
      continue;
    }

    /*
      Here we block the freeing of THD by ensuring that
      thd->scheduler.key is set to the operation that we are handling.
      The key is reset in iocp_unregister().

      We are ensuring that we have at most one thread working on the
      same THD at the same time.
    */
    pthread_mutex_lock(&thd->scheduler.LOCK_port);
    thd->scheduler.in_use--;
    if (thd->scheduler.killed)
    {
      pthread_mutex_unlock(&thd->scheduler.LOCK_port);
      /*
        Here we have either only a kill event or a more-data + kill event.
        The last event will delete the THD
      */
      iocp_unregister(thd);
      continue;
    }
    /*
      Mark that we are doing something
      This will stop all KILL events until event is handled.
    */
    thd->scheduler.key= (pool_command_op) completion_key;
    pthread_mutex_unlock(&thd->scheduler.LOCK_port);

    if ((pool_command_op) completion_key == CONNECT_OP)
    {
      DBUG_PRINT("info", ("init new connection.  sd: %d",
                          thd->net.vio->sd));
      if (login_connection(thd))
      {
        /*
          iocp_unregister() below will delete thd
          close_connection() here to avoid calling end_connection() later
          in iocp_unregister()
        */
        close_connection(thd, 0, 1);
        thd->scheduler.killed= 1;
        iocp_unregister(thd);
      }
      else
      {
        prepare_new_connection_state(thd);
        (void) iocp_start_waiting_for_data(thd);
        iocp_unregister(thd);
        continue;
      }
    }

    /* Process one query (if connection is not killed) */
    terminate= TRUE;
    if (thd->net.vio != 0 && thd->killed != THD::KILL_CONNECTION)
    {
      thd->net.no_send_error= 0;
      if (do_command(thd))
        thd->scheduler.killed= TRUE;
    }
    else
      thd->scheduler.killed= TRUE;
    (void) iocp_start_waiting_for_data(thd);
    (void) iocp_unregister(thd);
  }

  DBUG_PRINT("exit", ("ending thread"));
  pthread_mutex_lock(&LOCK_thread_count);
  killed_threads++;
  pthread_cond_signal(&COND_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  my_thread_end();
  pthread_exit(0);
  DBUG_RETURN(0);                               /* purify: deadcode */
}


/*
  Wait until all pool threads has been deleted for clean shutdown
*/

static void iocp_abort_threads()
{
  DBUG_ENTER("iocp_abort_threads");
  DBUG_PRINT("enter", ("created_threads: %d  killed_threads: %u",
                       created_threads, killed_threads));

  if (completion_port)
  {
    pthread_mutex_lock(&LOCK_thread_count);
    while (killed_threads != created_threads)
    {
      if (!PostQueuedCompletionStatus(completion_port, 0, DIE_OP, 0))
        break;
      (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
    }
    pthread_mutex_unlock(&LOCK_thread_count);
    CloseHandle(completion_port);
    completion_port= 0;                         // Safety
  }
  DBUG_VOID_RETURN;
}


void pool_of_threads_scheduler(scheduler_functions* func)
{
  func->max_threads= thread_pool_size;
  func->init= iocp_init;
  func->end=  iocp_abort_threads;
  func->post_kill_notification= iocp_post_kill_notification;
  func->add_connection= iocp_add_connection;
}

#endif /* HAVE_WINSOCK2 */
#endif /* EMBEDDED_LIBRARY */

--- New file ---
+++ sql/scheduler.h	07/03/14 12:47:56
/* Copyright (C) 2007 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  Classes for the thread scheduler
*/

#ifdef USE_PRAGMA_INTERFACE
#pragma interface
#endif

class THD;

/* Functions used when manipulating threads */

class scheduler_functions
{
public:
  uint max_threads;
  bool (*init)(void);
  bool (*init_new_connection_thread)(void);
  void (*add_connection)(THD *thd);
  void (*post_kill_notification)(THD *thd);
  bool (*end_thread)(THD *thd, bool cache_thread);
  void (*end)(void);
  scheduler_functions();
};

enum scheduler_types
{
  SCHEDULER_ONE_THREAD_PER_CONNECTION=1,
  SCHEDULER_NO_THREADS,
  SCHEDULER_POOL_OF_THREADS
};

void one_thread_per_connection_scheduler(scheduler_functions* func);
void one_thread_scheduler(scheduler_functions* func);

enum pool_command_op
{
  NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
};

#if defined(HAVE_PORT_CREATE)

#define HAVE_POOL_OF_THREADS 1

/* Class that is part of THD */

class thd_scheduler
{
public:
  ulong id;

  thd_scheduler();
  ~thd_scheduler();
};

#elif defined(HAVE_WINSOCK2)

#define HAVE_POOL_OF_THREADS 1

struct MY_WSAOVERLAPPED
{
  WSAOVERLAPPED overlapped;
  THD *thd;
  WSABUF ref;
  char   data[1];
};

class thd_scheduler
{
public:
  uint in_use;
  pthread_mutex_t LOCK_port;
  HANDLE context;
  bool killed;
  pool_command_op key;              // Key for last generated operation
  /* Preallocated overlapped structures used for notification */
  MY_WSAOVERLAPPED notification, port_wait, extra_read;

  thd_scheduler();
  ~thd_scheduler();
};

#endif

/*
  Setup default defines in case we don't have a system to handle pool of
  threads
*/

#ifdef HAVE_POOL_OF_THREADS
void pool_of_threads_scheduler(scheduler_functions* func);

#else

#define HAVE_POOL_OF_THREADS 0                  /* For easyer tests */
#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A)

class thd_scheduler
{};
#endif /* HAVE_POOL_OF_THREADS */

--- New file ---
+++ sql/sql_connect.cc	07/03/14 12:47:56
/* Copyright (C) 2007 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/*
  Functions to autenticate and handle reqests for a connection
*/

#include "mysql_priv.h"

#ifdef HAVE_OPENSSL
/*
  Without SSL the handshake consists of one packet. This packet
  has both client capabilites and scrambled password.
  With SSL the handshake might consist of two packets. If the first
  packet (client capabilities) has CLIENT_SSL flag set, we have to
  switch to SSL and read the second packet. The scrambled password
  is in the second packet and client_capabilites field will be ignored.
  Maybe it is better to accept flags other than CLIENT_SSL from the
  second packet?
*/
#define SSL_HANDSHAKE_SIZE      2
#define NORMAL_HANDSHAKE_SIZE   6
#define MIN_HANDSHAKE_SIZE      2
#else
#define MIN_HANDSHAKE_SIZE      6
#endif /* HAVE_OPENSSL */

#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif

#ifdef __WIN__
static void  test_signal(int sig_ptr)
{
#if !defined( DBUG_OFF)
  MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
#if defined(OS2)
  fprintf(stderr, "Test signal %d\n", sig_ptr);
  fflush(stderr);
#endif
}
static void init_signals(void)
{
  int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
  for (int i=0 ; i < 7 ; i++)
    signal( signals[i], test_signal) ;
}
#endif

/*
  Get structure for logging connection data for the current user
*/

#ifndef NO_EMBEDDED_ACCESS_CHECKS
static HASH hash_user_connections;

static int get_or_create_user_conn(THD *thd, const char *user,
				   const char *host,
				   USER_RESOURCES *mqh)
{
  int return_val= 0;
  uint temp_len, user_len;
  char temp_user[USER_HOST_BUFF_SIZE];
  struct  user_conn *uc;

  DBUG_ASSERT(user != 0);
  DBUG_ASSERT(host != 0);

  user_len= strlen(user);
  temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1;
  (void) pthread_mutex_lock(&LOCK_user_conn);
  if (!(uc = (struct  user_conn *) hash_search(&hash_user_connections,
					       (byte*) temp_user, temp_len)))
  {
    /* First connection for user; Create a user connection object */
    if (!(uc= ((struct user_conn*)
	       my_malloc(sizeof(struct user_conn) + temp_len+1,
			 MYF(MY_WME)))))
    {
      net_send_error(thd, 0, NullS);		// Out of memory
      return_val= 1;
      goto end;
    }
    uc->user=(char*) (uc+1);
    memcpy(uc->user,temp_user,temp_len+1);
    uc->host= uc->user + user_len +  1;
    uc->len= temp_len;
    uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0;
    uc->user_resources= *mqh;
    uc->intime= thd->thr_create_time;
    if (my_hash_insert(&hash_user_connections, (byte*) uc))
    {
      my_free((char*) uc,0);
      net_send_error(thd, 0, NullS);		// Out of memory
      return_val= 1;
      goto end;
    }
  }
  thd->user_connect=uc;
  uc->connections++;
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  return return_val;

}


/*
  check if user has already too many connections
  
  SYNOPSIS
  check_for_max_user_connections()
  thd			Thread handle
  uc			User connect object

  NOTES
    If check fails, we decrease user connection count, which means one
    shouldn't call decrease_user_connections() after this function.

  RETURN
    0	ok
    1	error
*/

int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
  int error=0;
  DBUG_ENTER("check_for_max_user_connections");

  (void) pthread_mutex_lock(&LOCK_user_conn);
  if (max_user_connections && !uc->user_resources.user_conn &&
      max_user_connections < (uint) uc->connections)
  {
    net_printf_error(thd, ER_TOO_MANY_USER_CONNECTIONS, uc->user);
    error=1;
    goto end;
  }
  time_out_user_resource_limits(thd, uc);
  if (uc->user_resources.user_conn &&
      uc->user_resources.user_conn < uc->connections)
  {
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
                     "max_user_connections",
                     (long) uc->user_resources.user_conn);
    error= 1;
    goto end;
  }
  if (uc->user_resources.conn_per_hour &&
      uc->user_resources.conn_per_hour <= uc->conn_per_hour)
  {
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user,
                     "max_connections_per_hour",
                     (long) uc->user_resources.conn_per_hour);
    error=1;
    goto end;
  }
  uc->conn_per_hour++;

  end:
  if (error)
    uc->connections--; // no need for decrease_user_connections() here
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  DBUG_RETURN(error);
}


/*
  Decrease user connection count

  SYNOPSIS
    decrease_user_connections()
    uc			User connection object

  NOTES
    If there is a n user connection object for a connection
    (which only happens if 'max_user_connections' is defined or
    if someone has created a resource grant for a user), then
    the connection count is always incremented on connect.

    The user connect object is not freed if some users has
    'max connections per hour' defined as we need to be able to hold
    count over the lifetime of the connection.
*/

void decrease_user_connections(USER_CONN *uc)
{
  DBUG_ENTER("decrease_user_connections");
  (void) pthread_mutex_lock(&LOCK_user_conn);
  DBUG_ASSERT(uc->connections);
  if (!--uc->connections && !mqh_used)
  {
    /* Last connection for user; Delete it */
    (void) hash_delete(&hash_user_connections,(byte*) uc);
  }
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  DBUG_VOID_RETURN;
}


/*
  Reset per-hour user resource limits when it has been more than
  an hour since they were last checked

  SYNOPSIS:
    time_out_user_resource_limits()
    thd			Thread handler
    uc			User connection details

  NOTE:
    This assumes that the LOCK_user_conn mutex has been acquired, so it is
    safe to test and modify members of the USER_CONN structure.
*/

void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
{
  time_t check_time = thd->start_time ?  thd->start_time : time(NULL);
  DBUG_ENTER("time_out_user_resource_limits");

  /* If more than a hour since last check, reset resource checking */
  if (check_time  - uc->intime >= 3600)
  {
    uc->questions=1;
    uc->updates=0;
    uc->conn_per_hour=0;
    uc->intime=check_time;
  }

  DBUG_VOID_RETURN;
}

/*
  Check if maximum queries per hour limit has been reached
  returns 0 if OK.
*/

bool check_mqh(THD *thd, uint check_command)
{
  bool error= 0;
  USER_CONN *uc=thd->user_connect;
  DBUG_ENTER("check_mqh");
  DBUG_ASSERT(uc != 0);

  (void) pthread_mutex_lock(&LOCK_user_conn);

  time_out_user_resource_limits(thd, uc);

  /* Check that we have not done too many questions / hour */
  if (uc->user_resources.questions &&
      uc->questions++ >= uc->user_resources.questions)
  {
    net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
                     (long) uc->user_resources.questions);
    error=1;
    goto end;
  }
  if (check_command < (uint) SQLCOM_END)
  {
    /* Check that we have not done too many updates / hour */
    if (uc->user_resources.updates && uc_update_queries[check_command]
&&
	uc->updates++ >= uc->user_resources.updates)
    {
      net_printf_error(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
                       (long) uc->user_resources.updates);
      error=1;
      goto end;
    }
  }
end:
  (void) pthread_mutex_unlock(&LOCK_user_conn);
  DBUG_RETURN(error);
}

#endif /* NO_EMBEDDED_ACCESS_CHECKS */


/*
  Check if user exist and password supplied is correct. 

  SYNOPSIS
    check_user()
    thd          thread handle, thd->security_ctx->{host,user,ip} are used
    command      originator of the check: now check_user is called
                 during connect and change user procedures; used for 
                 logging.
    passwd       scrambled password received from client
    passwd_len   length of scrambled password
    db           database name to connect to, may be NULL
    check_count  dont know exactly

    Note, that host, user and passwd may point to communication buffer.
    Current implementation does not depend on that, but future changes
    should be done with this in mind; 'thd' is INOUT, all other params
    are 'IN'.

  RETURN VALUE
    0  OK; thd->security_ctx->user/master_access/priv_user/db_access and
       thd->db are updated; OK is sent to client;
   -1  access denied or handshake error; error is sent to client;
   >0  error, not sent to client
*/

int check_user(THD *thd, enum enum_server_command command, 
	       const char *passwd, uint passwd_len, const char *db,
	       bool check_count)
{
  DBUG_ENTER("check_user");
  
#ifdef NO_EMBEDDED_ACCESS_CHECKS
  thd->main_security_ctx.master_access= GLOBAL_ACLS;       // Full rights
  /* Change database if necessary */
  if (db && db[0])
  {
    /*
      thd->db is saved in caller and needs to be freed by caller if this
      function returns 0
    */
    thd->reset_db(NULL, 0);
    if (mysql_change_db(thd, db, FALSE))
    {
      /* Send the error to the client */
      net_send_error(thd);
      DBUG_RETURN(-1);
    }
  }
  send_ok(thd);
  DBUG_RETURN(0);
#else

  my_bool opt_secure_auth_local;
  pthread_mutex_lock(&LOCK_global_system_variables);
  opt_secure_auth_local= opt_secure_auth;
  pthread_mutex_unlock(&LOCK_global_system_variables);
  
  /*
    If the server is running in secure auth mode, short scrambles are 
    forbidden.
  */
  if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
  {
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
  }
  if (passwd_len != 0 &&
      passwd_len != SCRAMBLE_LENGTH &&
      passwd_len != SCRAMBLE_LENGTH_323)
    DBUG_RETURN(ER_HANDSHAKE_ERROR);

  /*
    Clear thd->db as it points to something, that will be freed when 
    connection is closed. We don't want to accidentally free a wrong pointer
    if connect failed. Also in case of 'CHANGE USER' failure, current
    database will be switched to 'no database selected'.
  */
  thd->reset_db(NULL, 0);

  USER_RESOURCES ur;
  int res= acl_getroot(thd, &ur, passwd, passwd_len);
#ifndef EMBEDDED_LIBRARY
  if (res == -1)
  {
    /*
      This happens when client (new) sends password scrambled with
      scramble(), but database holds old value (scrambled with
      scramble_323()). Here we please client to send scrambled_password
      in old format.
    */
    NET *net= &thd->net;
    if (opt_secure_auth_local)
    {
      net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
                       thd->main_security_ctx.user,
                       thd->main_security_ctx.host_or_ip);
      mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
                      thd->main_security_ctx.user,
                      thd->main_security_ctx.host_or_ip);
      DBUG_RETURN(-1);
    }
    /* We have to read very specific packet size */
    if (send_old_password_request(thd) ||
        my_net_read(net) != SCRAMBLE_LENGTH_323 + 1)
    {
      inc_host_errors(&thd->remote.sin_addr);
      DBUG_RETURN(ER_HANDSHAKE_ERROR);
    }
    /* Final attempt to check the user based on reply */
    /* So as passwd is short, errcode is always >= 0 */
    res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
  }
#endif /*EMBEDDED_LIBRARY*/
  /* here res is always >= 0 */
  if (res == 0)
  {
    if (!(thd->main_security_ctx.master_access &
          NO_ACCESS)) // authentication is OK
    {
      DBUG_PRINT("info",
                 ("Capabilities: %lu  packet_length: %ld  Host: '%s'  "
                  "Login user: '%s' Priv_user: '%s'  Using password: %s "
                  "Access: %lu  db: '%s'",
                  thd->client_capabilities,
                  thd->max_client_packet_length,
                  thd->main_security_ctx.host_or_ip,
                  thd->main_security_ctx.user,
                  thd->main_security_ctx.priv_user,
                  passwd_len ? "yes": "no",
                  thd->main_security_ctx.master_access,
                  (thd->db ? thd->db : "*none*")));

      if (check_count)
      {
        VOID(pthread_mutex_lock(&LOCK_thread_count));
        bool count_ok= thread_count <= max_connections + delayed_insert_threads
                       || (thd->main_security_ctx.master_access & SUPER_ACL);
        VOID(pthread_mutex_unlock(&LOCK_thread_count));
        if (!count_ok)
        {                                         // too many connections
          net_send_error(thd, ER_CON_COUNT_ERROR);
          DBUG_RETURN(-1);
        }
      }

      /* Why logging is performed before all checks've passed? */
      mysql_log.write(thd, command,
                      (thd->main_security_ctx.priv_user ==
                       thd->main_security_ctx.user ?
                       (char*) "%s@%s on %s" :
                       (char*) "%s@%s as anonymous on %s"),
                      thd->main_security_ctx.user,
                      thd->main_security_ctx.host_or_ip,
                      db ? db : (char*) "");

      /*
        This is the default access rights for the current database.  It's
        set to 0 here because we don't have an active database yet (and we
        may not have an active database to set.
      */
      thd->main_security_ctx.db_access=0;

      /* Don't allow user to connect if he has done too many queries */
      if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
	   max_user_connections) &&
	  get_or_create_user_conn(thd,
            (opt_old_style_user_limits ? thd->main_security_ctx.user :
             thd->main_security_ctx.priv_user),
            (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip :
             thd->main_security_ctx.priv_host),
            &ur))
	DBUG_RETURN(-1);
      if (thd->user_connect &&
	  (thd->user_connect->user_resources.conn_per_hour ||
	   thd->user_connect->user_resources.user_conn ||
	   max_user_connections) &&
	  check_for_max_user_connections(thd, thd->user_connect))
	DBUG_RETURN(-1);

      /* Change database if necessary */
      if (db && db[0])
      {
        if (mysql_change_db(thd, db, FALSE))
        {
          /* Send error to the client */
          net_send_error(thd);
          if (thd->user_connect)
            decrease_user_connections(thd->user_connect);
          DBUG_RETURN(-1);
        }
      }
      send_ok(thd);
      thd->password= test(passwd_len);          // remember for error messages 
      /* Ready to handle queries */
      DBUG_RETURN(0);
    }
  }
  else if (res == 2) // client gave short hash, server has long hash
  {
    net_printf_error(thd, ER_NOT_SUPPORTED_AUTH_MODE);
    mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
    DBUG_RETURN(-1);
  }
  net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
                   thd->main_security_ctx.user,
                   thd->main_security_ctx.host_or_ip,
                   passwd_len ? ER(ER_YES) : ER(ER_NO));
  mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
                  thd->main_security_ctx.user,
                  thd->main_security_ctx.host_or_ip,
                  passwd_len ? ER(ER_YES) : ER(ER_NO));
  DBUG_RETURN(-1);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}


/*
  Check for maximum allowable user connections, if the mysqld server is
  started with corresponding variable that is greater then 0.
*/

extern "C" byte *get_key_conn(user_conn *buff, uint *length,
			      my_bool not_used __attribute__((unused)))
{
  *length=buff->len;
  return (byte*) buff->user;
}


extern "C" void free_user(struct user_conn *uc)
{
  my_free((char*) uc,MYF(0));
}


void init_max_user_conn(void)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
		   0,0,
		   (hash_get_key) get_key_conn, (hash_free_key) free_user,
		   0);
#endif
}


void free_max_user_conn(void)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  hash_free(&hash_user_connections);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}


void reset_mqh(LEX_USER *lu, bool get_them= 0)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  (void) pthread_mutex_lock(&LOCK_user_conn);
  if (lu)  // for GRANT
  {
    USER_CONN *uc;
    uint temp_len=lu->user.length+lu->host.length+2;
    char temp_user[USER_HOST_BUFF_SIZE];

    memcpy(temp_user,lu->user.str,lu->user.length);
    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
    if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
						(byte*) temp_user, temp_len)))
    {
      uc->questions=0;
      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
      uc->updates=0;
      uc->conn_per_hour=0;
    }
  }
  else
  {
    /* for FLUSH PRIVILEGES and FLUSH USER_RESOURCES */
    for (uint idx=0;idx < hash_user_connections.records; idx++)
    {
      USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
						      idx);
      if (get_them)
	get_mqh(uc->user,uc->host,uc);
      uc->questions=0;
      uc->updates=0;
      uc->conn_per_hour=0;
    }
  }
  (void) pthread_mutex_unlock(&LOCK_user_conn);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}


void thd_init_client_charset(THD *thd, uint cs_number)
{
  /*
   Use server character set and collation if
   - opt_character_set_client_handshake is not set
   - client has not specified a character set
   - client character set is the same as the servers
   - client character set doesn't exists in server
  */
  if (!opt_character_set_client_handshake ||
      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
      !my_strcasecmp(&my_charset_latin1,
                     global_system_variables.character_set_client->name,
                     thd->variables.character_set_client->name))
  {
    thd->variables.character_set_client=
      global_system_variables.character_set_client;
    thd->variables.collation_connection=
      global_system_variables.collation_connection;
    thd->variables.character_set_results=
      global_system_variables.character_set_results;
  }
  else
  {
    thd->variables.character_set_results=
      thd->variables.collation_connection= 
      thd->variables.character_set_client;
  }
}


/*
  Initialize connection threads
*/

bool init_new_connection_handler_thread()
{
  pthread_detach_this_thread();
#if defined(__WIN__)
  init_signals();
#endif
#if !defined( __WIN__) && !defined(OS2)	// Win32 calls this in pthread_create
  if (my_thread_init())
    return 1;
#endif
  return 0;
}


/*
  Perform handshake, authorize client and update thd ACL variables.

  SYNOPSIS
    check_connection()
    thd  thread handle

  RETURN
     0  success, OK is sent to user, thd is updated.
    -1  error, which is sent to user
   > 0  error code (not sent to user)
*/

#ifndef EMBEDDED_LIBRARY
static int check_connection(THD *thd)
{
  uint connect_errors= 0;
  NET *net= &thd->net;
  ulong pkt_len= 0;
  char *end;

  DBUG_PRINT("info",
             ("New connection received on %s", vio_description(net->vio)));
#ifdef SIGNAL_WITH_VIO_CLOSE
  thd->set_active_vio(net->vio);
#endif

  if (!thd->main_security_ctx.host)         // If TCP/IP connection
  {
    char ip[30];

    if (vio_peer_addr(net->vio, ip, &thd->peer_port))
      return (ER_BAD_HOST_ERROR);
    if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0))))
      return (ER_OUT_OF_RESOURCES);
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
    vio_in_addr(net->vio,&thd->remote.sin_addr);
    if (!(specialflag & SPECIAL_NO_RESOLVE))
    {
      vio_in_addr(net->vio,&thd->remote.sin_addr);
      thd->main_security_ctx.host=
        ip_to_hostname(&thd->remote.sin_addr, &connect_errors);
      /* Cut very long hostnames to avoid possible overflows */
      if (thd->main_security_ctx.host)
      {
        if (thd->main_security_ctx.host != my_localhost)
          thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host),
                                          HOSTNAME_LENGTH)]= 0;
        thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
      }
      if (connect_errors > max_connect_errors)
        return(ER_HOST_IS_BLOCKED);
    }
    DBUG_PRINT("info",("Host: %s  ip: %s",
		       (thd->main_security_ctx.host ?
                        thd->main_security_ctx.host : "unknown host"),
		       (thd->main_security_ctx.ip ?
                        thd->main_security_ctx.ip : "unknown ip")));
    if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
      return(ER_HOST_NOT_PRIVILEGED);
  }
  else /* Hostname given means that the connection was on a socket */
  {
    DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
    thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
    thd->main_security_ctx.ip= 0;
    /* Reset sin_addr */
    bzero((char*) &thd->remote, sizeof(thd->remote));
  }
  vio_keepalive(net->vio, TRUE);
  {
    /* buff[] needs to big enough to hold the server_version variable */
    char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
    ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
			  CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);

    if (opt_using_transactions)
      client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
    client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
#ifdef HAVE_OPENSSL
    if (ssl_acceptor_fd)
      client_flags |= CLIENT_SSL;       /* Wow, SSL is available! */
#endif /* HAVE_OPENSSL */

    end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
    int4store((uchar*) end, thd->thread_id);
    end+= 4;
    /*
      So as check_connection is the only entry point to authorization
      procedure, scramble is set here. This gives us new scramble for
      each handshake.
    */
    create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
    /*
      Old clients does not understand long scrambles, but can ignore packet
      tail: that's why first part of the scramble is placed here, and second
      part at the end of packet.
    */
    end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
   
    int2store(end, client_flags);
    /* write server characteristics: up to 16 bytes allowed */
    end[2]=(char) default_charset_info->number;
    int2store(end+3, thd->server_status);
    bzero(end+5, 13);
    end+= 18;
    /* write scramble tail */
    end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, 
                 SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;

    /* At this point we write connection message and read reply */
    if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
			  (uint) (end-buff)) ||
	(pkt_len= my_net_read(net)) == packet_error ||
	pkt_len < MIN_HANDSHAKE_SIZE)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
#ifdef _CUSTOMCONFIG_
#include "_cust_sql_parse.h"
#endif
  if (connect_errors)
    reset_host_errors(&thd->remote.sin_addr);
  if (thd->packet.alloc(thd->variables.net_buffer_length))
    return(ER_OUT_OF_RESOURCES);

  thd->client_capabilities=uint2korr(net->read_pos);
  if (thd->client_capabilities & CLIENT_PROTOCOL_41)
  {
    thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
    thd->max_client_packet_length= uint4korr(net->read_pos+4);
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
    thd_init_client_charset(thd, (uint) net->read_pos[8]);
    thd->update_charset();
    end= (char*) net->read_pos+32;
  }
  else
  {
    thd->max_client_packet_length= uint3korr(net->read_pos+2);
    end= (char*) net->read_pos+5;
  }

  if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
    thd->variables.sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
  DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
  if (thd->client_capabilities & CLIENT_SSL)
  {
    /* Do the SSL layering. */
    if (!ssl_acceptor_fd)
    {
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
    DBUG_PRINT("info", ("IO layer change in progress..."));
    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
    {
      DBUG_PRINT("error", ("Failed to accept new SSL connection"));
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
    DBUG_PRINT("info", ("Reading user information over SSL layer"));
    if ((pkt_len= my_net_read(net)) == packet_error ||
	pkt_len < NORMAL_HANDSHAKE_SIZE)
    {
      DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
			   pkt_len));
      inc_host_errors(&thd->remote.sin_addr);
      return(ER_HANDSHAKE_ERROR);
    }
  }
#endif /* HAVE_OPENSSL */

  if (end >= (char*) net->read_pos+ pkt_len +2)
  {
    inc_host_errors(&thd->remote.sin_addr);
    return(ER_HANDSHAKE_ERROR);
  }

  if (thd->client_capabilities & CLIENT_INTERACTIVE)
    thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
  if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
      opt_using_transactions)
    net->return_status= &thd->server_status;
  net->read_timeout=(uint) thd->variables.net_read_timeout;

  char *user= end;
  char *passwd= strend(user)+1;
  uint user_len= passwd - user - 1;
  char *db= passwd;
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
  char user_buff[USERNAME_LENGTH + 1];	// buffer to store user in utf8
  uint dummy_errors;

  /*
    Old clients send null-terminated string as password; new clients send
    the size (1 byte) + string (not null-terminated). Hence in case of empty
    password both send '\0'.
  */
  uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
    *passwd++ : strlen(passwd);
  db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
  uint db_len= db ? strlen(db) : 0;

  if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
  {
    inc_host_errors(&thd->remote.sin_addr);
    return ER_HANDSHAKE_ERROR;
  }

  /* Since 4.1 all database names are stored in utf8 */
  if (db)
  {
    db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                             system_charset_info,
                             db, db_len,
                             thd->charset(), &dummy_errors)]= 0;
    db= db_buff;
  }

  user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
                                       system_charset_info, user, user_len,
                                       thd->charset(), &dummy_errors)]= '\0';
  user= user_buff;

  /* If username starts and ends in "'", chop them off */
  if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
  {
    user[user_len-1]= 0;
    user++;
    user_len-= 2;
  }

  if (thd->main_security_ctx.user)
    x_free(thd->main_security_ctx.user);
  if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0))))
    return (ER_OUT_OF_RESOURCES);
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
}


/*
  Initialize THD to handle queries
*/

void prepare_new_connection_state(THD* thd)
{
  Security_context *sctx= thd->security_ctx;

#ifdef __NETWARE__
  netware_reg_user(sctx->ip, sctx->user, "MySQL");
#endif

  if (thd->variables.max_join_size == HA_POS_ERROR)
    thd->options |= OPTION_BIG_SELECTS;
  if (thd->client_capabilities & CLIENT_COMPRESS)
    thd->net.compress=1;				// Use compression

  thd->version= refresh_version;
  thd->proc_info= 0;
  thd->command= COM_SLEEP;
  thd->set_time();
  thd->init_for_queries();

  if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
  {
    execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
    if (thd->query_error)
    {
      thd->killed= THD::KILL_CONNECTION;
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
                        sctx->user ? sctx->user : "unauthenticated",
                        sctx->host_or_ip, "init_connect command failed");
      sql_print_warning("%s", thd->net.last_error);
    }
    thd->proc_info=0;
    thd->set_time();
    thd->init_for_queries();
  }
}


/*
  Setup thread to be used with the current thread

  SYNOPSIS
    bool setup_connection_thread_globals()
    thd    Thread/connection handler

  RETURN
    0   ok
    1   Error (out of memory)
        In this case we will close the connection and increment status
*/

bool setup_connection_thread_globals(THD *thd)
{
  if (thd->store_globals())
  {
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
    statistic_increment(aborted_connects,&LOCK_status);
    thread_scheduler.end_thread(thd, 0);
    return 1;                                   // Error
  }
  return 0;
}


/*
  Autenticate user, with error reporting

  SYNOPSIS
   login_connection()
   thd        Thread handler

  NOTES
    Connection is not closed in case of errors

  RETURN
    0    ok
    1    error
*/


bool login_connection(THD *thd)
{
  int error;
  NET *net= &thd->net;
  Security_context *sctx= thd->security_ctx;
  DBUG_ENTER("login_connection");
  DBUG_PRINT("info", ("handle_one_connection called by thread %lu",
                      thd->thread_id));

  net->no_send_error= 0;
  if ((error=check_connection(thd)))
  {						// Wrong permissions
    if (error > 0)
      net_printf_error(thd, error, sctx->host_or_ip);
#ifdef __NT__
    if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
      my_sleep(1000);				/* must wait after eof() */
#endif
    statistic_increment(aborted_connects,&LOCK_status);
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


/*
  Close an established connection

  NOTES
    This mainly updates status variables
*/

void end_connection(THD *thd)
{
  NET *net= &thd->net;
  if (thd->user_connect)
    decrease_user_connections(thd->user_connect);
  if (net->error && net->vio != 0 && net->report_error)
  {
    Security_context *sctx= thd->security_ctx;
    if (!thd->killed && thd->variables.log_warnings > 1)
      sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
                        thd->thread_id,(thd->db ? thd->db : "unconnected"),
                        sctx->user ? sctx->user : "unauthenticated",
                        sctx->host_or_ip,
                        (net->last_errno ? ER(net->last_errno) :
                         ER(ER_UNKNOWN_ERROR)));
    net_send_error(thd, net->last_errno, NullS);
    statistic_increment(aborted_threads,&LOCK_status);
  }
  else if (thd->killed)
    statistic_increment(aborted_threads,&LOCK_status);
}


/*
  Thread handler for a connection

  SYNOPSIS
    handle_one_connection()
    arg		Connection object (THD)

  IMPLEMENTATION
    This function (normally) does the following:
    - Initialize thread
    - Initialize THD to be used with this thread
    - Authenticate user
    - Execute all queries sent on the connection
    - Take connection down
    - End thread  / Handle next connection using thread from thread cache
*/

pthread_handler_t handle_one_connection(void *arg)
{
  THD *thd=(THD*) arg;
  uint launch_time  =
    (uint) ((thd->thr_create_time = time(NULL)) - thd->connect_time);

  if (init_new_connection_handler_thread())
  {
    close_connection(thd, ER_OUT_OF_RESOURCES, 1);
    statistic_increment(aborted_connects,&LOCK_status);
    thread_scheduler.end_thread(thd,0);
    return 0;
  }
  if (launch_time >= slow_launch_time)
    statistic_increment(slow_launch_threads,&LOCK_status);

  /*
    handle_one_connection() is normally the only way a thread would
    start and would always be on the very high end of the stack ,
    therefore, the thread stack always starts at the address of the
    first local variable of handle_one_connection, which is thd. We
    need to know the start of the stack so that we could check for
    stack overruns.
  */
  thd->thread_stack= (char*) &thd;
  if (setup_connection_thread_globals(thd))
    return 0;

  for (;;)
  {
    NET *net= &thd->net;
    if (login_connection(thd))
      goto end_thread;

    prepare_new_connection_state(thd);

    while (!net->error && net->vio != 0 &&
           !(thd->killed == THD::KILL_CONNECTION))
    {
      net->no_send_error= 0;
      if (do_command(thd))
	break;
    }
    end_connection(thd);
   
end_thread:
    close_connection(thd, 0, 1);
    if (thread_scheduler.end_thread(thd,1))
      return 0;                                 // Probably no-threads

    /*
      If end_thread() returns, we are either running with
      thread-handler=no-threads or this thread has been schedule to
      handle the next connection.
    */
    thd= current_thd;
    thd->thread_stack= (char*) &thd;
  }
}
#endif /* EMBEDDED_LIBRARY */


--- 1.72/libmysqld/Makefile.am	2006-12-30 22:02:04 +02:00
+++ 1.73/libmysqld/Makefile.am	2007-03-14 12:47:54 +02:00
@@ -55,7 +55,8 @@
 	sql_load.cc discover.cc sql_locale.cc \
 	sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
 	sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
-	sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc sql_parse.cc \
+	sql_lex.cc sql_list.cc sql_manager.cc sql_map.cc \
+	scheduler.cc sql_connect.cc sql_parse.cc \
 	sql_prepare.cc sql_derived.cc sql_rename.cc \
 	sql_select.cc sql_do.cc sql_show.cc set_var.cc \
 	sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \

--- 1.126/libmysqld/lib_sql.cc	2007-01-22 14:10:36 +02:00
+++ 1.127/libmysqld/lib_sql.cc	2007-03-14 12:47:54 +02:00
@@ -34,11 +34,6 @@
 #include "../sql/mysqld.cc"
 #endif
 
-int check_user(THD *thd, enum enum_server_command command, 
-	       const char *passwd, uint passwd_len, const char *db,
-	       bool check_count);
-void thd_init_client_charset(THD *thd, uint cs_number);
-
 C_MODE_START
 
 #include <mysql.h>
@@ -575,10 +570,6 @@
     fprintf(stderr,"store_globals failed.\n");
     goto err;
   }
-
-  thd->mysys_var= my_thread_var;
-  thd->dbug_thread_id= my_thread_id();
-  thd->thread_stack= (char*) &thd;
 
 /* TODO - add init_connect command execution */
 

--- 1.275/client/mysqltest.c	2007-01-22 14:10:36 +02:00
+++ 1.276/client/mysqltest.c	2007-03-14 12:47:54 +02:00
@@ -406,7 +406,8 @@
 TYPELIB command_typelib= {array_elements(command_names),"",
 			  command_names, 0};
 
-DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
+static DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
+static DYNAMIC_STRING global_ds_warnings, global_eval_query;
 
 void die(const char *fmt, ...)
   ATTRIBUTE_FORMAT(printf, 1, 2);
@@ -780,6 +781,9 @@
   dynstr_free(&ds_res);
   dynstr_free(&ds_progress);
   dynstr_free(&ds_warning_messages);
+  dynstr_free(&global_ds_warnings);
+  dynstr_free(&global_eval_query);
+
   free_all_replace();
   my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR));
   free_defaults(default_argv);
@@ -1844,7 +1848,7 @@
 
 void do_chmod_file(struct st_command *command)
 {
-  ulong mode= 0;
+  long mode= 0;
   static DYNAMIC_STRING ds_mode;
   static DYNAMIC_STRING ds_file;
   const struct command_arg chmod_file_args[] = {
@@ -5184,8 +5188,6 @@
   MYSQL *mysql= &cn->mysql;
   DYNAMIC_STRING *ds;
   DYNAMIC_STRING ds_result;
-  DYNAMIC_STRING ds_warnings;
-  DYNAMIC_STRING eval_query;
   char *query;
   int query_len;
   my_bool view_created= 0, sp_created= 0;
@@ -5193,7 +5195,7 @@
                            (flags & QUERY_REAP_FLAG));
   DBUG_ENTER("run_query");
 
-  init_dynamic_string(&ds_warnings, NULL, 0, 256);
+  init_dynamic_string(&global_ds_warnings, NULL, 0, 256);
 
   /* Scan for warning before sendign to server */
   scan_command_for_warnings(command);
@@ -5203,10 +5205,10 @@
   */
   if (command->type == Q_EVAL)
   {
-    init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
-    do_eval(&eval_query, command->query, command->end, FALSE);
-    query = eval_query.str;
-    query_len = eval_query.length;
+    init_dynamic_string(&global_eval_query, "", command->query_len+256, 1024);
+    do_eval(&global_eval_query, command->query, command->end, FALSE);
+    query = global_eval_query.str;
+    query_len = global_eval_query.length;
   }
   else
   {
@@ -5278,7 +5280,7 @@
         Collect warnings from create of the view that should otherwise
         have been produced when the SELECT was executed
       */
-      append_warnings(&ds_warnings, cur_con->util_mysql);
+      append_warnings(&global_ds_warnings, cur_con->util_mysql);
     }
 
     dynstr_free(&query_str);
@@ -5337,10 +5339,10 @@
   if (ps_protocol_enabled &&
       complete_query &&
       match_re(&ps_re, query))
-    run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings);
+    run_query_stmt(mysql, command, query, query_len, ds, &global_ds_warnings);
   else
     run_query_normal(cn, command, flags, query, query_len,
-		     ds, &ds_warnings);
+		     ds, &global_ds_warnings);
 
   if (sp_created)
   {
@@ -5364,11 +5366,11 @@
     check_require(ds, command->require_file);
   }
 
-  dynstr_free(&ds_warnings);
+  dynstr_free(&global_ds_warnings);
   if (ds == &ds_result)
     dynstr_free(&ds_result);
   if (command->type == Q_EVAL)
-    dynstr_free(&eval_query);
+    dynstr_free(&global_eval_query);
   DBUG_VOID_RETURN;
 }
 

--- 1.240/BitKeeper/etc/ignore	2007-01-22 12:56:22 +02:00
+++ 1.241/BitKeeper/etc/ignore	2007-02-20 17:47:23 +02:00
@@ -1334,3 +1334,5 @@
 zlib/*.ds?
 zlib/*.vcproj
 mysql-test/mysql-test-run-shell
+libmysqld/scheduler.cc
+libmysqld/sql_connect.cc

--- 1.64/sql/repl_failsafe.cc	2007-01-22 14:10:40 +02:00
+++ 1.65/sql/repl_failsafe.cc	2007-03-14 12:47:55 +02:00
@@ -70,22 +70,18 @@
   thd->net.read_timeout = slave_net_timeout;
   thd->max_client_packet_length=thd->net.max_packet;
   pthread_mutex_lock(&LOCK_thread_count);
-  thd->thread_id = thread_id++;
+  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
   pthread_mutex_unlock(&LOCK_thread_count);
 
   if (init_thr_lock() || thd->store_globals())
   {
+    /* purecov: begin inspected */
     close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
     statistic_increment(aborted_connects,&LOCK_status);
-    end_thread(thd,0);
+    one_thread_per_connection_end(thd,0);
     DBUG_RETURN(-1);
+    /* purecov: end */
   }
-
-#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
-  sigset_t set;
-  VOID(sigemptyset(&set));			// Get mask in use
-  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
 
   thd->mem_root->free= thd->mem_root->used= 0;
   if (thd->variables.max_join_size == HA_POS_ERROR)

--- 1.22/extra/yassl/src/ssl.cpp	2006-12-14 00:30:17 +02:00
+++ 1.23/extra/yassl/src/ssl.cpp	2007-03-14 12:47:54 +02:00
@@ -46,6 +46,7 @@
 #include "coding.hpp"           // HexDecoder
 #include "helpers.hpp"          // for placement new hack
 #include <stdio.h>
+#include <assert.h>
 
 #ifdef _WIN32
     #include <windows.h>    // FindFirstFile etc..
@@ -64,6 +65,9 @@
 {
     if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM)
         return SSL_BAD_FILETYPE;
+
+    if (file == NULL || !file[0])
+      return SSL_BAD_FILE;
 
     FILE* input = fopen(file, "rb");
     if (!input)

--- 1.30/vio/viosslfactories.c	2006-12-23 21:04:31 +02:00
+++ 1.31/vio/viosslfactories.c	2007-03-14 12:47:56 +02:00
@@ -229,6 +229,14 @@
   DH *dh;
   struct st_VioSSLFd *ssl_fd;
   DBUG_ENTER("new_VioSSLFd");
+  DBUG_PRINT("enter",
+             ("key_file: '%s'  cert_file: '%s'  ca_file: '%s'  ca_path: '%s'  "
+              "cipher: '%s'",
+              key_file ? key_file : "NULL",
+              cert_file ? cert_file : "NULL",
+              ca_file ? ca_file : "NULL",
+              ca_path ? ca_path : "NULL",
+              cipher ? cipher : "NULL"));
 
   check_ssl_init();
 
Thread
bk commit into 5.0 tree (monty:1.2387)monty14 Mar