summaryrefslogtreecommitdiff
path: root/storage/innodb_plugin/ut
diff options
context:
space:
mode:
authorSatya B <satya.bn@sun.com>2009-05-27 15:15:59 +0530
committerSatya B <satya.bn@sun.com>2009-05-27 15:15:59 +0530
commit3945d5e5549187a18c64a112899f90a7f6a320d6 (patch)
tree1857c73fc15e12543e009c30aeac2d2463f284fb /storage/innodb_plugin/ut
parent74a495cc81e5cebd56b99acf090b9d5436866b7e (diff)
downloadmariadb-git-3945d5e5549187a18c64a112899f90a7f6a320d6.tar.gz
Adding innodb_plugin-1.0.4 as storage/innodb_plugin.
Diffstat (limited to 'storage/innodb_plugin/ut')
-rw-r--r--storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_gcc.c43
-rw-r--r--storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c34
-rw-r--r--storage/innodb_plugin/ut/ut0auxconf_have_solaris_atomics.c39
-rw-r--r--storage/innodb_plugin/ut/ut0auxconf_sizeof_pthread_t.c35
-rw-r--r--storage/innodb_plugin/ut/ut0byte.c55
-rw-r--r--storage/innodb_plugin/ut/ut0dbg.c187
-rw-r--r--storage/innodb_plugin/ut/ut0list.c194
-rw-r--r--storage/innodb_plugin/ut/ut0mem.c706
-rw-r--r--storage/innodb_plugin/ut/ut0rnd.c97
-rw-r--r--storage/innodb_plugin/ut/ut0ut.c598
-rw-r--r--storage/innodb_plugin/ut/ut0vec.c79
-rw-r--r--storage/innodb_plugin/ut/ut0wqueue.c118
12 files changed, 2185 insertions, 0 deletions
diff --git a/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_gcc.c b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_gcc.c
new file mode 100644
index 00000000000..30de5aa6f17
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_gcc.c
@@ -0,0 +1,43 @@
+/*****************************************************************************
+
+Copyright (c) 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*****************************************************************************
+If this program compiles, then pthread_t objects can be used as arguments
+to GCC atomic builtin functions.
+
+Created March 5, 2009 Vasil Dimov
+*****************************************************************************/
+
+#include <pthread.h>
+#include <string.h>
+
+int
+main(int argc, char** argv)
+{
+ pthread_t x1;
+ pthread_t x2;
+ pthread_t x3;
+
+ memset(&x1, 0x0, sizeof(x1));
+ memset(&x2, 0x0, sizeof(x2));
+ memset(&x3, 0x0, sizeof(x3));
+
+ __sync_bool_compare_and_swap(&x1, x2, x3);
+
+ return(0);
+}
diff --git a/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c
new file mode 100644
index 00000000000..a18a537d1d4
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c
@@ -0,0 +1,34 @@
+/*****************************************************************************
+
+Copyright (c) 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*****************************************************************************
+If this program compiles, then pthread_t objects can be used as arguments
+to Solaris libc atomic functions.
+
+Created April 18, 2009 Vasil Dimov
+*****************************************************************************/
+
+#include <pthread.h>
+
+int
+main(int argc, char** argv)
+{
+ pthread_t x = 0;
+
+ return(0);
+}
diff --git a/storage/innodb_plugin/ut/ut0auxconf_have_solaris_atomics.c b/storage/innodb_plugin/ut/ut0auxconf_have_solaris_atomics.c
new file mode 100644
index 00000000000..7eb704edd4b
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0auxconf_have_solaris_atomics.c
@@ -0,0 +1,39 @@
+/*****************************************************************************
+
+Copyright (c) 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*****************************************************************************
+If this program compiles, then Solaris libc atomic funcions are available.
+
+Created April 18, 2009 Vasil Dimov
+*****************************************************************************/
+#include <atomic.h>
+
+int
+main(int argc, char** argv)
+{
+ ulong_t ulong = 0;
+ uint32_t uint32 = 0;
+ uint64_t uint64 = 0;
+
+ atomic_cas_ulong(&ulong, 0, 1);
+ atomic_cas_32(&uint32, 0, 1);
+ atomic_cas_64(&uint64, 0, 1);
+ atomic_add_long(&ulong, 0);
+
+ return(0);
+}
diff --git a/storage/innodb_plugin/ut/ut0auxconf_sizeof_pthread_t.c b/storage/innodb_plugin/ut/ut0auxconf_sizeof_pthread_t.c
new file mode 100644
index 00000000000..96add4526ef
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0auxconf_sizeof_pthread_t.c
@@ -0,0 +1,35 @@
+/*****************************************************************************
+
+Copyright (c) 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*****************************************************************************
+This program should compile and when run, print a single line like:
+#define SIZEOF_PTHREAD_T %d
+
+Created April 18, 2009 Vasil Dimov
+*****************************************************************************/
+
+#include <stdio.h>
+#include <pthread.h>
+
+int
+main(int argc, char** argv)
+{
+ printf("#define SIZEOF_PTHREAD_T %d\n", (int) sizeof(pthread_t));
+
+ return(0);
+}
diff --git a/storage/innodb_plugin/ut/ut0byte.c b/storage/innodb_plugin/ut/ut0byte.c
new file mode 100644
index 00000000000..4e093f72ce2
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0byte.c
@@ -0,0 +1,55 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/***************************************************************//**
+@file ut/ut0byte.c
+Byte utilities
+
+Created 5/11/1994 Heikki Tuuri
+********************************************************************/
+
+#include "ut0byte.h"
+
+#ifdef UNIV_NONINL
+#include "ut0byte.ic"
+#endif
+
+/** Zero value for a dulint */
+UNIV_INTERN const dulint ut_dulint_zero = {0, 0};
+
+/** Maximum value for a dulint */
+UNIV_INTERN const dulint ut_dulint_max = {0xFFFFFFFFUL, 0xFFFFFFFFUL};
+
+#ifdef notdefined /* unused code */
+#include "ut0sort.h"
+
+/************************************************************//**
+Sort function for dulint arrays. */
+UNIV_INTERN
+void
+ut_dulint_sort(
+/*===========*/
+ dulint* arr, /*!< in/out: array to be sorted */
+ dulint* aux_arr,/*!< in/out: auxiliary array (same size as arr) */
+ ulint low, /*!< in: low bound of sort interval, inclusive */
+ ulint high) /*!< in: high bound of sort interval, noninclusive */
+{
+ UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high,
+ ut_dulint_cmp);
+}
+#endif /* notdefined */
diff --git a/storage/innodb_plugin/ut/ut0dbg.c b/storage/innodb_plugin/ut/ut0dbg.c
new file mode 100644
index 00000000000..4484e6c36de
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0dbg.c
@@ -0,0 +1,187 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*****************************************************************//**
+@file ut/ut0dbg.c
+Debug utilities for Innobase.
+
+Created 1/30/1994 Heikki Tuuri
+**********************************************************************/
+
+#include "univ.i"
+#include "ut0dbg.h"
+
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#else
+/** This is used to eliminate compiler warnings */
+UNIV_INTERN ulint ut_dbg_zero = 0;
+#endif
+
+#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
+/** If this is set to TRUE by ut_dbg_assertion_failed(), all threads
+will stop at the next ut_a() or ut_ad(). */
+UNIV_INTERN ibool ut_dbg_stop_threads = FALSE;
+#endif
+#ifdef __NETWARE__
+/** Flag for ignoring further assertion failures. This is set to TRUE
+when on NetWare there happens an InnoDB assertion failure or other
+fatal error condition that requires an immediate shutdown. */
+UNIV_INTERN ibool panic_shutdown = FALSE;
+#elif !defined(UT_DBG_USE_ABORT)
+/** A null pointer that will be dereferenced to trigger a memory trap */
+UNIV_INTERN ulint* ut_dbg_null_ptr = NULL;
+#endif
+
+/*************************************************************//**
+Report a failed assertion. */
+UNIV_INTERN
+void
+ut_dbg_assertion_failed(
+/*====================*/
+ const char* expr, /*!< in: the failed assertion (optional) */
+ const char* file, /*!< in: source file containing the assertion */
+ ulint line) /*!< in: line number of the assertion */
+{
+ ut_print_timestamp(stderr);
+#ifdef UNIV_HOTBACKUP
+ fprintf(stderr, " InnoDB: Assertion failure in file %s line %lu\n",
+ file, line);
+#else /* UNIV_HOTBACKUP */
+ fprintf(stderr,
+ " InnoDB: Assertion failure in thread %lu"
+ " in file %s line %lu\n",
+ os_thread_pf(os_thread_get_curr_id()), file, line);
+#endif /* UNIV_HOTBACKUP */
+ if (expr) {
+ fprintf(stderr,
+ "InnoDB: Failing assertion: %s\n", expr);
+ }
+
+ fputs("InnoDB: We intentionally generate a memory trap.\n"
+ "InnoDB: Submit a detailed bug report"
+ " to http://bugs.mysql.com.\n"
+ "InnoDB: If you get repeated assertion failures"
+ " or crashes, even\n"
+ "InnoDB: immediately after the mysqld startup, there may be\n"
+ "InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
+ "InnoDB: " REFMAN "forcing-recovery.html\n"
+ "InnoDB: about forcing recovery.\n", stderr);
+#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
+ ut_dbg_stop_threads = TRUE;
+#endif
+}
+
+#ifdef __NETWARE__
+/*************************************************************//**
+Shut down MySQL/InnoDB after assertion failure. */
+UNIV_INTERN
+void
+ut_dbg_panic(void)
+/*==============*/
+{
+ if (!panic_shutdown) {
+ panic_shutdown = TRUE;
+ innobase_shutdown_for_mysql();
+ }
+ exit(1);
+}
+#else /* __NETWARE__ */
+# if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
+/*************************************************************//**
+Stop a thread after assertion failure. */
+UNIV_INTERN
+void
+ut_dbg_stop_thread(
+/*===============*/
+ const char* file,
+ ulint line)
+{
+#ifndef UNIV_HOTBACKUP
+ fprintf(stderr, "InnoDB: Thread %lu stopped in file %s line %lu\n",
+ os_thread_pf(os_thread_get_curr_id()), file, line);
+ os_thread_sleep(1000000000);
+#endif /* !UNIV_HOTBACKUP */
+}
+# endif
+#endif /* __NETWARE__ */
+
+#ifdef UNIV_COMPILE_TEST_FUNCS
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <unistd.h>
+
+#ifndef timersub
+#define timersub(a, b, r) \
+ do { \
+ (r)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (r)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((r)->tv_usec < 0) { \
+ (r)->tv_sec--; \
+ (r)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* timersub */
+
+/*******************************************************************//**
+Resets a speedo (records the current time in it). */
+UNIV_INTERN
+void
+speedo_reset(
+/*=========*/
+ speedo_t* speedo) /*!< out: speedo */
+{
+ gettimeofday(&speedo->tv, NULL);
+
+ getrusage(RUSAGE_SELF, &speedo->ru);
+}
+
+/*******************************************************************//**
+Shows the time elapsed and usage statistics since the last reset of a
+speedo. */
+UNIV_INTERN
+void
+speedo_show(
+/*========*/
+ const speedo_t* speedo) /*!< in: speedo */
+{
+ struct rusage ru_now;
+ struct timeval tv_now;
+ struct timeval tv_diff;
+
+ getrusage(RUSAGE_SELF, &ru_now);
+
+ gettimeofday(&tv_now, NULL);
+
+#define PRINT_TIMEVAL(prefix, tvp) \
+ fprintf(stderr, "%s% 5ld.%06ld sec\n", \
+ prefix, (tvp)->tv_sec, (tvp)->tv_usec)
+
+ timersub(&tv_now, &speedo->tv, &tv_diff);
+ PRINT_TIMEVAL("real", &tv_diff);
+
+ timersub(&ru_now.ru_utime, &speedo->ru.ru_utime, &tv_diff);
+ PRINT_TIMEVAL("user", &tv_diff);
+
+ timersub(&ru_now.ru_stime, &speedo->ru.ru_stime, &tv_diff);
+ PRINT_TIMEVAL("sys ", &tv_diff);
+}
+
+#endif /* UNIV_COMPILE_TEST_FUNCS */
diff --git a/storage/innodb_plugin/ut/ut0list.c b/storage/innodb_plugin/ut/ut0list.c
new file mode 100644
index 00000000000..895a575c535
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0list.c
@@ -0,0 +1,194 @@
+/*****************************************************************************
+
+Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*******************************************************************//**
+@file ut/ut0list.c
+A double-linked list
+
+Created 4/26/2006 Osku Salerma
+************************************************************************/
+
+#include "ut0list.h"
+#ifdef UNIV_NONINL
+#include "ut0list.ic"
+#endif
+
+/****************************************************************//**
+Create a new list.
+@return list */
+UNIV_INTERN
+ib_list_t*
+ib_list_create(void)
+/*=================*/
+{
+ ib_list_t* list = mem_alloc(sizeof(ib_list_t));
+
+ list->first = NULL;
+ list->last = NULL;
+ list->is_heap_list = FALSE;
+
+ return(list);
+}
+
+/****************************************************************//**
+Create a new list using the given heap. ib_list_free MUST NOT BE CALLED for
+lists created with this function.
+@return list */
+UNIV_INTERN
+ib_list_t*
+ib_list_create_heap(
+/*================*/
+ mem_heap_t* heap) /*!< in: memory heap to use */
+{
+ ib_list_t* list = mem_heap_alloc(heap, sizeof(ib_list_t));
+
+ list->first = NULL;
+ list->last = NULL;
+ list->is_heap_list = TRUE;
+
+ return(list);
+}
+
+/****************************************************************//**
+Free a list. */
+UNIV_INTERN
+void
+ib_list_free(
+/*=========*/
+ ib_list_t* list) /*!< in: list */
+{
+ ut_a(!list->is_heap_list);
+
+ /* We don't check that the list is empty because it's entirely valid
+ to e.g. have all the nodes allocated from a single heap that is then
+ freed after the list itself is freed. */
+
+ mem_free(list);
+}
+
+/****************************************************************//**
+Add the data to the start of the list.
+@return new list node */
+UNIV_INTERN
+ib_list_node_t*
+ib_list_add_first(
+/*==============*/
+ ib_list_t* list, /*!< in: list */
+ void* data, /*!< in: data */
+ mem_heap_t* heap) /*!< in: memory heap to use */
+{
+ return(ib_list_add_after(list, ib_list_get_first(list), data, heap));
+}
+
+/****************************************************************//**
+Add the data to the end of the list.
+@return new list node */
+UNIV_INTERN
+ib_list_node_t*
+ib_list_add_last(
+/*=============*/
+ ib_list_t* list, /*!< in: list */
+ void* data, /*!< in: data */
+ mem_heap_t* heap) /*!< in: memory heap to use */
+{
+ return(ib_list_add_after(list, ib_list_get_last(list), data, heap));
+}
+
+/****************************************************************//**
+Add the data after the indicated node.
+@return new list node */
+UNIV_INTERN
+ib_list_node_t*
+ib_list_add_after(
+/*==============*/
+ ib_list_t* list, /*!< in: list */
+ ib_list_node_t* prev_node, /*!< in: node preceding new node (can
+ be NULL) */
+ void* data, /*!< in: data */
+ mem_heap_t* heap) /*!< in: memory heap to use */
+{
+ ib_list_node_t* node = mem_heap_alloc(heap, sizeof(ib_list_node_t));
+
+ node->data = data;
+
+ if (!list->first) {
+ /* Empty list. */
+
+ ut_a(!prev_node);
+
+ node->prev = NULL;
+ node->next = NULL;
+
+ list->first = node;
+ list->last = node;
+ } else if (!prev_node) {
+ /* Start of list. */
+
+ node->prev = NULL;
+ node->next = list->first;
+
+ list->first->prev = node;
+
+ list->first = node;
+ } else {
+ /* Middle or end of list. */
+
+ node->prev = prev_node;
+ node->next = prev_node->next;
+
+ prev_node->next = node;
+
+ if (node->next) {
+ node->next->prev = node;
+ } else {
+ list->last = node;
+ }
+ }
+
+ return(node);
+}
+
+/****************************************************************//**
+Remove the node from the list. */
+UNIV_INTERN
+void
+ib_list_remove(
+/*===========*/
+ ib_list_t* list, /*!< in: list */
+ ib_list_node_t* node) /*!< in: node to remove */
+{
+ if (node->prev) {
+ node->prev->next = node->next;
+ } else {
+ /* First item in list. */
+
+ ut_ad(list->first == node);
+
+ list->first = node->next;
+ }
+
+ if (node->next) {
+ node->next->prev = node->prev;
+ } else {
+ /* Last item in list. */
+
+ ut_ad(list->last == node);
+
+ list->last = node->prev;
+ }
+}
diff --git a/storage/innodb_plugin/ut/ut0mem.c b/storage/innodb_plugin/ut/ut0mem.c
new file mode 100644
index 00000000000..7ed43d32fe0
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0mem.c
@@ -0,0 +1,706 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/********************************************************************//**
+@file ut/ut0mem.c
+Memory primitives
+
+Created 5/11/1994 Heikki Tuuri
+*************************************************************************/
+
+#include "ut0mem.h"
+
+#ifdef UNIV_NONINL
+#include "ut0mem.ic"
+#endif
+
+#ifndef UNIV_HOTBACKUP
+# include "os0thread.h"
+# include "srv0srv.h"
+
+#include <stdlib.h>
+
+/** This struct is placed first in every allocated memory block */
+typedef struct ut_mem_block_struct ut_mem_block_t;
+
+/** The total amount of memory currently allocated from the operating
+system with os_mem_alloc_large() or malloc(). Does not count malloc()
+if srv_use_sys_malloc is set. Protected by ut_list_mutex. */
+UNIV_INTERN ulint ut_total_allocated_memory = 0;
+
+/** Mutex protecting ut_total_allocated_memory and ut_mem_block_list */
+UNIV_INTERN os_fast_mutex_t ut_list_mutex;
+
+/** Dynamically allocated memory block */
+struct ut_mem_block_struct{
+ UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
+ /*!< mem block list node */
+ ulint size; /*!< size of allocated memory */
+ ulint magic_n;/*!< magic number (UT_MEM_MAGIC_N) */
+};
+
+/** The value of ut_mem_block_struct::magic_n. Used in detecting
+memory corruption. */
+#define UT_MEM_MAGIC_N 1601650166
+
+/** List of all memory blocks allocated from the operating system
+with malloc. Protected by ut_list_mutex. */
+static UT_LIST_BASE_NODE_T(ut_mem_block_t) ut_mem_block_list;
+
+/** Flag: has ut_mem_block_list been initialized? */
+static ibool ut_mem_block_list_inited = FALSE;
+
+/** A dummy pointer for generating a null pointer exception in
+ut_malloc_low() */
+static ulint* ut_mem_null_ptr = NULL;
+
+/**********************************************************************//**
+Initializes the mem block list at database startup. */
+UNIV_INTERN
+void
+ut_mem_init(void)
+/*=============*/
+{
+ ut_a(!ut_mem_block_list_inited);
+ os_fast_mutex_init(&ut_list_mutex);
+ UT_LIST_INIT(ut_mem_block_list);
+ ut_mem_block_list_inited = TRUE;
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/**********************************************************************//**
+Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
+defined and set_to_zero is TRUE.
+@return own: allocated memory */
+UNIV_INTERN
+void*
+ut_malloc_low(
+/*==========*/
+ ulint n, /*!< in: number of bytes to allocate */
+ ibool set_to_zero, /*!< in: TRUE if allocated memory should be
+ set to zero if UNIV_SET_MEM_TO_ZERO is
+ defined */
+ ibool assert_on_error)/*!< in: if TRUE, we crash mysqld if the
+ memory cannot be allocated */
+{
+#ifndef UNIV_HOTBACKUP
+ ulint retry_count;
+ void* ret;
+
+ if (UNIV_LIKELY(srv_use_sys_malloc)) {
+ ret = malloc(n);
+ ut_a(ret || !assert_on_error);
+
+#ifdef UNIV_SET_MEM_TO_ZERO
+ if (set_to_zero) {
+ memset(ret, '\0', n);
+ UNIV_MEM_ALLOC(ret, n);
+ }
+#endif
+ return(ret);
+ }
+
+ ut_ad((sizeof(ut_mem_block_t) % 8) == 0); /* check alignment ok */
+ ut_a(ut_mem_block_list_inited);
+
+ retry_count = 0;
+retry:
+ os_fast_mutex_lock(&ut_list_mutex);
+
+ ret = malloc(n + sizeof(ut_mem_block_t));
+
+ if (ret == NULL && retry_count < 60) {
+ if (retry_count == 0) {
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+ " InnoDB: Error: cannot allocate"
+ " %lu bytes of\n"
+ "InnoDB: memory with malloc!"
+ " Total allocated memory\n"
+ "InnoDB: by InnoDB %lu bytes."
+ " Operating system errno: %lu\n"
+ "InnoDB: Check if you should"
+ " increase the swap file or\n"
+ "InnoDB: ulimits of your operating system.\n"
+ "InnoDB: On FreeBSD check you"
+ " have compiled the OS with\n"
+ "InnoDB: a big enough maximum process size.\n"
+ "InnoDB: Note that in most 32-bit"
+ " computers the process\n"
+ "InnoDB: memory space is limited"
+ " to 2 GB or 4 GB.\n"
+ "InnoDB: We keep retrying"
+ " the allocation for 60 seconds...\n",
+ (ulong) n, (ulong) ut_total_allocated_memory,
+#ifdef __WIN__
+ (ulong) GetLastError()
+#else
+ (ulong) errno
+#endif
+ );
+ }
+
+ os_fast_mutex_unlock(&ut_list_mutex);
+
+ /* Sleep for a second and retry the allocation; maybe this is
+ just a temporary shortage of memory */
+
+ os_thread_sleep(1000000);
+
+ retry_count++;
+
+ goto retry;
+ }
+
+ if (ret == NULL) {
+ /* Flush stderr to make more probable that the error
+ message gets in the error file before we generate a seg
+ fault */
+
+ fflush(stderr);
+
+ os_fast_mutex_unlock(&ut_list_mutex);
+
+ /* Make an intentional seg fault so that we get a stack
+ trace */
+ /* Intentional segfault on NetWare causes an abend. Avoid this
+ by graceful exit handling in ut_a(). */
+#if (!defined __NETWARE__)
+ if (assert_on_error) {
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+ " InnoDB: We now intentionally"
+ " generate a seg fault so that\n"
+ "InnoDB: on Linux we get a stack trace.\n");
+
+ if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
+ } else {
+ return(NULL);
+ }
+#else
+ ut_a(0);
+#endif
+ }
+
+ if (set_to_zero) {
+#ifdef UNIV_SET_MEM_TO_ZERO
+ memset(ret, '\0', n + sizeof(ut_mem_block_t));
+#endif
+ }
+
+ UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
+
+ ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
+ ((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
+
+ ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
+
+ UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
+ ((ut_mem_block_t*)ret));
+ os_fast_mutex_unlock(&ut_list_mutex);
+
+ return((void*)((byte*)ret + sizeof(ut_mem_block_t)));
+#else /* !UNIV_HOTBACKUP */
+ void* ret = malloc(n);
+ ut_a(ret || !assert_on_error);
+
+# ifdef UNIV_SET_MEM_TO_ZERO
+ if (set_to_zero) {
+ memset(ret, '\0', n);
+ }
+# endif
+ return(ret);
+#endif /* !UNIV_HOTBACKUP */
+}
+
+/**********************************************************************//**
+Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
+defined.
+@return own: allocated memory */
+UNIV_INTERN
+void*
+ut_malloc(
+/*======*/
+ ulint n) /*!< in: number of bytes to allocate */
+{
+#ifndef UNIV_HOTBACKUP
+ return(ut_malloc_low(n, TRUE, TRUE));
+#else /* !UNIV_HOTBACKUP */
+ return(malloc(n));
+#endif /* !UNIV_HOTBACKUP */
+}
+
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
+out. It cannot be used if we want to return an error message. Prints to
+stderr a message if fails.
+@return TRUE if succeeded */
+UNIV_INTERN
+ibool
+ut_test_malloc(
+/*===========*/
+ ulint n) /*!< in: try to allocate this many bytes */
+{
+ void* ret;
+
+ ret = malloc(n);
+
+ if (ret == NULL) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: cannot allocate"
+ " %lu bytes of memory for\n"
+ "InnoDB: a BLOB with malloc! Total allocated memory\n"
+ "InnoDB: by InnoDB %lu bytes."
+ " Operating system errno: %d\n"
+ "InnoDB: Check if you should increase"
+ " the swap file or\n"
+ "InnoDB: ulimits of your operating system.\n"
+ "InnoDB: On FreeBSD check you have"
+ " compiled the OS with\n"
+ "InnoDB: a big enough maximum process size.\n",
+ (ulong) n,
+ (ulong) ut_total_allocated_memory,
+ (int) errno);
+ return(FALSE);
+ }
+
+ free(ret);
+
+ return(TRUE);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/**********************************************************************//**
+Frees a memory block allocated with ut_malloc. */
+UNIV_INTERN
+void
+ut_free(
+/*====*/
+ void* ptr) /*!< in, own: memory block */
+{
+#ifndef UNIV_HOTBACKUP
+ ut_mem_block_t* block;
+
+ if (UNIV_LIKELY(srv_use_sys_malloc)) {
+ free(ptr);
+ return;
+ }
+
+ block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
+
+ os_fast_mutex_lock(&ut_list_mutex);
+
+ ut_a(block->magic_n == UT_MEM_MAGIC_N);
+ ut_a(ut_total_allocated_memory >= block->size);
+
+ ut_total_allocated_memory -= block->size;
+
+ UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
+ free(block);
+
+ os_fast_mutex_unlock(&ut_list_mutex);
+#else /* !UNIV_HOTBACKUP */
+ free(ptr);
+#endif /* !UNIV_HOTBACKUP */
+}
+
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
+use this function because the allocation functions in mem0mem.h are the
+recommended ones in InnoDB.
+
+man realloc in Linux, 2004:
+
+ realloc() changes the size of the memory block pointed to
+ by ptr to size bytes. The contents will be unchanged to
+ the minimum of the old and new sizes; newly allocated mem­
+ ory will be uninitialized. If ptr is NULL, the call is
+ equivalent to malloc(size); if size is equal to zero, the
+ call is equivalent to free(ptr). Unless ptr is NULL, it
+ must have been returned by an earlier call to malloc(),
+ calloc() or realloc().
+
+RETURN VALUE
+ realloc() returns a pointer to the newly allocated memory,
+ which is suitably aligned for any kind of variable and may
+ be different from ptr, or NULL if the request fails. If
+ size was equal to 0, either NULL or a pointer suitable to
+ be passed to free() is returned. If realloc() fails the
+ original block is left untouched - it is not freed or
+ moved.
+@return own: pointer to new mem block or NULL */
+UNIV_INTERN
+void*
+ut_realloc(
+/*=======*/
+ void* ptr, /*!< in: pointer to old block or NULL */
+ ulint size) /*!< in: desired size */
+{
+ ut_mem_block_t* block;
+ ulint old_size;
+ ulint min_size;
+ void* new_ptr;
+
+ if (UNIV_LIKELY(srv_use_sys_malloc)) {
+ return(realloc(ptr, size));
+ }
+
+ if (ptr == NULL) {
+
+ return(ut_malloc(size));
+ }
+
+ if (size == 0) {
+ ut_free(ptr);
+
+ return(NULL);
+ }
+
+ block = (ut_mem_block_t*)((byte*)ptr - sizeof(ut_mem_block_t));
+
+ ut_a(block->magic_n == UT_MEM_MAGIC_N);
+
+ old_size = block->size - sizeof(ut_mem_block_t);
+
+ if (size < old_size) {
+ min_size = size;
+ } else {
+ min_size = old_size;
+ }
+
+ new_ptr = ut_malloc(size);
+
+ if (new_ptr == NULL) {
+
+ return(NULL);
+ }
+
+ /* Copy the old data from ptr */
+ ut_memcpy(new_ptr, ptr, min_size);
+
+ ut_free(ptr);
+
+ return(new_ptr);
+}
+
+/**********************************************************************//**
+Frees in shutdown all allocated memory not freed yet. */
+UNIV_INTERN
+void
+ut_free_all_mem(void)
+/*=================*/
+{
+ ut_mem_block_t* block;
+
+ ut_a(ut_mem_block_list_inited);
+ ut_mem_block_list_inited = FALSE;
+ os_fast_mutex_free(&ut_list_mutex);
+
+ while ((block = UT_LIST_GET_FIRST(ut_mem_block_list))) {
+
+ ut_a(block->magic_n == UT_MEM_MAGIC_N);
+ ut_a(ut_total_allocated_memory >= block->size);
+
+ ut_total_allocated_memory -= block->size;
+
+ UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
+ free(block);
+ }
+
+ if (ut_total_allocated_memory != 0) {
+ fprintf(stderr,
+ "InnoDB: Warning: after shutdown"
+ " total allocated memory is %lu\n",
+ (ulong) ut_total_allocated_memory);
+ }
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/**********************************************************************//**
+Copies up to size - 1 characters from the NUL-terminated string src to
+dst, NUL-terminating the result. Returns strlen(src), so truncation
+occurred if the return value >= size.
+@return strlen(src) */
+UNIV_INTERN
+ulint
+ut_strlcpy(
+/*=======*/
+ char* dst, /*!< in: destination buffer */
+ const char* src, /*!< in: source buffer */
+ ulint size) /*!< in: size of destination buffer */
+{
+ ulint src_size = strlen(src);
+
+ if (size != 0) {
+ ulint n = ut_min(src_size, size - 1);
+
+ memcpy(dst, src, n);
+ dst[n] = '\0';
+ }
+
+ return(src_size);
+}
+
+/**********************************************************************//**
+Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
+(size - 1) bytes of src, not the first.
+@return strlen(src) */
+UNIV_INTERN
+ulint
+ut_strlcpy_rev(
+/*===========*/
+ char* dst, /*!< in: destination buffer */
+ const char* src, /*!< in: source buffer */
+ ulint size) /*!< in: size of destination buffer */
+{
+ ulint src_size = strlen(src);
+
+ if (size != 0) {
+ ulint n = ut_min(src_size, size - 1);
+
+ memcpy(dst, src + src_size - n, n + 1);
+ }
+
+ return(src_size);
+}
+
+/**********************************************************************//**
+Make a quoted copy of a NUL-terminated string. Leading and trailing
+quotes will not be included; only embedded quotes will be escaped.
+See also ut_strlenq() and ut_memcpyq().
+@return pointer to end of dest */
+UNIV_INTERN
+char*
+ut_strcpyq(
+/*=======*/
+ char* dest, /*!< in: output buffer */
+ char q, /*!< in: the quote character */
+ const char* src) /*!< in: null-terminated string */
+{
+ while (*src) {
+ if ((*dest++ = *src++) == q) {
+ *dest++ = q;
+ }
+ }
+
+ return(dest);
+}
+
+/**********************************************************************//**
+Make a quoted copy of a fixed-length string. Leading and trailing
+quotes will not be included; only embedded quotes will be escaped.
+See also ut_strlenq() and ut_strcpyq().
+@return pointer to end of dest */
+UNIV_INTERN
+char*
+ut_memcpyq(
+/*=======*/
+ char* dest, /*!< in: output buffer */
+ char q, /*!< in: the quote character */
+ const char* src, /*!< in: string to be quoted */
+ ulint len) /*!< in: length of src */
+{
+ const char* srcend = src + len;
+
+ while (src < srcend) {
+ if ((*dest++ = *src++) == q) {
+ *dest++ = q;
+ }
+ }
+
+ return(dest);
+}
+
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Return the number of times s2 occurs in s1. Overlapping instances of s2
+are only counted once.
+@return the number of times s2 occurs in s1 */
+UNIV_INTERN
+ulint
+ut_strcount(
+/*========*/
+ const char* s1, /*!< in: string to search in */
+ const char* s2) /*!< in: string to search for */
+{
+ ulint count = 0;
+ ulint len = strlen(s2);
+
+ if (len == 0) {
+
+ return(0);
+ }
+
+ for (;;) {
+ s1 = strstr(s1, s2);
+
+ if (!s1) {
+
+ break;
+ }
+
+ count++;
+ s1 += len;
+ }
+
+ return(count);
+}
+
+/**********************************************************************//**
+Replace every occurrence of s1 in str with s2. Overlapping instances of s1
+are only replaced once.
+@return own: modified string, must be freed with mem_free() */
+UNIV_INTERN
+char*
+ut_strreplace(
+/*==========*/
+ const char* str, /*!< in: string to operate on */
+ const char* s1, /*!< in: string to replace */
+ const char* s2) /*!< in: string to replace s1 with */
+{
+ char* new_str;
+ char* ptr;
+ const char* str_end;
+ ulint str_len = strlen(str);
+ ulint s1_len = strlen(s1);
+ ulint s2_len = strlen(s2);
+ ulint count = 0;
+ int len_delta = (int)s2_len - (int)s1_len;
+
+ str_end = str + str_len;
+
+ if (len_delta <= 0) {
+ len_delta = 0;
+ } else {
+ count = ut_strcount(str, s1);
+ }
+
+ new_str = mem_alloc(str_len + count * len_delta + 1);
+ ptr = new_str;
+
+ while (str) {
+ const char* next = strstr(str, s1);
+
+ if (!next) {
+ next = str_end;
+ }
+
+ memcpy(ptr, str, next - str);
+ ptr += next - str;
+
+ if (next == str_end) {
+
+ break;
+ }
+
+ memcpy(ptr, s2, s2_len);
+ ptr += s2_len;
+
+ str = next + s1_len;
+ }
+
+ *ptr = '\0';
+
+ return(new_str);
+}
+
+#ifdef UNIV_COMPILE_TEST_FUNCS
+
+void
+test_ut_str_sql_format()
+{
+ char buf[128];
+ ulint ret;
+
+#define CALL_AND_TEST(str, str_len, buf, buf_size, ret_expected, buf_expected)\
+ do {\
+ ibool ok = TRUE;\
+ memset(buf, 'x', 10);\
+ buf[10] = '\0';\
+ fprintf(stderr, "TESTING \"%s\", %lu, %lu\n",\
+ str, (ulint) str_len, (ulint) buf_size);\
+ ret = ut_str_sql_format(str, str_len, buf, buf_size);\
+ if (ret != ret_expected) {\
+ fprintf(stderr, "expected ret %lu, got %lu\n",\
+ (ulint) ret_expected, ret);\
+ ok = FALSE;\
+ }\
+ if (strcmp((char*) buf, buf_expected) != 0) {\
+ fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
+ buf_expected, buf);\
+ ok = FALSE;\
+ }\
+ if (ok) {\
+ fprintf(stderr, "OK: %lu, \"%s\"\n\n",\
+ (ulint) ret, buf);\
+ } else {\
+ return;\
+ }\
+ } while (0)
+
+ CALL_AND_TEST("abcd", 4, buf, 0, 0, "xxxxxxxxxx");
+
+ CALL_AND_TEST("abcd", 4, buf, 1, 1, "");
+
+ CALL_AND_TEST("abcd", 4, buf, 2, 1, "");
+
+ CALL_AND_TEST("abcd", 0, buf, 3, 3, "''");
+ CALL_AND_TEST("abcd", 1, buf, 3, 1, "");
+ CALL_AND_TEST("abcd", 2, buf, 3, 1, "");
+ CALL_AND_TEST("abcd", 3, buf, 3, 1, "");
+ CALL_AND_TEST("abcd", 4, buf, 3, 1, "");
+
+ CALL_AND_TEST("abcd", 0, buf, 4, 3, "''");
+ CALL_AND_TEST("abcd", 1, buf, 4, 4, "'a'");
+ CALL_AND_TEST("abcd", 2, buf, 4, 4, "'a'");
+ CALL_AND_TEST("abcd", 3, buf, 4, 4, "'a'");
+ CALL_AND_TEST("abcd", 4, buf, 4, 4, "'a'");
+ CALL_AND_TEST("abcde", 5, buf, 4, 4, "'a'");
+ CALL_AND_TEST("'", 1, buf, 4, 3, "''");
+ CALL_AND_TEST("''", 2, buf, 4, 3, "''");
+ CALL_AND_TEST("a'", 2, buf, 4, 4, "'a'");
+ CALL_AND_TEST("'a", 2, buf, 4, 3, "''");
+ CALL_AND_TEST("ab", 2, buf, 4, 4, "'a'");
+
+ CALL_AND_TEST("abcdef", 0, buf, 5, 3, "''");
+ CALL_AND_TEST("abcdef", 1, buf, 5, 4, "'a'");
+ CALL_AND_TEST("abcdef", 2, buf, 5, 5, "'ab'");
+ CALL_AND_TEST("abcdef", 3, buf, 5, 5, "'ab'");
+ CALL_AND_TEST("abcdef", 4, buf, 5, 5, "'ab'");
+ CALL_AND_TEST("abcdef", 5, buf, 5, 5, "'ab'");
+ CALL_AND_TEST("abcdef", 6, buf, 5, 5, "'ab'");
+ CALL_AND_TEST("'", 1, buf, 5, 5, "''''");
+ CALL_AND_TEST("''", 2, buf, 5, 5, "''''");
+ CALL_AND_TEST("a'", 2, buf, 5, 4, "'a'");
+ CALL_AND_TEST("'a", 2, buf, 5, 5, "''''");
+ CALL_AND_TEST("ab", 2, buf, 5, 5, "'ab'");
+ CALL_AND_TEST("abc", 3, buf, 5, 5, "'ab'");
+
+ CALL_AND_TEST("ab", 2, buf, 6, 5, "'ab'");
+
+ CALL_AND_TEST("a'b'c", 5, buf, 32, 10, "'a''b''c'");
+ CALL_AND_TEST("a'b'c'", 6, buf, 32, 12, "'a''b''c'''");
+}
+
+#endif /* UNIV_COMPILE_TEST_FUNCS */
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/ut/ut0rnd.c b/storage/innodb_plugin/ut/ut0rnd.c
new file mode 100644
index 00000000000..cefd0990ecc
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0rnd.c
@@ -0,0 +1,97 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/***************************************************************//**
+@file ut/ut0rnd.c
+Random numbers and hashing
+
+Created 5/11/1994 Heikki Tuuri
+********************************************************************/
+
+#include "ut0rnd.h"
+
+#ifdef UNIV_NONINL
+#include "ut0rnd.ic"
+#endif
+
+/** These random numbers are used in ut_find_prime */
+/*@{*/
+#define UT_RANDOM_1 1.0412321
+#define UT_RANDOM_2 1.1131347
+#define UT_RANDOM_3 1.0132677
+/*@}*/
+
+/** Seed value of ut_rnd_gen_ulint(). */
+UNIV_INTERN ulint ut_rnd_ulint_counter = 65654363;
+
+/***********************************************************//**
+Looks for a prime number slightly greater than the given argument.
+The prime is chosen so that it is not near any power of 2.
+@return prime */
+UNIV_INTERN
+ulint
+ut_find_prime(
+/*==========*/
+ ulint n) /*!< in: positive number > 100 */
+{
+ ulint pow2;
+ ulint i;
+
+ n += 100;
+
+ pow2 = 1;
+ while (pow2 * 2 < n) {
+ pow2 = 2 * pow2;
+ }
+
+ if ((double)n < 1.05 * (double)pow2) {
+ n = (ulint) ((double)n * UT_RANDOM_1);
+ }
+
+ pow2 = 2 * pow2;
+
+ if ((double)n > 0.95 * (double)pow2) {
+ n = (ulint) ((double)n * UT_RANDOM_2);
+ }
+
+ if (n > pow2 - 20) {
+ n += 30;
+ }
+
+ /* Now we have n far enough from powers of 2. To make
+ n more random (especially, if it was not near
+ a power of 2), we then multiply it by a random number. */
+
+ n = (ulint) ((double)n * UT_RANDOM_3);
+
+ for (;; n++) {
+ i = 2;
+ while (i * i <= n) {
+ if (n % i == 0) {
+ goto next_n;
+ }
+ i++;
+ }
+
+ /* Found a prime */
+ break;
+next_n: ;
+ }
+
+ return(n);
+}
diff --git a/storage/innodb_plugin/ut/ut0ut.c b/storage/innodb_plugin/ut/ut0ut.c
new file mode 100644
index 00000000000..c0ea362bee3
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0ut.c
@@ -0,0 +1,598 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/***************************************************************//**
+@file ut/ut0ut.c
+Various utilities for Innobase.
+
+Created 5/11/1994 Heikki Tuuri
+********************************************************************/
+
+#include "ut0ut.h"
+
+#ifdef UNIV_NONINL
+#include "ut0ut.ic"
+#endif
+
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef UNIV_HOTBACKUP
+# include "trx0trx.h"
+# include "ha_prototypes.h"
+# include "mysql_com.h" /* NAME_LEN */
+#endif /* UNIV_HOTBACKUP */
+
+/** A constant to prevent the compiler from optimizing ut_delay() away. */
+UNIV_INTERN ibool ut_always_false = FALSE;
+
+#ifdef __WIN__
+/*****************************************************************//**
+NOTE: The Windows epoch starts from 1601/01/01 whereas the Unix
+epoch starts from 1970/1/1. For selection of constant see:
+http://support.microsoft.com/kb/167296/ */
+#define WIN_TO_UNIX_DELTA_USEC ((ib_int64_t) 11644473600000000ULL)
+
+
+/*****************************************************************//**
+This is the Windows version of gettimeofday(2).
+@return 0 if all OK else -1 */
+static
+int
+ut_gettimeofday(
+/*============*/
+ struct timeval* tv, /*!< out: Values are relative to Unix epoch */
+ void* tz) /*!< in: not used */
+{
+ FILETIME ft;
+ ib_int64_t tm;
+
+ if (!tv) {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ GetSystemTimeAsFileTime(&ft);
+
+ tm = (ib_int64_t) ft.dwHighDateTime << 32;
+ tm |= ft.dwLowDateTime;
+
+ ut_a(tm >= 0); /* If tm wraps over to negative, the quotient / 10
+ does not work */
+
+ tm /= 10; /* Convert from 100 nsec periods to usec */
+
+ /* If we don't convert to the Unix epoch the value for
+ struct timeval::tv_sec will overflow.*/
+ tm -= WIN_TO_UNIX_DELTA_USEC;
+
+ tv->tv_sec = (long) (tm / 1000000L);
+ tv->tv_usec = (long) (tm % 1000000L);
+
+ return(0);
+}
+#else
+/** An alias for gettimeofday(2). On Microsoft Windows, we have to
+reimplement this function. */
+#define ut_gettimeofday gettimeofday
+#endif
+
+/********************************************************//**
+Gets the high 32 bits in a ulint. That is makes a shift >> 32,
+but since there seem to be compiler bugs in both gcc and Visual C++,
+we do this by a special conversion.
+@return a >> 32 */
+UNIV_INTERN
+ulint
+ut_get_high32(
+/*==========*/
+ ulint a) /*!< in: ulint */
+{
+ ib_int64_t i;
+
+ i = (ib_int64_t)a;
+
+ i = i >> 32;
+
+ return((ulint)i);
+}
+
+/**********************************************************//**
+Returns system time. We do not specify the format of the time returned:
+the only way to manipulate it is to use the function ut_difftime.
+@return system time */
+UNIV_INTERN
+ib_time_t
+ut_time(void)
+/*=========*/
+{
+ return(time(NULL));
+}
+
+/**********************************************************//**
+Returns system time.
+Upon successful completion, the value 0 is returned; otherwise the
+value -1 is returned and the global variable errno is set to indicate the
+error.
+@return 0 on success, -1 otherwise */
+UNIV_INTERN
+int
+ut_usectime(
+/*========*/
+ ulint* sec, /*!< out: seconds since the Epoch */
+ ulint* ms) /*!< out: microseconds since the Epoch+*sec */
+{
+ struct timeval tv;
+ int ret;
+ int errno_gettimeofday;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+
+ ret = ut_gettimeofday(&tv, NULL);
+
+ if (ret == -1) {
+ errno_gettimeofday = errno;
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: gettimeofday(): %s\n",
+ strerror(errno_gettimeofday));
+ os_thread_sleep(100000); /* 0.1 sec */
+ errno = errno_gettimeofday;
+ } else {
+ break;
+ }
+ }
+
+ if (ret != -1) {
+ *sec = (ulint) tv.tv_sec;
+ *ms = (ulint) tv.tv_usec;
+ }
+
+ return(ret);
+}
+
+/**********************************************************//**
+Returns the number of microseconds since epoch. Similar to
+time(3), the return value is also stored in *tloc, provided
+that tloc is non-NULL.
+@return us since epoch */
+UNIV_INTERN
+ullint
+ut_time_us(
+/*=======*/
+ ullint* tloc) /*!< out: us since epoch, if non-NULL */
+{
+ struct timeval tv;
+ ullint us;
+
+ ut_gettimeofday(&tv, NULL);
+
+ us = (ullint) tv.tv_sec * 1000000 + tv.tv_usec;
+
+ if (tloc != NULL) {
+ *tloc = us;
+ }
+
+ return(us);
+}
+
+/**********************************************************//**
+Returns the difference of two times in seconds.
+@return time2 - time1 expressed in seconds */
+UNIV_INTERN
+double
+ut_difftime(
+/*========*/
+ ib_time_t time2, /*!< in: time */
+ ib_time_t time1) /*!< in: time */
+{
+ return(difftime(time2, time1));
+}
+
+/**********************************************************//**
+Prints a timestamp to a file. */
+UNIV_INTERN
+void
+ut_print_timestamp(
+/*===============*/
+ FILE* file) /*!< in: file where to print */
+{
+#ifdef __WIN__
+ SYSTEMTIME cal_tm;
+
+ GetLocalTime(&cal_tm);
+
+ fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
+ (int)cal_tm.wYear % 100,
+ (int)cal_tm.wMonth,
+ (int)cal_tm.wDay,
+ (int)cal_tm.wHour,
+ (int)cal_tm.wMinute,
+ (int)cal_tm.wSecond);
+#else
+ struct tm cal_tm;
+ struct tm* cal_tm_ptr;
+ time_t tm;
+
+ time(&tm);
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&tm, &cal_tm);
+ cal_tm_ptr = &cal_tm;
+#else
+ cal_tm_ptr = localtime(&tm);
+#endif
+ fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
+ cal_tm_ptr->tm_year % 100,
+ cal_tm_ptr->tm_mon + 1,
+ cal_tm_ptr->tm_mday,
+ cal_tm_ptr->tm_hour,
+ cal_tm_ptr->tm_min,
+ cal_tm_ptr->tm_sec);
+#endif
+}
+
+/**********************************************************//**
+Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */
+UNIV_INTERN
+void
+ut_sprintf_timestamp(
+/*=================*/
+ char* buf) /*!< in: buffer where to sprintf */
+{
+#ifdef __WIN__
+ SYSTEMTIME cal_tm;
+
+ GetLocalTime(&cal_tm);
+
+ sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
+ (int)cal_tm.wYear % 100,
+ (int)cal_tm.wMonth,
+ (int)cal_tm.wDay,
+ (int)cal_tm.wHour,
+ (int)cal_tm.wMinute,
+ (int)cal_tm.wSecond);
+#else
+ struct tm cal_tm;
+ struct tm* cal_tm_ptr;
+ time_t tm;
+
+ time(&tm);
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&tm, &cal_tm);
+ cal_tm_ptr = &cal_tm;
+#else
+ cal_tm_ptr = localtime(&tm);
+#endif
+ sprintf(buf, "%02d%02d%02d %2d:%02d:%02d",
+ cal_tm_ptr->tm_year % 100,
+ cal_tm_ptr->tm_mon + 1,
+ cal_tm_ptr->tm_mday,
+ cal_tm_ptr->tm_hour,
+ cal_tm_ptr->tm_min,
+ cal_tm_ptr->tm_sec);
+#endif
+}
+
+#ifdef UNIV_HOTBACKUP
+/**********************************************************//**
+Sprintfs a timestamp to a buffer with no spaces and with ':' characters
+replaced by '_'. */
+UNIV_INTERN
+void
+ut_sprintf_timestamp_without_extra_chars(
+/*=====================================*/
+ char* buf) /*!< in: buffer where to sprintf */
+{
+#ifdef __WIN__
+ SYSTEMTIME cal_tm;
+
+ GetLocalTime(&cal_tm);
+
+ sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
+ (int)cal_tm.wYear % 100,
+ (int)cal_tm.wMonth,
+ (int)cal_tm.wDay,
+ (int)cal_tm.wHour,
+ (int)cal_tm.wMinute,
+ (int)cal_tm.wSecond);
+#else
+ struct tm cal_tm;
+ struct tm* cal_tm_ptr;
+ time_t tm;
+
+ time(&tm);
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&tm, &cal_tm);
+ cal_tm_ptr = &cal_tm;
+#else
+ cal_tm_ptr = localtime(&tm);
+#endif
+ sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
+ cal_tm_ptr->tm_year % 100,
+ cal_tm_ptr->tm_mon + 1,
+ cal_tm_ptr->tm_mday,
+ cal_tm_ptr->tm_hour,
+ cal_tm_ptr->tm_min,
+ cal_tm_ptr->tm_sec);
+#endif
+}
+
+/**********************************************************//**
+Returns current year, month, day. */
+UNIV_INTERN
+void
+ut_get_year_month_day(
+/*==================*/
+ ulint* year, /*!< out: current year */
+ ulint* month, /*!< out: month */
+ ulint* day) /*!< out: day */
+{
+#ifdef __WIN__
+ SYSTEMTIME cal_tm;
+
+ GetLocalTime(&cal_tm);
+
+ *year = (ulint)cal_tm.wYear;
+ *month = (ulint)cal_tm.wMonth;
+ *day = (ulint)cal_tm.wDay;
+#else
+ struct tm cal_tm;
+ struct tm* cal_tm_ptr;
+ time_t tm;
+
+ time(&tm);
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&tm, &cal_tm);
+ cal_tm_ptr = &cal_tm;
+#else
+ cal_tm_ptr = localtime(&tm);
+#endif
+ *year = (ulint)cal_tm_ptr->tm_year + 1900;
+ *month = (ulint)cal_tm_ptr->tm_mon + 1;
+ *day = (ulint)cal_tm_ptr->tm_mday;
+#endif
+}
+#endif /* UNIV_HOTBACKUP */
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Runs an idle loop on CPU. The argument gives the desired delay
+in microseconds on 100 MHz Pentium + Visual C++.
+@return dummy value */
+UNIV_INTERN
+ulint
+ut_delay(
+/*=====*/
+ ulint delay) /*!< in: delay in microseconds on 100 MHz Pentium */
+{
+ ulint i, j;
+
+ j = 0;
+
+ for (i = 0; i < delay * 50; i++) {
+ j += i;
+ }
+
+ if (ut_always_false) {
+ ut_always_false = (ibool) j;
+ }
+
+ return(j);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/*************************************************************//**
+Prints the contents of a memory buffer in hex and ascii. */
+UNIV_INTERN
+void
+ut_print_buf(
+/*=========*/
+ FILE* file, /*!< in: file where to print */
+ const void* buf, /*!< in: memory buffer */
+ ulint len) /*!< in: length of the buffer */
+{
+ const byte* data;
+ ulint i;
+
+ UNIV_MEM_ASSERT_RW(buf, len);
+
+ fprintf(file, " len %lu; hex ", len);
+
+ for (data = (const byte*)buf, i = 0; i < len; i++) {
+ fprintf(file, "%02lx", (ulong)*data++);
+ }
+
+ fputs("; asc ", file);
+
+ data = (const byte*)buf;
+
+ for (i = 0; i < len; i++) {
+ int c = (int) *data++;
+ putc(isprint(c) ? c : ' ', file);
+ }
+
+ putc(';', file);
+}
+
+/*************************************************************//**
+Calculates fast the number rounded up to the nearest power of 2.
+@return first power of 2 which is >= n */
+UNIV_INTERN
+ulint
+ut_2_power_up(
+/*==========*/
+ ulint n) /*!< in: number != 0 */
+{
+ ulint res;
+
+ res = 1;
+
+ ut_ad(n > 0);
+
+ while (res < n) {
+ res = res * 2;
+ }
+
+ return(res);
+}
+
+/**********************************************************************//**
+Outputs a NUL-terminated file name, quoted with apostrophes. */
+UNIV_INTERN
+void
+ut_print_filename(
+/*==============*/
+ FILE* f, /*!< in: output stream */
+ const char* name) /*!< in: name to print */
+{
+ putc('\'', f);
+ for (;;) {
+ int c = *name++;
+ switch (c) {
+ case 0:
+ goto done;
+ case '\'':
+ putc(c, f);
+ /* fall through */
+ default:
+ putc(c, f);
+ }
+ }
+done:
+ putc('\'', f);
+}
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Outputs a fixed-length string, quoted as an SQL identifier.
+If the string contains a slash '/', the string will be
+output as two identifiers separated by a period (.),
+as in SQL database_name.identifier. */
+UNIV_INTERN
+void
+ut_print_name(
+/*==========*/
+ FILE* f, /*!< in: output stream */
+ trx_t* trx, /*!< in: transaction */
+ ibool table_id,/*!< in: TRUE=print a table name,
+ FALSE=print other identifier */
+ const char* name) /*!< in: name to print */
+{
+ ut_print_namel(f, trx, table_id, name, strlen(name));
+}
+
+/**********************************************************************//**
+Outputs a fixed-length string, quoted as an SQL identifier.
+If the string contains a slash '/', the string will be
+output as two identifiers separated by a period (.),
+as in SQL database_name.identifier. */
+UNIV_INTERN
+void
+ut_print_namel(
+/*===========*/
+ FILE* f, /*!< in: output stream */
+ trx_t* trx, /*!< in: transaction (NULL=no quotes) */
+ ibool table_id,/*!< in: TRUE=print a table name,
+ FALSE=print other identifier */
+ const char* name, /*!< in: name to print */
+ ulint namelen)/*!< in: length of name */
+{
+ /* 2 * NAME_LEN for database and table name,
+ and some slack for the #mysql50# prefix and quotes */
+ char buf[3 * NAME_LEN];
+ const char* bufend;
+
+ bufend = innobase_convert_name(buf, sizeof buf,
+ name, namelen,
+ trx ? trx->mysql_thd : NULL,
+ table_id);
+
+ fwrite(buf, 1, bufend - buf, f);
+}
+
+/**********************************************************************//**
+Catenate files. */
+UNIV_INTERN
+void
+ut_copy_file(
+/*=========*/
+ FILE* dest, /*!< in: output file */
+ FILE* src) /*!< in: input file to be appended to output */
+{
+ long len = ftell(src);
+ char buf[4096];
+
+ rewind(src);
+ do {
+ size_t maxs = len < (long) sizeof buf
+ ? (size_t) len
+ : sizeof buf;
+ size_t size = fread(buf, 1, maxs, src);
+ fwrite(buf, 1, size, dest);
+ len -= (long) size;
+ if (size < maxs) {
+ break;
+ }
+ } while (len > 0);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+#ifdef __WIN__
+# include <stdarg.h>
+/**********************************************************************//**
+A substitute for snprintf(3), formatted output conversion into
+a limited buffer.
+@return number of characters that would have been printed if the size
+were unlimited, not including the terminating '\0'. */
+UNIV_INTERN
+int
+ut_snprintf(
+/*========*/
+ char* str, /*!< out: string */
+ size_t size, /*!< in: str size */
+ const char* fmt, /*!< in: format */
+ ...) /*!< in: format values */
+{
+ int res;
+ va_list ap1;
+ va_list ap2;
+
+ va_start(ap1, fmt);
+ va_start(ap2, fmt);
+
+ res = _vscprintf(fmt, ap1);
+ ut_a(res != -1);
+
+ if (size > 0) {
+ _vsnprintf(str, size, fmt, ap2);
+
+ if ((size_t) res >= size) {
+ str[size - 1] = '\0';
+ }
+ }
+
+ va_end(ap1);
+ va_end(ap2);
+
+ return(res);
+}
+#endif /* __WIN__ */
diff --git a/storage/innodb_plugin/ut/ut0vec.c b/storage/innodb_plugin/ut/ut0vec.c
new file mode 100644
index 00000000000..45f2bc9771f
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0vec.c
@@ -0,0 +1,79 @@
+/*****************************************************************************
+
+Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+/*******************************************************************//**
+@file ut/ut0vec.c
+A vector of pointers to data items
+
+Created 4/6/2006 Osku Salerma
+************************************************************************/
+
+#include "ut0vec.h"
+#ifdef UNIV_NONINL
+#include "ut0vec.ic"
+#endif
+#include <string.h>
+
+/****************************************************************//**
+Create a new vector with the given initial size.
+@return vector */
+UNIV_INTERN
+ib_vector_t*
+ib_vector_create(
+/*=============*/
+ mem_heap_t* heap, /*!< in: heap */
+ ulint size) /*!< in: initial size */
+{
+ ib_vector_t* vec;
+
+ ut_a(size > 0);
+
+ vec = mem_heap_alloc(heap, sizeof(*vec));
+
+ vec->heap = heap;
+ vec->data = mem_heap_alloc(heap, sizeof(void*) * size);
+ vec->used = 0;
+ vec->total = size;
+
+ return(vec);
+}
+
+/****************************************************************//**
+Push a new element to the vector, increasing its size if necessary. */
+UNIV_INTERN
+void
+ib_vector_push(
+/*===========*/
+ ib_vector_t* vec, /*!< in: vector */
+ void* elem) /*!< in: data element */
+{
+ if (vec->used >= vec->total) {
+ void** new_data;
+ ulint new_total = vec->total * 2;
+
+ new_data = mem_heap_alloc(vec->heap,
+ sizeof(void*) * new_total);
+ memcpy(new_data, vec->data, sizeof(void*) * vec->total);
+
+ vec->data = new_data;
+ vec->total = new_total;
+ }
+
+ vec->data[vec->used] = elem;
+ vec->used++;
+}
diff --git a/storage/innodb_plugin/ut/ut0wqueue.c b/storage/innodb_plugin/ut/ut0wqueue.c
new file mode 100644
index 00000000000..5220d1e17f4
--- /dev/null
+++ b/storage/innodb_plugin/ut/ut0wqueue.c
@@ -0,0 +1,118 @@
+/*****************************************************************************
+
+Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
+
+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
+
+*****************************************************************************/
+
+#include "ut0wqueue.h"
+
+/*******************************************************************//**
+@file ut/ut0wqueue.c
+A work queue
+
+Created 4/26/2006 Osku Salerma
+************************************************************************/
+
+/****************************************************************//**
+Create a new work queue.
+@return work queue */
+UNIV_INTERN
+ib_wqueue_t*
+ib_wqueue_create(void)
+/*===================*/
+{
+ ib_wqueue_t* wq = mem_alloc(sizeof(ib_wqueue_t));
+
+ mutex_create(&wq->mutex, SYNC_WORK_QUEUE);
+
+ wq->items = ib_list_create();
+ wq->event = os_event_create(NULL);
+
+ return(wq);
+}
+
+/****************************************************************//**
+Free a work queue. */
+UNIV_INTERN
+void
+ib_wqueue_free(
+/*===========*/
+ ib_wqueue_t* wq) /*!< in: work queue */
+{
+ ut_a(!ib_list_get_first(wq->items));
+
+ mutex_free(&wq->mutex);
+ ib_list_free(wq->items);
+ os_event_free(wq->event);
+
+ mem_free(wq);
+}
+
+/****************************************************************//**
+Add a work item to the queue. */
+UNIV_INTERN
+void
+ib_wqueue_add(
+/*==========*/
+ ib_wqueue_t* wq, /*!< in: work queue */
+ void* item, /*!< in: work item */
+ mem_heap_t* heap) /*!< in: memory heap to use for allocating the
+ list node */
+{
+ mutex_enter(&wq->mutex);
+
+ ib_list_add_last(wq->items, item, heap);
+ os_event_set(wq->event);
+
+ mutex_exit(&wq->mutex);
+}
+
+/****************************************************************//**
+Wait for a work item to appear in the queue.
+@return work item */
+UNIV_INTERN
+void*
+ib_wqueue_wait(
+/*===========*/
+ ib_wqueue_t* wq) /*!< in: work queue */
+{
+ ib_list_node_t* node;
+
+ for (;;) {
+ os_event_wait(wq->event);
+
+ mutex_enter(&wq->mutex);
+
+ node = ib_list_get_first(wq->items);
+
+ if (node) {
+ ib_list_remove(wq->items, node);
+
+ if (!ib_list_get_first(wq->items)) {
+ /* We must reset the event when the list
+ gets emptied. */
+ os_event_reset(wq->event);
+ }
+
+ break;
+ }
+
+ mutex_exit(&wq->mutex);
+ }
+
+ mutex_exit(&wq->mutex);
+
+ return(node->data);
+}