diff options
author | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2010-03-24 18:03:44 +0300 |
---|---|---|
committer | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2010-03-24 18:03:44 +0300 |
commit | d95c1e3b470506c7df6dfce3fe6dc7e5b46930ee (patch) | |
tree | 9f13d4fcc3ac732dc94fe2cae446f6f8c2b4e02b /mysys | |
parent | abc6846d5b1df4846c4ffc03f4c93c82f874dd96 (diff) | |
parent | ae715642f46d4ed9ea8b5dd9b5cc9f3cace7f437 (diff) | |
download | mariadb-git-d95c1e3b470506c7df6dfce3fe6dc7e5b46930ee.tar.gz |
Manual merge of mysql-trunk into mysql-trunk-merge.
Conflicts:
Text conflict in client/mysqlbinlog.cc
Text conflict in mysql-test/Makefile.am
Text conflict in mysql-test/collections/default.daily
Text conflict in mysql-test/r/mysqlbinlog_row_innodb.result
Text conflict in mysql-test/suite/rpl/r/rpl_typeconv_innodb.result
Text conflict in mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test
Text conflict in mysql-test/suite/rpl/t/rpl_row_create_table.test
Text conflict in mysql-test/suite/rpl/t/rpl_slave_skip.test
Text conflict in mysql-test/suite/rpl/t/rpl_typeconv_innodb.test
Text conflict in mysys/charset.c
Text conflict in sql/field.cc
Text conflict in sql/field.h
Text conflict in sql/item.h
Text conflict in sql/item_func.cc
Text conflict in sql/log.cc
Text conflict in sql/log_event.cc
Text conflict in sql/log_event_old.cc
Text conflict in sql/mysqld.cc
Text conflict in sql/rpl_utility.cc
Text conflict in sql/rpl_utility.h
Text conflict in sql/set_var.cc
Text conflict in sql/share/Makefile.am
Text conflict in sql/sql_delete.cc
Text conflict in sql/sql_plugin.cc
Text conflict in sql/sql_select.cc
Text conflict in sql/sql_table.cc
Text conflict in storage/example/ha_example.h
Text conflict in storage/federated/ha_federated.cc
Text conflict in storage/myisammrg/ha_myisammrg.cc
Text conflict in storage/myisammrg/myrg_open.c
Diffstat (limited to 'mysys')
59 files changed, 4118 insertions, 888 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 21b04e7c968..2fbaac7fe72 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2006 MySQL AB +# Copyright (C) 2006 MySQL AB, 2009 Sun Microsystems, Inc # # 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 @@ -13,15 +13,9 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# Only the server link with this library, the client libraries and the client -# executables all link with recompiles of source found in the "mysys" directory. -# So we only need to create one version of this library, with the "static" -# Thread Local Storage model. -# -# Exception is the embedded server that needs this library compiled with -# dynamic TLS, i.e. define USE_TLS -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys) + +INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys) SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_modify.c errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c @@ -30,17 +24,45 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_arr_appstr.c mf_tempdir.c mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chsize.c - my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c + my_clock.c my_compress.c my_copy.c my_crc32.c my_create.c my_delete.c my_div.c my_error.c my_file.c my_fopen.c my_fstream.c my_gethostbyname.c my_gethwaddr.c my_getopt.c my_getsystime.c my_getwd.c my_handler.c my_init.c my_lib.c my_lock.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c - my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c - my_winerr.c my_winfile.c my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c + my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c + my_write.c ptr_cmp.c queues.c stacktrace.c rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c - thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c) + thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c + lf_alloc-pin.c lf_dynarray.c lf_hash.c + my_atomic.c my_getncpus.c + my_rdtsc.c) + +IF (WIN32) + SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_winthread.c my_wincond.c my_winerr.c my_winfile.c my_windac.c my_conio.c) +ENDIF() + +IF(NOT HAVE_CXX_NEW) + # gcc as C++ compiler does not have new/delete + SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_new.cc) + ADD_DEFINITIONS( -DUSE_MYSYS_NEW) +ENDIF() + +IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_C_COMPILER_ID MATCHES "SunPro") + # Inline assembly template for rdtsc + SET_SOURCE_FILES_PROPERTIES(my_rdtsc.c + PROPERTIES COMPILE_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/my_timer_cycles.il") +ENDIF() + +IF(HAVE_LARGE_PAGES) + SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_largepage.c) +ENDIF() -IF(NOT SOURCE_SUBLIBS) - ADD_LIBRARY(mysys ${MYSYS_SOURCES}) -ENDIF(NOT SOURCE_SUBLIBS) +IF(UNIX) + # some workarounds + SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_port.c) +ENDIF() +ADD_CONVENIENCE_LIBRARY(mysys ${MYSYS_SOURCES}) +TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY} + ${LIBNSL} ${LIBM} ${LIBRT}) +DTRACE_INSTRUMENT(mysys) diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 68fde34ee07..476b63d3ad5 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -16,7 +16,8 @@ MYSQLDATAdir = $(localstatedir) MYSQLSHAREdir = $(pkgdatadir) MYSQLBASEdir= $(prefix) -INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \ +INCLUDES = @ZLIB_INCLUDES@ @RDTSC_SPARC_ASSEMBLY@ \ + -I$(top_builddir)/include \ -I$(top_srcdir)/include -I$(srcdir) pkglib_LIBRARIES = libmysys.a LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a @@ -30,7 +31,8 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \ my_malloc.c my_realloc.c my_once.c mulalloc.c \ my_alloc.c safemalloc.c my_new.cc \ - my_vle.c my_atomic.c \ + my_vle.c my_atomic.c lf_hash.c \ + lf_dynarray.c lf_alloc-pin.c \ my_fopen.c my_fstream.c my_getsystime.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ @@ -52,7 +54,8 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_gethostbyname.c rijndael.c my_aes.c sha1.c \ my_handler.c my_netware.c my_largepage.c \ my_memmem.c stacktrace.c \ - my_windac.c my_access.c base64.c my_libwrap.c + my_windac.c my_access.c base64.c my_libwrap.c \ + my_rdtsc.c if NEED_THREAD # mf_keycache is used only in the server, so it is safe to leave the file @@ -64,7 +67,9 @@ endif EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ thr_mutex.c thr_rwlock.c \ CMakeLists.txt mf_soundex.c \ - my_conio.c my_wincond.c my_winthread.c my_winerr.c my_winfile.c + my_conio.c my_wincond.c my_winthread.c my_winerr.c \ + my_winfile.c \ + my_timer_cycles.il libmysys_a_LIBADD = @THREAD_LOBJECTS@ # test_dir_DEPENDENCIES= $(LIBRARIES) # testhash_DEPENDENCIES= $(LIBRARIES) diff --git a/mysys/charset-def.c b/mysys/charset-def.c index bf2576621ce..9089347f002 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -45,6 +45,53 @@ extern CHARSET_INFO my_charset_ucs2_hungarian_uca_ci; extern CHARSET_INFO my_charset_ucs2_sinhala_uca_ci; #endif + +#ifdef HAVE_CHARSET_utf32 +extern CHARSET_INFO my_charset_utf32_icelandic_uca_ci; +extern CHARSET_INFO my_charset_utf32_latvian_uca_ci; +extern CHARSET_INFO my_charset_utf32_romanian_uca_ci; +extern CHARSET_INFO my_charset_utf32_slovenian_uca_ci; +extern CHARSET_INFO my_charset_utf32_polish_uca_ci; +extern CHARSET_INFO my_charset_utf32_estonian_uca_ci; +extern CHARSET_INFO my_charset_utf32_spanish_uca_ci; +extern CHARSET_INFO my_charset_utf32_swedish_uca_ci; +extern CHARSET_INFO my_charset_utf32_turkish_uca_ci; +extern CHARSET_INFO my_charset_utf32_czech_uca_ci; +extern CHARSET_INFO my_charset_utf32_danish_uca_ci; +extern CHARSET_INFO my_charset_utf32_lithuanian_uca_ci; +extern CHARSET_INFO my_charset_utf32_slovak_uca_ci; +extern CHARSET_INFO my_charset_utf32_spanish2_uca_ci; +extern CHARSET_INFO my_charset_utf32_roman_uca_ci; +extern CHARSET_INFO my_charset_utf32_persian_uca_ci; +extern CHARSET_INFO my_charset_utf32_esperanto_uca_ci; +extern CHARSET_INFO my_charset_utf32_hungarian_uca_ci; +extern CHARSET_INFO my_charset_utf32_sinhala_uca_ci; +#endif /* HAVE_CHARSET_utf32 */ + + +#ifdef HAVE_CHARSET_utf16 +extern CHARSET_INFO my_charset_utf16_icelandic_uca_ci; +extern CHARSET_INFO my_charset_utf16_latvian_uca_ci; +extern CHARSET_INFO my_charset_utf16_romanian_uca_ci; +extern CHARSET_INFO my_charset_utf16_slovenian_uca_ci; +extern CHARSET_INFO my_charset_utf16_polish_uca_ci; +extern CHARSET_INFO my_charset_utf16_estonian_uca_ci; +extern CHARSET_INFO my_charset_utf16_spanish_uca_ci; +extern CHARSET_INFO my_charset_utf16_swedish_uca_ci; +extern CHARSET_INFO my_charset_utf16_turkish_uca_ci; +extern CHARSET_INFO my_charset_utf16_czech_uca_ci; +extern CHARSET_INFO my_charset_utf16_danish_uca_ci; +extern CHARSET_INFO my_charset_utf16_lithuanian_uca_ci; +extern CHARSET_INFO my_charset_utf16_slovak_uca_ci; +extern CHARSET_INFO my_charset_utf16_spanish2_uca_ci; +extern CHARSET_INFO my_charset_utf16_roman_uca_ci; +extern CHARSET_INFO my_charset_utf16_persian_uca_ci; +extern CHARSET_INFO my_charset_utf16_esperanto_uca_ci; +extern CHARSET_INFO my_charset_utf16_hungarian_uca_ci; +extern CHARSET_INFO my_charset_utf16_sinhala_uca_ci; +#endif /* HAVE_CHARSET_utf16 */ + + #ifdef HAVE_CHARSET_utf8 extern CHARSET_INFO my_charset_utf8_icelandic_uca_ci; extern CHARSET_INFO my_charset_utf8_latvian_uca_ci; @@ -70,6 +117,28 @@ extern CHARSET_INFO my_charset_utf8_general_cs; #endif #endif +#ifdef HAVE_CHARSET_utf8mb4 +extern CHARSET_INFO my_charset_utf8mb4_icelandic_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_latvian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_romanian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_slovenian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_polish_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_estonian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_spanish_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_swedish_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_turkish_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_czech_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_danish_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_lithuanian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_slovak_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_spanish2_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_roman_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_persian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_esperanto_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_hungarian_uca_ci; +extern CHARSET_INFO my_charset_utf8mb4_sinhala_uca_ci; +#endif /* HAVE_CHARSET_utf8mb4 */ + #endif /* HAVE_UCA_COLLATIONS */ my_bool init_compiled_charsets(myf flags __attribute__((unused))) @@ -191,7 +260,91 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_hungarian_uca_ci); add_compiled_collation(&my_charset_utf8_sinhala_uca_ci); #endif -#endif +#endif /* HAVE_CHARSET_utf8 */ + + +#ifdef HAVE_CHARSET_utf8mb4 + add_compiled_collation(&my_charset_utf8mb4_general_ci); + add_compiled_collation(&my_charset_utf8mb4_bin); +#ifdef HAVE_UCA_COLLATIONS + add_compiled_collation(&my_charset_utf8mb4_unicode_ci); + add_compiled_collation(&my_charset_utf8mb4_icelandic_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_latvian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_romanian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_slovenian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_polish_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_estonian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_spanish_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_swedish_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_turkish_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_czech_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_danish_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_lithuanian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_slovak_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_spanish2_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_roman_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_persian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_esperanto_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_hungarian_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_sinhala_uca_ci); +#endif /* HAVE_UCA_COLLATIONS */ +#endif /* HAVE_CHARSET_utf8mb4 */ + + +#ifdef HAVE_CHARSET_utf16 + add_compiled_collation(&my_charset_utf16_general_ci); + add_compiled_collation(&my_charset_utf16_bin); +#ifdef HAVE_UCA_COLLATIONS + add_compiled_collation(&my_charset_utf16_unicode_ci); + add_compiled_collation(&my_charset_utf16_icelandic_uca_ci); + add_compiled_collation(&my_charset_utf16_latvian_uca_ci); + add_compiled_collation(&my_charset_utf16_romanian_uca_ci); + add_compiled_collation(&my_charset_utf16_slovenian_uca_ci); + add_compiled_collation(&my_charset_utf16_polish_uca_ci); + add_compiled_collation(&my_charset_utf16_estonian_uca_ci); + add_compiled_collation(&my_charset_utf16_spanish_uca_ci); + add_compiled_collation(&my_charset_utf16_swedish_uca_ci); + add_compiled_collation(&my_charset_utf16_turkish_uca_ci); + add_compiled_collation(&my_charset_utf16_czech_uca_ci); + add_compiled_collation(&my_charset_utf16_danish_uca_ci); + add_compiled_collation(&my_charset_utf16_lithuanian_uca_ci); + add_compiled_collation(&my_charset_utf16_slovak_uca_ci); + add_compiled_collation(&my_charset_utf16_spanish2_uca_ci); + add_compiled_collation(&my_charset_utf16_roman_uca_ci); + add_compiled_collation(&my_charset_utf16_persian_uca_ci); + add_compiled_collation(&my_charset_utf16_esperanto_uca_ci); + add_compiled_collation(&my_charset_utf16_hungarian_uca_ci); + add_compiled_collation(&my_charset_utf16_sinhala_uca_ci); +#endif /* HAVE_UCA_COLLATIOINS */ +#endif /* HAVE_CHARSET_utf16 */ + + +#ifdef HAVE_CHARSET_utf32 + add_compiled_collation(&my_charset_utf32_general_ci); + add_compiled_collation(&my_charset_utf32_bin); +#ifdef HAVE_UCA_COLLATIONS + add_compiled_collation(&my_charset_utf32_unicode_ci); + add_compiled_collation(&my_charset_utf32_icelandic_uca_ci); + add_compiled_collation(&my_charset_utf32_latvian_uca_ci); + add_compiled_collation(&my_charset_utf32_romanian_uca_ci); + add_compiled_collation(&my_charset_utf32_slovenian_uca_ci); + add_compiled_collation(&my_charset_utf32_polish_uca_ci); + add_compiled_collation(&my_charset_utf32_estonian_uca_ci); + add_compiled_collation(&my_charset_utf32_spanish_uca_ci); + add_compiled_collation(&my_charset_utf32_swedish_uca_ci); + add_compiled_collation(&my_charset_utf32_turkish_uca_ci); + add_compiled_collation(&my_charset_utf32_czech_uca_ci); + add_compiled_collation(&my_charset_utf32_danish_uca_ci); + add_compiled_collation(&my_charset_utf32_lithuanian_uca_ci); + add_compiled_collation(&my_charset_utf32_slovak_uca_ci); + add_compiled_collation(&my_charset_utf32_spanish2_uca_ci); + add_compiled_collation(&my_charset_utf32_roman_uca_ci); + add_compiled_collation(&my_charset_utf32_persian_uca_ci); + add_compiled_collation(&my_charset_utf32_esperanto_uca_ci); + add_compiled_collation(&my_charset_utf32_hungarian_uca_ci); + add_compiled_collation(&my_charset_utf32_sinhala_uca_ci); +#endif /* HAVE_UCA_COLLATIONS */ +#endif /* HAVE_CHARSET_utf32 */ /* Copy compiled charsets */ for (cs=compiled_charsets; cs->name; cs++) diff --git a/mysys/charset.c b/mysys/charset.c index ab89a259481..9f9d18e31a4 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -254,7 +254,7 @@ static int add_collation(CHARSET_INFO *cs) newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII; #endif } - else if (!strcmp(cs->csname, "utf8")) + else if (!strcmp(cs->csname, "utf8") || !strcmp(cs->csname, "utf8mb3")) { #if defined (HAVE_CHARSET_utf8) && defined(HAVE_UCA_COLLATIONS) copy_uca_collation(newcs, &my_charset_utf8_unicode_ci); @@ -263,6 +263,28 @@ static int add_collation(CHARSET_INFO *cs) return MY_XML_ERROR; #endif } + else if (!strcmp(cs->csname, "utf8mb4")) + { +#if defined (HAVE_CHARSET_utf8mb4) && defined(HAVE_UCA_COLLATIONS) + copy_uca_collation(newcs, &my_charset_utf8mb4_unicode_ci); + newcs->ctype= my_charset_utf8mb4_unicode_ci.ctype; + newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED; +#endif + } + else if (!strcmp(cs->csname, "utf16")) + { +#if defined (HAVE_CHARSET_utf16) && defined(HAVE_UCA_COLLATIONS) + copy_uca_collation(newcs, &my_charset_utf16_unicode_ci); + newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII; +#endif + } + else if (!strcmp(cs->csname, "utf32")) + { +#if defined (HAVE_CHARSET_utf32) && defined(HAVE_UCA_COLLATIONS) + copy_uca_collation(newcs, &my_charset_utf32_unicode_ci); + newcs->state|= MY_CS_AVAILABLE | MY_CS_LOADED | MY_CS_NONASCII; +#endif + } else { uchar *sort_order= all_charsets[cs->number]->sort_order; @@ -344,10 +366,10 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) !(buf= (uchar*) my_malloc(len,myflags))) return TRUE; - if ((fd=my_open(filename,O_RDONLY,myflags)) < 0) + if ((fd= mysql_file_open(key_file_charset, filename, O_RDONLY, myflags)) < 0) goto error; - tmp_len=my_read(fd, buf, len, myflags); - my_close(fd,myflags); + tmp_len= mysql_file_read(fd, buf, len, myflags); + mysql_file_close(fd, myflags); if (tmp_len != len) goto error; @@ -417,7 +439,7 @@ static void init_available_charsets(void) bzero(&all_charsets,sizeof(all_charsets)); init_compiled_charsets(MYF(0)); - + /* Copy compiled charsets */ for (cs=all_charsets; cs < all_charsets+array_elements(all_charsets)-1 ; @@ -430,7 +452,7 @@ static void init_available_charsets(void) *cs= NULL; } } - + strmov(get_charsets_dir(fname), MY_CHARSET_INDEX); my_read_charset_file(fname, MYF(0)); } @@ -441,17 +463,36 @@ void free_charsets(void) charsets_initialized= charsets_template; } + +static const char* +get_collation_name_alias(const char *name, char *buf, size_t bufsize) +{ + if (!strncasecmp(name, "utf8mb3_", 8)) + { + my_snprintf(buf, bufsize, "utf8_%s", name + 8); + return buf; + } + return NULL; +} + + uint get_collation_number(const char *name) { + uint id; + char alias[64]; my_pthread_once(&charsets_initialized, init_available_charsets); - return get_collation_number_internal(name); + if ((id= get_collation_number_internal(name))) + return id; + if ((name= get_collation_name_alias(name, alias, sizeof(alias)))) + return get_collation_number_internal(name); + return 0; } -uint get_charset_number(const char *charset_name, uint cs_flags) +static uint +get_charset_number_internal(const char *charset_name, uint cs_flags) { CHARSET_INFO **cs; - my_pthread_once(&charsets_initialized, init_available_charsets); for (cs= all_charsets; cs < all_charsets + array_elements(all_charsets); @@ -465,6 +506,27 @@ uint get_charset_number(const char *charset_name, uint cs_flags) } +static const char* +get_charset_name_alias(const char *name) +{ + if (!my_strcasecmp(&my_charset_latin1, name, "utf8mb3")) + return "utf8"; + return NULL; +} + + +uint get_charset_number(const char *charset_name, uint cs_flags) +{ + uint id; + my_pthread_once(&charsets_initialized, init_available_charsets); + if ((id= get_charset_number_internal(charset_name, cs_flags))) + return id; + if ((charset_name= get_charset_name_alias(charset_name))) + return get_charset_number_internal(charset_name, cs_flags); + return 0; +} + + const char *get_charset_name(uint charset_number) { CHARSET_INFO *cs; @@ -492,7 +554,7 @@ static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags) To make things thread safe we are not allowing other threads to interfere while we may changing the cs_info_table */ - pthread_mutex_lock(&THR_LOCK_charset); + mysql_mutex_lock(&THR_LOCK_charset); if (!(cs->state & (MY_CS_COMPILED|MY_CS_LOADED))) /* if CS is not in memory */ { @@ -514,7 +576,7 @@ static CHARSET_INFO *get_internal_charset(uint cs_number, myf flags) else cs= NULL; - pthread_mutex_unlock(&THR_LOCK_charset); + mysql_mutex_unlock(&THR_LOCK_charset); } return cs; } diff --git a/mysys/default.c b/mysys/default.c index d6e015f464a..fc119bb3283 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -503,9 +503,13 @@ int my_load_defaults(const char *conf_file, const char **groups, ctx.args= &args; ctx.group= &group; - error= my_search_option_files(conf_file, argc, argv, &args_used, - handle_default_option, (void *) &ctx, - dirs); + if ((error= my_search_option_files(conf_file, argc, argv, &args_used, + handle_default_option, (void *) &ctx, + dirs))) + { + free_root(&alloc,MYF(0)); + DBUG_RETURN(error); + } /* Here error contains <> 0 only if we have a fully specified conf_file or a forced default file @@ -557,10 +561,10 @@ int my_load_defaults(const char *conf_file, const char **groups, exit(0); } - if (error == 0 && default_directories) + if (default_directories) *default_directories= dirs; - DBUG_RETURN(error); + DBUG_RETURN(0); err: fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); @@ -683,7 +687,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler, static const char includedir_keyword[]= "includedir"; static const char include_keyword[]= "include"; const int max_recursion_level= 10; - FILE *fp; + MYSQL_FILE *fp; uint line=0; my_bool found_group=0; uint i; @@ -723,10 +727,10 @@ static int search_default_file_with_ext(Process_option_func opt_handler, } } #endif - if (!(fp= my_fopen(name, O_RDONLY, MYF(0)))) + if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0)))) return 1; /* Ignore wrong files */ - while (fgets(buff, sizeof(buff) - 1, fp)) + while (mysql_file_fgets(buff, sizeof(buff) - 1, fp)) { line++; /* Ignore comment and empty lines */ @@ -916,11 +920,11 @@ static int search_default_file_with_ext(Process_option_func opt_handler, goto err; } } - my_fclose(fp,MYF(0)); + mysql_file_fclose(fp, MYF(0)); return(0); err: - my_fclose(fp,MYF(0)); + mysql_file_fclose(fp, MYF(0)); return -1; /* Fatal error */ } diff --git a/mysys/errors.c b/mysys/errors.c index 4000c5c4e52..37d33374fe1 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -104,7 +104,7 @@ void wait_for_free_space(const char *filename, int errors) MYF(ME_BELL | ME_NOREFRESH), MY_WAIT_FOR_USER_TO_FIX_PANIC, MY_WAIT_GIVE_USER_A_MESSAGE * MY_WAIT_FOR_USER_TO_FIX_PANIC ); - VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); + (void) sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC); } const char **get_global_errmsgs() diff --git a/mysys/hash.c b/mysys/hash.c index 9c1957bf0aa..39f3ad8d31e 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -33,16 +33,18 @@ typedef struct st_hash_info { uchar *data; /* data for current entry */ } HASH_LINK; -static uint my_hash_mask(size_t hashnr, size_t buffmax, size_t maxlength); +static uint my_hash_mask(my_hash_value_type hashnr, + size_t buffmax, size_t maxlength); static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink); static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key, size_t length); -static uint calc_hash(const HASH *hash, const uchar *key, size_t length) +static my_hash_value_type calc_hash(const HASH *hash, + const uchar *key, size_t length) { ulong nr1=1, nr2=4; hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2); - return nr1; + return (my_hash_value_type)nr1; } /** @@ -179,7 +181,8 @@ my_hash_key(const HASH *hash, const uchar *record, size_t *length, /* Calculate pos according to keys */ -static uint my_hash_mask(size_t hashnr, size_t buffmax, size_t maxlength) +static uint my_hash_mask(my_hash_value_type hashnr, size_t buffmax, + size_t maxlength) { if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1)); return (hashnr & ((buffmax >> 1) -1)); @@ -200,7 +203,7 @@ static #if !defined(__USLC__) && !defined(__sgi) inline #endif -unsigned int rec_hashnr(HASH *hash,const uchar *record) +my_hash_value_type rec_hashnr(HASH *hash,const uchar *record) { size_t length; uchar *key= (uchar*) my_hash_key(hash, record, &length, 0); @@ -214,6 +217,23 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length) return my_hash_first(hash, key, length, &state); } +uchar* my_hash_search_using_hash_value(const HASH *hash, + my_hash_value_type hash_value, + const uchar *key, + size_t length) +{ + HASH_SEARCH_STATE state; + return my_hash_first_from_hash_value(hash, hash_value, + key, length, &state); +} + +my_hash_value_type my_calc_hash(const HASH *hash, + const uchar *key, size_t length) +{ + return calc_hash(hash, key, length ? length : hash->key_length); +} + + /* Search after a record based on a key @@ -224,14 +244,31 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length) uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length, HASH_SEARCH_STATE *current_record) { + uchar *res; + if (my_hash_inited(hash)) + res= my_hash_first_from_hash_value(hash, + calc_hash(hash, key, length ? length : hash->key_length), + key, length, current_record); + else + res= 0; + return res; +} + + +uchar* my_hash_first_from_hash_value(const HASH *hash, + my_hash_value_type hash_value, + const uchar *key, + size_t length, + HASH_SEARCH_STATE *current_record) +{ HASH_LINK *pos; uint flag,idx; - DBUG_ENTER("my_hash_first"); + DBUG_ENTER("my_hash_first_from_hash_value"); flag=1; if (hash->records) { - idx= my_hash_mask(calc_hash(hash, key, length ? length : hash->key_length), + idx= my_hash_mask(hash_value, hash->blength, hash->records); do { @@ -331,7 +368,8 @@ static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key, my_bool my_hash_insert(HASH *info, const uchar *record) { int flag; - size_t idx,halfbuff,hash_nr,first_index; + size_t idx,halfbuff,first_index; + my_hash_value_type hash_nr; uchar *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2); HASH_LINK *data,*empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos; @@ -467,7 +505,8 @@ my_bool my_hash_insert(HASH *info, const uchar *record) my_bool my_hash_delete(HASH *hash, uchar *record) { - uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index; + uint blength,pos2,idx,empty_index; + my_hash_value_type pos_hashnr, lastpos_hashnr; HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty; DBUG_ENTER("my_hash_delete"); if (!hash->records) @@ -541,7 +580,7 @@ my_bool my_hash_delete(HASH *hash, uchar *record) pos->next=empty_index; exit: - VOID(pop_dynamic(&hash->array)); + (void) pop_dynamic(&hash->array); if (hash->free) (*hash->free)((uchar*) record); DBUG_RETURN(0); diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c new file mode 100644 index 00000000000..fda9b97791d --- /dev/null +++ b/mysys/lf_alloc-pin.c @@ -0,0 +1,534 @@ +/* QQ: TODO multi-pinbox */ +/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. + + 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 */ + +/* + wait-free concurrent allocator based on pinning addresses + + It works as follows: every thread (strictly speaking - every CPU, but + it's too difficult to do) has a small array of pointers. They're called + "pins". Before using an object its address must be stored in this array + (pinned). When an object is no longer necessary its address must be + removed from this array (unpinned). When a thread wants to free() an + object it scans all pins of all threads to see if somebody has this + object pinned. If yes - the object is not freed (but stored in a + "purgatory"). To reduce the cost of a single free() pins are not scanned + on every free() but only added to (thread-local) purgatory. On every + LF_PURGATORY_SIZE free() purgatory is scanned and all unpinned objects + are freed. + + Pins are used to solve ABA problem. To use pins one must obey + a pinning protocol: + + 1. Let's assume that PTR is a shared pointer to an object. Shared means + that any thread may modify it anytime to point to a different object + and free the old object. Later the freed object may be potentially + allocated by another thread. If we're unlucky that other thread may + set PTR to point to this object again. This is ABA problem. + 2. Create a local pointer LOCAL_PTR. + 3. Pin the PTR in a loop: + do + { + LOCAL_PTR= PTR; + pin(PTR, PIN_NUMBER); + } while (LOCAL_PTR != PTR) + 4. It is guaranteed that after the loop has ended, LOCAL_PTR + points to an object (or NULL, if PTR may be NULL), that + will never be freed. It is not guaranteed though + that LOCAL_PTR == PTR (as PTR can change any time) + 5. When done working with the object, remove the pin: + unpin(PIN_NUMBER) + 6. When copying pins (as in the list traversing loop: + pin(CUR, 1); + while () + { + do // standard + { // pinning + NEXT=CUR->next; // loop + pin(NEXT, 0); // see #3 + } while (NEXT != CUR->next); // above + ... + ... + CUR=NEXT; + pin(CUR, 1); // copy pin[0] to pin[1] + } + which keeps CUR address constantly pinned), note than pins may be + copied only upwards (!!!), that is pin[N] to pin[M], M > N. + 7. Don't keep the object pinned longer than necessary - the number of + pins you have is limited (and small), keeping an object pinned + prevents its reuse and cause unnecessary mallocs. + + Explanations: + + 3. The loop is important. The following can occur: + thread1> LOCAL_PTR= PTR + thread2> free(PTR); PTR=0; + thread1> pin(PTR, PIN_NUMBER); + now thread1 cannot access LOCAL_PTR, even if it's pinned, + because it points to a freed memory. That is, it *must* + verify that it has indeed pinned PTR, the shared pointer. + + 6. When a thread wants to free some LOCAL_PTR, and it scans + all lists of pins to see whether it's pinned, it does it + upwards, from low pin numbers to high. Thus another thread + must copy an address from one pin to another in the same + direction - upwards, otherwise the scanning thread may + miss it. + + Implementation details: + + Pins are given away from a "pinbox". Pinbox is stack-based allocator. + It used dynarray for storing pins, new elements are allocated by dynarray + as necessary, old are pushed in the stack for reuse. ABA is solved by + versioning a pointer - because we use an array, a pointer to pins is 16 bit, + upper 16 bits are used for a version. + + It is assumed that pins belong to a THD and are not transferable + between THD's (LF_PINS::stack_ends_here being a primary reason + for this limitation). +*/ +#include <my_global.h> +#include <my_sys.h> +#include <lf.h> + +#define LF_PINBOX_MAX_PINS 65536 + +static void _lf_pinbox_real_free(LF_PINS *pins); + +/* + Initialize a pinbox. Normally called from lf_alloc_init. + See the latter for details. +*/ +void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset, + lf_pinbox_free_func *free_func, void *free_func_arg) +{ + DBUG_ASSERT(free_ptr_offset % sizeof(void *) == 0); + compile_time_assert(sizeof(LF_PINS) == 64); + lf_dynarray_init(&pinbox->pinarray, sizeof(LF_PINS)); + pinbox->pinstack_top_ver= 0; + pinbox->pins_in_array= 0; + pinbox->free_ptr_offset= free_ptr_offset; + pinbox->free_func= free_func; + pinbox->free_func_arg= free_func_arg; +} + +void lf_pinbox_destroy(LF_PINBOX *pinbox) +{ + lf_dynarray_destroy(&pinbox->pinarray); +} + +/* + Get pins from a pinbox. Usually called via lf_alloc_get_pins() or + lf_hash_get_pins(). + + SYNOPSYS + pinbox - + + DESCRIPTION + get a new LF_PINS structure from a stack of unused pins, + or allocate a new one out of dynarray. + + NOTE + It is assumed that pins belong to a thread and are not transferable + between threads. +*/ +LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox) +{ + uint32 pins, next, top_ver; + LF_PINS *el; + /* + We have an array of max. 64k elements. + The highest index currently allocated is pinbox->pins_in_array. + Freed elements are in a lifo stack, pinstack_top_ver. + pinstack_top_ver is 32 bits; 16 low bits are the index in the + array, to the first element of the list. 16 high bits are a version + (every time the 16 low bits are updated, the 16 high bits are + incremented). Versioniong prevents the ABA problem. + */ + top_ver= pinbox->pinstack_top_ver; + do + { + if (!(pins= top_ver % LF_PINBOX_MAX_PINS)) + { + /* the stack of free elements is empty */ + pins= my_atomic_add32((int32 volatile*) &pinbox->pins_in_array, 1)+1; + if (unlikely(pins >= LF_PINBOX_MAX_PINS)) + return 0; + /* + note that the first allocated element has index 1 (pins==1). + index 0 is reserved to mean "NULL pointer" + */ + el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins); + if (unlikely(!el)) + return 0; + break; + } + el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins); + next= el->link; + } while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver, + (int32*) &top_ver, + top_ver-pins+next+LF_PINBOX_MAX_PINS)); + /* + set el->link to the index of el in the dynarray (el->link has two usages: + - if element is allocated, it's its own index + - if element is free, it's its next element in the free stack + */ + el->link= pins; + el->purgatory_count= 0; + el->pinbox= pinbox; + el->stack_ends_here= & my_thread_var->stack_ends_here; + return el; +} + +/* + Put pins back to a pinbox. Usually called via lf_alloc_put_pins() or + lf_hash_put_pins(). + + DESCRIPTION + empty the purgatory (XXX deadlock warning below!), + push LF_PINS structure to a stack +*/ +void _lf_pinbox_put_pins(LF_PINS *pins) +{ + LF_PINBOX *pinbox= pins->pinbox; + uint32 top_ver, nr; + nr= pins->link; +#ifdef MY_LF_EXTRA_DEBUG + { + int i; + for (i= 0; i < LF_PINBOX_PINS; i++) + DBUG_ASSERT(pins->pin[i] == 0); + } +#endif + /* + XXX this will deadlock if other threads will wait for + the caller to do something after _lf_pinbox_put_pins(), + and they would have pinned addresses that the caller wants to free. + Thus: only free pins when all work is done and nobody can wait for you!!! + */ + while (pins->purgatory_count) + { + _lf_pinbox_real_free(pins); + if (pins->purgatory_count) + { + my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock); + pthread_yield(); + my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock); + } + } + top_ver= pinbox->pinstack_top_ver; + do + { + pins->link= top_ver % LF_PINBOX_MAX_PINS; + } while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver, + (int32*) &top_ver, + top_ver-pins->link+nr+LF_PINBOX_MAX_PINS)); + return; +} + +static int ptr_cmp(void **a, void **b) +{ + return *a < *b ? -1 : *a == *b ? 0 : 1; +} + +#define add_to_purgatory(PINS, ADDR) \ + do \ + { \ + *(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)= \ + (PINS)->purgatory; \ + (PINS)->purgatory= (ADDR); \ + (PINS)->purgatory_count++; \ + } while (0) + +/* + Free an object allocated via pinbox allocator + + DESCRIPTION + add an object to purgatory. if necessary, call _lf_pinbox_real_free() + to actually free something. +*/ +void _lf_pinbox_free(LF_PINS *pins, void *addr) +{ + add_to_purgatory(pins, addr); + if (pins->purgatory_count % LF_PURGATORY_SIZE) + _lf_pinbox_real_free(pins); +} + +struct st_harvester { + void **granary; + int npins; +}; + +/* + callback for _lf_dynarray_iterate: + scan all pins of all threads and accumulate all pins +*/ +static int harvest_pins(LF_PINS *el, struct st_harvester *hv) +{ + int i; + LF_PINS *el_end= el+min(hv->npins, LF_DYNARRAY_LEVEL_LENGTH); + for (; el < el_end; el++) + { + for (i= 0; i < LF_PINBOX_PINS; i++) + { + void *p= el->pin[i]; + if (p) + *hv->granary++= p; + } + } + /* + hv->npins may become negative below, but it means that + we're on the last dynarray page and harvest_pins() won't be + called again. We don't bother to make hv->npins() correct + (that is 0) in this case. + */ + hv->npins-= LF_DYNARRAY_LEVEL_LENGTH; + return 0; +} + +/* + callback for _lf_dynarray_iterate: + scan all pins of all threads and see if addr is present there +*/ +static int match_pins(LF_PINS *el, void *addr) +{ + int i; + LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH; + for (; el < el_end; el++) + for (i= 0; i < LF_PINBOX_PINS; i++) + if (el->pin[i] == addr) + return 1; + return 0; +} + +#if STACK_DIRECTION < 0 +#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END)) +#else +#define available_stack_size(CUR,END) (long) ((char*)(END) - (char*)(CUR)) +#endif + +#define next_node(P, X) (*((uchar * volatile *)(((uchar *)(X)) + (P)->free_ptr_offset))) +#define anext_node(X) next_node(&allocator->pinbox, (X)) + +/* + Scan the purgatory and free everything that can be freed +*/ +static void _lf_pinbox_real_free(LF_PINS *pins) +{ + int npins, alloca_size; + void *list, **addr; + void *first, *last= NULL; + LF_PINBOX *pinbox= pins->pinbox; + + LINT_INIT(first); + npins= pinbox->pins_in_array+1; + +#ifdef HAVE_ALLOCA + alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins; + /* create a sorted list of pinned addresses, to speed up searches */ + if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size) + { + struct st_harvester hv; + addr= (void **) alloca(alloca_size); + hv.granary= addr; + hv.npins= npins; + /* scan the dynarray and accumulate all pinned addresses */ + _lf_dynarray_iterate(&pinbox->pinarray, + (lf_dynarray_func)harvest_pins, &hv); + + npins= hv.granary-addr; + /* and sort them */ + if (npins) + qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp); + } + else +#endif + addr= 0; + + list= pins->purgatory; + pins->purgatory= 0; + pins->purgatory_count= 0; + while (list) + { + void *cur= list; + list= *(void **)((char *)cur+pinbox->free_ptr_offset); + if (npins) + { + if (addr) /* use binary search */ + { + void **a, **b, **c; + for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2) + if (cur == *c) + a= b= c; + else if (cur > *c) + a= c; + else + b= c; + if (cur == *a || cur == *b) + goto found; + } + else /* no alloca - no cookie. linear search here */ + { + if (_lf_dynarray_iterate(&pinbox->pinarray, + (lf_dynarray_func)match_pins, cur)) + goto found; + } + } + /* not pinned - freeing */ + if (last) + last= next_node(pinbox, last)= (uchar *)cur; + else + first= last= (uchar *)cur; + continue; +found: + /* pinned - keeping */ + add_to_purgatory(pins, cur); + } + if (last) + pinbox->free_func(first, last, pinbox->free_func_arg); +} + +/* lock-free memory allocator for fixed-size objects */ + +LF_REQUIRE_PINS(1) + +/* + callback for _lf_pinbox_real_free to free a list of unpinned objects - + add it back to the allocator stack + + DESCRIPTION + 'first' and 'last' are the ends of the linked list of nodes: + first->el->el->....->el->last. Use first==last to free only one element. +*/ +static void alloc_free(uchar *first, + uchar volatile *last, + LF_ALLOCATOR *allocator) +{ + /* + we need a union here to access type-punned pointer reliably. + otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop + */ + union { uchar * node; void *ptr; } tmp; + tmp.node= allocator->top; + do + { + anext_node(last)= tmp.node; + } while (!my_atomic_casptr((void **)(char *)&allocator->top, + (void **)&tmp.ptr, first) && LF_BACKOFF); +} + +/* + initialize lock-free allocator + + SYNOPSYS + allocator - + size a size of an object to allocate + free_ptr_offset an offset inside the object to a sizeof(void *) + memory that is guaranteed to be unused after + the object is put in the purgatory. Unused by ANY + thread, not only the purgatory owner. + This memory will be used to link waiting-to-be-freed + objects in a purgatory list. +*/ +void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset) +{ + lf_pinbox_init(&allocator->pinbox, free_ptr_offset, + (lf_pinbox_free_func *)alloc_free, allocator); + allocator->top= 0; + allocator->mallocs= 0; + allocator->element_size= size; + allocator->constructor= 0; + allocator->destructor= 0; + DBUG_ASSERT(size >= sizeof(void*) + free_ptr_offset); +} + +/* + destroy the allocator, free everything that's in it + + NOTE + As every other init/destroy function here and elsewhere it + is not thread safe. No, this function is no different, ensure + that no thread needs the allocator before destroying it. + We are not responsible for any damage that may be caused by + accessing the allocator when it is being or has been destroyed. + Oh yes, and don't put your cat in a microwave. +*/ +void lf_alloc_destroy(LF_ALLOCATOR *allocator) +{ + uchar *node= allocator->top; + while (node) + { + uchar *tmp= anext_node(node); + if (allocator->destructor) + allocator->destructor(node); + my_free((void *)node, MYF(0)); + node= tmp; + } + lf_pinbox_destroy(&allocator->pinbox); + allocator->top= 0; +} + +/* + Allocate and return an new object. + + DESCRIPTION + Pop an unused object from the stack or malloc it is the stack is empty. + pin[0] is used, it's removed on return. +*/ +void *_lf_alloc_new(LF_PINS *pins) +{ + LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg); + uchar *node; + for (;;) + { + do + { + node= allocator->top; + _lf_pin(pins, 0, node); + } while (node != allocator->top && LF_BACKOFF); + if (!node) + { + node= (void *)my_malloc(allocator->element_size, MYF(MY_WME)); + if (allocator->constructor) + allocator->constructor(node); +#ifdef MY_LF_EXTRA_DEBUG + if (likely(node != 0)) + my_atomic_add32(&allocator->mallocs, 1); +#endif + break; + } + if (my_atomic_casptr((void **)(char *)&allocator->top, + (void *)&node, anext_node(node))) + break; + } + _lf_unpin(pins, 0); + return node; +} + +/* + count the number of objects in a pool. + + NOTE + This is NOT thread-safe !!! +*/ +uint lf_alloc_pool_count(LF_ALLOCATOR *allocator) +{ + uint i; + uchar *node; + for (node= allocator->top, i= 0; node; node= anext_node(node), i++) + /* no op */; + return i; +} + diff --git a/mysys/lf_dynarray.c b/mysys/lf_dynarray.c new file mode 100644 index 00000000000..b1cdce698a9 --- /dev/null +++ b/mysys/lf_dynarray.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2006 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 */ + +/* + Analog of DYNAMIC_ARRAY that never reallocs + (so no pointer into the array may ever become invalid). + + Memory is allocated in non-contiguous chunks. + This data structure is not space efficient for sparse arrays. + + Every element is aligned to sizeof(element) boundary + (to avoid false sharing if element is big enough). + + LF_DYNARRAY is a recursive structure. On the zero level + LF_DYNARRAY::level[0] it's an array of LF_DYNARRAY_LEVEL_LENGTH elements, + on the first level it's an array of LF_DYNARRAY_LEVEL_LENGTH pointers + to arrays of elements, on the second level it's an array of pointers + to arrays of pointers to arrays of elements. And so on. + + With four levels the number of elements is limited to 4311810304 + (but as in all functions index is uint, the real limit is 2^32-1) + + Actually, it's wait-free, not lock-free ;-) +*/ + +#include <my_global.h> +#include <m_string.h> +#include <my_sys.h> +#include <lf.h> + +void lf_dynarray_init(LF_DYNARRAY *array, uint element_size) +{ + bzero(array, sizeof(*array)); + array->size_of_element= element_size; + my_atomic_rwlock_init(&array->lock); +} + +static void recursive_free(void **alloc, int level) +{ + if (!alloc) + return; + + if (level) + { + int i; + for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++) + recursive_free(alloc[i], level-1); + my_free((void *)alloc, MYF(0)); + } + else + my_free(alloc[-1], MYF(0)); +} + +void lf_dynarray_destroy(LF_DYNARRAY *array) +{ + int i; + for (i= 0; i < LF_DYNARRAY_LEVELS; i++) + recursive_free(array->level[i], i); + my_atomic_rwlock_destroy(&array->lock); +} + +static const ulong dynarray_idxes_in_prev_levels[LF_DYNARRAY_LEVELS]= +{ + 0, /* +1 here to to avoid -1's below */ + LF_DYNARRAY_LEVEL_LENGTH, + LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH + + LF_DYNARRAY_LEVEL_LENGTH, + LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH * + LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH * + LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH +}; + +static const ulong dynarray_idxes_in_prev_level[LF_DYNARRAY_LEVELS]= +{ + 0, /* +1 here to to avoid -1's below */ + LF_DYNARRAY_LEVEL_LENGTH, + LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH, + LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH * + LF_DYNARRAY_LEVEL_LENGTH, +}; + +/* + Returns a valid lvalue pointer to the element number 'idx'. + Allocates memory if necessary. +*/ +void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx) +{ + void * ptr, * volatile * ptr_ptr= 0; + int i; + + for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--) + /* no-op */; + ptr_ptr= &array->level[i]; + idx-= dynarray_idxes_in_prev_levels[i]; + for (; i > 0; i--) + { + if (!(ptr= *ptr_ptr)) + { + void *alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * sizeof(void *), + MYF(MY_WME|MY_ZEROFILL)); + if (unlikely(!alloc)) + return(NULL); + if (my_atomic_casptr(ptr_ptr, &ptr, alloc)) + ptr= alloc; + else + my_free(alloc, MYF(0)); + } + ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i]; + idx%= dynarray_idxes_in_prev_level[i]; + } + if (!(ptr= *ptr_ptr)) + { + uchar *alloc, *data; + alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * array->size_of_element + + max(array->size_of_element, sizeof(void *)), + MYF(MY_WME|MY_ZEROFILL)); + if (unlikely(!alloc)) + return(NULL); + /* reserve the space for free() address */ + data= alloc + sizeof(void *); + { /* alignment */ + intptr mod= ((intptr)data) % array->size_of_element; + if (mod) + data+= array->size_of_element - mod; + } + ((void **)data)[-1]= alloc; /* free() will need the original pointer */ + if (my_atomic_casptr(ptr_ptr, &ptr, data)) + ptr= data; + else + my_free(alloc, MYF(0)); + } + return ((uchar*)ptr) + array->size_of_element * idx; +} + +/* + Returns a pointer to the element number 'idx' + or NULL if an element does not exists +*/ +void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx) +{ + void * ptr, * volatile * ptr_ptr= 0; + int i; + + for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--) + /* no-op */; + ptr_ptr= &array->level[i]; + idx-= dynarray_idxes_in_prev_levels[i]; + for (; i > 0; i--) + { + if (!(ptr= *ptr_ptr)) + return(NULL); + ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i]; + idx %= dynarray_idxes_in_prev_level[i]; + } + if (!(ptr= *ptr_ptr)) + return(NULL); + return ((uchar*)ptr) + array->size_of_element * idx; +} + +static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level, + lf_dynarray_func func, void *arg) +{ + int res, i; + if (!ptr) + return 0; + if (!level) + return func(ptr, arg); + for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++) + if ((res= recursive_iterate(array, ((void **)ptr)[i], level-1, func, arg))) + return res; + return 0; +} + +/* + Calls func(array, arg) on every array of LF_DYNARRAY_LEVEL_LENGTH elements + in lf_dynarray. + + DESCRIPTION + lf_dynarray consists of a set of arrays, LF_DYNARRAY_LEVEL_LENGTH elements + each. _lf_dynarray_iterate() calls user-supplied function on every array + from the set. It is the fastest way to scan the array, faster than + for (i=0; i < N; i++) { func(_lf_dynarray_value(dynarray, i)); } + + NOTE + if func() returns non-zero, the scan is aborted +*/ +int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg) +{ + int i, res; + for (i= 0; i < LF_DYNARRAY_LEVELS; i++) + if ((res= recursive_iterate(array, array->level[i], i, func, arg))) + return res; + return 0; +} + diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c new file mode 100644 index 00000000000..f478196c7c8 --- /dev/null +++ b/mysys/lf_hash.c @@ -0,0 +1,505 @@ +/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. + + 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 */ + +/* + extensible hash + + TODO + try to get rid of dummy nodes ? + for non-unique hash, count only _distinct_ values + (but how to do it in lf_hash_delete ?) +*/ +#include <my_global.h> +#include <m_string.h> +#include <my_sys.h> +#include <my_bit.h> +#include <lf.h> + +LF_REQUIRE_PINS(3) + +/* An element of the list */ +typedef struct { + intptr volatile link; /* a pointer to the next element in a listand a flag */ + uint32 hashnr; /* reversed hash number, for sorting */ + const uchar *key; + size_t keylen; + /* + data is stored here, directly after the keylen. + thus the pointer to data is (void*)(slist_element_ptr+1) + */ +} LF_SLIST; + +const int LF_HASH_OVERHEAD= sizeof(LF_SLIST); + +/* + a structure to pass the context (pointers two the three successive elements + in a list) from lfind to linsert/ldelete +*/ +typedef struct { + intptr volatile *prev; + LF_SLIST *curr, *next; +} CURSOR; + +/* + the last bit in LF_SLIST::link is a "deleted" flag. + the helper macros below convert it to a pure pointer or a pure flag +*/ +#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1)) +#define DELETED(V) ((V) & 1) + +/* + DESCRIPTION + Search for hashnr/key/keylen in the list starting from 'head' and + position the cursor. The list is ORDER BY hashnr, key + + RETURN + 0 - not found + 1 - found + + NOTE + cursor is positioned in either case + pins[0..2] are used, they are NOT removed on return +*/ +static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, + const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins) +{ + uint32 cur_hashnr; + const uchar *cur_key; + uint cur_keylen; + intptr link; + +retry: + cursor->prev= (intptr *)head; + do { /* PTR() isn't necessary below, head is a dummy node */ + cursor->curr= (LF_SLIST *)(*cursor->prev); + _lf_pin(pins, 1, cursor->curr); + } while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF); + for (;;) + { + if (unlikely(!cursor->curr)) + return 0; /* end of the list */ + do { + /* QQ: XXX or goto retry ? */ + link= cursor->curr->link; + cursor->next= PTR(link); + _lf_pin(pins, 0, cursor->next); + } while (link != cursor->curr->link && LF_BACKOFF); + cur_hashnr= cursor->curr->hashnr; + cur_key= cursor->curr->key; + cur_keylen= cursor->curr->keylen; + if (*cursor->prev != (intptr)cursor->curr) + { + (void)LF_BACKOFF; + goto retry; + } + if (!DELETED(link)) + { + if (cur_hashnr >= hashnr) + { + int r= 1; + if (cur_hashnr > hashnr || + (r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key, + keylen)) >= 0) + return !r; + } + cursor->prev= &(cursor->curr->link); + _lf_pin(pins, 2, cursor->curr); + } + else + { + /* + we found a deleted node - be nice, help the other thread + and remove this deleted node + */ + if (my_atomic_casptr((void **)cursor->prev, + (void **)&cursor->curr, cursor->next)) + _lf_alloc_free(pins, cursor->curr); + else + { + (void)LF_BACKOFF; + goto retry; + } + } + cursor->curr= cursor->next; + _lf_pin(pins, 1, cursor->curr); + } +} + +/* + DESCRIPTION + insert a 'node' in the list that starts from 'head' in the correct + position (as found by lfind) + + RETURN + 0 - inserted + not 0 - a pointer to a duplicate (not pinned and thus unusable) + + NOTE + it uses pins[0..2], on return all pins are removed. + if there're nodes with the same key value, a new node is added before them. +*/ +static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs, + LF_SLIST *node, LF_PINS *pins, uint flags) +{ + CURSOR cursor; + int res; + + for (;;) + { + if (lfind(head, cs, node->hashnr, node->key, node->keylen, + &cursor, pins) && + (flags & LF_HASH_UNIQUE)) + { + res= 0; /* duplicate found */ + break; + } + else + { + node->link= (intptr)cursor.curr; + DBUG_ASSERT(node->link != (intptr)node); /* no circular references */ + DBUG_ASSERT(cursor.prev != &node->link); /* no circular references */ + if (my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node)) + { + res= 1; /* inserted ok */ + break; + } + } + } + _lf_unpin(pins, 0); + _lf_unpin(pins, 1); + _lf_unpin(pins, 2); + /* + Note that cursor.curr is not pinned here and the pointer is unreliable, + the object may dissapear anytime. But if it points to a dummy node, the + pointer is safe, because dummy nodes are never freed - initialize_bucket() + uses this fact. + */ + return res ? 0 : cursor.curr; +} + +/* + DESCRIPTION + deletes a node as identified by hashnr/keey/keylen from the list + that starts from 'head' + + RETURN + 0 - ok + 1 - not found + + NOTE + it uses pins[0..2], on return all pins are removed. +*/ +static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, + const uchar *key, uint keylen, LF_PINS *pins) +{ + CURSOR cursor; + int res; + + for (;;) + { + if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins)) + { + res= 1; /* not found */ + break; + } + else + { + /* mark the node deleted */ + if (my_atomic_casptr((void **)&(cursor.curr->link), + (void **)&cursor.next, + (void *)(((intptr)cursor.next) | 1))) + { + /* and remove it from the list */ + if (my_atomic_casptr((void **)cursor.prev, + (void **)&cursor.curr, cursor.next)) + _lf_alloc_free(pins, cursor.curr); + else + { + /* + somebody already "helped" us and removed the node ? + Let's check if we need to help that someone too! + (to ensure the number of "set DELETED flag" actions + is equal to the number of "remove from the list" actions) + */ + lfind(head, cs, hashnr, key, keylen, &cursor, pins); + } + res= 0; + break; + } + } + } + _lf_unpin(pins, 0); + _lf_unpin(pins, 1); + _lf_unpin(pins, 2); + return res; +} + +/* + DESCRIPTION + searches for a node as identified by hashnr/keey/keylen in the list + that starts from 'head' + + RETURN + 0 - not found + node - found + + NOTE + it uses pins[0..2], on return the pin[2] keeps the node found + all other pins are removed. +*/ +static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs, + uint32 hashnr, const uchar *key, uint keylen, + LF_PINS *pins) +{ + CURSOR cursor; + int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins); + if (res) + _lf_pin(pins, 2, cursor.curr); + _lf_unpin(pins, 0); + _lf_unpin(pins, 1); + return res ? cursor.curr : 0; +} + +static inline const uchar* hash_key(const LF_HASH *hash, + const uchar *record, size_t *length) +{ + if (hash->get_key) + return (*hash->get_key)(record, length, 0); + *length= hash->key_length; + return record + hash->key_offset; +} + +/* + Compute the hash key value from the raw key. + + @note, that the hash value is limited to 2^31, because we need one + bit to distinguish between normal and dummy nodes. +*/ +static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen) +{ + ulong nr1= 1, nr2= 4; + hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen, + &nr1, &nr2); + return nr1 & INT_MAX32; +} + +#define MAX_LOAD 1.0 /* average number of elements in a bucket */ + +static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *); + +/* + Initializes lf_hash, the arguments are compatible with hash_init + + @note element_size sets both the size of allocated memory block for + lf_alloc and a size of memcpy'ed block size in lf_hash_insert. Typically + they are the same, indeed. But LF_HASH::element_size can be decreased + after lf_hash_init, and then lf_alloc will allocate larger block that + lf_hash_insert will copy over. It is desireable if part of the element + is expensive to initialize - for example if there is a mutex or + DYNAMIC_ARRAY. In this case they should be initialize in the + LF_ALLOCATOR::constructor, and lf_hash_insert should not overwrite them. + See wt_init() for example. +*/ +void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, + uint key_offset, uint key_length, my_hash_get_key get_key, + CHARSET_INFO *charset) +{ + lf_alloc_init(&hash->alloc, sizeof(LF_SLIST)+element_size, + offsetof(LF_SLIST, key)); + lf_dynarray_init(&hash->array, sizeof(LF_SLIST *)); + hash->size= 1; + hash->count= 0; + hash->element_size= element_size; + hash->flags= flags; + hash->charset= charset ? charset : &my_charset_bin; + hash->key_offset= key_offset; + hash->key_length= key_length; + hash->get_key= get_key; + DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length); +} + +void lf_hash_destroy(LF_HASH *hash) +{ + LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0); + + if (unlikely(!head)) + return; + el= *head; + + while (el) + { + intptr next= el->link; + if (el->hashnr & 1) + lf_alloc_direct_free(&hash->alloc, el); /* normal node */ + else + my_free((void *)el, MYF(0)); /* dummy node */ + el= (LF_SLIST *)next; + } + lf_alloc_destroy(&hash->alloc); + lf_dynarray_destroy(&hash->array); +} + +/* + DESCRIPTION + inserts a new element to a hash. it will have a _copy_ of + data, not a pointer to it. + + RETURN + 0 - inserted + 1 - didn't (unique key conflict) + -1 - out of memory + + NOTE + see linsert() for pin usage notes +*/ +int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) +{ + int csize, bucket, hashnr; + LF_SLIST *node, * volatile *el; + + lf_rwlock_by_pins(pins); + node= (LF_SLIST *)_lf_alloc_new(pins); + if (unlikely(!node)) + return -1; + memcpy(node+1, data, hash->element_size); + node->key= hash_key(hash, (uchar *)(node+1), &node->keylen); + hashnr= calc_hash(hash, node->key, node->keylen); + bucket= hashnr % hash->size; + el= _lf_dynarray_lvalue(&hash->array, bucket); + if (unlikely(!el)) + return -1; + if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) + return -1; + node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */ + if (linsert(el, hash->charset, node, pins, hash->flags)) + { + _lf_alloc_free(pins, node); + lf_rwunlock_by_pins(pins); + return 1; + } + csize= hash->size; + if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD) + my_atomic_cas32(&hash->size, &csize, csize*2); + lf_rwunlock_by_pins(pins); + return 0; +} + +/* + DESCRIPTION + deletes an element with the given key from the hash (if a hash is + not unique and there're many elements with this key - the "first" + matching element is deleted) + RETURN + 0 - deleted + 1 - didn't (not found) + -1 - out of memory + NOTE + see ldelete() for pin usage notes +*/ +int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) +{ + LF_SLIST * volatile *el; + uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen); + + bucket= hashnr % hash->size; + lf_rwlock_by_pins(pins); + el= _lf_dynarray_lvalue(&hash->array, bucket); + if (unlikely(!el)) + return -1; + /* + note that we still need to initialize_bucket here, + we cannot return "node not found", because an old bucket of that + node may've been split and the node was assigned to a new bucket + that was never accessed before and thus is not initialized. + */ + if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) + return -1; + if (ldelete(el, hash->charset, my_reverse_bits(hashnr) | 1, + (uchar *)key, keylen, pins)) + { + lf_rwunlock_by_pins(pins); + return 1; + } + my_atomic_add32(&hash->count, -1); + lf_rwunlock_by_pins(pins); + return 0; +} + +/* + RETURN + a pointer to an element with the given key (if a hash is not unique and + there're many elements with this key - the "first" matching element) + NULL if nothing is found + MY_ERRPTR if OOM + + NOTE + see lsearch() for pin usage notes +*/ +void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) +{ + LF_SLIST * volatile *el, *found; + uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen); + + bucket= hashnr % hash->size; + lf_rwlock_by_pins(pins); + el= _lf_dynarray_lvalue(&hash->array, bucket); + if (unlikely(!el)) + return MY_ERRPTR; + if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) + return MY_ERRPTR; + found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1, + (uchar *)key, keylen, pins); + lf_rwunlock_by_pins(pins); + return found ? found+1 : 0; +} + +static const uchar *dummy_key= (uchar*)""; + +/* + RETURN + 0 - ok + -1 - out of memory +*/ +static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node, + uint bucket, LF_PINS *pins) +{ + uint parent= my_clear_highest_bit(bucket); + LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME)); + LF_SLIST **tmp= 0, *cur; + LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent); + if (unlikely(!el || !dummy)) + return -1; + if (*el == NULL && bucket && + unlikely(initialize_bucket(hash, el, parent, pins))) + return -1; + dummy->hashnr= my_reverse_bits(bucket) | 0; /* dummy node */ + dummy->key= dummy_key; + dummy->keylen= 0; + if ((cur= linsert(el, hash->charset, dummy, pins, LF_HASH_UNIQUE))) + { + my_free((void *)dummy, MYF(0)); + dummy= cur; + } + my_atomic_casptr((void **)node, (void **)&tmp, dummy); + /* + note that if the CAS above failed (after linsert() succeeded), + it would mean that some other thread has executed linsert() for + the same dummy node, its linsert() failed, it picked up our + dummy node (in "dummy= cur") and executed the same CAS as above. + Which means that even if CAS above failed we don't need to retry, + and we should not free(dummy) - there's no memory leak here + */ + return 0; +} diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 1a47982b221..620ac667a8b 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -58,9 +58,9 @@ static void my_aiowait(my_aio_result *result); #ifdef THREAD #define lock_append_buffer(info) \ - pthread_mutex_lock(&(info)->append_buffer_lock) + mysql_mutex_lock(&(info)->append_buffer_lock) #define unlock_append_buffer(info) \ - pthread_mutex_unlock(&(info)->append_buffer_lock) + mysql_mutex_unlock(&(info)->append_buffer_lock) #else #define lock_append_buffer(info) #define unlock_append_buffer(info) @@ -265,7 +265,8 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, info->append_read_pos = info->write_pos = info->write_buffer; info->write_end = info->write_buffer + info->buffer_length; #ifdef THREAD - pthread_mutex_init(&info->append_buffer_lock,MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_IO_CACHE_append_buffer_lock, + &info->append_buffer_lock, MY_MUTEX_INIT_FAST); #endif } #if defined(SAFE_MUTEX) && defined(THREAD) @@ -639,9 +640,10 @@ void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, DBUG_ASSERT(read_cache->type == READ_CACHE); DBUG_ASSERT(!write_cache || (write_cache->type == WRITE_CACHE)); - pthread_mutex_init(&cshare->mutex, MY_MUTEX_INIT_FAST); - pthread_cond_init(&cshare->cond, 0); - pthread_cond_init(&cshare->cond_writer, 0); + mysql_mutex_init(key_IO_CACHE_SHARE_mutex, + &cshare->mutex, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_IO_CACHE_SHARE_cond, &cshare->cond, 0); + mysql_cond_init(key_IO_CACHE_SHARE_cond_writer, &cshare->cond_writer, 0); cshare->running_threads= num_threads; cshare->total_threads= num_threads; @@ -692,7 +694,7 @@ void remove_io_thread(IO_CACHE *cache) if (cache == cshare->source_cache) flush_io_cache(cache); - pthread_mutex_lock(&cshare->mutex); + mysql_mutex_lock(&cshare->mutex); DBUG_PRINT("io_cache_share", ("%s: 0x%lx", (cache == cshare->source_cache) ? "writer" : "reader", (long) cache)); @@ -715,18 +717,18 @@ void remove_io_thread(IO_CACHE *cache) if (!--cshare->running_threads) { DBUG_PRINT("io_cache_share", ("the last running thread leaves, wake all")); - pthread_cond_signal(&cshare->cond_writer); - pthread_cond_broadcast(&cshare->cond); + mysql_cond_signal(&cshare->cond_writer); + mysql_cond_broadcast(&cshare->cond); } - pthread_mutex_unlock(&cshare->mutex); + mysql_mutex_unlock(&cshare->mutex); if (!total) { DBUG_PRINT("io_cache_share", ("last thread removed, destroy share")); - pthread_cond_destroy (&cshare->cond_writer); - pthread_cond_destroy (&cshare->cond); - pthread_mutex_destroy(&cshare->mutex); + mysql_cond_destroy (&cshare->cond_writer); + mysql_cond_destroy (&cshare->cond); + mysql_mutex_destroy(&cshare->mutex); } DBUG_VOID_RETURN; @@ -767,7 +769,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos) DBUG_ENTER("lock_io_cache"); /* Enter the lock. */ - pthread_mutex_lock(&cshare->mutex); + mysql_mutex_lock(&cshare->mutex); cshare->running_threads--; DBUG_PRINT("io_cache_share", ("%s: 0x%lx pos: %lu running: %u", (cache == cshare->source_cache) ? @@ -784,7 +786,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos) while (cshare->running_threads) { DBUG_PRINT("io_cache_share", ("writer waits in lock")); - pthread_cond_wait(&cshare->cond_writer, &cshare->mutex); + mysql_cond_wait(&cshare->cond_writer, &cshare->mutex); } DBUG_PRINT("io_cache_share", ("writer awoke, going to copy")); @@ -796,7 +798,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos) if (!cshare->running_threads) { DBUG_PRINT("io_cache_share", ("waking writer")); - pthread_cond_signal(&cshare->cond_writer); + mysql_cond_signal(&cshare->cond_writer); } /* @@ -808,7 +810,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos) cshare->source_cache) { DBUG_PRINT("io_cache_share", ("reader waits in lock")); - pthread_cond_wait(&cshare->cond, &cshare->mutex); + mysql_cond_wait(&cshare->cond, &cshare->mutex); } /* @@ -850,7 +852,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos) cshare->running_threads) { DBUG_PRINT("io_cache_share", ("reader waits in lock")); - pthread_cond_wait(&cshare->cond, &cshare->mutex); + mysql_cond_wait(&cshare->cond, &cshare->mutex); } /* If the block is not yet read, continue with a locked cache and read. */ @@ -872,7 +874,7 @@ static int lock_io_cache(IO_CACHE *cache, my_off_t pos) Leave the lock. Do not call unlock_io_cache() later. The thread that filled the buffer did this and marked all threads as running. */ - pthread_mutex_unlock(&cshare->mutex); + mysql_mutex_unlock(&cshare->mutex); DBUG_RETURN(0); } @@ -915,8 +917,8 @@ static void unlock_io_cache(IO_CACHE *cache) cshare->total_threads)); cshare->running_threads= cshare->total_threads; - pthread_cond_broadcast(&cshare->cond); - pthread_mutex_unlock(&cshare->mutex); + mysql_cond_broadcast(&cshare->cond); + mysql_mutex_unlock(&cshare->mutex); DBUG_VOID_RETURN; } @@ -1837,7 +1839,7 @@ int end_io_cache(IO_CACHE *info) /* Destroy allocated mutex */ info->type= TYPE_NOT_SET; #ifdef THREAD - pthread_mutex_destroy(&info->append_buffer_lock); + mysql_mutex_destroy(&info->append_buffer_lock); #endif } DBUG_RETURN(error); diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index c54c7d13548..5e34bff2b51 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -82,7 +82,7 @@ my_off_t my_b_append_tell(IO_CACHE* info) answer to the question. */ #ifdef THREAD - pthread_mutex_lock(&info->append_buffer_lock); + mysql_mutex_lock(&info->append_buffer_lock); #endif #ifndef DBUG_OFF /* @@ -104,7 +104,7 @@ my_off_t my_b_append_tell(IO_CACHE* info) #endif res = info->end_of_file + (info->write_pos-info->append_read_pos); #ifdef THREAD - pthread_mutex_unlock(&info->append_buffer_lock); + mysql_mutex_unlock(&info->append_buffer_lock); #endif return res; } @@ -135,7 +135,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) b) see if there is a better way to make it work */ if (info->type == SEQ_READ_APPEND) - VOID(flush_io_cache(info)); + (void) flush_io_cache(info); offset=(pos - info->pos_in_file); @@ -163,7 +163,7 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) info->write_pos = info->write_buffer + offset; DBUG_VOID_RETURN; } - VOID(flush_io_cache(info)); + (void) flush_io_cache(info); /* Correct buffer end so that we write in increments of IO_SIZE */ info->write_end=(info->write_buffer+info->buffer_length- (pos & (IO_SIZE-1))); diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 139a61da1f0..9cbe3a21bce 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -59,13 +59,13 @@ time only. Before starting to wait on its condition variable with - pthread_cond_wait(), the thread enters itself to a specific wait queue + mysql_cond_wait(), the thread enters itself to a specific wait queue with link_into_queue() (double linked with '*next' + '**prev') or wait_on_queue() (single linked with '*next'). Another thread, when releasing a resource, looks up the waiting thread in the related wait queue. It sends a signal with - pthread_cond_signal() to the waiting thread. + mysql_cond_signal() to the waiting thread. NOTE: Depending on the particular wait situation, either the sending thread removes the waiting thread from the wait queue with @@ -128,8 +128,8 @@ accessing it; to set this number equal to <N> add #define MAX_THREADS <N> - - to substitute calls of pthread_cond_wait for calls of - pthread_cond_timedwait (wait with timeout set up); + - to substitute calls of mysql_cond_wait for calls of + mysql_cond_timedwait (wait with timeout set up); this setting should be used only when you want to trap a deadlock situation, which theoretically should not happen; to set timeout equal to <T> seconds add @@ -160,7 +160,7 @@ #define COND_FOR_SAVED 1 #define COND_FOR_READERS 2 -typedef pthread_cond_t KEYCACHE_CONDVAR; +typedef mysql_cond_t KEYCACHE_CONDVAR; /* descriptor of the page in the key cache block buffer */ struct st_keycache_page @@ -227,7 +227,7 @@ KEY_CACHE *dflt_key_cache= &dflt_key_cache_var; static int flush_all_key_blocks(KEY_CACHE *keycache); #ifdef THREAD static void wait_on_queue(KEYCACHE_WQUEUE *wqueue, - pthread_mutex_t *mutex); + mysql_mutex_t *mutex); static void release_whole_queue(KEYCACHE_WQUEUE *wqueue); #else #define wait_on_queue(wqueue, mutex) do {} while (0) @@ -314,20 +314,20 @@ static long keycache_thread_id; ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK))) #if (defined(KEYCACHE_TIMEOUT) && !defined(__WIN__)) || defined(KEYCACHE_DEBUG) -static int keycache_pthread_cond_wait(pthread_cond_t *cond, - pthread_mutex_t *mutex); +static int keycache_pthread_cond_wait(mysql_cond_t *cond, + mysql_mutex_t *mutex); #else -#define keycache_pthread_cond_wait pthread_cond_wait +#define keycache_pthread_cond_wait(C, M) mysql_cond_wait(C, M) #endif #if defined(KEYCACHE_DEBUG) -static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex); -static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex); -static int keycache_pthread_cond_signal(pthread_cond_t *cond); +static int keycache_pthread_mutex_lock(mysql_mutex_t *mutex); +static void keycache_pthread_mutex_unlock(mysql_mutex_t *mutex); +static int keycache_pthread_cond_signal(mysql_cond_t *cond); #else -#define keycache_pthread_mutex_lock pthread_mutex_lock -#define keycache_pthread_mutex_unlock pthread_mutex_unlock -#define keycache_pthread_cond_signal pthread_cond_signal +#define keycache_pthread_mutex_lock(M) mysql_mutex_lock(M) +#define keycache_pthread_mutex_unlock(M) mysql_mutex_unlock(M) +#define keycache_pthread_cond_signal(C) mysql_cond_signal(C) #endif /* defined(KEYCACHE_DEBUG) */ #if !defined(DBUG_OFF) @@ -403,7 +403,8 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, keycache->cnt_for_resize_op= 0; keycache->waiting_for_resize_cnt.last_thread= NULL; keycache->in_init= 0; - pthread_mutex_init(&keycache->cache_lock, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_KEY_CACHE_cache_lock, + &keycache->cache_lock, MY_MUTEX_INIT_FAST); keycache->resize_queue.last_thread= NULL; } @@ -773,7 +774,7 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) if (cleanup) { - pthread_mutex_destroy(&keycache->cache_lock); + mysql_mutex_destroy(&keycache->cache_lock); keycache->key_cache_inited= keycache->can_be_used= 0; KEYCACHE_DEBUG_CLOSE; } @@ -888,7 +889,7 @@ static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue, */ static void wait_on_queue(KEYCACHE_WQUEUE *wqueue, - pthread_mutex_t *mutex) + mysql_mutex_t *mutex) { struct st_my_thread_var *last; struct st_my_thread_var *thread= my_thread_var; @@ -4166,7 +4167,7 @@ static int flush_all_key_blocks(KEY_CACHE *keycache) do { - safe_mutex_assert_owner(&keycache->cache_lock); + mysql_mutex_assert_owner(&keycache->cache_lock); total_found= 0; /* @@ -4407,8 +4408,8 @@ static void keycache_dump(KEY_CACHE *keycache) #if defined(KEYCACHE_TIMEOUT) && !defined(__WIN__) -static int keycache_pthread_cond_wait(pthread_cond_t *cond, - pthread_mutex_t *mutex) +static int keycache_pthread_cond_wait(mysql_cond_t *cond, + mysql_mutex_t *mutex) { int rc; struct timeval now; /* time when we started waiting */ @@ -4435,7 +4436,7 @@ static int keycache_pthread_cond_wait(pthread_cond_t *cond, fprintf(keycache_debug_log, "waiting...\n"); fflush(keycache_debug_log); #endif - rc= pthread_cond_timedwait(cond, mutex, &timeout); + rc= mysql_cond_timedwait(cond, mutex, &timeout); KEYCACHE_THREAD_TRACE_BEGIN("finished waiting"); if (rc == ETIMEDOUT || rc == ETIME) { @@ -4456,12 +4457,12 @@ static int keycache_pthread_cond_wait(pthread_cond_t *cond, } #else #if defined(KEYCACHE_DEBUG) -static int keycache_pthread_cond_wait(pthread_cond_t *cond, - pthread_mutex_t *mutex) +static int keycache_pthread_cond_wait(mysql_cond_t *cond, + mysql_mutex_t *mutex) { int rc; KEYCACHE_THREAD_TRACE_END("started waiting"); - rc= pthread_cond_wait(cond, mutex); + rc= mysql_cond_wait(cond, mutex); KEYCACHE_THREAD_TRACE_BEGIN("finished waiting"); return rc; } @@ -4471,27 +4472,27 @@ static int keycache_pthread_cond_wait(pthread_cond_t *cond, #if defined(KEYCACHE_DEBUG) -static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex) +static int keycache_pthread_mutex_lock(mysql_mutex_t *mutex) { int rc; - rc= pthread_mutex_lock(mutex); + rc= mysql_mutex_lock(mutex); KEYCACHE_THREAD_TRACE_BEGIN(""); return rc; } -static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex) +static void keycache_pthread_mutex_unlock(mysql_mutex_t *mutex) { KEYCACHE_THREAD_TRACE_END(""); - pthread_mutex_unlock(mutex); + mysql_mutex_unlock(mutex); } -static int keycache_pthread_cond_signal(pthread_cond_t *cond) +static int keycache_pthread_cond_signal(mysql_cond_t *cond) { int rc; KEYCACHE_THREAD_TRACE("signal"); - rc= pthread_cond_signal(cond); + rc= mysql_cond_signal(cond); return rc; } diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c index 48a69207839..fbf6f7f5d57 100644 --- a/mysys/mf_loadpath.c +++ b/mysys/mf_loadpath.c @@ -34,7 +34,7 @@ char * my_load_path(char * to, const char *path, if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) || test_if_hard_path(path)) - VOID(strmov(buff,path)); + (void) strmov(buff,path); else if ((is_cur=(path[0] == FN_CURLIB && path[1] == FN_LIBCHAR)) || (is_prefix(path,FN_PARENTDIR)) || ! own_path_prefix) @@ -42,12 +42,12 @@ char * my_load_path(char * to, const char *path, if (is_cur) is_cur=2; /* Remove current dir */ if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)+is_cur),MYF(0))) - VOID(strcat(buff,path+is_cur)); + (void) strcat(buff,path+is_cur); else - VOID(strmov(buff,path)); /* Return org file name */ + (void) strmov(buff,path); /* Return org file name */ } else - VOID(strxmov(buff,own_path_prefix,path,NullS)); + (void) strxmov(buff,own_path_prefix,path,NullS); strmov(to,buff); DBUG_PRINT("exit",("to: %s",to)); DBUG_RETURN(to); diff --git a/mysys/mf_path.c b/mysys/mf_path.c index 73e73cb7f76..d51cac732f5 100644 --- a/mysys/mf_path.c +++ b/mysys/mf_path.c @@ -42,7 +42,7 @@ char * my_path(char * to, const char *progname, ((prog=getenv("_")) != 0 && dirname_part(to, prog, &to_length)))) { - VOID(intern_filename(to,to)); + (void) intern_filename(to,to); if (!test_if_hard_path(to)) { if (!my_getwd(curr_dir,FN_REFLEN,MYF(0))) @@ -60,11 +60,11 @@ char * my_path(char * to, const char *progname, end= (char*) "/my/"; #endif } - VOID(intern_filename(to,end)); + (void) intern_filename(to,end); to=strend(to); if (to != start && to[-1] != FN_LIBCHAR) *to++ = FN_LIBCHAR; - VOID(strmov(to,own_pathname_part)); + (void) strmov(to,own_pathname_part); } DBUG_PRINT("exit",("to: '%s'",start)); DBUG_RETURN(start); diff --git a/mysys/mf_tempdir.c b/mysys/mf_tempdir.c index f41bbab946f..5633182ab3a 100644 --- a/mysys/mf_tempdir.c +++ b/mysys/mf_tempdir.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -29,7 +29,7 @@ my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist) DBUG_ENTER("init_tmpdir"); DBUG_PRINT("enter", ("pathlist: %s", pathlist ? pathlist : "NULL")); - pthread_mutex_init(&tmpdir->mutex, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_TMPDIR_mutex, &tmpdir->mutex, MY_MUTEX_INIT_FAST); if (my_init_dynamic_array(&tmpdir->full_list, sizeof(char*), 1, 5)) goto err; if (!pathlist || !pathlist[0]) @@ -65,7 +65,7 @@ my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist) err: delete_dynamic(&tmpdir->full_list); /* Safe to free */ - pthread_mutex_destroy(&tmpdir->mutex); + mysql_mutex_destroy(&tmpdir->mutex); DBUG_RETURN(TRUE); } @@ -75,10 +75,10 @@ char *my_tmpdir(MY_TMPDIR *tmpdir) char *dir; if (!tmpdir->max) return tmpdir->list[0]; - pthread_mutex_lock(&tmpdir->mutex); + mysql_mutex_lock(&tmpdir->mutex); dir=tmpdir->list[tmpdir->cur]; tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1; - pthread_mutex_unlock(&tmpdir->mutex); + mysql_mutex_unlock(&tmpdir->mutex); return dir; } @@ -90,6 +90,6 @@ void free_tmpdir(MY_TMPDIR *tmpdir) for (i=0; i<=tmpdir->max; i++) my_free(tmpdir->list[i], MYF(0)); delete_dynamic(&tmpdir->full_list); - pthread_mutex_destroy(&tmpdir->mutex); + mysql_mutex_destroy(&tmpdir->mutex); } diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 2607ea57d08..9c45cdc2277 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -155,7 +155,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) DBUG_ASSERT(alloc_root_inited(mem_root)); length+=ALIGN_SIZE(sizeof(USED_MEM)); - if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME)))) + if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR)))) { if (mem_root->error_handler) (*mem_root->error_handler)(); @@ -198,7 +198,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) get_size= length+ALIGN_SIZE(sizeof(USED_MEM)); get_size= max(get_size, block_size); - if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME)))) + if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR)))) { if (mem_root->error_handler) (*mem_root->error_handler)(); diff --git a/mysys/my_append.c b/mysys/my_append.c index d8789f95d95..1ef3905b6f5 100644 --- a/mysys/my_append.c +++ b/mysys/my_append.c @@ -58,7 +58,7 @@ int my_append(const char *from, const char *to, myf MyFlags) } } err: - if (from_file >= 0) VOID(my_close(from_file,MyFlags)); - if (to_file >= 0) VOID(my_close(to_file,MyFlags)); + if (from_file >= 0) (void) my_close(from_file,MyFlags); + if (to_file >= 0) (void) my_close(to_file,MyFlags); DBUG_RETURN(-1); } diff --git a/mysys/my_atomic.c b/mysys/my_atomic.c index aa04d55f624..6bc76f0de3c 100644 --- a/mysys/my_atomic.c +++ b/mysys/my_atomic.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -14,7 +14,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_sys.h> #ifndef HAVE_INLINE /* the following will cause all inline functions to be instantiated */ @@ -43,3 +43,32 @@ int my_atomic_initialize() #endif } +#ifdef SAFE_MUTEX +#undef pthread_mutex_init +#undef pthread_mutex_destroy +#undef pthread_mutex_lock +#undef pthread_mutex_unlock + +void plain_pthread_mutex_init(safe_mutex_t *m) +{ + pthread_mutex_init(& m->mutex, NULL); +} + +void plain_pthread_mutex_destroy(safe_mutex_t *m) +{ + pthread_mutex_destroy(& m->mutex); +} + +void plain_pthread_mutex_lock(safe_mutex_t *m) +{ + pthread_mutex_lock(& m->mutex); +} + +void plain_pthread_mutex_unlock(safe_mutex_t *m) +{ + pthread_mutex_unlock(& m->mutex); +} + +#endif + + diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index e127b2584ae..91370bd3727 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -87,7 +87,7 @@ static inline void bitmap_lock(MY_BITMAP *map __attribute__((unused))) { #ifdef THREAD if (map->mutex) - pthread_mutex_lock(map->mutex); + mysql_mutex_lock(map->mutex); #endif } @@ -95,7 +95,7 @@ static inline void bitmap_unlock(MY_BITMAP *map __attribute__((unused))) { #ifdef THREAD if (map->mutex) - pthread_mutex_unlock(map->mutex); + mysql_mutex_unlock(map->mutex); #endif } @@ -112,7 +112,7 @@ my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, if (thread_safe) { size_in_bytes= ALIGN_SIZE(size_in_bytes); - extra= sizeof(pthread_mutex_t); + extra= sizeof(mysql_mutex_t); } map->mutex= 0; #endif @@ -121,8 +121,8 @@ my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, #ifdef THREAD if (thread_safe) { - map->mutex= (pthread_mutex_t *) ((char*) buf + size_in_bytes); - pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST); + map->mutex= (mysql_mutex_t *) ((char*) buf + size_in_bytes); + mysql_mutex_init(key_BITMAP_mutex, map->mutex, MY_MUTEX_INIT_FAST); } #endif } @@ -148,7 +148,7 @@ void bitmap_free(MY_BITMAP *map) { #ifdef THREAD if (map->mutex) - pthread_mutex_destroy(map->mutex); + mysql_mutex_destroy(map->mutex); #endif my_free((char*) map->bitmap, MYF(0)); map->bitmap=0; diff --git a/mysys/my_clock.c b/mysys/my_clock.c index adc755028d5..d17f26ed316 100644 --- a/mysys/my_clock.c +++ b/mysys/my_clock.c @@ -24,7 +24,7 @@ long my_clock(void) { #if !defined(__WIN__) && !defined(__NETWARE__) struct tms tmsbuf; - VOID(times(&tmsbuf)); + (void) times(&tmsbuf); return (tmsbuf.tms_utime + tmsbuf.tms_stime); #else return clock(); diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 418e2b6f8a2..d38507c111a 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -112,19 +112,19 @@ int my_copy(const char *from, const char *to, myf MyFlags) struct utimbuf timep; timep.actime = stat_buff.st_atime; timep.modtime = stat_buff.st_mtime; - VOID(utime((char*) to, &timep)); /* last accessed and modified times */ + (void) utime((char*) to, &timep); /* last accessed and modified times */ } #endif DBUG_RETURN(0); } err: - if (from_file >= 0) VOID(my_close(from_file,MyFlags)); + if (from_file >= 0) (void) my_close(from_file,MyFlags); if (to_file >= 0) { - VOID(my_close(to_file, MyFlags)); + (void) my_close(to_file, MyFlags); /* attempt to delete the to-file we've partially written */ - VOID(my_delete(to, MyFlags)); + (void) my_delete(to, MyFlags); } DBUG_RETURN(-1); } /* my_copy */ diff --git a/mysys/my_create.c b/mysys/my_create.c index d0436276d03..49529f9b7b5 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -39,14 +39,11 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, DBUG_ENTER("my_create"); DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d", FileName, CreateFlags, access_flags, MyFlags)); - -#if !defined(NO_OPEN_3) - fd= open((char *) FileName, access_flags | O_CREAT, - CreateFlags ? CreateFlags : my_umask); -#elif defined(_WIN32) +#if defined(_WIN32) fd= my_win_open(FileName, access_flags | O_CREAT); #else - fd= open(FileName, access_flags); + fd= open((char *) FileName, access_flags | O_CREAT, + CreateFlags ? CreateFlags : my_umask); #endif if ((MyFlags & MY_SYNC_DIR) && (fd >=0) && diff --git a/mysys/my_delete.c b/mysys/my_delete.c index 3ab6ba399f9..edee1c4e875 100644 --- a/mysys/my_delete.c +++ b/mysys/my_delete.c @@ -37,7 +37,7 @@ int my_delete(const char *name, myf MyFlags) } /* my_delete */ #if defined(__WIN__) -/* +/** Delete file which is possibly not closed. This function is intended to be used exclusively as a temporal solution @@ -53,6 +53,20 @@ int my_delete(const char *name, myf MyFlags) renamed to <name>.<num>.deleted where <name> - the initial name of the file, <num> - a hexadecimal number chosen to make the temporal name to be unique. + + @param the name of the being deleted file + @param the flags instructing how to react on an error internally in + the function + + @note The per-thread @c my_errno holds additional info for a caller to + decide how critical the error can be. + + @retval + 0 ok + @retval + 1 error + + */ int nt_share_delete(const char *name, myf MyFlags) { @@ -63,6 +77,7 @@ int nt_share_delete(const char *name, myf MyFlags) for (cnt= GetTickCount(); cnt; cnt--) { + errno= 0; sprintf(buf, "%s.%08X.deleted", name, cnt); if (MoveFile(name, buf)) break; @@ -78,15 +93,23 @@ int nt_share_delete(const char *name, myf MyFlags) name, buf, errno)); break; } - - if (DeleteFile(buf)) - DBUG_RETURN(0); - - my_errno= GetLastError(); + + if (errno == ERROR_FILE_NOT_FOUND) + { + my_errno= ENOENT; // marking, that `name' doesn't exist + } + else if (errno == 0) + { + if (DeleteFile(buf)) + DBUG_RETURN(0); + else if ((my_errno= GetLastError()) == 0) + my_errno= ENOENT; // marking, that `buf' doesn't exist + } else + my_errno= errno; + if (MyFlags & (MY_FAE+MY_WME)) - my_error(EE_DELETE, MYF(ME_BELL + ME_WAITTANG + (MyFlags & ME_NOINPUT)), - name, my_errno); - + my_error(EE_DELETE, MYF(ME_BELL + ME_WAITTANG + (MyFlags & ME_NOINPUT)), + name, my_errno); DBUG_RETURN(-1); } #endif diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 879acac0111..3f2bc08df65 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -63,18 +63,18 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) thread_safe_increment(my_stream_opened,&THR_LOCK_open); DBUG_RETURN(fd); /* safeguard */ } - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); if ((my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags))) { my_stream_opened++; my_file_total_opened++; my_file_info[filedesc].type= STREAM_BY_FOPEN; - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); DBUG_RETURN(fd); } - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); (void) my_fclose(fd,MyFlags); my_errno=ENOMEM; } @@ -98,7 +98,7 @@ int my_fclose(FILE *fd, myf MyFlags) DBUG_ENTER("my_fclose"); DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags)); - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); file= my_fileno(fd); #ifndef _WIN32 err= fclose(fd); @@ -119,7 +119,7 @@ int my_fclose(FILE *fd, myf MyFlags) my_file_info[file].type = UNOPEN; my_free(my_file_info[file].name, MYF(MY_ALLOW_ZERO_PTR)); } - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); DBUG_RETURN(err); } /* my_fclose */ @@ -149,7 +149,7 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) } else { - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); my_stream_opened++; if ((uint) Filedes < (uint) my_file_limit) { @@ -163,7 +163,7 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) } my_file_info[Filedes].type = STREAM_BY_FDOPEN; } - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); } DBUG_PRINT("exit",("stream: 0x%lx", (long) fd)); diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c index 2059e1a9f18..0c7e4ef7aa3 100644 --- a/mysys/my_fstream.c +++ b/mysys/my_fstream.c @@ -119,7 +119,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags) #ifdef EINTR if (errno == EINTR) { - VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0))); + (void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)); continue; } #endif @@ -133,7 +133,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags) { wait_for_free_space("[stream]", errors); errors++; - VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0))); + (void) my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)); continue; } #endif diff --git a/mysys/my_gethostbyname.c b/mysys/my_gethostbyname.c index 067fdfee9db..4b7e9054d61 100644 --- a/mysys/my_gethostbyname.c +++ b/mysys/my_gethostbyname.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2004 MySQL AB +/* Copyright (C) 2002, 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -79,7 +79,7 @@ struct hostent *my_gethostbyname_r(const char *name, #else /* !HAVE_GETHOSTBYNAME_R */ #ifdef THREAD -extern pthread_mutex_t LOCK_gethostbyname_r; +extern mysql_mutex_t LOCK_gethostbyname_r; #endif /* @@ -96,7 +96,7 @@ struct hostent *my_gethostbyname_r(const char *name, int buflen, int *h_errnop) { struct hostent *hp; - pthread_mutex_lock(&LOCK_gethostbyname_r); + mysql_mutex_lock(&LOCK_gethostbyname_r); hp= gethostbyname(name); *h_errnop= h_errno; return hp; @@ -104,7 +104,7 @@ struct hostent *my_gethostbyname_r(const char *name, void my_gethostbyname_r_free() { - pthread_mutex_unlock(&LOCK_gethostbyname_r); + mysql_mutex_unlock(&LOCK_gethostbyname_r); } #endif /* !HAVE_GETHOSTBYNAME_R */ diff --git a/mysys/my_getncpus.c b/mysys/my_getncpus.c index 82e87dee2e4..5be961e3bc9 100644 --- a/mysys/my_getncpus.c +++ b/mysys/my_getncpus.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -16,24 +16,34 @@ /* get the number of (online) CPUs */ #include "mysys_priv.h" +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif static int ncpus=0; -#ifdef _SC_NPROCESSORS_ONLN int my_getncpus() { if (!ncpus) + { +#ifdef _SC_NPROCESSORS_ONLN ncpus= sysconf(_SC_NPROCESSORS_ONLN); - return ncpus; -} - +#elif defined(__WIN__) + SYSTEM_INFO sysinfo; + + /* + * We are not calling GetNativeSystemInfo here because (1) we + * don't believe that they return different values for number + * of processors and (2) if WOW64 limits processors for Win32 + * then we don't want to try to override that. + */ + GetSystemInfo(&sysinfo); + + ncpus= sysinfo.dwNumberOfProcessors; #else -/* unknown */ -int my_getncpus() -{ - return 2; -} - +/* unknown so play safe: assume SMP and forbid uniprocessor build */ + ncpus= 2; #endif - + } + return ncpus; +} diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index b91f46df0c4..9a49d537ea2 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002-2006 MySQL AB +/* Copyright (C) 2002-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -22,30 +22,21 @@ #include <errno.h> #include <m_string.h> -typedef void (*init_func_p)(const struct my_option *option, uchar* *variable, +typedef void (*init_func_p)(const struct my_option *option, uchar **variable, longlong value); static void default_reporter(enum loglevel level, const char *format, ...); my_error_reporter my_getopt_error_reporter= &default_reporter; -static int findopt(char *optpat, uint length, - const struct my_option **opt_res, - char **ffname); -my_bool getopt_compare_strings(const char *s, - const char *t, - uint length); +static int findopt(char *, uint, const struct my_option **, char **); +my_bool getopt_compare_strings(const char *, const char *, uint); static longlong getopt_ll(char *arg, const struct my_option *optp, int *err); -static ulonglong getopt_ull(char *arg, const struct my_option *optp, - int *err); +static ulonglong getopt_ull(char *, const struct my_option *, int *); static double getopt_double(char *arg, const struct my_option *optp, int *err); -static void init_variables(const struct my_option *options, - init_func_p init_one_value); -static void init_one_value(const struct my_option *option, uchar* *variable, - longlong value); -static void fini_one_value(const struct my_option *option, uchar* *variable, - longlong value); -static int setval(const struct my_option *opts, uchar* *value, char *argument, - my_bool set_maximum_value); +static void init_variables(const struct my_option *, init_func_p); +static void init_one_value(const struct my_option *, uchar **, longlong); +static void fini_one_value(const struct my_option *, uchar **, longlong); +static int setval(const struct my_option *, uchar **, char *, my_bool); static char *check_struct_option(char *cur_arg, char *key_name); /* @@ -60,6 +51,7 @@ enum enum_special_opt { OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE}; char *disabled_my_option= (char*) "0"; +char *enabled_my_option= (char*) "1"; /* This is a flag that can be set in client programs. 0 means that @@ -91,16 +83,6 @@ static void default_reporter(enum loglevel level, fflush(stderr); } -/* - function: handle_options - - Sort options; put options first, until special end of options (--), or - until end of argv. Parse options; check that the given option matches with - one of the options in struct 'my_option', return error in case of ambiguous - or unknown option. Check that option was given an argument if it requires - one. Call function 'get_one_option()' once for each option. -*/ - static uchar** (*getopt_get_addr)(const char *, uint, const struct my_option *, int *); void my_getopt_register_get_addr(uchar** (*func_addr)(const char *, uint, @@ -109,6 +91,22 @@ void my_getopt_register_get_addr(uchar** (*func_addr)(const char *, uint, getopt_get_addr= func_addr; } +/** + Handle command line options. + Sort options. + Put options first, until special end of options (--), + or until the end of argv. Parse options, check that the given option + matches with one of the options in struct 'my_option'. + Check that option was given an argument if it requires one + Call the optional 'get_one_option()' function once for each option. + @param [in, out] argc command line options (count) + @param [in, out] argv command line options (values) + @param [in] longopts descriptor of all valid options + @param [in] get_one_option optional callback function to process each option, + can be NULL. + @return error in case of ambiguous or unknown options, + 0 on success. +*/ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_get_one_option get_one_option) @@ -167,78 +165,15 @@ int handle_options(int *argc, char ***argv, option_is_loose= 0; cur_arg++; /* skip '-' */ - if (*cur_arg == '-' || *cur_arg == 'O') /* check for long option, */ - { /* --set-variable, or -O */ - if (*cur_arg == 'O') - { - my_getopt_error_reporter(WARNING_LEVEL, - "%s: Option '-O' is deprecated. " - "Use --variable-name=value instead.", - my_progname); - must_be_var= 1; - - if (!(*++cur_arg)) /* If not -Ovar=# */ - { - /* the argument must be in next argv */ - if (!*++pos) - { - if (my_getopt_print_errors) - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Option '-O' requires an argument", - my_progname); - return EXIT_ARGUMENT_REQUIRED; - } - cur_arg= *pos; - (*argc)--; - } - } - else if (!getopt_compare_strings(cur_arg, "-set-variable", 13)) - { - my_getopt_error_reporter(WARNING_LEVEL, - "%s: Option '--set-variable' is deprecated. " - "Use --variable-name=value instead.", - my_progname); - - must_be_var= 1; - if (cur_arg[13] == '=') - { - cur_arg+= 14; - if (!*cur_arg) - { - if (my_getopt_print_errors) - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Option '--set-variable' requires an argument", - my_progname); - return EXIT_ARGUMENT_REQUIRED; - } - } - else if (cur_arg[14]) /* garbage, or another option. break out */ - must_be_var= 0; - else - { - /* the argument must be in next argv */ - if (!*++pos) - { - if (my_getopt_print_errors) - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Option '--set-variable' requires an argument", - my_progname); - return EXIT_ARGUMENT_REQUIRED; - } - cur_arg= *pos; - (*argc)--; - } - } - else if (!must_be_var) - { - if (!*++cur_arg) /* skip the double dash */ - { - /* '--' means end of options, look no further */ - end_of_options= 1; - (*argc)--; - continue; - } - } + if (*cur_arg == '-') /* check for long option, */ + { + if (!*++cur_arg) /* skip the double dash */ + { + /* '--' means end of options, look no further */ + end_of_options= 1; + (*argc)--; + continue; + } opt_str= check_struct_option(cur_arg, key_name); optend= strcend(opt_str, '='); length= (uint) (optend - opt_str); @@ -285,7 +220,7 @@ int handle_options(int *argc, char ***argv, my_getopt_error_reporter(ERROR_LEVEL, "%s: ambiguous option '--%s-%s' (--%s-%s)", my_progname, special_opt_prefix[i], - cur_arg, special_opt_prefix[i], + opt_str, special_opt_prefix[i], prev_found); return EXIT_AMBIGUOUS_OPTION; } @@ -297,11 +232,11 @@ int handle_options(int *argc, char ***argv, for example: --skip-option=0 -> option = TRUE */ optend= (optend && *optend == '0' && !(*(optend + 1))) ? - (char*) "1" : disabled_my_option; + enabled_my_option : disabled_my_option; break; case OPT_ENABLE: optend= (optend && *optend == '0' && !(*(optend + 1))) ? - disabled_my_option : (char*) "1"; + disabled_my_option : enabled_my_option; break; case OPT_MAXIMUM: set_maximum_value= 1; @@ -318,12 +253,7 @@ int handle_options(int *argc, char ***argv, { if (my_getopt_skip_unknown) { - /* - preserve all the components of this unknown option, this may - occurr when the user provides options like: "-O foo" or - "--set-variable foo" (note that theres a space in there) - Generally, these kind of options are to be avoided - */ + /* Preserve all the components of this unknown option. */ do { (*argv)[argvpos++]= *first++; } while (first <= pos); @@ -389,7 +319,7 @@ int handle_options(int *argc, char ***argv, } return EXIT_OPTION_DISABLED; } - if (must_be_var && (optp->var_type & GET_TYPE_MASK) == GET_NO_ARG) + if (must_be_var && optp->arg_type == NO_ARG) { if (my_getopt_print_errors) my_getopt_error_reporter(ERROR_LEVEL, @@ -431,33 +361,19 @@ int handle_options(int *argc, char ***argv, else { my_getopt_error_reporter(WARNING_LEVEL, - "%s: ignoring option '--%s' due to \ -invalid value '%s'", + "%s: ignoring option '--%s' " + "due to invalid value '%s'", my_progname, optp->name, optend); continue; } - if (get_one_option(optp->id, optp, + if (get_one_option && get_one_option(optp->id, optp, *((my_bool*) value) ? - (char*) "1" : disabled_my_option)) + enabled_my_option : disabled_my_option)) return EXIT_ARGUMENT_INVALID; continue; } argument= optend; } - else if (optp->arg_type == OPT_ARG && - (((optp->var_type & GET_TYPE_MASK) == GET_BOOL) || - (optp->var_type & GET_TYPE_MASK) == GET_ENUM)) - { - if (optend == disabled_my_option) - init_one_value(optp, value, 0); - else - { - if (!optend) /* No argument -> enable option */ - init_one_value(optp, value, 1); - else - argument= optend; - } - } else if (optp->arg_type == REQUIRED_ARG && !optend) { /* Check if there are more arguments after this one, @@ -484,9 +400,9 @@ invalid value '%s'", for (optend= cur_arg; *optend; optend++) { opt_found= 0; - for (optp= longopts; optp->id; optp++) + for (optp= longopts; optp->name; optp++) { - if (optp->id == (int) (uchar) *optend) + if (optp->id && optp->id == (int) (uchar) *optend) { /* Option recognized. Find next what to do with it */ opt_found= 1; @@ -502,7 +418,7 @@ invalid value '%s'", optp->arg_type == NO_ARG) { *((my_bool*) optp->value)= (my_bool) 1; - if (get_one_option(optp->id, optp, argument)) + if (get_one_option && get_one_option(optp->id, optp, argument)) return EXIT_UNSPECIFIED_ERROR; continue; } @@ -522,7 +438,7 @@ invalid value '%s'", { if (optp->var_type == GET_BOOL) *((my_bool*) optp->value)= (my_bool) 1; - if (get_one_option(optp->id, optp, argument)) + if (get_one_option && get_one_option(optp->id, optp, argument)) return EXIT_UNSPECIFIED_ERROR; continue; } @@ -542,13 +458,8 @@ invalid value '%s'", } if ((error= setval(optp, optp->value, argument, set_maximum_value))) - { - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Error while setting value '%s' to '%s'", - my_progname, argument, optp->name); return error; - } - if (get_one_option(optp->id, optp, argument)) + if (get_one_option && get_one_option(optp->id, optp, argument)) return EXIT_UNSPECIFIED_ERROR; break; } @@ -566,13 +477,8 @@ invalid value '%s'", continue; } if ((error= setval(optp, value, argument, set_maximum_value))) - { - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Error while setting value '%s' to '%s'", - my_progname, argument, optp->name); return error; - } - if (get_one_option(optp->id, optp, argument)) + if (get_one_option && get_one_option(optp->id, optp, argument)) return EXIT_UNSPECIFIED_ERROR; (*argc)--; /* option handled (short or long), decrease argument count */ @@ -640,79 +546,130 @@ static char *check_struct_option(char *cur_arg, char *key_name) Will set the option value to given value */ -static int setval(const struct my_option *opts, uchar* *value, char *argument, +static int setval(const struct my_option *opts, uchar **value, char *argument, my_bool set_maximum_value) { - int err= 0; + int err= 0, res= 0; - if (value && argument) - { - uchar* *result_pos= ((set_maximum_value) ? - opts->u_max_value : value); + if (!argument) + argument= enabled_my_option; - if (!result_pos) + if (value) + { + if (set_maximum_value && !(value= opts->u_max_value)) + { + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Maximum value of '%s' cannot be set", + my_progname, opts->name); return EXIT_NO_PTR_TO_VARIABLE; + } switch ((opts->var_type & GET_TYPE_MASK)) { case GET_BOOL: /* If argument differs from 0, enable option, else disable */ - *((my_bool*) result_pos)= (my_bool) atoi(argument) != 0; + *((my_bool*) value)= (my_bool) atoi(argument) != 0; break; case GET_INT: - *((int*) result_pos)= (int) getopt_ll(argument, opts, &err); + *((int*) value)= (int) getopt_ll(argument, opts, &err); break; case GET_UINT: - *((uint*) result_pos)= (uint) getopt_ull(argument, opts, &err); + *((uint*) value)= (uint) getopt_ull(argument, opts, &err); break; case GET_LONG: - *((long*) result_pos)= (long) getopt_ll(argument, opts, &err); + *((long*) value)= (long) getopt_ll(argument, opts, &err); break; case GET_ULONG: - *((long*) result_pos)= (long) getopt_ull(argument, opts, &err); + *((long*) value)= (long) getopt_ull(argument, opts, &err); break; case GET_LL: - *((longlong*) result_pos)= getopt_ll(argument, opts, &err); + *((longlong*) value)= getopt_ll(argument, opts, &err); break; case GET_ULL: - *((ulonglong*) result_pos)= getopt_ull(argument, opts, &err); + *((ulonglong*) value)= getopt_ull(argument, opts, &err); break; case GET_DOUBLE: - *((double*) result_pos)= getopt_double(argument, opts, &err); + *((double*) value)= getopt_double(argument, opts, &err); break; case GET_STR: - *((char**) result_pos)= argument; + if (argument == enabled_my_option) + break; /* string options don't use this default of "1" */ + *((char**) value)= argument; break; case GET_STR_ALLOC: - if ((*((char**) result_pos))) - my_free((*(char**) result_pos), MYF(MY_WME | MY_FAE)); - if (!(*((char**) result_pos)= my_strdup(argument, MYF(MY_WME)))) - return EXIT_OUT_OF_MEMORY; + if (argument == enabled_my_option) + break; /* string options don't use this default of "1" */ + if ((*((char**) value))) + my_free((*(char**) value), MYF(MY_WME | MY_FAE)); + if (!(*((char**) value)= my_strdup(argument, MYF(MY_WME)))) + { + res= EXIT_OUT_OF_MEMORY; + goto ret; + }; break; case GET_ENUM: - if (((*(int*)result_pos)= - find_type(argument, opts->typelib, 2) - 1) < 0) + if (((*(uint*)value)= + find_type(argument, opts->typelib, 2) - 1) == (uint)-1) { - /* - Accept an integer representation of the enumerated item. - */ + /* Accept an integer representation of the enumerated item */ char *endptr; - unsigned int arg= (unsigned int) strtol(argument, &endptr, 10); + uint arg= (uint) strtol(argument, &endptr, 10); if (*endptr || arg >= opts->typelib->count) - return EXIT_ARGUMENT_INVALID; - *(int*)result_pos= arg; + { + res= EXIT_ARGUMENT_INVALID; + goto ret; + }; + *(uint*)value= arg; } break; case GET_SET: - *((ulonglong*)result_pos)= find_typeset(argument, opts->typelib, &err); + *((ulonglong*)value)= find_typeset(argument, opts->typelib, &err); if (err) - return EXIT_ARGUMENT_INVALID; + { + /* Accept an integer representation of the set */ + char *endptr; + ulonglong arg= (ulonglong) strtol(argument, &endptr, 10); + if (*endptr || (arg >> 1) >= (1ULL << (opts->typelib->count-1))) + { + res= EXIT_ARGUMENT_INVALID; + goto ret; + }; + *(ulonglong*)value= arg; + err= 0; + } break; - default: /* dummy default to avoid compiler warnings */ + case GET_FLAGSET: + { + char *error; + uint error_len; + + *((ulonglong*)value)= + find_set_from_flags(opts->typelib, opts->typelib->count, + *(ulonglong *)value, opts->def_value, + argument, strlen(argument), + &error, &error_len); + if (error) + { + res= EXIT_ARGUMENT_INVALID; + goto ret; + }; + } + break; + case GET_NO_ARG: /* get_one_option has taken care of the value already */ + default: /* dummy default to avoid compiler warnings */ break; } if (err) - return EXIT_UNKNOWN_SUFFIX; + { + res= EXIT_UNKNOWN_SUFFIX; + goto ret; + }; } return 0; + +ret: + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Error while setting value '%s' to '%s'", + my_progname, argument, opts->name); + return res; } @@ -890,7 +847,7 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp, break; } - num= ((num - optp->sub_size) / block_size); + num= (num / block_size); num= (longlong) (num * block_size); if (num < optp->min_value) @@ -901,7 +858,7 @@ longlong getopt_ll_limit_value(longlong num, const struct my_option *optp, } if (fix) - *fix= adjusted; + *fix= old != num; else if (adjusted) my_getopt_error_reporter(WARNING_LEVEL, "option '%s': signed value %s adjusted to %s", @@ -973,7 +930,7 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp, } if (fix) - *fix= adjusted; + *fix= old != num; else if (adjusted) my_getopt_error_reporter(WARNING_LEVEL, "option '%s': unsigned value %s adjusted to %s", @@ -982,6 +939,29 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp, return num; } +double getopt_double_limit_value(double num, const struct my_option *optp, + my_bool *fix) +{ + my_bool adjusted= FALSE; + double old= num; + if (optp->max_value && num > (double) optp->max_value) + { + num= (double) optp->max_value; + adjusted= TRUE; + } + if (num < (double) optp->min_value) + { + num= (double) optp->min_value; + adjusted= TRUE; + } + if (fix) + *fix= adjusted; + else if (adjusted) + my_getopt_error_reporter(WARNING_LEVEL, + "option '%s': value %g adjusted to %g", + optp->name, old, num); + return num; +} /* Get double value withing ranges @@ -1003,15 +983,12 @@ static double getopt_double(char *arg, const struct my_option *optp, int *err) num= my_strtod(arg, &end, &error); if (end[0] != 0 || error) { - fprintf(stderr, - "%s: ERROR: Invalid decimal value for option '%s'\n", - my_progname, optp->name); + my_getopt_error_reporter(ERROR_LEVEL, + "Invalid decimal value for option '%s'\n", optp->name); *err= EXIT_ARGUMENT_INVALID; return 0.0; } - if (optp->max_value && num > (double) optp->max_value) - num= (double) optp->max_value; - return max(num, (double) optp->min_value); + return getopt_double_limit_value(num, optp, NULL); } /* @@ -1053,6 +1030,7 @@ static void init_one_value(const struct my_option *option, uchar* *variable, *((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value((ulonglong) value, option, NULL); break; case GET_SET: + case GET_FLAGSET: *((ulonglong*) variable)= (ulonglong) value; break; case GET_DOUBLE: @@ -1128,7 +1106,7 @@ void my_cleanup_options(const struct my_option *options) NOTES We will initialize the value that is pointed to by options->value. - If the value is of type GET_ASK_ADDR, we will also ask for the address + If the value is of type GET_ASK_ADDR, we will ask for the address for a value and initialize. */ @@ -1138,7 +1116,7 @@ static void init_variables(const struct my_option *options, DBUG_ENTER("init_variables"); for (; options->name; options++) { - uchar* *variable; + uchar **value; DBUG_PRINT("options", ("name: '%s'", options->name)); /* We must set u_max_value first as for some variables @@ -1147,15 +1125,22 @@ static void init_variables(const struct my_option *options, */ if (options->u_max_value) init_one_value(options, options->u_max_value, options->max_value); - if (options->value) - init_one_value(options, options->value, options->def_value); - if (options->var_type & GET_ASK_ADDR && - (variable= (*getopt_get_addr)("", 0, options, 0))) - init_one_value(options, variable, options->def_value); + value= (options->var_type & GET_ASK_ADDR ? + (*getopt_get_addr)("", 0, options, 0) : options->value); + if (value) + init_one_value(options, value, options->def_value); } DBUG_VOID_RETURN; } +/** Prints variable or option name, replacing _ with - */ +static uint print_name(const struct my_option *optp) +{ + const char *s= optp->name; + for (;*s;s++) + putchar(*s == '_' ? '-' : *s); + return s - optp->name; +} /* function: my_print_options @@ -1171,9 +1156,9 @@ void my_print_help(const struct my_option *options) const char *line_end; const struct my_option *optp; - for (optp= options; optp->id; optp++) + for (optp= options; optp->name; optp++) { - if (optp->id < 256) + if (optp->id && optp->id < 256) { printf(" -%c%s", optp->id, strlen(optp->name) ? ", " : " "); col= 6; @@ -1185,21 +1170,24 @@ void my_print_help(const struct my_option *options) } if (strlen(optp->name)) { - printf("--%s", optp->name); - col+= 2 + (uint) strlen(optp->name); - if ((optp->var_type & GET_TYPE_MASK) == GET_STR || - (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC) + printf("--"); + col+= 2 + print_name(optp); + if (optp->arg_type == NO_ARG || + (optp->var_type & GET_TYPE_MASK) == GET_BOOL) + { + putchar(' '); + col++; + } + else if ((optp->var_type & GET_TYPE_MASK) == GET_STR || + (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC || + (optp->var_type & GET_TYPE_MASK) == GET_ENUM || + (optp->var_type & GET_TYPE_MASK) == GET_SET || + (optp->var_type & GET_TYPE_MASK) == GET_FLAGSET ) { printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "", optp->arg_type == OPT_ARG ? "]" : ""); col+= (optp->arg_type == OPT_ARG) ? 8 : 6; } - else if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG || - (optp->var_type & GET_TYPE_MASK) == GET_BOOL) - { - putchar(' '); - col++; - } else { printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "", @@ -1231,6 +1219,15 @@ void my_print_help(const struct my_option *options) printf("%s", comment); } putchar('\n'); + if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL) + { + if (optp->def_value != 0) + { + printf("%*s(Defaults to on; use --skip-", name_space, ""); + print_name(optp); + printf(" to disable.)\n"); + } + } } } @@ -1244,35 +1241,52 @@ void my_print_help(const struct my_option *options) void my_print_variables(const struct my_option *options) { uint name_space= 34, length, nr; - ulonglong bit, llvalue; + ulonglong llvalue; char buff[255]; const struct my_option *optp; + for (optp= options; optp->name; optp++) + { + length= strlen(optp->name)+1; + if (length > name_space) + name_space= length; + } + printf("\nVariables (--variable-name=value)\n"); - printf("and boolean options {FALSE|TRUE} Value (after reading options)\n"); - printf("--------------------------------- -----------------------------\n"); - for (optp= options; optp->id; optp++) + printf("%-*s%s", name_space, "and boolean options {FALSE|TRUE}", + "Value (after reading options)\n"); + for (length=1; length < 75; length++) + putchar(length == name_space ? ' ' : '-'); + putchar('\n'); + + for (optp= options; optp->name; optp++) { - uchar* *value= (optp->var_type & GET_ASK_ADDR ? + uchar **value= (optp->var_type & GET_ASK_ADDR ? (*getopt_get_addr)("", 0, optp, 0) : optp->value); if (value) { - printf("%s ", optp->name); - length= (uint) strlen(optp->name)+1; + length= print_name(optp); for (; length < name_space; length++) putchar(' '); switch ((optp->var_type & GET_TYPE_MASK)) { case GET_SET: if (!(llvalue= *(ulonglong*) value)) - printf("%s\n", "(No default value)"); + printf("%s\n", ""); else - for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1) + for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1) { - if (!(bit & llvalue)) - continue; - llvalue&= ~bit; - printf( llvalue ? "%s," : "%s\n", get_type(optp->typelib, nr)); + if (llvalue & 1) + printf( llvalue > 1 ? "%s," : "%s\n", get_type(optp->typelib, nr)); + } + break; + case GET_FLAGSET: + llvalue= *(ulonglong*) value; + for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1) + { + printf("%s%s=", (nr ? "," : ""), get_type(optp->typelib, nr)); + printf(llvalue & 1 ? "on" : "off"); } + printf("\n"); break; case GET_ENUM: printf("%s\n", get_type(optp->typelib, *(uint*) value)); @@ -1307,6 +1321,9 @@ void my_print_variables(const struct my_option *options) case GET_DOUBLE: printf("%g\n", *(double*) value); break; + case GET_NO_ARG: + printf("(No default value)\n"); + break; default: printf("(Disabled)\n"); break; diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c index b692b18bfc7..ea12f73fe3d 100644 --- a/mysys/my_getsystime.c +++ b/mysys/my_getsystime.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB +/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -150,7 +150,10 @@ ulonglong my_micro_time() Value in microseconds from some undefined point in time */ -#define DELTA_FOR_SECONDS LL(500000000) /* Half a second */ +#define DELTA_FOR_SECONDS 500000000LL /* Half a second */ + +/* Difference between GetSystemTimeAsFileTime() and now() */ +#define OFFSET_TO_EPOCH 116444736000000000ULL ulonglong my_micro_time_and_time(time_t *time_arg) { @@ -168,7 +171,7 @@ ulonglong my_micro_time_and_time(time_t *time_arg) static time_t cur_time= 0; hrtime_t cur_gethrtime; - pthread_mutex_lock(&THR_LOCK_time); + mysql_mutex_lock(&THR_LOCK_time); cur_gethrtime= gethrtime(); if ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS) { @@ -176,7 +179,7 @@ ulonglong my_micro_time_and_time(time_t *time_arg) prev_gethrtime= cur_gethrtime; } *time_arg= cur_time; - pthread_mutex_unlock(&THR_LOCK_time); + mysql_mutex_unlock(&THR_LOCK_time); return cur_gethrtime/1000; #else ulonglong newtime; diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c index e0c5b94b53e..6ef8d571492 100644 --- a/mysys/my_getwd.c +++ b/mysys/my_getwd.c @@ -51,7 +51,7 @@ int my_getwd(char * buf, size_t size, myf MyFlags) (long) buf, (uint) size, MyFlags)); if (curr_dir[0]) /* Current pos is saved here */ - VOID(strmake(buf,&curr_dir[0],size-1)); + (void) strmake(buf,&curr_dir[0],size-1); else { #if defined(HAVE_GETCWD) diff --git a/mysys/my_handler.c b/mysys/my_handler.c index 3bc27b622cb..3f8af553db6 100644 --- a/mysys/my_handler.c +++ b/mysys/my_handler.c @@ -576,6 +576,10 @@ HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a) will ignore calls to register already registered error numbers. */ +static const char **get_handler_error_messages() +{ + return handler_error_messages; +} void my_handler_error_register(void) { @@ -587,7 +591,7 @@ void my_handler_error_register(void) */ compile_time_assert(HA_ERR_FIRST + array_elements(handler_error_messages) == HA_ERR_LAST + 1); - my_error_register(handler_error_messages, HA_ERR_FIRST, + my_error_register(get_handler_error_messages, HA_ERR_FIRST, HA_ERR_FIRST+ array_elements(handler_error_messages)-1); } diff --git a/mysys/my_init.c b/mysys/my_init.c index c4fda599481..80f9a493bb0 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -43,6 +43,8 @@ static void netware_init(); #endif my_bool my_init_done= 0; +/** True if @c my_basic_init() has been called. */ +my_bool my_basic_init_done= 0; uint mysys_usage_id= 0; /* Incremented for each my_init() */ ulong my_thread_stack_size= 65536; @@ -57,28 +59,50 @@ static ulong atoi_octal(const char *str) return (ulong) tmp; } - -/* - Init my_sys functions and my_sys variabels - - SYNOPSIS - my_init() - - RETURN - 0 ok - 1 Couldn't initialize environment +MYSQL_FILE *mysql_stdin= NULL; +static MYSQL_FILE instrumented_stdin; + +/** + Perform a limited initialisation of mysys. + This initialisation is sufficient to: + - allocate memory, + - read configuration files, + - parse command lines arguments. + To complete the mysys initialisation, + call my_init(). + @return 0 on success */ - -my_bool my_init(void) +my_bool my_basic_init(void) { char * str; - if (my_init_done) + + if (my_basic_init_done) return 0; - my_init_done=1; + my_basic_init_done= 1; + mysys_usage_id++; my_umask= 0660; /* Default umask for new files */ my_umask_dir= 0700; /* Default umask for new directories */ + +#ifndef VMS + /* Default creation of new files */ + if ((str= getenv("UMASK")) != 0) + my_umask= (int) (atoi_octal(str) | 0600); + /* Default creation of new dir's */ + if ((str= getenv("UMASK_DIR")) != 0) + my_umask_dir= (int) (atoi_octal(str) | 0700); +#endif + + /* $HOME is needed early to parse configuration files located in ~/ */ + if ((home_dir= getenv("HOME")) != 0) + home_dir= intern_filename(home_dir_buff, home_dir); + init_glob_errs(); + + instrumented_stdin.m_file= stdin; + instrumented_stdin.m_psi= NULL; /* not yet instrumented */ + mysql_stdin= & instrumented_stdin; + #if defined(THREAD) if (my_thread_global_init()) return 1; @@ -94,6 +118,37 @@ my_bool my_init(void) #if defined(HAVE_PTHREAD_INIT) pthread_init(); /* Must be called before DBUG_ENTER */ #endif + if (my_thread_basic_global_init()) + return 1; +#endif + + return 0; +} + + +/* + Init my_sys functions and my_sys variabels + + SYNOPSIS + my_init() + + RETURN + 0 ok + 1 Couldn't initialize environment +*/ + +my_bool my_init(void) +{ + if (my_init_done) + return 0; + my_init_done= 1; + + if (my_basic_init()) + return 1; + +#ifdef THREAD + if (my_thread_global_init()) + return 1; #if !defined( __WIN__) && !defined(__NETWARE__) sigfillset(&my_signals); /* signals blocked by mf_brkhant */ #endif @@ -101,24 +156,11 @@ my_bool my_init(void) { DBUG_ENTER("my_init"); DBUG_PROCESS((char*) (my_progname ? my_progname : "unknown")); - if (!home_dir) - { /* Don't initialize twice */ - my_win_init(); - if ((home_dir=getenv("HOME")) != 0) - home_dir=intern_filename(home_dir_buff,home_dir); -#ifndef VMS - /* Default creation of new files */ - if ((str=getenv("UMASK")) != 0) - my_umask=(int) (atoi_octal(str) | 0600); - /* Default creation of new dir's */ - if ((str=getenv("UMASK_DIR")) != 0) - my_umask_dir=(int) (atoi_octal(str) | 0700); -#endif + my_win_init(); #ifdef VMS - init_ctype(); /* Stupid linker don't link _ctype.c */ + init_ctype(); /* Stupid linker don't link _ctype.c */ #endif - DBUG_PRINT("exit",("home: '%s'",home_dir)); - } + DBUG_PRINT("exit", ("home: '%s'", home_dir)); #ifdef __WIN__ win32_init_tcp_ip(); #endif @@ -239,6 +281,7 @@ Voluntary context switches %ld, Involuntary context switches %ld\n", WSACleanup(); #endif /* __WIN__ */ my_init_done=0; + my_basic_init_done= 0; } /* my_end */ @@ -538,3 +581,118 @@ static void netware_init() DBUG_VOID_RETURN; } #endif /* __NETWARE__ */ + +#ifdef HAVE_PSI_INTERFACE + +#if !defined(HAVE_PREAD) && !defined(_WIN32) +PSI_mutex_key key_my_file_info_mutex; +#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */ + +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) +PSI_mutex_key key_LOCK_localtime_r; +#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */ + +#ifndef HAVE_GETHOSTBYNAME_R +PSI_mutex_key key_LOCK_gethostbyname_r; +#endif /* HAVE_GETHOSTBYNAME_R */ + +PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock, + key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm, + key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap, + key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc, + key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net, + key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time, + key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap; + +static PSI_mutex_info all_mysys_mutexes[]= +{ +#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) + { &key_my_file_info_mutex, "st_my_file_info:mutex", 0}, +#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */ +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) + { &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL}, +#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */ +#ifndef HAVE_GETHOSTBYNAME_R + { &key_LOCK_gethostbyname_r, "LOCK_gethostbyname_r", PSI_FLAG_GLOBAL}, +#endif /* HAVE_GETHOSTBYNAME_R */ + { &key_BITMAP_mutex, "BITMAP::mutex", 0}, + { &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0}, + { &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0}, + { &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0}, + { &key_LOCK_alarm, "LOCK_alarm", PSI_FLAG_GLOBAL}, + { &key_my_thread_var_mutex, "my_thread_var::mutex", 0}, + { &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_isam, "THR_LOCK_isam", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_lock, "THR_LOCK_lock", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_malloc, "THR_LOCK_malloc", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_mutex, "THR_LOCK::mutex", 0}, + { &key_THR_LOCK_myisam, "THR_LOCK_myisam", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_time, "THR_LOCK_time", PSI_FLAG_GLOBAL}, + { &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL}, + { &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL} +}; + +PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond, + key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend, + key_THR_COND_threads; + +static PSI_cond_info all_mysys_conds[]= +{ + { &key_COND_alarm, "COND_alarm", PSI_FLAG_GLOBAL}, + { &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0}, + { &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0}, + { &key_my_thread_var_suspend, "my_thread_var::suspend", 0}, + { &key_THR_COND_threads, "THR_COND_threads", 0} +}; + +#ifdef USE_ALARM_THREAD +PSI_thread_key key_thread_alarm; + +static PSI_thread_info all_mysys_threads[]= +{ + { &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL} +}; +#endif /* USE_ALARM_THREAD */ + +#ifdef HUGETLB_USE_PROC_MEMINFO +PSI_file_key key_file_proc_meminfo; +#endif /* HUGETLB_USE_PROC_MEMINFO */ +PSI_file_key key_file_charset, key_file_cnf; + +static PSI_file_info all_mysys_files[]= +{ +#ifdef HUGETLB_USE_PROC_MEMINFO + { &key_file_proc_meminfo, "proc_meminfo", 0}, +#endif /* HUGETLB_USE_PROC_MEMINFO */ + { &key_file_charset, "charset", 0}, + { &key_file_cnf, "cnf", 0} +}; + +void my_init_mysys_psi_keys() +{ + const char* category= "mysys"; + int count; + + if (PSI_server == NULL) + return; + + count= sizeof(all_mysys_mutexes)/sizeof(all_mysys_mutexes[0]); + PSI_server->register_mutex(category, all_mysys_mutexes, count); + + count= sizeof(all_mysys_conds)/sizeof(all_mysys_conds[0]); + PSI_server->register_cond(category, all_mysys_conds, count); + +#ifdef USE_ALARM_THREAD + count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]); + PSI_server->register_thread(category, all_mysys_threads, count); +#endif /* USE_ALARM_THREAD */ + + count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]); + PSI_server->register_file(category, all_mysys_files, count); +} +#endif /* HAVE_PSI_INTERFACE */ + diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c index d96e1048fd0..e65d3a0a5f5 100644 --- a/mysys/my_largepage.c +++ b/mysys/my_largepage.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB +/* Copyright (C) 2004 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -91,19 +91,20 @@ void my_large_free(uchar* ptr, myf my_flags __attribute__((unused))) uint my_get_large_page_size_int(void) { - FILE *f; + MYSQL_FILE *f; uint size = 0; char buf[256]; DBUG_ENTER("my_get_large_page_size_int"); - if (!(f = my_fopen("/proc/meminfo", O_RDONLY, MYF(MY_WME)))) + if (!(f= mysql_file_fopen(key_file_proc_meminfo, "/proc/meminfo", + O_RDONLY, MYF(MY_WME)))) goto finish; - while (fgets(buf, sizeof(buf), f)) + while (mysql_file_fgets(buf, sizeof(buf), f)) if (sscanf(buf, "Hugepagesize: %u kB", &size)) break; - my_fclose(f, MYF(MY_WME)); + mysql_file_fclose(f, MYF(MY_WME)); finish: DBUG_RETURN(size * 1024); diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 033f8789b49..0113d1498df 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -110,7 +110,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags)); #if defined(THREAD) && !defined(HAVE_READDIR_R) - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); #endif dirp = opendir(directory_file_name(tmp_path,(char *) path)); @@ -159,8 +159,8 @@ MY_DIR *my_dir(const char *path, myf MyFlags) goto error; bzero(finfo.mystat, sizeof(MY_STAT)); - VOID(strmov(tmp_file,dp->d_name)); - VOID(my_stat(tmp_path, finfo.mystat, MyFlags)); + (void) strmov(tmp_file,dp->d_name); + (void) my_stat(tmp_path, finfo.mystat, MyFlags); if (!(finfo.mystat->st_mode & MY_S_IREAD)) continue; } @@ -173,7 +173,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) (void) closedir(dirp); #if defined(THREAD) && !defined(HAVE_READDIR_R) - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); #endif result->dir_entry= (FILEINFO *)dir_entries_storage->buffer; result->number_off_files= dir_entries_storage->elements; @@ -185,7 +185,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) error: #if defined(THREAD) && !defined(HAVE_READDIR_R) - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); #endif my_errno=errno; if (dirp) @@ -266,7 +266,7 @@ char * directory_file_name (char * dst, const char *src) /* what about when we have logical_name:???? */ if (src[slen] == FN_DEVCHAR) { /* Xlate logical name and see what we get */ - VOID(strmov(dst,src)); + (void) strmov(dst,src); dst[slen] = 0; /* remove colon */ if (!(src = getenv (dst))) return dst; /* Can't translate */ @@ -282,13 +282,13 @@ char * directory_file_name (char * dst, const char *src) slen = strlen (src) - 1; if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2) { /* no recursion here! */ - VOID(strmov(dst, src)); + (void) strmov(dst, src); return(dst); } } else { /* not a directory spec */ - VOID(strmov(dst, src)); + (void) strmov(dst, src); return(dst); } } @@ -296,13 +296,13 @@ char * directory_file_name (char * dst, const char *src) bracket = src[slen]; /* End char */ if (!(ptr = strchr (src, bracket - 2))) { /* no opening bracket */ - VOID(strmov (dst, src)); + (void) strmov (dst, src); return dst; } if (!(rptr = strrchr (src, '.'))) rptr = ptr; slen = rptr - src; - VOID(strmake (dst, src, slen)); + (void) strmake (dst, src, slen); if (*rptr == '.') { /* Put bracket and add */ @@ -323,7 +323,7 @@ char * directory_file_name (char * dst, const char *src) && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2) && ptr[rlen - 1] == '.') { - VOID(strmov(esa,ptr)); + (void) strmov(esa,ptr); esa[rlen - 1] = FN_C_AFTER_DIR; esa[rlen] = '\0'; return (directory_file_name (dst, esa)); @@ -331,13 +331,13 @@ char * directory_file_name (char * dst, const char *src) else dst[slen - 1] = ':'; } - VOID(strmov(dst+slen,"[000000]")); + (void) strmov(dst+slen,"[000000]"); slen += 8; } - VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1")); + (void) strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"); return dst; } - VOID(strmov(dst, src)); + (void) strmov(dst, src); if (dst[slen] == '/' && slen > 1) dst[slen] = 0; return dst; diff --git a/mysys/my_lock.c b/mysys/my_lock.c index 62f39bd3b71..1436c845286 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -206,8 +206,8 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, else timeout_sec= WIN_LOCK_INFINITE; - if(win_lock(fd, locktype, start, length, timeout_sec) == 0) - DBUG_RETURN(0); + if (win_lock(fd, locktype, start, length, timeout_sec) == 0) + DBUG_RETURN(0); } #else #if defined(HAVE_FCNTL) diff --git a/mysys/my_lockmem.c b/mysys/my_lockmem.c index b96331cd3cf..1b582783d33 100644 --- a/mysys/my_lockmem.c +++ b/mysys/my_lockmem.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -59,16 +59,16 @@ uchar *my_malloc_lock(uint size,myf MyFlags) /* Add block in a list for munlock */ if (!(element=(struct st_mem_list*) my_malloc(sizeof(*element),MyFlags))) { - VOID(munlock((uchar*) ptr,size)); + (void) munlock((uchar*) ptr,size); free(ptr); DBUG_RETURN(0); } element->list.data=(uchar*) element; element->page=ptr; element->size=size; - pthread_mutex_lock(&THR_LOCK_malloc); + mysql_mutex_lock(&THR_LOCK_malloc); mem_list=list_add(mem_list,&element->list); - pthread_mutex_unlock(&THR_LOCK_malloc); + mysql_mutex_unlock(&THR_LOCK_malloc); } DBUG_RETURN(ptr); } @@ -79,18 +79,18 @@ void my_free_lock(uchar *ptr,myf Myflags __attribute__((unused))) LIST *list; struct st_mem_list *element=0; - pthread_mutex_lock(&THR_LOCK_malloc); + mysql_mutex_lock(&THR_LOCK_malloc); for (list=mem_list ; list ; list=list->next) { element=(struct st_mem_list*) list->data; if (ptr == element->page) { /* Found locked mem */ - VOID(munlock((uchar*) ptr,element->size)); + (void) munlock((uchar*) ptr,element->size); mem_list=list_delete(mem_list,list); break; } } - pthread_mutex_unlock(&THR_LOCK_malloc); + mysql_mutex_unlock(&THR_LOCK_malloc); if (element) my_free((uchar*) element,MYF(0)); free(ptr); /* Free even if not locked */ diff --git a/mysys/my_net.c b/mysys/my_net.c index 81d977210f8..e584e541175 100644 --- a/mysys/my_net.c +++ b/mysys/my_net.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -35,8 +35,8 @@ void my_inet_ntoa(struct in_addr in, char *buf) { char *ptr; - pthread_mutex_lock(&THR_LOCK_net); + mysql_mutex_lock(&THR_LOCK_net); ptr=inet_ntoa(in); strmov(buf,ptr); - pthread_mutex_unlock(&THR_LOCK_net); + mysql_mutex_unlock(&THR_LOCK_net); } diff --git a/mysys/my_once.c b/mysys/my_once.c index b6f6656fce2..727b8477365 100644 --- a/mysys/my_once.c +++ b/mysys/my_once.c @@ -25,7 +25,8 @@ #include <m_string.h> /* - Alloc for things we don't nead to free + Alloc for things we don't nend to free run-time (that only + should be free'd on exit) SYNOPSIS my_once_alloc() @@ -100,7 +101,7 @@ void *my_once_memdup(const void *src, size_t len, myf myflags) /* - Deallocate everything used by my_once_alloc + Deallocate everything that was allocated with my_once_alloc SYNOPSIS my_once_free() diff --git a/mysys/my_open.c b/mysys/my_open.c index 79a4da242f9..a50baf2c417 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -70,7 +70,7 @@ int my_close(File fd, myf MyFlags) DBUG_ENTER("my_close"); DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags)); - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); #ifndef _WIN32 do { @@ -90,12 +90,12 @@ int my_close(File fd, myf MyFlags) { my_free(my_file_info[fd].name, MYF(0)); #if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) - pthread_mutex_destroy(&my_file_info[fd].mutex); + mysql_mutex_destroy(&my_file_info[fd].mutex); #endif my_file_info[fd].type = UNOPEN; } my_file_opened--; - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); DBUG_RETURN(err); } /* my_close */ @@ -134,20 +134,21 @@ File my_register_filename(File fd, const char *FileName, enum file_type } else { - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags))) { my_file_opened++; my_file_total_opened++; my_file_info[fd].type = type_of_file; #if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) - pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex, + MY_MUTEX_INIT_FAST); #endif - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); DBUG_PRINT("exit",("fd: %d",fd)); DBUG_RETURN(fd); } - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); my_errno= ENOMEM; } (void) my_close(fd, MyFlags); diff --git a/mysys/my_pread.c b/mysys/my_pread.c index eaabcb1b728..d0a0ddaec66 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -60,12 +60,12 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, { errno= 0; /* Linux, Windows don't reset this on EOF/success */ #if !defined (HAVE_PREAD) && !defined (_WIN32) - pthread_mutex_lock(&my_file_info[Filedes].mutex); + mysql_mutex_lock(&my_file_info[Filedes].mutex); readbytes= (uint) -1; error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 || (readbytes= read(Filedes, Buffer, Count)) != Count); save_errno= errno; - pthread_mutex_unlock(&my_file_info[Filedes].mutex); + mysql_mutex_unlock(&my_file_info[Filedes].mutex); if (error) errno= save_errno; #else @@ -150,10 +150,10 @@ size_t my_pwrite(File Filedes, const uchar *Buffer, size_t Count, #if !defined (HAVE_PREAD) && !defined (_WIN32) int error; writtenbytes= (size_t) -1; - pthread_mutex_lock(&my_file_info[Filedes].mutex); + mysql_mutex_lock(&my_file_info[Filedes].mutex); error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 && (writtenbytes= write(Filedes, Buffer, Count)) == Count); - pthread_mutex_unlock(&my_file_info[Filedes].mutex); + mysql_mutex_unlock(&my_file_info[Filedes].mutex); if (error) break; #elif defined (_WIN32) diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index aba3e47d754..b6b7e7db857 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -31,46 +31,6 @@ uint thd_lib_detected= 0; -#ifndef my_pthread_setprio -void my_pthread_setprio(pthread_t thread_id,int prior) -{ -#ifdef HAVE_PTHREAD_SETSCHEDPARAM - struct sched_param tmp_sched_param; - bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param)); - tmp_sched_param.sched_priority=prior; - VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param)); -#endif -} -#endif - -#ifndef my_pthread_getprio -int my_pthread_getprio(pthread_t thread_id) -{ -#ifdef HAVE_PTHREAD_SETSCHEDPARAM - struct sched_param tmp_sched_param; - int policy; - if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param)) - { - return tmp_sched_param.sched_priority; - } -#endif - return -1; -} -#endif - -#ifndef my_pthread_attr_setprio -void my_pthread_attr_setprio(pthread_attr_t *attr, int priority) -{ -#ifdef HAVE_PTHREAD_SETSCHEDPARAM - struct sched_param tmp_sched_param; - bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param)); - tmp_sched_param.sched_priority=priority; - VOID(pthread_attr_setschedparam(attr,&tmp_sched_param)); -#endif -} -#endif - - /* To allow use of pthread_getspecific with two arguments */ #ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC @@ -136,7 +96,7 @@ int my_sigwait(const sigset_t *set,int *sig) #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) -extern pthread_mutex_t LOCK_localtime_r; +extern mysql_mutex_t LOCK_localtime_r; #endif @@ -144,10 +104,10 @@ extern pthread_mutex_t LOCK_localtime_r; struct tm *localtime_r(const time_t *clock, struct tm *res) { struct tm *tmp; - pthread_mutex_lock(&LOCK_localtime_r); + mysql_mutex_lock(&LOCK_localtime_r); tmp=localtime(clock); *res= *tmp; - pthread_mutex_unlock(&LOCK_localtime_r); + mysql_mutex_unlock(&LOCK_localtime_r); return res; } #endif @@ -161,10 +121,10 @@ struct tm *localtime_r(const time_t *clock, struct tm *res) struct tm *gmtime_r(const time_t *clock, struct tm *res) { struct tm *tmp; - pthread_mutex_lock(&LOCK_localtime_r); + mysql_mutex_lock(&LOCK_localtime_r); tmp= gmtime(clock); *res= *tmp; - pthread_mutex_unlock(&LOCK_localtime_r); + mysql_mutex_unlock(&LOCK_localtime_r); return res; } #endif @@ -308,7 +268,7 @@ void sigwait_handle_sig(int sig) { pthread_mutex_lock(&LOCK_sigwait); sigaddset(&pending_set, sig); - VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */ + pthread_cond_signal(&COND_sigwait); /* inform sigwait() about signal */ pthread_mutex_unlock(&LOCK_sigwait); } @@ -357,16 +317,15 @@ int sigwait(sigset_t *setp, int *sigp) pthread_t sigwait_thread_id; inited=1; sigemptyset(&pending_set); - pthread_mutex_init(&LOCK_sigwait,MY_MUTEX_INIT_FAST); - pthread_cond_init(&COND_sigwait,NULL); + pthread_mutex_init(&LOCK_sigwait, MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_sigwait, NULL); pthread_attr_init(&thr_attr); pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&thr_attr,8196); - my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */ - VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp)); - VOID(pthread_attr_destroy(&thr_attr)); + pthread_create(&sigwait_thread_id, &thr_attr, sigwait_thread, setp); + pthread_attr_destroy(&thr_attr); } pthread_mutex_lock(&LOCK_sigwait); @@ -392,7 +351,7 @@ int sigwait(sigset_t *setp, int *sigp) return 0; } } - VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait)); + pthread_cond_wait(&COND_sigwait, &LOCK_sigwait); } return 0; } diff --git a/mysys/my_rdtsc.c b/mysys/my_rdtsc.c new file mode 100644 index 00000000000..073663e3d96 --- /dev/null +++ b/mysys/my_rdtsc.c @@ -0,0 +1,1004 @@ +/* Copyright (C) 2008-2010 Sun Microsystems, Inc + + 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 */ + +/* + rdtsc3 -- multi-platform timer code + pgulutzan@mysql.com, 2005-08-29 + modified 2008-11-02 + + Functions: + + my_timer_cycles ulonglong cycles + my_timer_nanoseconds ulonglong nanoseconds + my_timer_microseconds ulonglong "microseconds" + my_timer_milliseconds ulonglong milliseconds + my_timer_ticks ulonglong ticks + my_timer_init initialization / test + + We'll call the first 5 functions (the ones that return + a ulonglong) "my_timer_xxx" functions. + Each my_timer_xxx function returns a 64-bit timing value + since an arbitrary 'epoch' start. Since the only purpose + is to determine elapsed times, wall-clock time-of-day + is not known and not relevant. + + The my_timer_init function is necessary for initializing. + It returns information (underlying routine name, + frequency, resolution, overhead) about all my_timer_xxx + functions. A program should call my_timer_init once, + use the information to decide what my_timer_xxx function + to use, and subsequently call that function by function + pointer. + + A typical use would be: + my_timer_init() ... once, at program start + ... + time1= my_timer_xxx() ... time before start + [code that's timed] + time2= my_timer_xxx() ... time after end + elapsed_time= (time2 - time1) - overhead +*/ + +#include "my_global.h" +#include "my_rdtsc.h" + +#if defined(_WIN32) +#include <stdio.h> +#include "windows.h" +#else +#include <stdio.h> +#endif + +#if !defined(_WIN32) +#if TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> /* for clock_gettime */ +#else +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#elif defined(HAVE_TIME_H) +#include <time.h> +#endif +#endif +#endif + +#if defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL) +#include <asm/msr.h> /* for rdtscll */ +#endif + +#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME) +#include <sys/timeb.h> /* for ftime */ +#endif + +#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES) +#include <sys/times.h> /* for times */ +#endif + +#if defined(__NETWARE__) +#include <nks/time.h> /* for NXGetTime */ +#endif + +#if defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) +#include <ia64intrin.h> /* for __GetReg */ +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#include <mach/mach_time.h> +#endif + +#if defined(__SUNPRO_CC) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7) +extern "C" ulonglong my_timer_cycles_il_sparc64(); +#elif defined(__SUNPRO_CC) && defined(_ILP32) && !defined(__SunOS_5_7) +extern "C" ulonglong my_timer_cycles_il_sparc32(); +#elif defined(__SUNPRO_CC) && defined(__i386) && defined(_ILP32) +extern "C" ulonglong my_timer_cycles_il_i386(); +#elif defined(__SUNPRO_CC) && defined(__x86_64) && defined(_LP64) +extern "C" ulonglong my_timer_cycles_il_x86_64(); +#elif defined(__SUNPRO_C) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7) +ulonglong my_timer_cycles_il_sparc64(); +#elif defined(__SUNPRO_C) && defined(_ILP32) && !defined(__SunOS_5_7) +ulonglong my_timer_cycles_il_sparc32(); +#elif defined(__SUNPRO_C) && defined(__i386) && defined(_ILP32) +ulonglong my_timer_cycles_il_i386(); +#elif defined(__SUNPRO_C) && defined(__x86_64) && defined(_LP64) +ulonglong my_timer_cycles_il_x86_64(); +#endif + +#if defined(__INTEL_COMPILER) +/* + icc warning #1011 is: + missing return statement at end of non-void function +*/ +#pragma warning (disable:1011) +#endif + +/* + For cycles, we depend on RDTSC for x86 platforms, + or on time buffer (which is not really a cycle count + but a separate counter with less than nanosecond + resolution) for most PowerPC platforms, or on + gethrtime which is okay for hpux and solaris, or on + clock_gettime(CLOCK_SGI_CYCLE) for Irix platforms, + or on read_real_time for aix platforms. There is + nothing for Alpha platforms, they would be tricky. +*/ + +ulonglong my_timer_cycles(void) +{ +#if defined(__GNUC__) && defined(__i386__) + /* This works much better if compiled with "gcc -O3". */ + ulonglong result; + __asm__ __volatile__ ("rdtsc" : "=A" (result)); + return result; +#elif defined(__SUNPRO_C) && defined(__i386) + __asm("rdtsc"); +#elif defined(__GNUC__) && defined(__x86_64__) + ulonglong result; + __asm__ __volatile__ ("rdtsc\n\t" \ + "shlq $32,%%rdx\n\t" \ + "orq %%rdx,%%rax" + : "=a" (result) :: "%edx"); + return result; +#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL) + { + ulonglong result; + rdtscll(result); + return result; + } +#elif defined(_WIN32) && defined(_M_IX86) + __asm {rdtsc}; +#elif defined(_WIN64) && defined(_M_X64) + /* For 64-bit Windows: unsigned __int64 __rdtsc(); */ + return __rdtsc(); +#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) + return (ulonglong) __getReg(_IA64_REG_AR_ITC); /* (3116) */ +#elif defined(__GNUC__) && defined(__ia64__) + { + ulonglong result; + __asm __volatile__ ("mov %0=ar.itc" : "=r" (result)); + return result; + } +#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64)) + { + ulonglong result; + __asm __volatile__ ("mftb %0" : "=r" (result)); + return result; + } +#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64)) + { + /* + mftbu means "move from time-buffer-upper to result". + The loop is saying: x1=upper, x2=lower, x3=upper, + if x1!=x3 there was an overflow so repeat. + */ + unsigned int x1, x2, x3; + ulonglong result; + for (;;) + { + __asm __volatile__ ( "mftbu %0" : "=r"(x1) ); + __asm __volatile__ ( "mftb %0" : "=r"(x2) ); + __asm __volatile__ ( "mftbu %0" : "=r"(x3) ); + if (x1 == x3) break; + } + result = x1; + return ( result << 32 ) | x2; + } +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7) + return (my_timer_cycles_il_sparc64()); +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7) + return (my_timer_cycles_il_sparc32()); +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32) + /* This is probably redundant for __SUNPRO_C. */ + return (my_timer_cycles_il_i386()); +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64) + return (my_timer_cycles_il_x86_64()); +#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2) + { + ulonglong result; + __asm __volatile__ ("rd %%tick,%0" : "=r" (result)); + return result; + } +#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2) + { + union { + ulonglong wholeresult; + struct { + ulong high; + ulong low; + } splitresult; + } result; + __asm __volatile__ ("rd %%tick,%1; srlx %1,32,%0" : "=r" (result.splitresult.high), "=r" (result.splitresult.low)); + return result.wholeresult; + } +#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE) + { + struct timespec tp; + clock_gettime(CLOCK_SGI_CYCLE, &tp); + return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec; + } +#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) + /* gethrtime may appear as either cycle or nanosecond counter */ + return (ulonglong) gethrtime(); +#else + return 0; +#endif +} + +#if defined(__INTEL_COMPILER) +/* re-enable warning#1011 which was only for my_timer_cycles() */ +/* There may be an icc bug which means we must leave disabled. */ +#pragma warning (default:1011) +#endif + +/* + For nanoseconds, most platforms have nothing available that + (a) doesn't require bringing in a 40-kb librt.so library + (b) really has nanosecond resolution. +*/ + +ulonglong my_timer_nanoseconds(void) +{ +#if defined(HAVE_READ_REAL_TIME) + { + timebasestruct_t tr; + read_real_time(&tr, TIMEBASE_SZ); + return (ulonglong) tr.tb_high * 1000000000 + (ulonglong) tr.tb_low; + } +#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) + /* SunOS 5.10+, Solaris, HP-UX: hrtime_t gethrtime(void) */ + return (ulonglong) gethrtime(); +#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + { + struct timespec tp; + clock_gettime(CLOCK_REALTIME, &tp); + return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec; + } +#elif defined(__NETWARE__) + { + NXTime_t tm; + NXGetTime(NX_SINCE_1970, NX_NSECONDS, &tm); + return (ulonglong) tm; + } +#elif defined(__APPLE__) && defined(__MACH__) + { + ulonglong tm; + static mach_timebase_info_data_t timebase_info= {0,0}; + if (timebase_info.denom == 0) + (void) mach_timebase_info(&timebase_info); + tm= mach_absolute_time(); + return (tm * timebase_info.numer) / timebase_info.denom; + } +#else + return 0; +#endif +} + +/* + For microseconds, gettimeofday() is available on + almost all platforms. On Windows we use + QueryPerformanceCounter which will usually tick over + 3.5 million times per second, and we don't throw + away the extra precision. (On Windows Server 2003 + the frequency is same as the cycle frequency.) +*/ + +ulonglong my_timer_microseconds(void) +{ +#if defined(HAVE_GETTIMEOFDAY) + { + static ulonglong last_value= 0; + struct timeval tv; + if (gettimeofday(&tv, NULL) == 0) + last_value= (ulonglong) tv.tv_sec * 1000000 + (ulonglong) tv.tv_usec; + else + { + /* + There are reports that gettimeofday(2) can have intermittent failures + on some platform, see for example Bug#36819. + We are not trying again or looping, just returning the best value possible + under the circumstances ... + */ + last_value++; + } + return last_value; + } +#elif defined(_WIN32) + { + /* QueryPerformanceCounter usually works with about 1/3 microsecond. */ + LARGE_INTEGER t_cnt; + + QueryPerformanceCounter(&t_cnt); + return (ulonglong) t_cnt.QuadPart; + } +#elif defined(__NETWARE__) + { + NXTime_t tm; + NXGetTime(NX_SINCE_1970, NX_USECONDS, &tm); + return (ulonglong) tm; + } +#else + return 0; +#endif +} + +/* + For milliseconds, we use ftime() if it's supported + or time()*1000 if it's not. With modern versions of + Windows and with HP Itanium, resolution is 10-15 + milliseconds. +*/ + +ulonglong my_timer_milliseconds(void) +{ +#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME) + /* ftime() is obsolete but maybe the platform is old */ + struct timeb ft; + ftime(&ft); + return (ulonglong)ft.time * 1000 + (ulonglong)ft.millitm; +#elif defined(HAVE_TIME) + return (ulonglong) time(NULL) * 1000; +#elif defined(_WIN32) + FILETIME ft; + GetSystemTimeAsFileTime( &ft ); + return ((ulonglong)ft.dwLowDateTime + + (((ulonglong)ft.dwHighDateTime) << 32))/10000; +#elif defined(__NETWARE__) + { + NXTime_t tm; + NXGetTime(NX_SINCE_1970, NX_MSECONDS, &tm); + return (ulonglong)tm; + } +#else + return 0; +#endif +} + +/* + For ticks, which we handle with times(), the frequency + is usually 100/second and the overhead is surprisingly + bad, sometimes even worse than gettimeofday's overhead. +*/ + +ulonglong my_timer_ticks(void) +{ +#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES) + { + struct tms times_buf; + return (ulonglong) times(×_buf); + } +#elif defined(__NETWARE__) + { + NXTime_t tm; + NXGetTime(NX_SINCE_BOOT, NX_TICKS, &tm); + return (ulonglong) tm; + } +#elif defined(_WIN32) + return (ulonglong) GetTickCount(); +#else + return 0; +#endif +} + +/* + The my_timer_init() function and its sub-functions + have several loops which call timers. If there's + something wrong with a timer -- which has never + happened in tests -- we want the loop to end after + an arbitrary number of iterations, and my_timer_info + will show a discouraging result. The arbitrary + number is 1,000,000. +*/ +#define MY_TIMER_ITERATIONS 1000000 + +/* + Calculate overhead. Called from my_timer_init(). + Usually best_timer_overhead = cycles.overhead or + nanoseconds.overhead, so returned amount is in + cycles or nanoseconds. We repeat the calculation + ten times, so that we can disregard effects of + caching or interrupts. Result is quite consistent + for cycles, at least. But remember it's a minimum. +*/ + +static void my_timer_init_overhead(ulonglong *overhead, + ulonglong (*cycle_timer)(void), + ulonglong (*this_timer)(void), + ulonglong best_timer_overhead) +{ + ulonglong time1, time2; + int i; + + /* *overhead, least of 20 calculations - cycles.overhead */ + for (i= 0, *overhead= 1000000000; i < 20; ++i) + { + time1= cycle_timer(); + this_timer(); /* rather than 'time_tmp= timer();' */ + time2= cycle_timer() - time1; + if (*overhead > time2) + *overhead= time2; + } + *overhead-= best_timer_overhead; +} + +/* + Calculate Resolution. Called from my_timer_init(). + If a timer goes up by jumps, e.g. 1050, 1075, 1100, ... + then the best resolution is the minimum jump, e.g. 25. + If it's always divisible by 1000 then it's just a + result of multiplication of a lower-precision timer + result, e.g. nanoseconds are often microseconds * 1000. + If the minimum jump is less than an arbitrary passed + figure (a guess based on maximum overhead * 2), ignore. + Usually we end up with nanoseconds = 1 because it's too + hard to detect anything <= 100 nanoseconds. + Often GetTickCount() has resolution = 15. + We don't check with ticks because they take too long. +*/ +static ulonglong my_timer_init_resolution(ulonglong (*this_timer)(void), + ulonglong overhead_times_2) +{ + ulonglong time1, time2; + ulonglong best_jump; + int i, jumps, divisible_by_1000, divisible_by_1000000; + + divisible_by_1000= divisible_by_1000000= 0; + best_jump= 1000000; + for (i= jumps= 0; jumps < 3 && i < MY_TIMER_ITERATIONS * 10; ++i) + { + time1= this_timer(); + time2= this_timer(); + time2-= time1; + if (time2) + { + ++jumps; + if (!(time2 % 1000)) + { + ++divisible_by_1000; + if (!(time2 % 1000000)) + ++divisible_by_1000000; + } + if (best_jump > time2) + best_jump= time2; + /* For milliseconds, one jump is enough. */ + if (overhead_times_2 == 0) + break; + } + } + if (jumps == 3) + { + if (jumps == divisible_by_1000000) + return 1000000; + if (jumps == divisible_by_1000) + return 1000; + } + if (best_jump > overhead_times_2) + return best_jump; + return 1; +} + +/* + Calculate cycle frequency by seeing how many cycles pass + in a 200-microsecond period. I tried with 10-microsecond + periods originally, and the result was often very wrong. +*/ + +static ulonglong my_timer_init_frequency(MY_TIMER_INFO *mti) +{ + int i; + ulonglong time1, time2, time3, time4; + time1= my_timer_cycles(); + time2= my_timer_microseconds(); + time3= time2; /* Avoids a Microsoft/IBM compiler warning */ + for (i= 0; i < MY_TIMER_ITERATIONS; ++i) + { + time3= my_timer_microseconds(); + if (time3 - time2 > 200) break; + } + time4= my_timer_cycles() - mti->cycles.overhead; + time4-= mti->microseconds.overhead; + return (mti->microseconds.frequency * (time4 - time1)) / (time3 - time2); +} + +/* + Call my_timer_init before the first call to my_timer_xxx(). + If something must be initialized, it happens here. + Set: what routine is being used e.g. "asm_x86" + Set: function, overhead, actual frequency, resolution. +*/ + +void my_timer_init(MY_TIMER_INFO *mti) +{ + ulonglong (*best_timer)(void); + ulonglong best_timer_overhead; + ulonglong time1, time2; + int i; + + /* cycles */ + mti->cycles.frequency= 1000000000; +#if defined(__GNUC__) && defined(__i386__) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86; +#elif defined(__SUNPRO_C) && defined(__i386) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86; +#elif defined(__GNUC__) && defined(__x86_64__) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_64; +#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL) + mti->cycles.routine= MY_TIMER_ROUTINE_RDTSCLL; +#elif defined(_WIN32) && defined(_M_IX86) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_WIN; +#elif defined(_WIN64) && defined(_M_X64) + mti->cycles.routine= MY_TIMER_ROUTINE_RDTSC; +#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64; +#elif defined(__GNUC__) && defined(__ia64__) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64; +#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64)) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC64; +#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64)) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC; +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC64; +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC32; +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_I386; +#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_X86_64; +#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC64; +#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC32; +#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE) + mti->cycles.routine= MY_TIMER_ROUTINE_SGI_CYCLE; +#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) + mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME; +#else + mti->cycles.routine= 0; +#endif + + if (!mti->cycles.routine || !my_timer_cycles()) + { + mti->cycles.routine= 0; + mti->cycles.resolution= 0; + mti->cycles.frequency= 0; + mti->cycles.overhead= 0; + } + + /* nanoseconds */ + mti->nanoseconds.frequency= 1000000000; /* initial assumption */ +#if defined(HAVE_READ_REAL_TIME) + mti->nanoseconds.routine= MY_TIMER_ROUTINE_READ_REAL_TIME; +#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) + mti->nanoseconds.routine= MY_TIMER_ROUTINE_GETHRTIME; +#elif defined(HAVE_CLOCK_GETTIME) + mti->nanoseconds.routine= MY_TIMER_ROUTINE_CLOCK_GETTIME; +#elif defined(__NETWARE__) + mti->nanoseconds.routine= MY_TIMER_ROUTINE_NXGETTIME; +#elif defined(__APPLE__) && defined(__MACH__) + mti->nanoseconds.routine= MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME; +#else + mti->nanoseconds.routine= 0; +#endif + if (!mti->nanoseconds.routine || !my_timer_nanoseconds()) + { + mti->nanoseconds.routine= 0; + mti->nanoseconds.resolution= 0; + mti->nanoseconds.frequency= 0; + mti->nanoseconds.overhead= 0; + } + + /* microseconds */ + mti->microseconds.frequency= 1000000; /* initial assumption */ +#if defined(HAVE_GETTIMEOFDAY) + mti->microseconds.routine= MY_TIMER_ROUTINE_GETTIMEOFDAY; +#elif defined(_WIN32) + { + LARGE_INTEGER li; + /* Windows: typical frequency = 3579545, actually 1/3 microsecond. */ + if (!QueryPerformanceFrequency(&li)) + mti->microseconds.routine= 0; + else + { + mti->microseconds.frequency= li.QuadPart; + mti->microseconds.routine= MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER; + } + } +#elif defined(__NETWARE__) + mti->microseconds.routine= MY_TIMER_ROUTINE_NXGETTIME; +#else + mti->microseconds.routine= 0; +#endif + if (!mti->microseconds.routine || !my_timer_microseconds()) + { + mti->microseconds.routine= 0; + mti->microseconds.resolution= 0; + mti->microseconds.frequency= 0; + mti->microseconds.overhead= 0; + } + + /* milliseconds */ + mti->milliseconds.frequency= 1000; /* initial assumption */ +#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME) + mti->milliseconds.routine= MY_TIMER_ROUTINE_FTIME; +#elif defined(_WIN32) + mti->milliseconds.routine= MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME; +#elif defined(__NETWARE__) + mti->milliseconds.routine= MY_TIMER_ROUTINE_NXGETTIME; +#elif defined(HAVE_TIME) + mti->milliseconds.routine= MY_TIMER_ROUTINE_TIME; +#else + mti->milliseconds.routine= 0; +#endif + if (!mti->milliseconds.routine || !my_timer_milliseconds()) + { + mti->milliseconds.routine= 0; + mti->milliseconds.resolution= 0; + mti->milliseconds.frequency= 0; + mti->milliseconds.overhead= 0; + } + + /* ticks */ + mti->ticks.frequency= 100; /* permanent assumption */ +#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES) + mti->ticks.routine= MY_TIMER_ROUTINE_TIMES; +#elif defined(__NETWARE__) + mti->ticks.routine= MY_TIMER_ROUTINE_NXGETTIME; +#elif defined(_WIN32) + mti->ticks.routine= MY_TIMER_ROUTINE_GETTICKCOUNT; +#else + mti->ticks.routine= 0; +#endif + if (!mti->ticks.routine || !my_timer_ticks()) + { + mti->ticks.routine= 0; + mti->ticks.resolution= 0; + mti->ticks.frequency= 0; + mti->ticks.overhead= 0; + } + + /* + Calculate overhead in terms of the timer that + gives the best resolution: cycles or nanoseconds. + I doubt it ever will be as bad as microseconds. + */ + if (mti->cycles.routine) + best_timer= &my_timer_cycles; + else + { + if (mti->nanoseconds.routine) + { + best_timer= &my_timer_nanoseconds; + } + else + best_timer= &my_timer_microseconds; + } + + /* best_timer_overhead = least of 20 calculations */ + for (i= 0, best_timer_overhead= 1000000000; i < 20; ++i) + { + time1= best_timer(); + time2= best_timer() - time1; + if (best_timer_overhead > time2) + best_timer_overhead= time2; + } + if (mti->cycles.routine) + my_timer_init_overhead(&mti->cycles.overhead, + best_timer, + &my_timer_cycles, + best_timer_overhead); + if (mti->nanoseconds.routine) + my_timer_init_overhead(&mti->nanoseconds.overhead, + best_timer, + &my_timer_nanoseconds, + best_timer_overhead); + if (mti->microseconds.routine) + my_timer_init_overhead(&mti->microseconds.overhead, + best_timer, + &my_timer_microseconds, + best_timer_overhead); + if (mti->milliseconds.routine) + my_timer_init_overhead(&mti->milliseconds.overhead, + best_timer, + &my_timer_milliseconds, + best_timer_overhead); + if (mti->ticks.routine) + my_timer_init_overhead(&mti->ticks.overhead, + best_timer, + &my_timer_ticks, + best_timer_overhead); + +/* + Calculate resolution for nanoseconds or microseconds + or milliseconds, by seeing if it's always divisible + by 1000, and by noticing how much jumping occurs. + For ticks, just assume the resolution is 1. +*/ + if (mti->cycles.routine) + mti->cycles.resolution= 1; + if (mti->nanoseconds.routine) + mti->nanoseconds.resolution= + my_timer_init_resolution(&my_timer_nanoseconds, 20000); + if (mti->microseconds.routine) + mti->microseconds.resolution= + my_timer_init_resolution(&my_timer_microseconds, 20); + if (mti->milliseconds.routine) + { + if (mti->milliseconds.routine == MY_TIMER_ROUTINE_TIME) + mti->milliseconds.resolution= 1000; + else + mti->milliseconds.resolution= + my_timer_init_resolution(&my_timer_milliseconds, 0); + } + if (mti->ticks.routine) + mti->ticks.resolution= 1; + +/* + Calculate cycles frequency, + if we have both a cycles routine and a microseconds routine. + In tests, this usually results in a figure within 2% of + what "cat /proc/cpuinfo" says. + If the microseconds routine is QueryPerformanceCounter + (i.e. it's Windows), and the microseconds frequency is > + 500,000,000 (i.e. it's Windows Server so it uses RDTSC) + and the microseconds resolution is > 100 (i.e. dreadful), + then calculate cycles frequency = microseconds frequency. +*/ + if (mti->cycles.routine + && mti->microseconds.routine) + { + if (mti->microseconds.routine == + MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER + && mti->microseconds.frequency > 500000000 + && mti->microseconds.resolution > 100) + mti->cycles.frequency= mti->microseconds.frequency; + else + { + ulonglong time1, time2; + time1= my_timer_init_frequency(mti); + /* Repeat once in case there was an interruption. */ + time2= my_timer_init_frequency(mti); + if (time1 < time2) mti->cycles.frequency= time1; + else mti->cycles.frequency= time2; + } + } + +/* + Calculate milliseconds frequency = + (cycles-frequency/#-of-cycles) * #-of-milliseconds, + if we have both a milliseconds routine and a cycles + routine. + This will be inaccurate if milliseconds resolution > 1. + This is probably only useful when testing new platforms. +*/ + if (mti->milliseconds.routine + && mti->milliseconds.resolution < 1000 + && mti->microseconds.routine + && mti->cycles.routine) + { + int i; + ulonglong time1, time2, time3, time4; + time1= my_timer_cycles(); + time2= my_timer_milliseconds(); + time3= time2; /* Avoids a Microsoft/IBM compiler warning */ + for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i) + { + time3= my_timer_milliseconds(); + if (time3 - time2 > 10) break; + } + time4= my_timer_cycles(); + mti->milliseconds.frequency= + (mti->cycles.frequency * (time3 - time2)) / (time4 - time1); + } + +/* + Calculate ticks.frequency = + (cycles-frequency/#-of-cycles * #-of-ticks, + if we have both a ticks routine and a cycles + routine, + This is probably only useful when testing new platforms. +*/ + if (mti->ticks.routine + && mti->microseconds.routine + && mti->cycles.routine) + { + int i; + ulonglong time1, time2, time3, time4; + time1= my_timer_cycles(); + time2= my_timer_ticks(); + time3= time2; /* Avoids a Microsoft/IBM compiler warning */ + for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i) + { + time3= my_timer_ticks(); + if (time3 - time2 > 10) break; + } + time4= my_timer_cycles(); + mti->ticks.frequency= + (mti->cycles.frequency * (time3 - time2)) / (time4 - time1); + } +} + +/* + Additional Comments + ------------------- + + This is for timing, i.e. finding out how long a piece of code + takes. If you want time of day matching a wall clock, the + my_timer_xxx functions won't help you. + + The best timer is the one with highest frequency, lowest + overhead, and resolution=1. The my_timer_info() routine will tell + you at runtime which timer that is. Usually it will be + my_timer_cycles() but be aware that, although it's best, + it has possible flaws and dangers. Depending on platform: + - The frequency might change. We don't test for this. It + happens on laptops for power saving, and on blade servers + for avoiding overheating. + - The overhead that my_timer_init() returns is the minimum. + In fact it could be slightly greater because of caching or + because you call the routine by address, as recommended. + It could be hugely greater if there's an interrupt. + - The x86 cycle counter, RDTSC doesn't "serialize". That is, + if there is out-of-order execution, rdtsc might be processed + after an instruction that logically follows it. + (We could force serialization, but that would be slower.) + - It is possible to set a flag which renders RDTSC + inoperative. Somebody responsible for the kernel + of the operating system would have to make this + decision. For the platforms we've tested with, there's + no such problem. + - With a multi-processor arrangement, it's possible + to get the cycle count from one processor in + thread X, and the cycle count from another processor + in thread Y. They may not always be in synch. + - You can't depend on a cycle counter being available for + all platforms. On Alphas, the + cycle counter is only 32-bit, so it would overflow quickly, + so we don't bother with it. On platforms that we haven't + tested, there might be some if/endif combination that we + didn't expect, or some assembler routine that we didn't + supply. + + The recommended way to use the timer routines is: + 1. Somewhere near the beginning of the program, call + my_timer_init(). This should only be necessary once, + although you can call it again if you think that the + frequency has changed. + 2. Determine the best timer based on frequency, resolution, + overhead -- all things that my_timer_init() returns. + Preserve the address of the timer and the my_timer_into + results in an easily-accessible place. + 3. Instrument the code section that you're monitoring, thus: + time1= my_timer_xxx(); + Instrumented code; + time2= my_timer_xxx(); + elapsed_time= (time2 - time1) - overhead; + If the timer is always on, then overhead is always there, + so don't subtract it. + 4. Save the elapsed time, or add it to a totaller. + 5. When all timing processes are complete, transfer the + saved / totalled elapsed time to permanent storage. + Optionally you can convert cycles to microseconds at + this point. (Don't do so every time you calculate + elapsed_time! That would waste time and lose precision!) + For converting cycles to microseconds, use the frequency + that my_timer_init() returns. You'll also need to convert + if the my_timer_microseconds() function is the Windows + function QueryPerformanceCounter(), since that's sometimes + a counter with precision slightly better than microseconds. + + Since we recommend calls by function pointer, we supply + no inline functions. + + Some comments on the many candidate routines for timing ... + + clock() -- We don't use because it would overflow frequently. + + clock_gettime() -- Often we don't use this even when it exists. + In configure.in, we use AC_CHECK_FUNCS(clock_gettime). Not + AC_CHECK_LIB(rc,clock_gettime) + AC_CHECK_FUNCS(clock_gettime) + If we had the above lines in configure.in, we'd have to use + /usr/lib/librt.so or /usr/lib64/librt.so when linking, and + the size of librt.so is 40KB. In tests, clock_gettime often + had resolution = 1000. + + ftime() -- A "man ftime" says: "This function is obsolete. + Don't use it." On every platform that we tested, if ftime() + was available, then so was gettimeofday(), and gettimeofday() + overhead was always at least as good as ftime() overhead. + + gettimeofday() -- available on most platforms, though not + on Windows. There is a hardware timer (sometimes a Programmable + Interrupt Timer or "PIT") (sometimes a "HPET") used for + interrupt generation. When it interrupts (a "tick" or "jiffy", + typically 1 centisecond) it sets xtime. For gettimeofday, a + Linux kernel routine usually gets xtime and then gets rdtsc + to get elapsed nanoseconds since the last tick. On Red Hat + Enterprise Linux 3, there was once a bug which caused the + resolution to be 1000, i.e. one centisecond. We never check + for time-zone change. + + getnstimeofday() -- something to watch for in future Linux + + do_gettimeofday() -- exists on Linux but not for "userland" + + get_cycles() -- a multi-platform function, worth watching + in future Linux versions. But we found platform-specific + functions which were better documented in operating-system + manuals. And get_cycles() can fail or return a useless + 32-bit number. It might be available on some platforms, + such as arm, which we didn't test. Using + "include <linux/timex.h>" or "include <asm/timex.h>" + can lead to autoconf or compile errors, depending on system. + + rdtsc, __rdtsc, rdtscll: available for x86 with Linux BSD, + Solaris, Windows. See "possible flaws and dangers" comments. + + times(): what we use for ticks. Should just read the last + (xtime) tick count, therefore should be fast, but usually + isn't. + + GetTickCount(): we use this for my_timer_ticks() on + Windows. Actually it really is a tick counter, so resolution + >= 10 milliseconds unless you have a very old Windows version. + With Windows 95 or 98 or ME, timeGetTime() has better resolution than + GetTickCount (1ms rather than 55ms). But with Windows NT or XP or 2000, + they're both getting from a variable in the Process Environment Block + (PEB), and the variable is set by the programmable interrupt timer, so + the resolution is the same (usually 10-15 milliseconds). Also timeGetTime + is slower on old machines: + http://www.doumo.jp/aon-java/jsp/postgretips/tips.jsp?tips=74. + Also timeGetTime requires linking winmm.lib, + Therefore we use GetTickCount. + It will overflow every 49 days because the return is 32-bit. + There is also a GetTickCount64 but it requires Vista or Windows Server 2008. + (As for GetSystemTimeAsFileTime, its precision is spurious, it + just reads the tick variable like the other functions do. + However, we don't expect it to overflow every 49 days, so we + will prefer it for my_timer_milliseconds().) + + QueryPerformanceCounter() we use this for my_timer_microseconds() + on Windows. 1-PIT-tick (often 1/3-microsecond). Usually reads + the PIT so it's slow. On some Windows variants, uses RDTSC. + + GetLocalTime() this is available on Windows but we don't use it. + + getclock(): documented for Alpha, but not found during tests. + + mach_absolute_time() and UpTime() are recommended for Apple. + Inititally they weren't tried, because asm_ppc seems to do the job. + But now we use mach_absolute_time for nanoseconds. + + Any clock-based timer can be affected by NPT (ntpd program), + which means: + - full-second correction can occur for leap second + - tiny corrections can occcur approimately every 11 minutes + (but I think they only affect the RTC which isn't the PIT). + + We define "precision" as "frequency" and "high precision" is + "frequency better than 1 microsecond". We define "resolution" + as a synonym for "granularity". We define "accuracy" as + "closeness to the truth" as established by some authoritative + clock, but we can't measure accuracy. + + Do not expect any of our timers to be monotonic; we + won't guarantee that they return constantly-increasing + unique numbers. + + We tested with AIX, Solaris (x86 + Sparc), Linux (x86 + + Itanium), Windows, 64-bit Windows, QNX, FreeBSD, HPUX, + Irix, Mac. We didn't test with NetWare or SCO. + +*/ + diff --git a/mysys/my_redel.c b/mysys/my_redel.c index 6521253f949..77040870048 100644 --- a/mysys/my_redel.c +++ b/mysys/my_redel.c @@ -89,7 +89,7 @@ int my_copystat(const char *from, const char *to, int MyFlags) } if ((statbuf.st_mode & S_IFMT) != S_IFREG) return 1; - VOID(chmod(to, statbuf.st_mode & 07777)); /* Copy modes */ + (void) chmod(to, statbuf.st_mode & 07777); /* Copy modes */ #if !defined(__WIN__) && !defined(__NETWARE__) if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING) @@ -107,7 +107,7 @@ int my_copystat(const char *from, const char *to, int MyFlags) struct utimbuf timep; timep.actime = statbuf.st_atime; timep.modtime = statbuf.st_mtime; - VOID(utime((char*) to, &timep));/* Update last accessed and modified times */ + (void) utime((char*) to, &timep);/* Update last accessed and modified times */ } #else if (MyFlags & MY_COPYTIME) @@ -115,7 +115,7 @@ int my_copystat(const char *from, const char *to, int MyFlags) time_t time[2]; time[0]= statbuf.st_atime; time[1]= statbuf.st_mtime; - VOID(utime((char*) to, time));/* Update last accessed and modified times */ + (void) utime((char*) to, time);/* Update last accessed and modified times */ } #endif #endif diff --git a/mysys/my_static.c b/mysys/my_static.c index 62e6d402315..a86fe6c7ab7 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -92,6 +92,19 @@ void (*error_handler_hook)(uint error,const char *str,myf MyFlags)= void (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)= my_message_no_curses; +static const char *proc_info_dummy(void *a __attribute__((unused)), + const char *b __attribute__((unused)), + const char *c __attribute__((unused)), + const char *d __attribute__((unused)), + const unsigned int e __attribute__((unused))) +{ + return 0; +} + +/* this is to be able to call set_thd_proc_info from the C code */ +const char *(*proc_info_hook)(void *, const char *, const char *, const char *, + const unsigned int)= proc_info_dummy; + #if defined(ENABLED_DEBUG_SYNC) /** Global pointer to be set if callback function is defined @@ -111,3 +124,31 @@ my_bool NEAR my_disable_async_io=0; my_bool NEAR my_disable_flush_key_blocks=0; my_bool NEAR my_disable_symlinks=0; my_bool NEAR mysys_uses_curses=0; + +/* + Note that PSI_hook and PSI_server are unconditionally + (no ifdef HAVE_PSI_INTERFACE) defined. + This is to ensure binary compatibility between the server and plugins, + in the case when: + - the server is not compiled with HAVE_PSI_INTERFACE + - a plugin is compiled with HAVE_PSI_INTERFACE + See the doxygen documentation for the performance schema. +*/ + +/** + Hook for the instrumentation interface. + Code implementing the instrumentation interface should register here. +*/ +struct PSI_bootstrap *PSI_hook= NULL; + +/** + Instance of the instrumentation interface for the MySQL server. + @todo This is currently a global variable, which is handy when + compiling instrumented code that is bundled with the server. + When dynamic plugin are truly supported, this variable will need + to be replaced by a macro, so that each XYZ plugin can have it's own + xyz_psi_server variable, obtained from PSI_bootstrap::get_interface() + with the version used at compile time for plugin XYZ. +*/ +PSI *PSI_server= NULL; + diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index a99cbfca30c..236b694726f 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -24,19 +24,19 @@ #ifdef THREAD pthread_key(struct st_my_thread_var*, THR_KEY_mysys); -pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open, - THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap, - THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time, - THR_LOCK_myisam_mmap; +mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, + THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_myisam, THR_LOCK_heap, + THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time, + THR_LOCK_myisam_mmap; -pthread_cond_t THR_COND_threads; +mysql_cond_t THR_COND_threads; uint THR_thread_count= 0; uint my_thread_end_wait_time= 5; #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) -pthread_mutex_t LOCK_localtime_r; +mysql_mutex_t LOCK_localtime_r; #endif #ifndef HAVE_GETHOSTBYNAME_R -pthread_mutex_t LOCK_gethostbyname_r; +mysql_mutex_t LOCK_gethostbyname_r; #endif #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_t my_fast_mutexattr; @@ -67,6 +67,108 @@ nptl_pthread_exit_hack_handler(void *arg __attribute((unused))) static uint get_thread_lib(void); +/** True if @c my_thread_basic_global_init() has been called. */ +static my_bool my_thread_basic_global_init_done= 0; + +/** + Perform a minimal initialisation of mysys, when compiled with threads. + The initialisation performed is sufficient to: + - allocate memory + - perform file operations + - use charsets + - use my_errno + @sa my_basic_init + @sa my_thread_basic_global_reinit +*/ +my_bool my_thread_basic_global_init(void) +{ + int pth_ret; + + if (my_thread_basic_global_init_done) + return 0; + my_thread_basic_global_init_done= 1; + +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP + /* + Set mutex type to "fast" a.k.a "adaptive" + + In this case the thread may steal the mutex from some other thread + that is waiting for the same mutex. This will save us some + context switches but may cause a thread to 'starve forever' while + waiting for the mutex (not likely if the code within the mutex is + short). + */ + pthread_mutexattr_init(&my_fast_mutexattr); + pthread_mutexattr_settype(&my_fast_mutexattr, + PTHREAD_MUTEX_ADAPTIVE_NP); +#endif + +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + /* + Set mutex type to "errorcheck" + */ + pthread_mutexattr_init(&my_errorcheck_mutexattr); + pthread_mutexattr_settype(&my_errorcheck_mutexattr, + PTHREAD_MUTEX_ERRORCHECK); +#endif + + mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST); + + if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0) + { + fprintf(stderr, "Can't initialize threads: error %d\n", pth_ret); + return 1; + } + + if (my_thread_init()) + return 1; + + return 0; +} + +/** + Re-initialize components initialized early with @c my_thread_basic_global_init. + Some mutexes were initialized before the instrumentation. + Destroy + create them again, now that the instrumentation + is in place. + This is safe, since this function() is called before creating new threads, + so the mutexes are not in use. +*/ +void my_thread_basic_global_reinit(void) +{ + struct st_my_thread_var *tmp; + + DBUG_ASSERT(my_thread_basic_global_init_done); + +#ifdef HAVE_PSI_INTERFACE + my_init_mysys_psi_keys(); +#endif + + mysql_mutex_destroy(&THR_LOCK_malloc); + mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST); + + mysql_mutex_destroy(&THR_LOCK_open); + mysql_mutex_init(key_THR_LOCK_open, &THR_LOCK_open, MY_MUTEX_INIT_FAST); + + mysql_mutex_destroy(&THR_LOCK_charset); + mysql_mutex_init(key_THR_LOCK_charset, &THR_LOCK_charset, MY_MUTEX_INIT_FAST); + + mysql_mutex_destroy(&THR_LOCK_threads); + mysql_mutex_init(key_THR_LOCK_threads, &THR_LOCK_threads, MY_MUTEX_INIT_FAST); + + tmp= my_pthread_getspecific(struct st_my_thread_var*, THR_KEY_mysys); + DBUG_ASSERT(tmp); + + mysql_mutex_destroy(&tmp->mutex); + mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST); + + mysql_cond_destroy(&tmp->suspend); + mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL); +} + /* initialize thread environment @@ -80,14 +182,10 @@ static uint get_thread_lib(void); my_bool my_thread_global_init(void) { - int pth_ret; - thd_lib_detected= get_thread_lib(); - - if ((pth_ret= pthread_key_create(&THR_KEY_mysys, NULL)) != 0) - { - fprintf(stderr,"Can't initialize threads: error %d\n", pth_ret); + if (my_thread_basic_global_init()) return 1; - } + + thd_lib_detected= get_thread_lib(); #ifdef TARGET_OS_LINUX /* @@ -116,47 +214,21 @@ my_bool my_thread_global_init(void) } #endif /* TARGET_OS_LINUX */ -#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP - /* - Set mutex type to "fast" a.k.a "adaptive" - - In this case the thread may steal the mutex from some other thread - that is waiting for the same mutex. This will save us some - context switches but may cause a thread to 'starve forever' while - waiting for the mutex (not likely if the code within the mutex is - short). - */ - pthread_mutexattr_init(&my_fast_mutexattr); - pthread_mutexattr_settype(&my_fast_mutexattr, - PTHREAD_MUTEX_ADAPTIVE_NP); -#endif -#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP - /* - Set mutex type to "errorcheck" - */ - pthread_mutexattr_init(&my_errorcheck_mutexattr); - pthread_mutexattr_settype(&my_errorcheck_mutexattr, - PTHREAD_MUTEX_ERRORCHECK); -#endif - - pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW); - pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW); - pthread_mutex_init(&THR_LOCK_myisam_mmap,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST); - pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST); - pthread_cond_init(&THR_COND_threads, NULL); + mysql_mutex_init(key_THR_LOCK_lock, &THR_LOCK_lock, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_isam, &THR_LOCK_isam, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_THR_LOCK_myisam, &THR_LOCK_myisam, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_THR_LOCK_time, &THR_LOCK_time, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL); #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) - pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW); #endif #ifndef HAVE_GETHOSTBYNAME_R - pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_gethostbyname_r, + &LOCK_gethostbyname_r, MY_MUTEX_INIT_SLOW); #endif #ifdef _MSC_VER @@ -178,11 +250,11 @@ void my_thread_global_end(void) my_bool all_threads_killed= 1; set_timespec(abstime, my_thread_end_wait_time); - pthread_mutex_lock(&THR_LOCK_threads); + mysql_mutex_lock(&THR_LOCK_threads); while (THR_thread_count > 0) { - int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads, - &abstime); + int error= mysql_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads, + &abstime); if (error == ETIMEDOUT || error == ETIME) { #ifdef HAVE_PTHREAD_KILL @@ -200,7 +272,7 @@ void my_thread_global_end(void) break; } } - pthread_mutex_unlock(&THR_LOCK_threads); + mysql_mutex_unlock(&THR_LOCK_threads); pthread_key_delete(THR_KEY_mysys); #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP @@ -209,26 +281,26 @@ void my_thread_global_end(void) #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP pthread_mutexattr_destroy(&my_errorcheck_mutexattr); #endif - pthread_mutex_destroy(&THR_LOCK_malloc); - pthread_mutex_destroy(&THR_LOCK_open); - pthread_mutex_destroy(&THR_LOCK_lock); - pthread_mutex_destroy(&THR_LOCK_isam); - pthread_mutex_destroy(&THR_LOCK_myisam); - pthread_mutex_destroy(&THR_LOCK_myisam_mmap); - pthread_mutex_destroy(&THR_LOCK_heap); - pthread_mutex_destroy(&THR_LOCK_net); - pthread_mutex_destroy(&THR_LOCK_time); - pthread_mutex_destroy(&THR_LOCK_charset); + mysql_mutex_destroy(&THR_LOCK_malloc); + mysql_mutex_destroy(&THR_LOCK_open); + mysql_mutex_destroy(&THR_LOCK_lock); + mysql_mutex_destroy(&THR_LOCK_isam); + mysql_mutex_destroy(&THR_LOCK_myisam); + mysql_mutex_destroy(&THR_LOCK_myisam_mmap); + mysql_mutex_destroy(&THR_LOCK_heap); + mysql_mutex_destroy(&THR_LOCK_net); + mysql_mutex_destroy(&THR_LOCK_time); + mysql_mutex_destroy(&THR_LOCK_charset); if (all_threads_killed) { - pthread_mutex_destroy(&THR_LOCK_threads); - pthread_cond_destroy(&THR_COND_threads); + mysql_mutex_destroy(&THR_LOCK_threads); + mysql_cond_destroy(&THR_COND_threads); } #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) - pthread_mutex_destroy(&LOCK_localtime_r); + mysql_mutex_destroy(&LOCK_localtime_r); #endif #ifndef HAVE_GETHOSTBYNAME_R - pthread_mutex_destroy(&LOCK_gethostbyname_r); + mysql_mutex_destroy(&LOCK_gethostbyname_r); #endif } @@ -284,14 +356,17 @@ my_bool my_thread_init(void) } pthread_setspecific(THR_KEY_mysys,tmp); tmp->pthread_self= pthread_self(); - pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST); - pthread_cond_init(&tmp->suspend, NULL); - tmp->init= 1; + mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL); + + tmp->stack_ends_here= (char*)&tmp + + STACK_DIRECTION * (long)my_thread_stack_size; - pthread_mutex_lock(&THR_LOCK_threads); + mysql_mutex_lock(&THR_LOCK_threads); tmp->id= ++thread_id; ++THR_thread_count; - pthread_mutex_unlock(&THR_LOCK_threads); + mysql_mutex_unlock(&THR_LOCK_threads); + tmp->init= 1; #ifndef DBUG_OFF /* Generate unique name for thread */ (void) my_thread_name(); @@ -323,6 +398,17 @@ void my_thread_end(void) 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 + +#ifdef HAVE_PSI_INTERFACE + /* + Remove the instrumentation for this thread. + This must be done before trashing st_my_thread_var, + because the LF_HASH depends on it. + */ + if (PSI_server) + PSI_server->delete_current_thread(); +#endif + if (tmp && tmp->init) { #if !defined(DBUG_OFF) @@ -336,9 +422,9 @@ void my_thread_end(void) #endif #if !defined(__bsdi__) && !defined(__OpenBSD__) /* bsdi and openbsd 3.5 dumps core here */ - pthread_cond_destroy(&tmp->suspend); + mysql_cond_destroy(&tmp->suspend); #endif - pthread_mutex_destroy(&tmp->mutex); + mysql_mutex_destroy(&tmp->mutex); free(tmp); /* @@ -347,11 +433,11 @@ void my_thread_end(void) my_thread_end and thus freed all memory they have allocated in my_thread_init() and DBUG_xxxx */ - pthread_mutex_lock(&THR_LOCK_threads); + mysql_mutex_lock(&THR_LOCK_threads); DBUG_ASSERT(THR_thread_count != 0); if (--THR_thread_count == 0) - pthread_cond_signal(&THR_COND_threads); - pthread_mutex_unlock(&THR_LOCK_threads); + mysql_cond_signal(&THR_COND_threads); + mysql_mutex_unlock(&THR_LOCK_threads); } pthread_setspecific(THR_KEY_mysys,0); } diff --git a/mysys/my_timer_cycles.il b/mysys/my_timer_cycles.il new file mode 100644 index 00000000000..2f3f776530b --- /dev/null +++ b/mysys/my_timer_cycles.il @@ -0,0 +1,38 @@ +/* Copyright (C) 2008 Sun Microsystems, Inc + + 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 */ + +/* Sun Studio SPARC inline templates for cycle timer */ +/* Sun Studio i386 and x86_64 inline templates for cycle timer */ +/* I didn't say ".volatile" or ".nonvolatile". */ + +.inline my_timer_cycles_il_sparc64,0 +rd %tick,%o0 +.end + +.inline my_timer_cycles_il_sparc32,0 +rd %tick,%o2 +srlx %o2,32,%o0 +sra %o2,0,%o1 +.end + +.inline my_timer_cycles_il_i386,0 +rdtsc +.end + +.inline my_timer_cycles_il_x86_64,0 +rdtsc +shlq $32,%rdx +orq %rdx,%rax +.end diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c index e7d8073a163..ad1636011db 100644 --- a/mysys/my_wincond.c +++ b/mysys/my_wincond.c @@ -181,7 +181,6 @@ int pthread_attr_init(pthread_attr_t *connect_att) { connect_att->dwStackSize = 0; connect_att->dwCreatingFlag = 0; - connect_att->priority = 0; return 0; } @@ -191,12 +190,6 @@ int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack) return 0; } -int pthread_attr_setprio(pthread_attr_t *connect_att,int priority) -{ - connect_att->priority=priority; - return 0; -} - int pthread_attr_destroy(pthread_attr_t *connect_att) { bzero((uchar*) connect_att,sizeof(*connect_att)); diff --git a/mysys/my_winfile.c b/mysys/my_winfile.c index 6a2cda5ba29..6c0b191ca2c 100644 --- a/mysys/my_winfile.c +++ b/mysys/my_winfile.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 MySQL AB +/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -57,7 +57,7 @@ File my_open_osfhandle(HANDLE handle, int oflag) uint i; DBUG_ENTER("my_open_osfhandle"); - pthread_mutex_lock(&THR_LOCK_open); + mysql_mutex_lock(&THR_LOCK_open); for(i= MY_FILE_MIN; i < my_file_limit;i++) { if(my_file_info[i].fhandle == 0) @@ -70,7 +70,7 @@ File my_open_osfhandle(HANDLE handle, int oflag) break; } } - pthread_mutex_unlock(&THR_LOCK_open); + mysql_mutex_unlock(&THR_LOCK_open); if(offset == -1) errno= EMFILE; /* to many file handles open */ DBUG_RETURN(offset); diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c index 290351099a4..aecb2f7cc78 100644 --- a/mysys/my_winthread.c +++ b/mysys/my_winthread.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -63,8 +63,8 @@ static unsigned int __stdcall pthread_start(void *p) } -int pthread_create(pthread_t *thread_id, pthread_attr_t *attr, - pthread_handler func, void *param) +int pthread_create(pthread_t *thread_id, const pthread_attr_t *attr, + pthread_handler func, void *param) { uintptr_t handle; struct thread_start_parameter *par; @@ -129,6 +129,24 @@ error_return: return -1; } +int pthread_cancel(pthread_t thread) +{ + + HANDLE handle= 0; + BOOL ok= FALSE; + + handle= OpenThread(THREAD_TERMINATE, FALSE, thread); + if (handle) + { + ok= TerminateThread(handle,0); + CloseHandle(handle); + } + if (ok) + return 0; + + errno= EINVAL; + return -1; +} /* One time initialization. For simplicity, we assume initializer thread @@ -160,5 +178,4 @@ int my_pthread_once(my_pthread_once_t *once_control, } return 0; } - #endif diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index 4c4d6ea3598..1ae6a9e3a99 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -26,12 +26,54 @@ #ifdef THREAD #include <my_pthread.h> -extern pthread_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache; -extern pthread_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net; -extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time; -#else + +#ifdef HAVE_PSI_INTERFACE + +#if !defined(HAVE_PREAD) && !defined(_WIN32) +extern PSI_mutex_key key_my_file_info_mutex; +#endif /* !defined(HAVE_PREAD) && !defined(_WIN32) */ + +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) +extern PSI_mutex_key key_LOCK_localtime_r; +#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */ + +#ifndef HAVE_GETHOSTBYNAME_R +extern PSI_mutex_key key_LOCK_gethostbyname_r; +#endif /* HAVE_GETHOSTBYNAME_R */ + +extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock, + key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm, + key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap, + key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc, + key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net, + key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time, + key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap; + +extern PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond, + key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend, + key_THR_COND_threads; + +#ifdef USE_ALARM_THREAD +extern PSI_thread_key key_thread_alarm; +#endif /* USE_ALARM_THREAD */ + +#endif /* HAVE_PSI_INTERFACE */ + +extern mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache; +extern mysql_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net; +extern mysql_mutex_t THR_LOCK_charset, THR_LOCK_time; +#else /* THREAD */ #include <my_no_pthread.h> -#endif +#endif /* THREAD */ + +#include <mysql/psi/mysql_file.h> + +#ifdef HAVE_PSI_INTERFACE +#ifdef HUGETLB_USE_PROC_MEMINFO +extern PSI_file_key key_file_proc_meminfo; +#endif /* HUGETLB_USE_PROC_MEMINFO */ +extern PSI_file_key key_file_charset, key_file_cnf; +#endif /* HAVE_PSI_INTERFACE */ /* EDQUOT is used only in 3 C files only in mysys/. If it does not exist on @@ -44,6 +86,7 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time; void my_error_unregister_all(void); #ifdef _WIN32 +#include <sys/stat.h> /* my_winfile.c exports, should not be used outside mysys */ extern File my_win_open(const char *path, int oflag); extern int my_win_close(File fd); @@ -59,8 +102,8 @@ extern FILE* my_win_fopen(const char *filename, const char *type); extern File my_win_fclose(FILE *file); extern File my_win_fileno(FILE *file); extern FILE* my_win_fdopen(File Filedes, const char *type); -extern int my_win_stat(const char *path, struct _stat64 *buf); -extern int my_win_fstat(File fd, struct _stat64 *buf); +extern int my_win_stat(const char *path, struct _stati64 *buf); +extern int my_win_fstat(File fd, struct _stati64 *buf); extern int my_win_fsync(File fd); extern File my_win_dup(File fd); extern File my_win_sopen(const char *path, int oflag, int shflag, int perm); diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index 24ab6a1ea9c..2005e3eb2b7 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -22,16 +22,39 @@ #include "mysys_priv.h" #include <myisampack.h> +#ifdef TARGET_OS_SOLARIS +/* + * On Solaris, memcmp() is normally faster than the unrolled ptr_compare_N + * functions, as memcmp() is usually a platform-specific implementation + * written in assembler, provided in /usr/lib/libc/libc_hwcap*.so.1. + * This implementation is also usually faster than the built-in memcmp + * supplied by GCC, so it is recommended to build with "-fno-builtin-memcmp" + * in CFLAGS if building with GCC on Solaris. + */ + +#include <string.h> + +static int native_compare(size_t *length, unsigned char **a, unsigned char **b) +{ + return memcmp(*a, *b, *length); +} + +#else /* TARGET_OS_SOLARIS */ + static int ptr_compare(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_0(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_1(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_2(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_3(size_t *compare_length, uchar **a, uchar **b); +#endif /* TARGET_OS_SOLARIS */ /* Get a pointer to a optimal byte-compare function for a given size */ qsort2_cmp get_ptr_compare (size_t size) { +#ifdef TARGET_OS_SOLARIS + return (qsort2_cmp) native_compare; +#else if (size < 4) return (qsort2_cmp) ptr_compare; switch (size & 3) { @@ -41,6 +64,7 @@ qsort2_cmp get_ptr_compare (size_t size) case 3: return (qsort2_cmp) ptr_compare_3; } return 0; /* Impossible */ +#endif /* TARGET_OS_SOLARIS */ } diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index c484f1d4c54..efe281ba1bb 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -158,7 +158,7 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags) my_message(EE_OUTOFMEMORY, buff, MYF(ME_BELL+ME_WAITTANG+ME_NOREFRESH)); } DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'", - sf_malloc_max_memory,lineno, filename)); + (long)sf_malloc_max_memory,lineno, filename)); if (MyFlags & MY_FAE) exit(1); DBUG_RETURN ((void*) 0); @@ -178,7 +178,7 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags) irem->prev= NULL; /* Add this remember structure to the linked list */ - pthread_mutex_lock(&THR_LOCK_malloc); + mysql_mutex_lock(&THR_LOCK_malloc); if ((irem->next= sf_malloc_root)) sf_malloc_root->prev= irem; sf_malloc_root= irem; @@ -188,7 +188,7 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags) if (sf_malloc_cur_memory > sf_malloc_max_memory) sf_malloc_max_memory= sf_malloc_cur_memory; sf_malloc_count++; - pthread_mutex_unlock(&THR_LOCK_malloc); + mysql_mutex_unlock(&THR_LOCK_malloc); /* Set the memory to the aribtrary wierd value */ if ((MyFlags & MY_ZEROFILL) || !sf_malloc_quick) @@ -291,7 +291,7 @@ void _myfree(void *ptr, const char *filename, uint lineno, myf myflags) } /* Remove this structure from the linked list */ - pthread_mutex_lock(&THR_LOCK_malloc); + mysql_mutex_lock(&THR_LOCK_malloc); if (irem->prev) irem->prev->next= irem->next; else @@ -302,7 +302,7 @@ void _myfree(void *ptr, const char *filename, uint lineno, myf myflags) /* Handle the statistics */ sf_malloc_cur_memory-= irem->datasize; sf_malloc_count--; - pthread_mutex_unlock(&THR_LOCK_malloc); + mysql_mutex_unlock(&THR_LOCK_malloc); #ifndef HAVE_purify /* Mark this data as free'ed */ @@ -365,7 +365,7 @@ void TERMINATE(FILE *file, uint flag) { struct st_irem *irem; DBUG_ENTER("TERMINATE"); - pthread_mutex_lock(&THR_LOCK_malloc); + mysql_mutex_lock(&THR_LOCK_malloc); /* Report the difference between number of calls to @@ -428,7 +428,7 @@ void TERMINATE(FILE *file, uint flag) DBUG_PRINT("safe",("Maximum memory usage: %lu bytes (%luk)", (ulong) sf_malloc_max_memory, (ulong) (sf_malloc_max_memory + 1023L) /1024L)); - pthread_mutex_unlock(&THR_LOCK_malloc); + mysql_mutex_unlock(&THR_LOCK_malloc); DBUG_VOID_RETURN; } @@ -505,7 +505,7 @@ int _sanity(const char *filename, uint lineno) reg2 int flag=0; uint count=0; - pthread_mutex_lock(&THR_LOCK_malloc); + mysql_mutex_lock(&THR_LOCK_malloc); #ifndef PEDANTIC_SAFEMALLOC if (sf_malloc_tampered && (int) sf_malloc_count < 0) sf_malloc_count=0; @@ -513,7 +513,7 @@ int _sanity(const char *filename, uint lineno) count=sf_malloc_count; for (irem= sf_malloc_root; irem != NULL && count-- ; irem= irem->next) flag+= _checkchunk (irem, filename, lineno); - pthread_mutex_unlock(&THR_LOCK_malloc); + mysql_mutex_unlock(&THR_LOCK_malloc); if (count || irem) { const char *format="Error: Safemalloc link list destroyed, discovered at '%s:%d'"; diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 75fda93b56e..f1b96cd03da 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -13,9 +13,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ -#define DONT_DEFINE_VOID 1 - #include <my_global.h> #include <my_stacktrace.h> diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index b710a7eee39..8ee89cfb55d 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -15,6 +15,7 @@ /* To avoid problems with alarms in debug code, we disable DBUG here */ #define FORCE_DBUG_OFF +#include "mysys_priv.h" #include <my_global.h> #if defined(THREAD) && !defined(DONT_USE_THR_ALARM) @@ -43,8 +44,8 @@ static sig_handler process_alarm_part2(int sig); #if !defined(__WIN__) -static pthread_mutex_t LOCK_alarm; -static pthread_cond_t COND_alarm; +static mysql_mutex_t LOCK_alarm; +static mysql_cond_t COND_alarm; static sigset_t full_signal_set; static QUEUE alarm_queue; static uint max_used_alarms=0; @@ -52,7 +53,7 @@ pthread_t alarm_thread; #ifdef USE_ALARM_THREAD static void *alarm_handler(void *arg); -#define reschedule_alarms() pthread_cond_signal(&COND_alarm) +#define reschedule_alarms() mysql_cond_signal(&COND_alarm) #else #define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM) #endif @@ -75,8 +76,8 @@ void init_thr_alarm(uint max_alarms) init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0, compare_ulong,NullS); sigfillset(&full_signal_set); /* Neaded to block signals */ - pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST); - pthread_cond_init(&COND_alarm,NULL); + mysql_mutex_init(key_LOCK_alarm, &LOCK_alarm, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_alarm, &COND_alarm, NULL); if (thd_lib_detected == THD_LIB_LT) thr_client_alarm= SIGALRM; else @@ -97,10 +98,9 @@ void init_thr_alarm(uint max_alarms) pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&thr_attr,8196); - - my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */ - VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL)); - VOID(pthread_attr_destroy(&thr_attr)); + mysql_thread_create(key_thread_alarm, + &alarm_thread, &thr_attr, alarm_handler, NULL); + pthread_attr_destroy(&thr_attr); } #elif defined(USE_ONE_SIGNAL_HAND) pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */ @@ -119,14 +119,14 @@ void init_thr_alarm(uint max_alarms) void resize_thr_alarm(uint max_alarms) { - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); /* It's ok not to shrink the queue as there may be more pending alarms than than max_alarms */ if (alarm_queue.elements < max_alarms) resize_queue(&alarm_queue,max_alarms+1); - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); } @@ -164,12 +164,12 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); #endif - pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */ + mysql_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */ if (alarm_aborted > 0) { /* No signal thread */ DBUG_PRINT("info", ("alarm aborted")); *alrm= 0; /* No alarm */ - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_SETMASK,&old_mask,NULL); #endif @@ -185,7 +185,7 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) DBUG_PRINT("info", ("alarm queue full")); fprintf(stderr,"Warning: thr_alarm queue is full\n"); *alrm= 0; /* No alarm */ - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_SETMASK,&old_mask,NULL); #endif @@ -200,7 +200,7 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) { DBUG_PRINT("info", ("failed my_malloc()")); *alrm= 0; /* No alarm */ - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_SETMASK,&old_mask,NULL); #endif @@ -228,7 +228,7 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) else reschedule_alarms(); /* Reschedule alarms */ } - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_SETMASK,&old_mask,NULL); #endif @@ -253,7 +253,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); #endif - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed)); for (i=0 ; i < alarm_queue.elements ; i++) @@ -278,7 +278,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) DBUG_PRINT("warning",("Didn't find alarm 0x%lx in queue\n", (long) *alarmed)); } - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); #ifndef USE_ONE_SIGNAL_HAND pthread_sigmask(SIG_SETMASK,&old_mask,NULL); #endif @@ -321,14 +321,14 @@ sig_handler process_alarm(int sig __attribute__((unused))) #ifndef USE_ALARM_THREAD pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask); - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); #endif process_alarm_part2(sig); #ifndef USE_ALARM_THREAD #if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND) my_sigset(THR_SERVER_ALARM,process_alarm); #endif - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); #endif return; @@ -436,7 +436,7 @@ void end_thr_alarm(my_bool free_structures) DBUG_ENTER("end_thr_alarm"); if (alarm_aborted != 1) /* If memory not freed */ { - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); alarm_aborted= -1; /* mark aborted */ if (alarm_queue.elements || (alarm_thread_running && free_structures)) @@ -456,21 +456,21 @@ void end_thr_alarm(my_bool free_structures) set_timespec(abstime, 10); /* Wait up to 10 seconds */ while (alarm_thread_running) { - int error= pthread_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime); + int error= mysql_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime); if (error == ETIME || error == ETIMEDOUT) break; /* Don't wait forever */ } delete_queue(&alarm_queue); alarm_aborted= 1; - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); if (!alarm_thread_running) /* Safety */ { - pthread_mutex_destroy(&LOCK_alarm); - pthread_cond_destroy(&COND_alarm); + mysql_mutex_destroy(&LOCK_alarm); + mysql_cond_destroy(&COND_alarm); } } else - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); } DBUG_VOID_RETURN; } @@ -485,7 +485,7 @@ void thr_alarm_kill(my_thread_id thread_id) uint i; if (alarm_aborted) return; - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); for (i=0 ; i < alarm_queue.elements ; i++) { if (((ALARM*) queue_element(&alarm_queue,i))->thread_id == thread_id) @@ -497,13 +497,13 @@ void thr_alarm_kill(my_thread_id thread_id) break; } } - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); } void thr_alarm_info(ALARM_INFO *info) { - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); info->next_alarm_time= 0; info->max_used_alarms= max_used_alarms; if ((info->active_alarms= alarm_queue.elements)) @@ -514,7 +514,7 @@ void thr_alarm_info(ALARM_INFO *info) time_diff= (long) (alarm_data->expire_time - now); info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff); } - pthread_mutex_unlock(&LOCK_alarm); + mysql_mutex_unlock(&LOCK_alarm); } /* @@ -551,7 +551,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) #endif my_thread_init(); alarm_thread_running= 1; - pthread_mutex_lock(&LOCK_alarm); + mysql_mutex_lock(&LOCK_alarm); for (;;) { if (alarm_queue.elements) @@ -566,7 +566,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) abstime.tv_sec=sleep_time; abstime.tv_nsec=0; next_alarm_expire_time= sleep_time; - if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) && + if ((error= mysql_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime)) && error != ETIME && error != ETIMEDOUT) { #ifdef MAIN @@ -581,7 +581,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) else { next_alarm_expire_time= ~ (time_t) 0; - if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm))) + if ((error= mysql_cond_wait(&COND_alarm, &LOCK_alarm))) { #ifdef MAIN printf("Got error: %d from ptread_cond_wait (errno: %d)\n", @@ -593,8 +593,8 @@ static void *alarm_handler(void *arg __attribute__((unused))) } bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */ alarm_thread_running= 0; - pthread_cond_signal(&COND_alarm); - pthread_mutex_unlock(&LOCK_alarm); + mysql_cond_signal(&COND_alarm); + mysql_mutex_unlock(&LOCK_alarm); pthread_exit(0); return 0; /* Impossible */ } @@ -696,8 +696,8 @@ void resize_thr_alarm(uint max_alarms) #ifdef MAIN #if defined(THREAD) && !defined(DONT_USE_THR_ALARM) -static pthread_cond_t COND_thread_count; -static pthread_mutex_t LOCK_thread_count; +static mysql_cond_t COND_thread_count; +static mysql_mutex_t LOCK_thread_count; static uint thread_count; #ifdef HPUX10 @@ -774,7 +774,7 @@ static void *test_thread(void *arg) break; continue; } - VOID(getchar()); /* Somebody was playing */ + (void) getchar(); /* Somebody was playing */ } } } @@ -784,10 +784,10 @@ static void *test_thread(void *arg) thr_end_alarm(&got_alarm); fflush(stdout); } - pthread_mutex_lock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_thread_count); thread_count--; - VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */ - pthread_mutex_unlock(&LOCK_thread_count); + mysql_cond_signal(&COND_thread_count); /* Tell main we are ready */ + mysql_mutex_unlock(&LOCK_thread_count); free((uchar*) arg); return 0; } @@ -814,9 +814,9 @@ static void *signal_hand(void *arg __attribute__((unused))) my_thread_init(); pthread_detach_this_thread(); init_thr_alarm(10); /* Setup alarm handler */ - pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */ - VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */ - pthread_mutex_unlock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_thread_count); /* Required by bsdi */ + mysql_cond_signal(&COND_thread_count); /* Tell main we are ready */ + mysql_mutex_unlock(&LOCK_thread_count); sigemptyset(&set); /* Catch all signals */ sigaddset(&set,SIGINT); @@ -887,8 +887,8 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) { DBUG_PUSH(argv[1]+2); } - pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); - pthread_cond_init(&COND_thread_count,NULL); + mysql_mutex_init(0, &LOCK_thread_count, MY_MUTEX_INIT_FAST); + mysql_cond_init(0, &COND_thread_count, NULL); /* Start a alarm handling thread */ sigemptyset(&set); @@ -906,7 +906,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) #ifdef NOT_USED sigemptyset(&set); sigaddset(&set, thr_client_alarm); - VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0)); + pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0); #endif pthread_attr_init(&thr_attr); @@ -915,10 +915,11 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) pthread_attr_setstacksize(&thr_attr,65536L); /* Start signal thread and wait for it to start */ - VOID(pthread_mutex_lock(&LOCK_thread_count)); - pthread_create(&tid,&thr_attr,signal_hand,NULL); - VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + mysql_mutex_lock(&LOCK_thread_count); + mysql_thread_create(0, + &tid, &thr_attr, signal_hand, NULL); + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); DBUG_PRINT("info",("signal thread created")); thr_setconcurrency(3); @@ -928,32 +929,34 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) { param=(int*) malloc(sizeof(int)); *param= i; - pthread_mutex_lock(&LOCK_thread_count); - if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param))) + mysql_mutex_lock(&LOCK_thread_count); + if ((error= mysql_thread_create(0, + &tid, &thr_attr, test_thread, + (void*) param))) { printf("Can't create thread %d, error: %d\n",i,error); exit(1); } thread_count++; - pthread_mutex_unlock(&LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); } pthread_attr_destroy(&thr_attr); - pthread_mutex_lock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_thread_count); thr_alarm_info(&alarm_info); printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n", alarm_info.active_alarms, alarm_info.max_used_alarms, alarm_info.next_alarm_time); while (thread_count) { - VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)); + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); if (thread_count == 1) { printf("Calling end_thr_alarm. This should cancel the last thread\n"); end_thr_alarm(0); } } - pthread_mutex_unlock(&LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); thr_alarm_info(&alarm_info); end_thr_alarm(1); printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n", diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 4bb818b1b30..43db0470735 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -83,7 +83,6 @@ multiple read locks. my_bool thr_lock_inited=0; ulong locks_immediate = 0L, locks_waited = 0L; -ulong table_lock_wait_timeout; enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; /* The following constants are only for debug output */ @@ -94,7 +93,7 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; LIST *thr_lock_thread_list; /* List of threads in use */ ulong max_write_lock_count= ~(ulong) 0L; -static inline pthread_cond_t *get_cond(void) +static inline mysql_cond_t *get_cond(void) { return &my_thread_var->suspend; } @@ -316,16 +315,16 @@ void thr_lock_init(THR_LOCK *lock) { DBUG_ENTER("thr_lock_init"); bzero((char*) lock,sizeof(*lock)); - VOID(pthread_mutex_init(&lock->mutex,MY_MUTEX_INIT_FAST)); + mysql_mutex_init(key_THR_LOCK_mutex, &lock->mutex, MY_MUTEX_INIT_FAST); lock->read.last= &lock->read.data; lock->read_wait.last= &lock->read_wait.data; lock->write_wait.last= &lock->write_wait.data; lock->write.last= &lock->write.data; - pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */ + mysql_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */ lock->list.data=(void*) lock; thr_lock_thread_list=list_add(thr_lock_thread_list,&lock->list); - pthread_mutex_unlock(&THR_LOCK_lock); + mysql_mutex_unlock(&THR_LOCK_lock); DBUG_VOID_RETURN; } @@ -333,10 +332,10 @@ void thr_lock_init(THR_LOCK *lock) void thr_lock_delete(THR_LOCK *lock) { DBUG_ENTER("thr_lock_delete"); - pthread_mutex_lock(&THR_LOCK_lock); + mysql_mutex_lock(&THR_LOCK_lock); thr_lock_thread_list=list_delete(thr_lock_thread_list,&lock->list); - pthread_mutex_unlock(&THR_LOCK_lock); - pthread_mutex_destroy(&lock->mutex); + mysql_mutex_unlock(&THR_LOCK_lock); + mysql_mutex_destroy(&lock->mutex); DBUG_VOID_RETURN; } @@ -389,13 +388,13 @@ static void wake_up_waiters(THR_LOCK *lock); static enum enum_thr_lock_result wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, - my_bool in_wait_list) + my_bool in_wait_list, ulong lock_wait_timeout) { struct st_my_thread_var *thread_var= my_thread_var; - pthread_cond_t *cond= &thread_var->suspend; + mysql_cond_t *cond= &thread_var->suspend; struct timespec wait_timeout; enum enum_thr_lock_result result= THR_LOCK_ABORTED; - my_bool can_deadlock= test(data->owner->info->n_cursors); + const char *old_proc_info; DBUG_ENTER("wait_for_lock"); /* @@ -434,14 +433,13 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, thread_var->current_cond= cond; data->cond= cond; - if (can_deadlock) - set_timespec(wait_timeout, table_lock_wait_timeout); + old_proc_info= proc_info_hook(NULL, "Table lock", + __func__, __FILE__, __LINE__); + + set_timespec(wait_timeout, lock_wait_timeout); while (!thread_var->abort || in_wait_list) { - int rc= (can_deadlock ? - pthread_cond_timedwait(cond, &data->lock->mutex, - &wait_timeout) : - pthread_cond_wait(cond, &data->lock->mutex)); + int rc= mysql_cond_timedwait(cond, &data->lock->mutex, &wait_timeout); /* We must break the wait if one of the following occurs: - the connection has been aborted (!thread_var->abort), but @@ -497,20 +495,23 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, (*data->lock->get_status)(data->status_param, 0); check_locks(data->lock,"got wait_for_lock",0); } - pthread_mutex_unlock(&data->lock->mutex); + mysql_mutex_unlock(&data->lock->mutex); /* The following must be done after unlock of lock->mutex */ - pthread_mutex_lock(&thread_var->mutex); + mysql_mutex_lock(&thread_var->mutex); thread_var->current_mutex= 0; thread_var->current_cond= 0; - pthread_mutex_unlock(&thread_var->mutex); + mysql_mutex_unlock(&thread_var->mutex); + + proc_info_hook(NULL, old_proc_info, __func__, __FILE__, __LINE__); + DBUG_RETURN(result); } enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, - enum thr_lock_type lock_type) + enum thr_lock_type lock_type, ulong lock_wait_timeout) { THR_LOCK *lock=data->lock; enum enum_thr_lock_result result= THR_LOCK_SUCCESS; @@ -522,7 +523,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, data->cond=0; /* safety */ data->type=lock_type; data->owner= owner; /* Must be reset ! */ - VOID(pthread_mutex_lock(&lock->mutex)); + mysql_mutex_lock(&lock->mutex); DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d", (long) data, data->owner->info->thread_id, (long) lock, (int) lock_type)); @@ -533,13 +534,31 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, /* Request for READ lock */ if (lock->write.data) { - /* We can allow a read lock even if there is already a write lock - on the table in one the following cases: - - This thread alread have a write lock on the table - - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED - and the read lock is TL_READ_HIGH_PRIORITY or TL_READ - - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE - and the read lock is not TL_READ_NO_INSERT + /* + We can allow a read lock even if there is already a + write lock on the table if they are owned by the same + thread or if they satisfy the following lock + compatibility matrix: + + Request + /------- + H|++++ WRITE_ALLOW_WRITE + e|++++ WRITE_ALLOW_READ + l|+++- WRITE_CONCURRENT_INSERT + d|++++ WRITE_DELAYED + |||| + |||\= READ_NO_INSERT + ||\ = READ_HIGH_PRIORITY + |\ = READ_WITH_SHARED_LOCKS + \ = READ + + + = Request can be satisified. + - = Request cannot be satisified. + + READ_NO_INSERT and WRITE_ALLOW_WRITE should in principle + be incompatible. However this will cause starvation of + LOCK TABLE READ in InnoDB under high write load. + See Bug#42147 for more information. */ DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx", @@ -547,8 +566,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock->write.data->type <= TL_WRITE_DELAYED && (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) || - (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT && - lock->write.data->type != TL_WRITE_ALLOW_READ)))) + (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT)))) { /* Already got a write lock */ (*lock->read.last)=data; /* Add to running FIFO */ data->prev=lock->read.last; @@ -631,6 +649,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, { if (lock->write.data->type == TL_WRITE_ONLY) { + /* purecov: begin tested */ /* Allow lock owner to bypass TL_WRITE_ONLY. */ if (!thr_lock_owner_equal(data->owner, lock->write.data->owner)) { @@ -639,6 +658,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, result= THR_LOCK_ABORTED; /* Can't wait for this one */ goto end; } + /* purecov: end */ } /* @@ -647,14 +667,23 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, write locks are of TL_WRITE_ALLOW_WRITE type. Note that, since lock requests for the same table are sorted in - such way that requests with higher thr_lock_type value come first, - lock being requested usually has equal or "weaker" type than one - which thread might have already acquired. - The exceptions are situations when: - - old lock type is TL_WRITE_ALLOW_READ and new lock type is - TL_WRITE_ALLOW_WRITE - - when old lock type is TL_WRITE_DELAYED - But these should never happen within MySQL. + such way that requests with higher thr_lock_type value come first + (with one exception (*)), lock being requested usually (**) has + equal or "weaker" type than one which thread might have already + acquired. + *) The only exception to this rule is case when type of old lock + is TL_WRITE_LOW_PRIORITY and type of new lock is changed inside + of thr_lock() from TL_WRITE_CONCURRENT_INSERT to TL_WRITE since + engine turns out to be not supporting concurrent inserts. + Note that since TL_WRITE has the same compatibility rules as + TL_WRITE_LOW_PRIORITY (their only difference is priority), + it is OK to grant new lock without additional checks in such + situation. + **) The exceptions are situations when: + - old lock type is TL_WRITE_ALLOW_READ and new lock type is + TL_WRITE_ALLOW_WRITE + - when old lock type is TL_WRITE_DELAYED + But these should never happen within MySQL. Therefore it is OK to allow acquiring write lock on the table if this thread already holds some write lock on it. @@ -663,7 +692,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, different types of write lock on the same table). */ DBUG_ASSERT(! has_old_lock(lock->write.data, data->owner) || - (lock_type <= lock->write.data->type && + ((lock_type <= lock->write.data->type || + (lock_type == TL_WRITE && + lock->write.data->type == TL_WRITE_LOW_PRIORITY)) && ! ((lock_type < TL_WRITE_ALLOW_READ && lock->write.data->type == TL_WRITE_ALLOW_READ) || lock->write.data->type == TL_WRITE_DELAYED))); @@ -745,9 +776,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, goto end; } /* Can't get lock yet; Wait for it */ - DBUG_RETURN(wait_for_lock(wait_queue, data, 0)); + DBUG_RETURN(wait_for_lock(wait_queue, data, 0, lock_wait_timeout)); end: - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_RETURN(result); } @@ -769,7 +800,7 @@ static inline void free_all_read_locks(THR_LOCK *lock, do { - pthread_cond_t *cond=data->cond; + mysql_cond_t *cond= data->cond; if ((int) data->type == (int) TL_READ_NO_INSERT) { if (using_concurrent_insert) @@ -794,7 +825,7 @@ static inline void free_all_read_locks(THR_LOCK *lock, data->owner->info->thread_id)); /* purecov: end */ data->cond=0; /* Mark thread free */ - VOID(pthread_cond_signal(cond)); + mysql_cond_signal(cond); } while ((data=data->next)); *lock->read_wait.last=0; if (!lock->read_wait.data) @@ -811,7 +842,7 @@ void thr_unlock(THR_LOCK_DATA *data) DBUG_ENTER("thr_unlock"); DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx", (long) data, data->owner->info->thread_id, (long) lock)); - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); check_locks(lock,"start of release lock",0); if (((*data->prev)=data->next)) /* remove from lock-list */ @@ -843,7 +874,7 @@ void thr_unlock(THR_LOCK_DATA *data) data->type=TL_UNLOCK; /* Mark unlocked */ check_locks(lock,"after releasing lock",1); wake_up_waiters(lock); - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_VOID_RETURN; } @@ -902,9 +933,9 @@ static void wake_up_waiters(THR_LOCK *lock) data->type, data->owner->info->thread_id)); /* purecov: end */ { - pthread_cond_t *cond=data->cond; + mysql_cond_t *cond= data->cond; data->cond=0; /* Mark thread free */ - VOID(pthread_cond_signal(cond)); /* Start waiting thread */ + mysql_cond_signal(cond); /* Start waiting thread */ } if (data->type != TL_WRITE_ALLOW_WRITE || !lock->write_wait.data || @@ -945,7 +976,7 @@ static void wake_up_waiters(THR_LOCK *lock) goto end; } do { - pthread_cond_t *cond=data->cond; + mysql_cond_t *cond= data->cond; if (((*data->prev)=data->next)) /* remove from wait-list */ data->next->prev= data->prev; else @@ -955,7 +986,7 @@ static void wake_up_waiters(THR_LOCK *lock) lock->write.last= &data->next; data->next=0; /* Only one write lock */ data->cond=0; /* Mark thread free */ - VOID(pthread_cond_signal(cond)); /* Start waiting thread */ + mysql_cond_signal(cond); /* Start waiting thread */ } while (lock_type == TL_WRITE_ALLOW_WRITE && (data=lock->write_wait.data) && data->type == TL_WRITE_ALLOW_WRITE); @@ -1004,7 +1035,8 @@ static void sort_locks(THR_LOCK_DATA **data,uint count) enum enum_thr_lock_result -thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) +thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner, + ulong lock_wait_timeout) { THR_LOCK_DATA **pos,**end; DBUG_ENTER("thr_multi_lock"); @@ -1014,7 +1046,8 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) /* lock everything */ for (pos=data,end=data+count; pos < end ; pos++) { - enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type); + enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type, + lock_wait_timeout); if (result != THR_LOCK_SUCCESS) { /* Aborted */ thr_multi_unlock(data,(uint) (pos-data)); @@ -1026,12 +1059,43 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) (long) pos[0]->lock, pos[0]->type); fflush(stdout); #endif } - /* - Ensure that all get_locks() have the same status - If we lock the same table multiple times, we must use the same - status_param! - */ + thr_lock_merge_status(data, count); + DBUG_RETURN(THR_LOCK_SUCCESS); +} + + +/** + Ensure that all locks for a given table have the same + status_param. + + This is a MyISAM and possibly Maria specific crutch. MyISAM + engine stores data file length, record count and other table + properties in status_param member of handler. When a table is + locked, connection-local copy is made from a global copy + (myisam_share) by mi_get_status(). When a table is unlocked, + the changed status is transferred back to the global share by + mi_update_status(). + + One thing MyISAM doesn't do is to ensure that when the same + table is opened twice in a connection all instances share the + same status_param. This is necessary, however: for one, to keep + all instances of a connection "on the same page" with regard to + the current state of the table. For other, unless this is done, + myisam_share will always get updated from the last unlocked + instance (in mi_update_status()), and when this instance was not + the one that was used to update data, records may be lost. + + For each table, this function looks up the last lock_data in the + list of acquired locks, and makes sure that all other instances + share status_param with it. +*/ + +void +thr_lock_merge_status(THR_LOCK_DATA **data, uint count) +{ #if !defined(DONT_USE_RW_LOCKS) + THR_LOCK_DATA **pos= data; + THR_LOCK_DATA **end= data + count; if (count > 1) { THR_LOCK_DATA *last_lock= end[-1]; @@ -1073,7 +1137,6 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner) } while (pos != data); } #endif - DBUG_RETURN(THR_LOCK_SUCCESS); } /* free all locks */ @@ -1112,19 +1175,19 @@ void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock) { THR_LOCK_DATA *data; DBUG_ENTER("thr_abort_locks"); - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); for (data=lock->read_wait.data; data ; data=data->next) { data->type=TL_UNLOCK; /* Mark killed */ /* It's safe to signal the cond first: we're still holding the mutex. */ - pthread_cond_signal(data->cond); + mysql_cond_signal(data->cond); data->cond=0; /* Removed from list */ } for (data=lock->write_wait.data; data ; data=data->next) { data->type=TL_UNLOCK; - pthread_cond_signal(data->cond); + mysql_cond_signal(data->cond); data->cond=0; } lock->read_wait.last= &lock->read_wait.data; @@ -1132,7 +1195,7 @@ void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock) lock->read_wait.data=lock->write_wait.data=0; if (upgrade_lock && lock->write.data) lock->write.data->type=TL_WRITE_ONLY; - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_VOID_RETURN; } @@ -1149,7 +1212,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) my_bool found= FALSE; DBUG_ENTER("thr_abort_locks_for_thread"); - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); for (data= lock->read_wait.data; data ; data= data->next) { if (data->owner->info->thread_id == thread_id) /* purecov: tested */ @@ -1158,7 +1221,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) data->type= TL_UNLOCK; /* Mark killed */ /* It's safe to signal the cond first: we're still holding the mutex. */ found= TRUE; - pthread_cond_signal(data->cond); + mysql_cond_signal(data->cond); data->cond= 0; /* Removed from list */ if (((*data->prev)= data->next)) @@ -1174,7 +1237,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) DBUG_PRINT("info",("Aborting write-wait lock")); data->type= TL_UNLOCK; found= TRUE; - pthread_cond_signal(data->cond); + mysql_cond_signal(data->cond); data->cond= 0; if (((*data->prev)= data->next)) @@ -1184,7 +1247,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) } } wake_up_waiters(lock); - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_RETURN(found); } @@ -1233,7 +1296,7 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *in_data, #endif DBUG_ENTER("thr_downgrade_write_only_lock"); - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); DBUG_ASSERT(old_lock_type == TL_WRITE_ONLY); DBUG_ASSERT(old_lock_type > new_lock_type); in_data->type= new_lock_type; @@ -1325,7 +1388,7 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *in_data, next= data->next; if (start_writers && data->type == new_lock_type) { - pthread_cond_t *cond= data->cond; + mysql_cond_t *cond= data->cond; /* It is ok to start this waiter. Move from being first in wait queue to be last in write queue. @@ -1339,7 +1402,7 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *in_data, data->next= 0; check_locks(lock, "Started write lock after downgrade",0); data->cond= 0; - pthread_cond_signal(cond); + mysql_cond_signal(cond); } else { @@ -1379,7 +1442,7 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *in_data, if (new_lock_type != TL_WRITE_ALLOW_READ || data->type != TL_READ_NO_INSERT) { - pthread_cond_t *cond= data->cond; + mysql_cond_t *cond= data->cond; if (((*data->prev)= data->next)) data->next->prev= data->prev; else @@ -1392,28 +1455,29 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *in_data, lock->read_no_write_count++; check_locks(lock, "Started read lock after downgrade",0); data->cond= 0; - pthread_cond_signal(cond); + mysql_cond_signal(cond); } } } check_locks(lock,"after starting waiters after downgrading lock",0); #endif - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_VOID_RETURN; } /* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, - enum thr_lock_type new_lock_type) + enum thr_lock_type new_lock_type, + ulong lock_wait_timeout) { THR_LOCK *lock=data->lock; DBUG_ENTER("thr_upgrade_write_delay_lock"); - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); if (data->type == TL_UNLOCK || data->type >= TL_WRITE_LOW_PRIORITY) { - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_RETURN(data->type == TL_UNLOCK); /* Test if Aborted */ } check_locks(lock,"before upgrading lock",0); @@ -1427,7 +1491,7 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, { /* We have the lock */ if (data->lock->get_status) (*data->lock->get_status)(data->status_param, 0); - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_RETURN(0); } @@ -1448,22 +1512,23 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data, { check_locks(lock,"waiting for lock",0); } - DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1)); + DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1, lock_wait_timeout)); } /* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */ -my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data) +my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data, + ulong lock_wait_timeout) { THR_LOCK *lock=data->lock; enum thr_lock_type write_lock_type; DBUG_ENTER("thr_reschedule_write_lock"); - pthread_mutex_lock(&lock->mutex); + mysql_mutex_lock(&lock->mutex); if (!lock->read_wait.data) /* No waiting read locks */ { - pthread_mutex_unlock(&lock->mutex); + mysql_mutex_unlock(&lock->mutex); DBUG_RETURN(0); } @@ -1485,8 +1550,9 @@ my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data) lock->write_wait.data=data; free_all_read_locks(lock,0); - pthread_mutex_unlock(&lock->mutex); - DBUG_RETURN(thr_upgrade_write_delay_lock(data, write_lock_type)); + mysql_mutex_unlock(&lock->mutex); + DBUG_RETURN(thr_upgrade_write_delay_lock(data, write_lock_type, + lock_wait_timeout)); } @@ -1520,13 +1586,13 @@ void thr_print_locks(void) LIST *list; uint count=0; - pthread_mutex_lock(&THR_LOCK_lock); + mysql_mutex_lock(&THR_LOCK_lock); puts("Current locks:"); for (list= thr_lock_thread_list; list && count++ < MAX_THREADS; list= list_rest(list)) { THR_LOCK *lock=(THR_LOCK*) list->data; - VOID(pthread_mutex_lock(&lock->mutex)); + mysql_mutex_lock(&lock->mutex); printf("lock: 0x%lx:",(ulong) lock); if ((lock->write_wait.data || lock->read_wait.data) && (! lock->read.data && ! lock->write.data)) @@ -1544,11 +1610,11 @@ void thr_print_locks(void) thr_print_lock("write_wait",&lock->write_wait); thr_print_lock("read",&lock->read); thr_print_lock("read_wait",&lock->read_wait); - VOID(pthread_mutex_unlock(&lock->mutex)); + mysql_mutex_unlock(&lock->mutex); puts(""); } fflush(stdout); - pthread_mutex_unlock(&THR_LOCK_lock); + mysql_mutex_unlock(&THR_LOCK_lock); } #endif /* THREAD */ @@ -1609,8 +1675,8 @@ int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test), }; -static pthread_cond_t COND_thread_count; -static pthread_mutex_t LOCK_thread_count; +static mysql_cond_t COND_thread_count; +static mysql_mutex_t LOCK_thread_count; static uint thread_count; static ulong sum=0; @@ -1662,7 +1728,7 @@ static void *test_thread(void *arg) data[i].type= tests[param][i].lock_type; } thr_multi_lock(multi_locks, lock_counts[param], &owner); - pthread_mutex_lock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_thread_count); { int tmp=rand() & 7; /* Do something from 0-2 sec */ if (tmp == 0) @@ -1676,16 +1742,16 @@ static void *test_thread(void *arg) sum+=k; } } - pthread_mutex_unlock(&LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); thr_multi_unlock(multi_locks,lock_counts[param]); } printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout); thr_print_locks(); - pthread_mutex_lock(&LOCK_thread_count); + mysql_mutex_lock(&LOCK_thread_count); thread_count--; - VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */ - pthread_mutex_unlock(&LOCK_thread_count); + mysql_cond_signal(&COND_thread_count); /* Tell main we are ready */ + mysql_mutex_unlock(&LOCK_thread_count); free((uchar*) arg); return 0; } @@ -1702,15 +1768,15 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) printf("Main thread: %s\n",my_thread_name()); - if ((error=pthread_cond_init(&COND_thread_count,NULL))) + if ((error= mysql_cond_init(0, &COND_thread_count, NULL))) { - fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)", + fprintf(stderr, "Got error: %d from mysql_cond_init (errno: %d)", error,errno); exit(1); } - if ((error=pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST))) + if ((error= mysql_mutex_init(0, &LOCK_thread_count, MY_MUTEX_INIT_FAST))) { - fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)", + fprintf(stderr, "Got error: %d from mysql_cond_init (errno: %d)", error,errno); exit(1); } @@ -1745,40 +1811,42 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) } #endif #ifdef HAVE_THR_SETCONCURRENCY - VOID(thr_setconcurrency(2)); + (void) thr_setconcurrency(2); #endif for (i=0 ; i < (int) array_elements(lock_counts) ; i++) { param=(int*) malloc(sizeof(int)); *param=i; - if ((error=pthread_mutex_lock(&LOCK_thread_count))) + if ((error= mysql_mutex_lock(&LOCK_thread_count))) { - fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)", - error,errno); + fprintf(stderr, "Got error: %d from mysql_mutex_lock (errno: %d)", + error, errno); exit(1); } - if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param))) + if ((error= mysql_thread_create(0, + &tid, &thr_attr, test_thread, + (void*) param))) { - fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n", - error,errno); - pthread_mutex_unlock(&LOCK_thread_count); + fprintf(stderr, "Got error: %d from mysql_thread_create (errno: %d)\n", + error, errno); + mysql_mutex_unlock(&LOCK_thread_count); exit(1); } thread_count++; - pthread_mutex_unlock(&LOCK_thread_count); + mysql_mutex_unlock(&LOCK_thread_count); } pthread_attr_destroy(&thr_attr); - if ((error=pthread_mutex_lock(&LOCK_thread_count))) - fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error); + if ((error= mysql_mutex_lock(&LOCK_thread_count))) + fprintf(stderr, "Got error: %d from mysql_mutex_lock\n", error); while (thread_count) { - if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count))) - fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error); + if ((error= mysql_cond_wait(&COND_thread_count, &LOCK_thread_count))) + fprintf(stderr, "Got error: %d from mysql_cond_wait\n", error); } - if ((error=pthread_mutex_unlock(&LOCK_thread_count))) - fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error); + if ((error= mysql_mutex_unlock(&LOCK_thread_count))) + fprintf(stderr, "Got error: %d from mysql_mutex_unlock\n", error); for (i=0 ; i < (int) array_elements(locks) ; i++) thr_lock_delete(locks+i); #ifdef EXTRA_DEBUG diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index 8f9928026ba..db35d5a13a6 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -39,6 +39,7 @@ #endif #endif /* DO_NOT_REMOVE_THREAD_WRAPPERS */ +/* Not instrumented */ static pthread_mutex_t THR_LOCK_mutex; static ulong safe_mutex_count= 0; /* Number of mutexes created */ #ifdef SAFE_MUTEX_DETECT_DESTROY @@ -85,7 +86,9 @@ int safe_mutex_init(safe_mutex_t *mp, pthread_mutex_unlock(&THR_LOCK_mutex); } #else - thread_safe_increment(safe_mutex_count, &THR_LOCK_mutex); + pthread_mutex_lock(&THR_LOCK_mutex); + safe_mutex_count++; + pthread_mutex_unlock(&THR_LOCK_mutex); #endif /* SAFE_MUTEX_DETECT_DESTROY */ return 0; } @@ -344,7 +347,9 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line) mp->info= NULL; /* Get crash if double free */ } #else - thread_safe_sub(safe_mutex_count, 1, &THR_LOCK_mutex); + pthread_mutex_lock(&THR_LOCK_mutex); + safe_mutex_count--; + pthread_mutex_unlock(&THR_LOCK_mutex); #endif /* SAFE_MUTEX_DETECT_DESTROY */ return error; } diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c index 0aa4d3fc3c4..2ac4a00695e 100644 --- a/mysys/thr_rwlock.c +++ b/mysys/thr_rwlock.c @@ -16,7 +16,8 @@ /* Synchronization - readers / writer thread locks */ #include "mysys_priv.h" -#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT) +#if defined(THREAD) +#if defined(NEED_MY_RW_LOCK) #include <errno.h> /* @@ -58,7 +59,7 @@ * Mountain View, California 94043 */ -int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused))) +int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr) { pthread_condattr_t cond_attr; @@ -70,12 +71,14 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused))) rwp->state = 0; rwp->waiters = 0; + /* If attribute argument is NULL use default value - prefer writers. */ + rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE; return(0); } -int my_rwlock_destroy(rw_lock_t *rwp) +int my_rw_destroy(my_rw_lock_t *rwp) { pthread_mutex_destroy( &rwp->lock ); pthread_cond_destroy( &rwp->readers ); @@ -84,12 +87,13 @@ int my_rwlock_destroy(rw_lock_t *rwp) } -int my_rw_rdlock(rw_lock_t *rwp) +int my_rw_rdlock(my_rw_lock_t *rwp) { pthread_mutex_lock(&rwp->lock); /* active or queued writers */ - while (( rwp->state < 0 ) || rwp->waiters) + while (( rwp->state < 0 ) || + (rwp->waiters && ! rwp->prefer_readers)) pthread_cond_wait( &rwp->readers, &rwp->lock); rwp->state++; @@ -97,11 +101,12 @@ int my_rw_rdlock(rw_lock_t *rwp) return(0); } -int my_rw_tryrdlock(rw_lock_t *rwp) +int my_rw_tryrdlock(my_rw_lock_t *rwp) { int res; pthread_mutex_lock(&rwp->lock); - if ((rwp->state < 0 ) || rwp->waiters) + if ((rwp->state < 0 ) || + (rwp->waiters && ! rwp->prefer_readers)) res= EBUSY; /* Can't get lock */ else { @@ -113,7 +118,7 @@ int my_rw_tryrdlock(rw_lock_t *rwp) } -int my_rw_wrlock(rw_lock_t *rwp) +int my_rw_wrlock(my_rw_lock_t *rwp) { pthread_mutex_lock(&rwp->lock); rwp->waiters++; /* another writer queued */ @@ -127,7 +132,7 @@ int my_rw_wrlock(rw_lock_t *rwp) } -int my_rw_trywrlock(rw_lock_t *rwp) +int my_rw_trywrlock(my_rw_lock_t *rwp) { int res; pthread_mutex_lock(&rwp->lock); @@ -143,7 +148,7 @@ int my_rw_trywrlock(rw_lock_t *rwp) } -int my_rw_unlock(rw_lock_t *rwp) +int my_rw_unlock(my_rw_lock_t *rwp) { DBUG_PRINT("rw_unlock", ("state: %d waiters: %d", rwp->state, rwp->waiters)); @@ -160,7 +165,8 @@ int my_rw_unlock(rw_lock_t *rwp) } else { - if ( --rwp->state == 0 ) /* no more readers */ + if ( --rwp->state == 0 && /* no more readers */ + rwp->waiters) pthread_cond_signal( &rwp->writers ); } @@ -168,4 +174,30 @@ int my_rw_unlock(rw_lock_t *rwp) return(0); } -#endif + +int rw_pr_init(struct st_my_rw_lock_t *rwlock) +{ + my_bool prefer_readers_attr= TRUE; + return my_rw_init(rwlock, &prefer_readers_attr); +} + +#else + +/* + We are on system which has native read/write locks which support + preferring of readers. +*/ + +int rw_pr_init(rw_pr_lock_t *rwlock) +{ + pthread_rwlockattr_t rwlock_attr; + + pthread_rwlockattr_init(&rwlock_attr); + pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_READER_NP); + pthread_rwlock_init(rwlock, NULL); + pthread_rwlockattr_destroy(&rwlock_attr); + return 0; +} + +#endif /* defined(NEED_MY_RW_LOCK) */ +#endif /* defined(THREAD) */ diff --git a/mysys/typelib.c b/mysys/typelib.c index cb72c91e20d..c332c82d17a 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -20,7 +20,7 @@ #include <m_ctype.h> -static const char field_separator=','; +#define is_field_separator(X) ((X) == ',' || (X) == '=') int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) { @@ -44,26 +44,26 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) } -/* +/** Search after a string in a list of strings. Endspace in x is not compared. - SYNOPSIS - find_type() - x String to find - lib TYPELIB (struct of pointer to values + count) - full_name bitmap of what to do - If & 1 accept only whole names - If & 2 don't expand if half field - If & 4 allow #number# as type - If & 8 use ',' as string terminator - - NOTES - If part, uniq field is found and full_name == 0 then x is expanded - to full field. - - RETURN - -1 Too many matching values - 0 No matching value + @param x String to find + @param lib TYPELIB (struct of pointer to values + count) + @param full_name bitmap of what to do + If & 1 accept only whole names + If & 2 don't expand if half field + If & 4 allow #number# as type + If & 8 use ',' as string terminator + + @note + If part, uniq field is found and full_name == 0 then x is expanded + to full field. + + @retval + -1 Too many matching values + @retval + 0 No matching value + @retval >0 Offset+1 in typelib for matched string */ @@ -86,17 +86,17 @@ int find_type(char *x, const TYPELIB *typelib, uint full_name) for (pos=0 ; (j=typelib->type_names[pos]) ; pos++) { for (i=x ; - *i && (!(full_name & 8) || *i != field_separator) && + *i && (!(full_name & 8) || !is_field_separator(*i)) && my_toupper(&my_charset_latin1,*i) == my_toupper(&my_charset_latin1,*j) ; i++, j++) ; if (! *j) { while (*i == ' ') i++; /* skip_end_space */ - if (! *i || ((full_name & 8) && *i == field_separator)) + if (! *i || ((full_name & 8) && is_field_separator(*i))) DBUG_RETURN(pos+1); } - if ((!*i && (!(full_name & 8) || *i != field_separator)) && + if ((!*i && (!(full_name & 8) || !is_field_separator(*i))) && (!*j || !(full_name & 1))) { find++; @@ -122,8 +122,12 @@ int find_type(char *x, const TYPELIB *typelib, uint full_name) } /* find_type */ - /* Get name of type nr 'nr' */ - /* Warning first type is 1, 0 = empty field */ +/** + Get name of type nr + + @note + first type is 1, 0 = empty field +*/ void make_type(register char * to, register uint nr, register TYPELIB *typelib) @@ -137,8 +141,12 @@ void make_type(register char * to, register uint nr, } /* make_type */ - /* Get type */ - /* Warning first type is 0 */ +/** + Get type + + @note + first type is 0 +*/ const char *get_type(TYPELIB *typelib, uint nr) { @@ -148,18 +156,16 @@ const char *get_type(TYPELIB *typelib, uint nr) } -/* +/** Create an integer value to represent the supplied comma-seperated string where each string in the TYPELIB denotes a bit position. - SYNOPSIS - find_typeset() - x string to decompose - lib TYPELIB (struct of pointer to values + count) - err index (not char position) of string element which was not + @param x string to decompose + @param lib TYPELIB (struct of pointer to values + count) + @param err index (not char position) of string element which was not found or 0 if there was no error - RETURN + @retval a integer representation of the supplied string */ @@ -182,9 +188,9 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err) { (*err)++; i= x; - while (*x && *x != field_separator) + while (*x && !is_field_separator(*x)) x++; - if (x[0] && x[1]) /* skip separator if found */ + if (x[0] && x[1]) /* skip separator if found */ x++; if ((find= find_type(i, lib, 2 | 8) - 1) < 0) DBUG_RETURN(0); @@ -195,16 +201,15 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err) } /* find_set */ -/* +/** Create a copy of a specified TYPELIB structure. - SYNOPSIS - copy_typelib() - root pointer to a MEM_ROOT object for allocations - from pointer to a source TYPELIB structure + @param root pointer to a MEM_ROOT object for allocations + @param from pointer to a source TYPELIB structure - RETURN - pointer to the new TYPELIB structure on successful copy, or + @retval + pointer to the new TYPELIB structure on successful copy + @retval NULL otherwise */ @@ -244,3 +249,140 @@ TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from) return to; } + + +static const char *on_off_default_names[]= { "off","on","default", 0}; +static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1, + "", on_off_default_names, 0}; + +/** + Parse a TYPELIB name from the buffer + + @param lib Set of names to scan for. + @param strpos INOUT Start of the buffer (updated to point to the next + character after the name) + @param end End of the buffer + + @note + The buffer is assumed to contain one of the names specified in the TYPELIB, + followed by comma, '=', or end of the buffer. + + @retval + 0 No matching name + @retval + >0 Offset+1 in typelib for matched name +*/ + +static uint parse_name(const TYPELIB *lib, const char **strpos, const char *end) +{ + const char *pos= *strpos; + uint find= find_type((char*)pos, lib, 8); + for (; pos != end && *pos != '=' && *pos !=',' ; pos++); + *strpos= pos; + return find; +} + +/** + Parse and apply a set of flag assingments + + @param lib Flag names + @param default_name Number of "default" in the typelib + @param cur_set Current set of flags (start from this state) + @param default_set Default set of flags (use this for assign-default + keyword and flag=default assignments) + @param str String to be parsed + @param length Length of the string + @param err_pos OUT If error, set to point to start of wrong set string + NULL on success + @param err_len OUT If error, set to the length of wrong set string + + @details + Parse a set of flag assignments, that is, parse a string in form: + + param_name1=value1,param_name2=value2,... + + where the names are specified in the TYPELIB, and each value can be + either 'on','off', or 'default'. Setting the same name twice is not + allowed. + + Besides param=val assignments, we support the "default" keyword (keyword + #default_name in the typelib). It can be used one time, if specified it + causes us to build the new set over the default_set rather than cur_set + value. + + @note + it's not charset aware + + @retval + Parsed set value if (*errpos == NULL), otherwise undefined +*/ + +my_ulonglong find_set_from_flags(const TYPELIB *lib, uint default_name, + my_ulonglong cur_set, my_ulonglong default_set, + const char *str, uint length, + char **err_pos, uint *err_len) +{ + const char *end= str + length; + my_ulonglong flags_to_set= 0, flags_to_clear= 0, res; + my_bool set_defaults= 0; + + *err_pos= 0; /* No error yet */ + if (str != end) + { + const char *start= str; + for (;;) + { + const char *pos= start; + uint flag_no, value; + + if (!(flag_no= parse_name(lib, &pos, end))) + goto err; + + if (flag_no == default_name) + { + /* Using 'default' twice isn't allowed. */ + if (set_defaults) + goto err; + set_defaults= TRUE; + } + else + { + my_ulonglong bit= (1ULL << (flag_no - 1)); + /* parse the '=on|off|default' */ + if ((flags_to_clear | flags_to_set) & bit || + pos >= end || *pos++ != '=' || + !(value= parse_name(&on_off_default_typelib, &pos, end))) + goto err; + + if (value == 1) // this is '=off' + flags_to_clear|= bit; + else if (value == 2) // this is '=on' + flags_to_set|= bit; + else // this is '=default' + { + if (default_set & bit) + flags_to_set|= bit; + else + flags_to_clear|= bit; + } + } + if (pos >= end) + break; + + if (*pos++ != ',') + goto err; + + start=pos; + continue; + err: + *err_pos= (char*)start; + *err_len= end - start; + break; + } + } + res= set_defaults? default_set : cur_set; + res|= flags_to_set; + res&= ~flags_to_clear; + return res; +} + |