summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@montyprogram.com>2012-02-27 19:32:44 +0100
committerVladislav Vaintroub <wlad@montyprogram.com>2012-02-27 19:32:44 +0100
commit62dcaf8c2911572d730ba5e617a7c3cbbf86b22a (patch)
treedd1e73c8a65fd1570c4594870bb0e8afd2d271f6 /mysys
parent58c3e32dbdd43e8635c0320fcf5cc744e354fc65 (diff)
parent3ebb4b883370da9528b7482b8ba4ed9521f07553 (diff)
downloadmariadb-git-62dcaf8c2911572d730ba5e617a7c3cbbf86b22a.tar.gz
merge 5.5
Diffstat (limited to 'mysys')
-rw-r--r--mysys/CMakeLists.txt2
-rw-r--r--mysys/my_access.c16
-rw-r--r--mysys/my_context.c717
-rw-r--r--mysys/my_init.c1
-rw-r--r--mysys/stacktrace.c17
-rw-r--r--mysys/thr_lock.c43
-rw-r--r--mysys/wqueue.c16
7 files changed, 780 insertions, 32 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index c565f7f12d5..7397990eddb 100644
--- a/mysys/CMakeLists.txt
+++ b/mysys/CMakeLists.txt
@@ -37,7 +37,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c
safemalloc.c my_new.cc
my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c
my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c
- my_rdtsc.c)
+ my_rdtsc.c my_context.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)
diff --git a/mysys/my_access.c b/mysys/my_access.c
index 210946d50a8..d7d06f814d6 100644
--- a/mysys/my_access.c
+++ b/mysys/my_access.c
@@ -26,11 +26,6 @@
path Path to file
amode Access method
- DESCRIPTION
- This function wraps the normal access method because the access
- available in MSVCRT> +reports that filenames such as LPT1 and
- COM1 are valid (they are but should not be so for us).
-
RETURN VALUES
0 ok
-1 error (We use -1 as my_access is mapped to access on other platforms)
@@ -38,12 +33,11 @@
int my_access(const char *path, int amode)
{
- WIN32_FILE_ATTRIBUTE_DATA fileinfo;
- BOOL result;
-
- result= GetFileAttributesEx(path, GetFileExInfoStandard, &fileinfo);
- if (! result ||
- (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && (amode & W_OK))
+ DWORD attributes;
+
+ attributes = GetFileAttributes(path);
+ if (attributes == INVALID_FILE_ATTRIBUTES ||
+ (attributes & FILE_ATTRIBUTE_READONLY) && (amode & W_OK))
{
my_errno= errno= EACCES;
return -1;
diff --git a/mysys/my_context.c b/mysys/my_context.c
new file mode 100644
index 00000000000..d2374391a39
--- /dev/null
+++ b/mysys/my_context.c
@@ -0,0 +1,717 @@
+/*
+ Copyright 2011 Kristian Nielsen and Monty Program Ab
+
+ This file is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ Implementation of async context spawning using Posix ucontext and
+ swapcontext().
+*/
+
+#include "mysys_priv.h"
+#include "m_string.h"
+#include "my_context.h"
+
+#ifdef HAVE_VALGRIND
+#include <valgrind/valgrind.h>
+#endif
+
+#ifdef MY_CONTEXT_USE_UCONTEXT
+/*
+ The makecontext() only allows to pass integers into the created context :-(
+ We want to pass pointers, so we do it this kinda hackish way.
+ Anyway, it should work everywhere, and at least it does not break strict
+ aliasing.
+*/
+union pass_void_ptr_as_2_int {
+ int a[2];
+ void *p;
+};
+
+
+/*
+ We use old-style function definition here, as this is passed to
+ makecontext(). And the type of the makecontext() argument does not match
+ the actual type (as the actual type can differ from call to call).
+*/
+static void
+my_context_spawn_internal(i0, i1)
+int i0, i1;
+{
+ int err;
+ struct my_context *c;
+ union pass_void_ptr_as_2_int u;
+
+ u.a[0]= i0;
+ u.a[1]= i1;
+ c= (struct my_context *)u.p;
+
+ (*c->user_func)(c->user_data);
+ c->active= 0;
+ err= setcontext(&c->base_context);
+ fprintf(stderr, "Aieie, setcontext() failed: %d (errno=%d)\n", err, errno);
+}
+
+
+int
+my_context_continue(struct my_context *c)
+{
+ int err;
+
+ if (!c->active)
+ return 0;
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+ err= swapcontext(&c->base_context, &c->spawned_context);
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+ if (err)
+ {
+ fprintf(stderr, "Aieie, swapcontext() failed: %d (errno=%d)\n",
+ err, errno);
+ return -1;
+ }
+
+ return c->active;
+}
+
+
+int
+my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
+{
+ int err;
+ union pass_void_ptr_as_2_int u;
+
+ err= getcontext(&c->spawned_context);
+ if (err)
+ return -1;
+ c->spawned_context.uc_stack.ss_sp= c->stack;
+ c->spawned_context.uc_stack.ss_size= c->stack_size;
+ c->spawned_context.uc_link= NULL;
+ c->user_func= f;
+ c->user_data= d;
+ c->active= 1;
+ u.p= c;
+ makecontext(&c->spawned_context, my_context_spawn_internal, 2,
+ u.a[0], u.a[1]);
+
+ return my_context_continue(c);
+}
+
+
+int
+my_context_yield(struct my_context *c)
+{
+ int err;
+
+ if (!c->active)
+ return -1;
+
+ err= swapcontext(&c->spawned_context, &c->base_context);
+ if (err)
+ return -1;
+ return 0;
+}
+
+int
+my_context_init(struct my_context *c, size_t stack_size)
+{
+#if SIZEOF_CHARP > SIZEOF_INT*2
+#error Error: Unable to store pointer in 2 ints on this architecture
+#endif
+ bzero(c, sizeof(*c));
+ if (!(c->stack= malloc(stack_size)))
+ return -1; /* Out of memory */
+ c->stack_size= stack_size;
+#ifdef HAVE_VALGRIND
+ c->valgrind_stack_id=
+ VALGRIND_STACK_REGISTER(c->stack, ((unsigned char *)(c->stack))+stack_size);
+#endif
+ return 0;
+}
+
+void
+my_context_destroy(struct my_context *c)
+{
+ if (c->stack)
+ {
+#ifdef HAVE_VALGRIND
+ VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
+#endif
+ free(c->stack);
+ }
+ DBUG_FREE_CODE_STATE(&c->dbug_state);
+}
+
+#endif /* MY_CONTEXT_USE_UCONTEXT */
+
+
+#ifdef MY_CONTEXT_USE_X86_64_GCC_ASM
+/*
+ GCC-amd64 implementation of my_context.
+
+ This is slightly optimized in the common case where we never yield
+ (eg. fetch next row and it is already fully received in buffer). In this
+ case we do not need to restore registers at return (though we still need to
+ save them as we cannot know if we will yield or not in advance).
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ Layout of saved registers etc.
+ Since this is accessed through gcc inline assembler, it is simpler to just
+ use numbers than to try to define nice constants or structs.
+
+ 0 0 %rsp
+ 1 8 %rbp
+ 2 16 %rbx
+ 3 24 %r12
+ 4 32 %r13
+ 5 40 %r14
+ 6 48 %r15
+ 7 56 %rip for done
+ 8 64 %rip for yield/continue
+*/
+
+int
+my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
+{
+ int ret;
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ /*
+ There are 6 callee-save registers we need to save and restore when
+ suspending and continuing, plus stack pointer %rsp and instruction pointer
+ %rip.
+
+ However, if we never suspend, the user-supplied function will in any case
+ restore the 6 callee-save registers, so we can avoid restoring them in
+ this case.
+ */
+ __asm__ __volatile__
+ (
+ "movq %%rsp, (%[save])\n\t"
+ "movq %[stack], %%rsp\n\t"
+#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
+ /*
+ This emits a DWARF DW_CFA_undefined directive to make the return address
+ undefined. This indicates that this is the top of the stack frame, and
+ helps tools that use DWARF stack unwinding to obtain stack traces.
+ (I use numeric constant to avoid a dependency on libdwarf includes).
+ */
+ ".cfi_escape 0x07, 16\n\t"
+#endif
+ "movq %%rbp, 8(%[save])\n\t"
+ "movq %%rbx, 16(%[save])\n\t"
+ "movq %%r12, 24(%[save])\n\t"
+ "movq %%r13, 32(%[save])\n\t"
+ "movq %%r14, 40(%[save])\n\t"
+ "movq %%r15, 48(%[save])\n\t"
+ "leaq 1f(%%rip), %%rax\n\t"
+ "leaq 2f(%%rip), %%rcx\n\t"
+ "movq %%rax, 56(%[save])\n\t"
+ "movq %%rcx, 64(%[save])\n\t"
+ /*
+ Constraint below puts the argument to the user function into %rdi, as
+ needed for the calling convention.
+ */
+ "callq *%[f]\n\t"
+ "jmpq *56(%[save])\n"
+ /*
+ Come here when operation is done.
+ We do not need to restore callee-save registers, as the called function
+ will do this for us if needed.
+ */
+ "1:\n\t"
+ "movq (%[save]), %%rsp\n\t"
+ "xorl %[ret], %[ret]\n\t"
+ "jmp 3f\n"
+ /* Come here when operation was suspended. */
+ "2:\n\t"
+ "movl $1, %[ret]\n"
+ "3:\n"
+ : [ret] "=a" (ret),
+ [f] "+S" (f),
+ /* Need this in %rdi to follow calling convention. */
+ [d] "+D" (d)
+ : [stack] "a" (c->stack_top),
+ /* Need this in callee-save register to preserve in function call. */
+ [save] "b" (&c->save[0])
+ : "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc"
+ );
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ return ret;
+}
+
+int
+my_context_continue(struct my_context *c)
+{
+ int ret;
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ __asm__ __volatile__
+ (
+ "movq (%[save]), %%rax\n\t"
+ "movq %%rsp, (%[save])\n\t"
+ "movq %%rax, %%rsp\n\t"
+ "movq 8(%[save]), %%rax\n\t"
+ "movq %%rbp, 8(%[save])\n\t"
+ "movq %%rax, %%rbp\n\t"
+ "movq 24(%[save]), %%rax\n\t"
+ "movq %%r12, 24(%[save])\n\t"
+ "movq %%rax, %%r12\n\t"
+ "movq 32(%[save]), %%rax\n\t"
+ "movq %%r13, 32(%[save])\n\t"
+ "movq %%rax, %%r13\n\t"
+ "movq 40(%[save]), %%rax\n\t"
+ "movq %%r14, 40(%[save])\n\t"
+ "movq %%rax, %%r14\n\t"
+ "movq 48(%[save]), %%rax\n\t"
+ "movq %%r15, 48(%[save])\n\t"
+ "movq %%rax, %%r15\n\t"
+
+ "leaq 1f(%%rip), %%rax\n\t"
+ "leaq 2f(%%rip), %%rcx\n\t"
+ "movq %%rax, 56(%[save])\n\t"
+ "movq 64(%[save]), %%rax\n\t"
+ "movq %%rcx, 64(%[save])\n\t"
+
+ "movq 16(%[save]), %%rcx\n\t"
+ "movq %%rbx, 16(%[save])\n\t"
+ "movq %%rcx, %%rbx\n\t"
+
+ "jmpq *%%rax\n"
+ /*
+ Come here when operation is done.
+ Be sure to use the same callee-save register for %[save] here and in
+ my_context_spawn(), so we preserve the value correctly at this point.
+ */
+ "1:\n\t"
+ "movq (%[save]), %%rsp\n\t"
+ "movq 8(%[save]), %%rbp\n\t"
+ /* %rbx is preserved from my_context_spawn() in this case. */
+ "movq 24(%[save]), %%r12\n\t"
+ "movq 32(%[save]), %%r13\n\t"
+ "movq 40(%[save]), %%r14\n\t"
+ "movq 48(%[save]), %%r15\n\t"
+ "xorl %[ret], %[ret]\n\t"
+ "jmp 3f\n"
+ /* Come here when operation is suspended. */
+ "2:\n\t"
+ "movl $1, %[ret]\n"
+ "3:\n"
+ : [ret] "=a" (ret)
+ : /* Need this in callee-save register to preserve in function call. */
+ [save] "b" (&c->save[0])
+ : "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", "memory", "cc"
+ );
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ return ret;
+}
+
+int
+my_context_yield(struct my_context *c)
+{
+ uint64_t *save= &c->save[0];
+ __asm__ __volatile__
+ (
+ "movq (%[save]), %%rax\n\t"
+ "movq %%rsp, (%[save])\n\t"
+ "movq %%rax, %%rsp\n\t"
+ "movq 8(%[save]), %%rax\n\t"
+ "movq %%rbp, 8(%[save])\n\t"
+ "movq %%rax, %%rbp\n\t"
+ "movq 16(%[save]), %%rax\n\t"
+ "movq %%rbx, 16(%[save])\n\t"
+ "movq %%rax, %%rbx\n\t"
+ "movq 24(%[save]), %%rax\n\t"
+ "movq %%r12, 24(%[save])\n\t"
+ "movq %%rax, %%r12\n\t"
+ "movq 32(%[save]), %%rax\n\t"
+ "movq %%r13, 32(%[save])\n\t"
+ "movq %%rax, %%r13\n\t"
+ "movq 40(%[save]), %%rax\n\t"
+ "movq %%r14, 40(%[save])\n\t"
+ "movq %%rax, %%r14\n\t"
+ "movq 48(%[save]), %%rax\n\t"
+ "movq %%r15, 48(%[save])\n\t"
+ "movq %%rax, %%r15\n\t"
+ "movq 64(%[save]), %%rax\n\t"
+ "leaq 1f(%%rip), %%rcx\n\t"
+ "movq %%rcx, 64(%[save])\n\t"
+
+ "jmpq *%%rax\n"
+
+ "1:\n"
+ : [save] "+D" (save)
+ :
+ : "rax", "rcx", "rdx", "rsi", "r8", "r9", "r10", "r11", "memory", "cc"
+ );
+ return 0;
+}
+
+int
+my_context_init(struct my_context *c, size_t stack_size)
+{
+ bzero(c, sizeof(*c));
+
+ if (!(c->stack_bot= malloc(stack_size)))
+ return -1; /* Out of memory */
+ /*
+ The x86_64 ABI specifies 16-byte stack alignment.
+ Also put two zero words at the top of the stack.
+ */
+ c->stack_top= (void *)
+ (( ((intptr)c->stack_bot + stack_size) & ~(intptr)0xf) - 16);
+ bzero(c->stack_top, 16);
+
+#ifdef HAVE_VALGRIND
+ c->valgrind_stack_id=
+ VALGRIND_STACK_REGISTER(c->stack_bot, c->stack_top);
+#endif
+ return 0;
+}
+
+void
+my_context_destroy(struct my_context *c)
+{
+ if (c->stack_bot)
+ {
+ free(c->stack_bot);
+#ifdef HAVE_VALGRIND
+ VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
+#endif
+ }
+ DBUG_FREE_CODE_STATE(&c->dbug_state);
+}
+
+#endif /* MY_CONTEXT_USE_X86_64_GCC_ASM */
+
+
+#ifdef MY_CONTEXT_USE_I386_GCC_ASM
+/*
+ GCC-i386 implementation of my_context.
+
+ This is slightly optimized in the common case where we never yield
+ (eg. fetch next row and it is already fully received in buffer). In this
+ case we do not need to restore registers at return (though we still need to
+ save them as we cannot know if we will yield or not in advance).
+*/
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ Layout of saved registers etc.
+ Since this is accessed through gcc inline assembler, it is simpler to just
+ use numbers than to try to define nice constants or structs.
+
+ 0 0 %esp
+ 1 4 %ebp
+ 2 8 %ebx
+ 3 12 %esi
+ 4 16 %edi
+ 5 20 %eip for done
+ 6 24 %eip for yield/continue
+*/
+
+int
+my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
+{
+ int ret;
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ /*
+ There are 4 callee-save registers we need to save and restore when
+ suspending and continuing, plus stack pointer %esp and instruction pointer
+ %eip.
+
+ However, if we never suspend, the user-supplied function will in any case
+ restore the 4 callee-save registers, so we can avoid restoring them in
+ this case.
+ */
+ __asm__ __volatile__
+ (
+ "movl %%esp, (%[save])\n\t"
+ "movl %[stack], %%esp\n\t"
+ /* Push the parameter on the stack. */
+ "pushl %[d]\n\t"
+ "movl %%ebp, 4(%[save])\n\t"
+ "movl %%ebx, 8(%[save])\n\t"
+ "movl %%esi, 12(%[save])\n\t"
+ "movl %%edi, 16(%[save])\n\t"
+ /* Get label addresses in -fPIC-compatible way (no pc-relative on 32bit) */
+ "call 1f\n"
+ "1:\n\t"
+ "popl %%eax\n\t"
+ "addl $(2f-1b), %%eax\n\t"
+ "movl %%eax, 20(%[save])\n\t"
+ "addl $(3f-2f), %%eax\n\t"
+ "movl %%eax, 24(%[save])\n\t"
+ "call *%[f]\n\t"
+ "jmp *20(%[save])\n"
+ /*
+ Come here when operation is done.
+ We do not need to restore callee-save registers, as the called function
+ will do this for us if needed.
+ */
+ "2:\n\t"
+ "movl (%[save]), %%esp\n\t"
+ "xorl %[ret], %[ret]\n\t"
+ "jmp 4f\n"
+ /* Come here when operation was suspended. */
+ "3:\n\t"
+ "movl $1, %[ret]\n"
+ "4:\n"
+ : [ret] "=a" (ret)
+ : [stack] "a" (c->stack_top),
+ /* Need this in callee-save register to preserve across function call. */
+ [save] "D" (&c->save[0]),
+ [f] "m" (f),
+ [d] "m" (d)
+ : "ecx", "edx", "memory", "cc"
+ );
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ return ret;
+}
+
+int
+my_context_continue(struct my_context *c)
+{
+ int ret;
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ __asm__ __volatile__
+ (
+ "movl (%[save]), %%eax\n\t"
+ "movl %%esp, (%[save])\n\t"
+ "movl %%eax, %%esp\n\t"
+ "movl 4(%[save]), %%eax\n\t"
+ "movl %%ebp, 4(%[save])\n\t"
+ "movl %%eax, %%ebp\n\t"
+ "movl 8(%[save]), %%eax\n\t"
+ "movl %%ebx, 8(%[save])\n\t"
+ "movl %%eax, %%ebx\n\t"
+ "movl 12(%[save]), %%eax\n\t"
+ "movl %%esi, 12(%[save])\n\t"
+ "movl %%eax, %%esi\n\t"
+
+ "movl 24(%[save]), %%eax\n\t"
+ "call 1f\n"
+ "1:\n\t"
+ "popl %%ecx\n\t"
+ "addl $(2f-1b), %%ecx\n\t"
+ "movl %%ecx, 20(%[save])\n\t"
+ "addl $(3f-2f), %%ecx\n\t"
+ "movl %%ecx, 24(%[save])\n\t"
+
+ /* Must restore %edi last as it is also our %[save] register. */
+ "movl 16(%[save]), %%ecx\n\t"
+ "movl %%edi, 16(%[save])\n\t"
+ "movl %%ecx, %%edi\n\t"
+
+ "jmp *%%eax\n"
+ /*
+ Come here when operation is done.
+ Be sure to use the same callee-save register for %[save] here and in
+ my_context_spawn(), so we preserve the value correctly at this point.
+ */
+ "2:\n\t"
+ "movl (%[save]), %%esp\n\t"
+ "movl 4(%[save]), %%ebp\n\t"
+ "movl 8(%[save]), %%ebx\n\t"
+ "movl 12(%[save]), %%esi\n\t"
+ "movl 16(%[save]), %%edi\n\t"
+ "xorl %[ret], %[ret]\n\t"
+ "jmp 4f\n"
+ /* Come here when operation is suspended. */
+ "3:\n\t"
+ "movl $1, %[ret]\n"
+ "4:\n"
+ : [ret] "=a" (ret)
+ : /* Need this in callee-save register to preserve in function call. */
+ [save] "D" (&c->save[0])
+ : "ecx", "edx", "memory", "cc"
+ );
+
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+
+ return ret;
+}
+
+int
+my_context_yield(struct my_context *c)
+{
+ uint64_t *save= &c->save[0];
+ __asm__ __volatile__
+ (
+ "movl (%[save]), %%eax\n\t"
+ "movl %%esp, (%[save])\n\t"
+ "movl %%eax, %%esp\n\t"
+ "movl 4(%[save]), %%eax\n\t"
+ "movl %%ebp, 4(%[save])\n\t"
+ "movl %%eax, %%ebp\n\t"
+ "movl 8(%[save]), %%eax\n\t"
+ "movl %%ebx, 8(%[save])\n\t"
+ "movl %%eax, %%ebx\n\t"
+ "movl 12(%[save]), %%eax\n\t"
+ "movl %%esi, 12(%[save])\n\t"
+ "movl %%eax, %%esi\n\t"
+ "movl 16(%[save]), %%eax\n\t"
+ "movl %%edi, 16(%[save])\n\t"
+ "movl %%eax, %%edi\n\t"
+
+ "movl 24(%[save]), %%eax\n\t"
+ "call 1f\n"
+ "1:\n\t"
+ "popl %%ecx\n\t"
+ "addl $(2f-1b), %%ecx\n\t"
+ "movl %%ecx, 24(%[save])\n\t"
+
+ "jmp *%%eax\n"
+
+ "2:\n"
+ : [save] "+d" (save)
+ :
+ : "eax", "ecx", "memory", "cc"
+ );
+ return 0;
+}
+
+int
+my_context_init(struct my_context *c, size_t stack_size)
+{
+ bzero(c, sizeof(*c));
+ if (!(c->stack_bot= malloc(stack_size)))
+ return -1; /* Out of memory */
+ c->stack_top= (void *)
+ (( ((intptr)c->stack_bot + stack_size) & ~(intptr)0xf) - 16);
+ bzero(c->stack_top, 16);
+
+#ifdef HAVE_VALGRIND
+ c->valgrind_stack_id=
+ VALGRIND_STACK_REGISTER(c->stack_bot, c->stack_top);
+#endif
+ return 0;
+}
+
+void
+my_context_destroy(struct my_context *c)
+{
+ if (c->stack_bot)
+ {
+ free(c->stack_bot);
+#ifdef HAVE_VALGRIND
+ VALGRIND_STACK_DEREGISTER(c->valgrind_stack_id);
+#endif
+ }
+ DBUG_FREE_CODE_STATE(&c->dbug_state);
+}
+
+#endif /* MY_CONTEXT_USE_I386_GCC_ASM */
+
+
+#ifdef MY_CONTEXT_USE_WIN32_FIBERS
+int
+my_context_yield(struct my_context *c)
+{
+ c->return_value= 1;
+ SwitchToFiber(c->app_fiber);
+ return 0;
+}
+
+
+static void WINAPI
+my_context_trampoline(void *p)
+{
+ struct my_context *c= (struct my_context *)p;
+ /*
+ Reuse the Fiber by looping infinitely, each time we are scheduled we
+ spawn the appropriate function and switch back when it is done.
+
+ This way we avoid the overhead of CreateFiber() for every asynchroneous
+ operation.
+ */
+ for(;;)
+ {
+ (*(c->user_func))(c->user_arg);
+ c->return_value= 0;
+ SwitchToFiber(c->app_fiber);
+ }
+}
+
+int
+my_context_init(struct my_context *c, size_t stack_size)
+{
+ bzero(c, sizeof(*c));
+ c->lib_fiber= CreateFiber(stack_size, my_context_trampoline, c);
+ if (c->lib_fiber)
+ return 0;
+ return -1;
+}
+
+void
+my_context_destroy(struct my_context *c)
+{
+ DBUG_FREE_CODE_STATE(&c->dbug_state);
+ if (c->lib_fiber)
+ {
+ DeleteFiber(c->lib_fiber);
+ c->lib_fiber= NULL;
+ }
+}
+
+int
+my_context_spawn(struct my_context *c, void (*f)(void *), void *d)
+{
+ void *current_fiber;
+ c->user_func= f;
+ c->user_arg= d;
+ /*
+ This seems to be a common trick to run ConvertThreadToFiber() only on the
+ first occurence in a thread, in a way that works on multiple Windows
+ versions.
+ */
+ current_fiber= GetCurrentFiber();
+ if (current_fiber == NULL || current_fiber == (void *)0x1e00)
+ current_fiber= ConvertThreadToFiber(c);
+ c->app_fiber= current_fiber;
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+ SwitchToFiber(c->lib_fiber);
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+ return c->return_value;
+}
+
+int
+my_context_continue(struct my_context *c)
+{
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+ SwitchToFiber(c->lib_fiber);
+ DBUG_SWAP_CODE_STATE(&c->dbug_state);
+ return c->return_value;
+}
+
+#endif /* MY_CONTEXT_USE_WIN32_FIBERS */
diff --git a/mysys/my_init.c b/mysys/my_init.c
index abb0c0d7824..bb72d0e0426 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates
+ Copyright (c) 2009, 2011, Monty Program 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
diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c
index 30c9fafcb82..db51195db25 100644
--- a/mysys/stacktrace.c
+++ b/mysys/stacktrace.c
@@ -163,7 +163,7 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
my_safe_printf_stderr("%s",
"Error when traversing the stack, stack appears corrupt.\n");
else
- my_safe_printf_stderr("%s"
+ my_safe_printf_stderr("%s",
"Please read "
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n"
@@ -499,10 +499,11 @@ static void add_to_symbol_path(char *path, size_t path_buffer_size,
}
/*
- Get symbol path - semicolon-separated list of directories to search for debug
- symbols. We expect PDB in the same directory as corresponding exe or dll,
- so the path is build from directories of the loaded modules. If environment
- variable _NT_SYMBOL_PATH is set, it's value appended to the symbol search path
+ Get symbol path - semicolon-separated list of directories to search
+ for debug symbols. We expect PDB in the same directory as
+ corresponding exe or dll, so the path is build from directories of
+ the loaded modules. If environment variable _NT_SYMBOL_PATH is set,
+ it's value appended to the symbol search path
*/
static void get_symbol_path(char *path, size_t size)
{
@@ -640,9 +641,9 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
if(!have_module)
{
/*
- ModuleInfo structure has been "compatibly" extended in releases after XP,
- and its size was increased. To make XP dbghelp.dll function
- happy, pretend passing the old structure.
+ ModuleInfo structure has been "compatibly" extended in
+ releases after XP, and its size was increased. To make XP
+ dbghelp.dll function happy, pretend passing the old structure.
*/
module.SizeOfStruct= MODULE64_SIZE_WINXP;
have_module= SymGetModuleInfo64(hProcess, addr, &module);
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index c3a99d78d25..e99956f9c8f 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates
+ Copyright (c) 2012, Monty Program 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
@@ -176,7 +177,8 @@ thr_lock_owner_equal(THR_LOCK_INFO *rhs, THR_LOCK_INFO *lhs)
static uint found_errors=0;
static int check_lock(struct st_lock_list *list, const char* lock_type,
- const char *where, my_bool same_owner, my_bool no_cond)
+ const char *where, my_bool same_owner, my_bool no_cond,
+ my_bool read_lock)
{
THR_LOCK_DATA *data,**prev;
uint count=0;
@@ -189,6 +191,23 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
{
+ if (data->type == TL_UNLOCK)
+ {
+ fprintf(stderr,
+ "Warning: Found unlocked lock at %s: %s\n",
+ lock_type, where);
+ return 1;
+ }
+ if ((read_lock && data->type > TL_READ_NO_INSERT) ||
+ (!read_lock && data->type <= TL_READ_NO_INSERT))
+ {
+ fprintf(stderr,
+ "Warning: Found %s lock in %s queue at %s: %s\n",
+ read_lock ? "write" : "read",
+ read_lock ? "read" : "write",
+ lock_type, where);
+ return 1;
+ }
if (data->type != last_lock_type)
last_lock_type=TL_IGNORE;
if (data->prev != prev)
@@ -245,11 +264,14 @@ static void check_locks(THR_LOCK *lock, const char *where,
if (found_errors < MAX_FOUND_ERRORS)
{
- if (check_lock(&lock->write,"write",where,1,1) |
- check_lock(&lock->write_wait,"write_wait",where,0,0) |
- check_lock(&lock->read,"read",where,0,1) |
- check_lock(&lock->read_wait,"read_wait",where,0,0))
+ if (check_lock(&lock->write,"write",where,1,1,0) |
+ check_lock(&lock->write_wait,"write_wait",where,0,0,0) |
+ check_lock(&lock->read,"read",where,0,1,1) |
+ check_lock(&lock->read_wait,"read_wait",where,0,0,1))
+ {
+ DBUG_ASSERT(my_assert_on_error == 0);
found_errors++;
+ }
if (found_errors < MAX_FOUND_ERRORS)
{
@@ -625,17 +647,16 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
static enum enum_thr_lock_result
-thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner,
- enum thr_lock_type lock_type, ulong lock_wait_timeout)
+thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
{
THR_LOCK *lock=data->lock;
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
struct st_lock_list *wait_queue;
+ enum thr_lock_type lock_type= data->type;
DBUG_ENTER("thr_lock");
data->next=0;
data->cond=0; /* safety */
- data->type=lock_type;
data->owner= owner; /* Must be reset ! */
data->priority&= ~THR_LOCK_LATE_PRIV;
mysql_mutex_lock(&lock->mutex);
@@ -968,9 +989,7 @@ void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags)
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count--;
data->type=TL_UNLOCK; /* Mark unlocked */
- check_locks(lock,"after releasing lock", lock_type, 1);
wake_up_waiters(lock);
- check_locks(lock,"end of thr_unlock", lock_type, 1);
mysql_mutex_unlock(&lock->mutex);
DBUG_VOID_RETURN;
}
@@ -990,6 +1009,7 @@ static void wake_up_waiters(THR_LOCK *lock)
enum thr_lock_type lock_type;
DBUG_ENTER("wake_up_waiters");
+ check_locks(lock, "before waking up waiters", TL_UNLOCK, 1);
if (!lock->write.data) /* If no active write locks */
{
data=lock->write_wait.data;
@@ -1144,8 +1164,7 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_INFO *owner,
/* lock everything */
for (pos=data,end=data+count; pos < end ; pos++)
{
- enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type,
- lock_wait_timeout);
+ enum enum_thr_lock_result result= thr_lock(*pos, owner, lock_wait_timeout);
if (result != THR_LOCK_SUCCESS)
{ /* Aborted */
thr_multi_unlock(data,(uint) (pos-data), 0);
diff --git a/mysys/wqueue.c b/mysys/wqueue.c
index b6f52ba5c31..2fcced14f77 100644
--- a/mysys/wqueue.c
+++ b/mysys/wqueue.c
@@ -1,3 +1,19 @@
+/*
+ Copyright (c) 2007, 2008, Sun Microsystems, Inc,
+ Copyright (c) 2011, 2012, Monty Program 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 */
#include <wqueue.h>