From 005e305c226770deef7cdfcd4c03b857f96687ff Mon Sep 17 00:00:00 2001 From: Vijay Pai <vpai@google.com> Date: Fri, 10 Jul 2015 15:18:45 -0700 Subject: [PATCH] Initial checkin commit for lockfree stack. Tests not yet included. --- BUILD | 4 + Makefile | 1 + build.json | 2 + gRPC.podspec | 3 + src/core/support/stack_lockfree.c | 130 +++++++++++++++++++++++ src/core/support/stack_lockfree.h | 50 +++++++++ tools/doxygen/Doxyfile.core.internal | 2 + tools/run_tests/sources_and_headers.json | 3 + vsprojects/gpr/gpr.vcxproj | 3 + vsprojects/gpr/gpr.vcxproj.filters | 6 ++ 10 files changed, 204 insertions(+) create mode 100644 src/core/support/stack_lockfree.c create mode 100644 src/core/support/stack_lockfree.h diff --git a/BUILD b/BUILD index da9866df81..a375b04cb5 100644 --- a/BUILD +++ b/BUILD @@ -47,6 +47,7 @@ cc_library( "src/core/support/env.h", "src/core/support/file.h", "src/core/support/murmur_hash.h", + "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h", @@ -73,6 +74,7 @@ cc_library( "src/core/support/murmur_hash.c", "src/core/support/slice.c", "src/core/support/slice_buffer.c", + "src/core/support/stack_lockfree.c", "src/core/support/string.c", "src/core/support/string_posix.c", "src/core/support/string_win32.c", @@ -873,6 +875,7 @@ objc_library( "src/core/support/murmur_hash.c", "src/core/support/slice.c", "src/core/support/slice_buffer.c", + "src/core/support/stack_lockfree.c", "src/core/support/string.c", "src/core/support/string_posix.c", "src/core/support/string_win32.c", @@ -920,6 +923,7 @@ objc_library( "src/core/support/env.h", "src/core/support/file.h", "src/core/support/murmur_hash.h", + "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h", diff --git a/Makefile b/Makefile index f1c99a909d..0b4c889fd8 100644 --- a/Makefile +++ b/Makefile @@ -3100,6 +3100,7 @@ LIBGPR_SRC = \ src/core/support/murmur_hash.c \ src/core/support/slice.c \ src/core/support/slice_buffer.c \ + src/core/support/stack_lockfree.c \ src/core/support/string.c \ src/core/support/string_posix.c \ src/core/support/string_win32.c \ diff --git a/build.json b/build.json index 2a11275636..6b6a7866c9 100644 --- a/build.json +++ b/build.json @@ -373,6 +373,7 @@ "src/core/support/env.h", "src/core/support/file.h", "src/core/support/murmur_hash.h", + "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h" @@ -401,6 +402,7 @@ "src/core/support/murmur_hash.c", "src/core/support/slice.c", "src/core/support/slice_buffer.c", + "src/core/support/stack_lockfree.c", "src/core/support/string.c", "src/core/support/string_posix.c", "src/core/support/string_win32.c", diff --git a/gRPC.podspec b/gRPC.podspec index 921a4ab096..2df6f5132c 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -64,6 +64,7 @@ Pod::Spec.new do |s| ss.source_files = 'src/core/support/env.h', 'src/core/support/file.h', 'src/core/support/murmur_hash.h', + 'src/core/support/stack_lockfree.h', 'src/core/support/grpc_string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', @@ -118,6 +119,7 @@ Pod::Spec.new do |s| 'src/core/support/murmur_hash.c', 'src/core/support/slice.c', 'src/core/support/slice_buffer.c', + 'src/core/support/stack_lockfree.c', 'src/core/support/string.c', 'src/core/support/string_posix.c', 'src/core/support/string_win32.c', @@ -389,6 +391,7 @@ Pod::Spec.new do |s| ss.private_header_files = 'src/core/support/env.h', 'src/core/support/file.h', 'src/core/support/murmur_hash.h', + 'src/core/support/stack_lockfree.h', 'src/core/support/string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c new file mode 100644 index 0000000000..4d6a75cd33 --- /dev/null +++ b/src/core/support/stack_lockfree.c @@ -0,0 +1,130 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/support/stack_lockfree.h" + +#include <stdlib.h> +#include <string.h> + +#include <grpc/support/port_platform.h> +#include <grpc/support/alloc.h> +#include <grpc/support/atm.h> +#include <grpc/support/log.h> + +/* The lockfree node structure is a single architecture-level + word that allows for an atomic CAS to set it up. */ +struct lockfree_node_contents { + /* next thing to look at. Actual index for head, next index otherwise */ + gpr_uint16 index; +#ifdef GPR_ARCH_64 + gpr_uint16 pad; + gpr_uint32 aba_ctr; +#else +#ifdef GPR_ARCH_32 + gpr_uint16 aba_ctr; +#else +#error Unsupported bit width architecture +#endif +#endif +}; + +/* Use a union to make sure that these are in the same bits as an atm word */ +typedef union lockfree_node { + gpr_atm atm; + struct lockfree_node_contents contents; +} lockfree_node; + +#define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */ +#define INVALID_ENTRY_INDEX ((1<<16)-1) /* reserve this entry as invalid */ + +struct gpr_stack_lockfree { + lockfree_node *entries; + lockfree_node head; /* An atomic entry describing curr head */ +}; + +gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) { + gpr_stack_lockfree *stack; + stack = gpr_malloc(sizeof(*stack)); + /* Since we only allocate 16 bits to represent an entry number, + * make sure that we are within the desired range */ + /* Reserve the highest entry number as a dummy */ + GPR_ASSERT(entries < INVALID_ENTRY_INDEX); + stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]), + ENTRY_ALIGNMENT_BITS); + /* Clear out all entries */ + memset(stack->entries, 0, entries * sizeof(stack->entries[0])); + + /* Point the head at reserved dummy entry */ + stack->head.contents.index = INVALID_ENTRY_INDEX; + return stack; +} + +void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) { + gpr_free_aligned(stack->entries); + gpr_free(stack); +} + +void gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) { + lockfree_node head; + lockfree_node newhead; + + /* First fill in the entry's index and aba ctr for new head */ + newhead.contents.index = (gpr_uint16)entry; + /* Also post-increment the aba_ctr */ + newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++; + + do { + /* Atomically get the existing head value for use */ + head.atm = gpr_atm_no_barrier_load(&(stack->head.atm)); + /* Point to it */ + stack->entries[entry].contents.index = head.contents.index; + } while (!gpr_atm_rel_cas(&(stack->head.atm), + head.atm, newhead.atm)); + /* Use rel_cas above to make sure that entry index is set properly */ +} + +int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) { + lockfree_node head; + lockfree_node newhead; + do { + head.atm = gpr_atm_acq_load(&(stack->head.atm)); + if (head.contents.index == INVALID_ENTRY_INDEX) { + return -1; + } + newhead.contents.index = stack->entries[head.contents.index].contents.index; + + } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), + head.atm, + newhead.atm)); + return newhead.contents.index; +} diff --git a/src/core/support/stack_lockfree.h b/src/core/support/stack_lockfree.h new file mode 100644 index 0000000000..7919ef38cc --- /dev/null +++ b/src/core/support/stack_lockfree.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H +#define GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H + +typedef struct gpr_stack_lockfree gpr_stack_lockfree; + +/* This stack must specify the maximum number of entries to track. + The current implementation only allows up to 65534 entries */ +gpr_stack_lockfree *gpr_stack_lockfree_create(int entries); +void gpr_stack_lockfree_destroy(gpr_stack_lockfree *); + +/* Pass in a valid entry number for the next stack entry */ +void gpr_stack_lockfree_push(gpr_stack_lockfree *, int entry); + +/* Returns -1 on empty or the actual entry number */ +int gpr_stack_lockfree_pop(gpr_stack_lockfree *); + +#endif /* GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H */ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index ac411e3c02..3e57dbdff1 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1044,6 +1044,7 @@ include/grpc/support/useful.h \ src/core/support/env.h \ src/core/support/file.h \ src/core/support/murmur_hash.h \ +src/core/support/stack_lockfree.h \ src/core/support/string.h \ src/core/support/string_win32.h \ src/core/support/thd_internal.h \ @@ -1070,6 +1071,7 @@ src/core/support/log_win32.c \ src/core/support/murmur_hash.c \ src/core/support/slice.c \ src/core/support/slice_buffer.c \ +src/core/support/stack_lockfree.c \ src/core/support/string.c \ src/core/support/string_posix.c \ src/core/support/string_win32.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index 3f13b7b9ad..9297a35d9a 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -8595,6 +8595,7 @@ "src/core/support/env.h", "src/core/support/file.h", "src/core/support/murmur_hash.h", + "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h" @@ -8656,6 +8657,8 @@ "src/core/support/murmur_hash.h", "src/core/support/slice.c", "src/core/support/slice_buffer.c", + "src/core/support/stack_lockfree.c", + "src/core/support/stack_lockfree.h", "src/core/support/string.c", "src/core/support/string.h", "src/core/support/string_posix.c", diff --git a/vsprojects/gpr/gpr.vcxproj b/vsprojects/gpr/gpr.vcxproj index 3e6bb2036e..32a08a2321 100644 --- a/vsprojects/gpr/gpr.vcxproj +++ b/vsprojects/gpr/gpr.vcxproj @@ -179,6 +179,7 @@ <ClInclude Include="..\..\src\core\support\env.h" /> <ClInclude Include="..\..\src\core\support\file.h" /> <ClInclude Include="..\..\src\core\support\murmur_hash.h" /> + <ClInclude Include="..\..\src\core\support\stack_lockfree.h" /> <ClInclude Include="..\..\src\core\support\string.h" /> <ClInclude Include="..\..\src\core\support\string_win32.h" /> <ClInclude Include="..\..\src\core\support\thd_internal.h" /> @@ -230,6 +231,8 @@ </ClCompile> <ClCompile Include="..\..\src\core\support\slice_buffer.c"> </ClCompile> + <ClCompile Include="..\..\src\core\support\stack_lockfree.c"> + </ClCompile> <ClCompile Include="..\..\src\core\support\string.c"> </ClCompile> <ClCompile Include="..\..\src\core\support\string_posix.c"> diff --git a/vsprojects/gpr/gpr.vcxproj.filters b/vsprojects/gpr/gpr.vcxproj.filters index a270902236..ace549fa45 100644 --- a/vsprojects/gpr/gpr.vcxproj.filters +++ b/vsprojects/gpr/gpr.vcxproj.filters @@ -70,6 +70,9 @@ <ClCompile Include="..\..\src\core\support\slice_buffer.c"> <Filter>src\core\support</Filter> </ClCompile> + <ClCompile Include="..\..\src\core\support\stack_lockfree.c"> + <Filter>src\core\support</Filter> + </ClCompile> <ClCompile Include="..\..\src\core\support\string.c"> <Filter>src\core\support</Filter> </ClCompile> @@ -209,6 +212,9 @@ <ClInclude Include="..\..\src\core\support\murmur_hash.h"> <Filter>src\core\support</Filter> </ClInclude> + <ClInclude Include="..\..\src\core\support\stack_lockfree.h"> + <Filter>src\core\support</Filter> + </ClInclude> <ClInclude Include="..\..\src\core\support\string.h"> <Filter>src\core\support</Filter> </ClInclude> -- GitLab