├── .travis.yml
├── appveyor.yml
├── cmake_uninstall.cmake.in
├── lfstack_vs
├── lfstack_vs.vcxproj.filters
├── lfstack_vs.sln
└── lfstack_vs.vcxproj
├── LICENSE
├── test.cpp
├── lfstack.dev
├── example_wins.c
├── CMakeLists.txt
├── README.md
├── lfstack.h
├── example.c
└── lfstack.c
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 |
3 | compiler:
4 | - gcc
5 | - clang
6 |
7 | before_script:
8 | - mkdir build
9 | - cd build
10 | - cmake ..
11 |
12 | script: make && make test
13 |
14 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0.{build}
2 | configuration: Release
3 | platform:
4 | - x86
5 | - x64
6 | build:
7 | verbosity: minimal
8 | after_build:
9 | - cmd: IF "%PLATFORM%"=="x64" ( C:\projects\lfstack\lfstack_vs\%PLATFORM%\Release\lfstack_vs.exe ) ELSE ( C:\projects\lfstack\lfstack_vs\Release\lfstack_vs.exe )
--------------------------------------------------------------------------------
/cmake_uninstall.cmake.in:
--------------------------------------------------------------------------------
1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
4 |
5 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
6 | string(REGEX REPLACE "\n" ";" files "${files}")
7 | foreach(file ${files})
8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
9 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
10 | exec_program(
11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
12 | OUTPUT_VARIABLE rm_out
13 | RETURN_VALUE rm_retval
14 | )
15 | if(NOT "${rm_retval}" STREQUAL 0)
16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
17 | endif(NOT "${rm_retval}" STREQUAL 0)
18 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
20 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
21 | endforeach(file)
--------------------------------------------------------------------------------
/lfstack_vs/lfstack_vs.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 |
26 |
27 | Header Files
28 |
29 |
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2018, Taymindis Woon
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/test.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "lfstack.h"
10 |
11 |
12 | lfstack_t results;
13 |
14 | void *worker(void *arg)
15 | {
16 | int i = 10000;
17 | long long *int_data;
18 | while (i--) {
19 | int_data = (long long*) malloc(sizeof(long long));
20 | assert(int_data != NULL);
21 | *int_data = i;
22 | while (lfstack_push(&results, int_data) == -1) ;
23 |
24 | while ( (int_data =(long long*) lfstack_pop(&results)) == NULL);
25 |
26 | free(int_data);
27 |
28 | }
29 |
30 | return NULL;
31 | }
32 |
33 | TEST(lfstackTest, CROSS_THREAD_MAIN_CALL) {
34 | int nthreads = sysconf(_SC_NPROCESSORS_ONLN); // Linux
35 | int i;
36 |
37 | lfstack_init(&results);
38 |
39 | /* Spawn threads. */
40 | pthread_t threads[nthreads];
41 | printf("Using %d thread%s.\n", nthreads, nthreads == 1 ? "" : "s");
42 | for (i = 0; i < nthreads; i++)
43 | pthread_create(threads + i, NULL, worker, NULL);
44 |
45 |
46 | for (i = 0; i < nthreads; i++)
47 | pthread_join(threads[i], NULL);
48 |
49 | lfstack_destroy(&results);
50 | }
51 |
52 | int main(int argc, char **argv) {
53 | ::testing::InitGoogleTest(&argc, argv);
54 | return RUN_ALL_TESTS();
55 | }
56 |
--------------------------------------------------------------------------------
/lfstack.dev:
--------------------------------------------------------------------------------
1 | [Project]
2 | FileName=lfstack.dev
3 | Name=lfstack
4 | Type=1
5 | Ver=2
6 | ObjFiles=
7 | Includes=
8 | Libs=
9 | PrivateResource=
10 | ResourceIncludes=
11 | MakeIncludes=
12 | Compiler=
13 | CppCompiler=
14 | Linker=
15 | IsCpp=0
16 | Icon=
17 | ExeOutput=
18 | ObjectOutput=
19 | LogOutput=
20 | LogOutputEnabled=0
21 | OverrideOutput=0
22 | OverrideOutputName=
23 | HostApplication=
24 | UseCustomMakefile=0
25 | CustomMakefile=
26 | CommandLine=
27 | Folders=
28 | IncludeVersionInfo=0
29 | SupportXPThemes=0
30 | CompilerSet=1
31 | CompilerSettings=0000000000000000001000000
32 | UnitCount=3
33 |
34 | [VersionInfo]
35 | Major=1
36 | Minor=0
37 | Release=0
38 | Build=0
39 | LanguageID=1033
40 | CharsetID=1252
41 | CompanyName=
42 | FileVersion=
43 | FileDescription=Developed using the Dev-C++ IDE
44 | InternalName=
45 | LegalCopyright=
46 | LegalTrademarks=
47 | OriginalFilename=
48 | ProductName=
49 | ProductVersion=
50 | AutoIncBuildNr=0
51 | SyncProduct=1
52 |
53 | [Unit1]
54 | FileName=example.c
55 | CompileCpp=0
56 | Folder=
57 | Compile=1
58 | Link=1
59 | Priority=1000
60 | OverrideBuildCmd=0
61 | BuildCmd=
62 |
63 | [Unit2]
64 | FileName=lfstack.c
65 | CompileCpp=0
66 | Folder=
67 | Compile=1
68 | Link=1
69 | Priority=1000
70 | OverrideBuildCmd=0
71 | BuildCmd=
72 |
73 | [Unit3]
74 | FileName=lfstack.h
75 | CompileCpp=0
76 | Folder=
77 | Compile=1
78 | Link=1
79 | Priority=1000
80 | OverrideBuildCmd=0
81 | BuildCmd=
82 |
83 |
--------------------------------------------------------------------------------
/lfstack_vs/lfstack_vs.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2042
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lfstack_vs", "lfstack_vs.vcxproj", "{C08C7611-D4DA-4FBE-8808-3E474223F691}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x64.ActiveCfg = Debug|x64
17 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x64.Build.0 = Debug|x64
18 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x86.ActiveCfg = Debug|Win32
19 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Debug|x86.Build.0 = Debug|Win32
20 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x64.ActiveCfg = Release|x64
21 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x64.Build.0 = Release|x64
22 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x86.ActiveCfg = Release|Win32
23 | {C08C7611-D4DA-4FBE-8808-3E474223F691}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {A5B792B3-4685-4389-B1E4-C8BA4F94A888}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/example_wins.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "lfstack.h"
7 | #include
8 | #include
9 |
10 | struct timeval tv1, tv2;
11 | lfstack_t mystack;
12 |
13 | #define nthreads 8
14 | #define total_put 50000
15 |
16 | unsigned __stdcall worker(void *);
17 | unsigned __stdcall worker(void *arg)
18 | {
19 | int i = 0;
20 | int *int_data;
21 | while (i < total_put) {
22 | int_data = (int*)malloc(sizeof(int));
23 | assert(int_data != NULL);
24 | *int_data = i++;
25 | while (lfstack_push(&mystack, int_data)) {
26 | printf("ENQ FULL?\n");
27 | }
28 |
29 | while ((int_data = lfstack_pop(&mystack)) == NULL) {
30 | // usleep(1000);
31 | printf("POP EMPTY?\n");
32 | }
33 | free(int_data);
34 | }
35 | return 0;
36 | }
37 |
38 | #define join_threads \
39 | for (i = 0; i < nthreads; i++){\
40 | WaitForSingleObject(threads[i], INFINITE);\
41 | }
42 | /*
43 | #define detach_thread_and_loop \
44 | for (i = 0; i < nthreads; i++)\
45 | pthread_detach(threads[i]);\
46 | while (1) {\
47 | sleep(2);\
48 | printf("current size= %zu\n", lfstack_size(&mystack) );\
49 | }*/
50 |
51 |
52 | int main(void)
53 | {
54 | //const static int nthreads = 2;//sysconf(_SC_NPROCESSORS_ONLN); // Linux
55 | int i, n;
56 | if (lfstack_init(&mystack) == -1)
57 | return -1;
58 |
59 | for (n = 0; n < 100; n++) {
60 | /* Spawn threads. */
61 | printf("Current running at %d, Total threads = %d\n", n, nthreads);
62 | clock_t start = clock();
63 | HANDLE threads[nthreads];
64 |
65 | for (i = 0; i < nthreads; i++) {
66 | unsigned udpthreadid;
67 | threads[i] = (HANDLE)_beginthreadex(NULL, 0, worker, NULL, 0, &udpthreadid);
68 | }
69 |
70 | join_threads;
71 | // detach_thread_and_loop;
72 |
73 | clock_t end = clock();
74 |
75 | printf("Total time = %f seconds\n", (float)(end - start) / CLOCKS_PER_SEC);
76 |
77 | assert(0 == lfstack_size(&mystack) && "Error, all queue should be consumed but not");
78 |
79 | }
80 | printf("Take a 4 seconds sleep \n");
81 | Sleep(4000);
82 | printf("Flush all the inactive memory \n");
83 | lfstack_flush(&mystack);
84 | //printf("Press Any Key to Continue\n");
85 | lfstack_destroy(&mystack);
86 | return 0;
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 | project(lfstack)
3 |
4 | set(PROJNAME lfstack)
5 |
6 | IF (NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
7 | SET(CMAKE_INSTALL_INCLUDEDIR /usr/local/include)
8 | ENDIF(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
9 |
10 | file(GLOB_RECURSE sources lfstack.c lfstack.h)
11 | file(GLOB_RECURSE sources_test test.cpp)
12 | file(GLOB_RECURSE example_test lfstack.c lfstack.h example.c)
13 |
14 | enable_testing()
15 | add_executable(lfstack-example ${example_test})
16 | target_link_libraries(lfstack-example PUBLIC pthread)
17 |
18 | include_directories(src /usr/local/include)
19 |
20 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Wstrict-prototypes -Wmissing-prototypes")
21 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual")
22 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare -std=c11 -pedantic")
23 |
24 |
25 | ###############################################################################
26 | ## packaging ##################################################################
27 | ###############################################################################
28 | add_library(${PROJNAME}.static STATIC ${sources})
29 | target_link_libraries(${PROJNAME}.static)
30 | set_target_properties(${PROJNAME}.static PROPERTIES OUTPUT_NAME ${PROJNAME})
31 | add_library(${PROJNAME} SHARED ${sources})
32 | target_link_libraries(${PROJNAME})
33 | add_test (NAME lfstack_test COMMAND lfstack-example)
34 |
35 |
36 | # link_directories(/usr/local/lib /usr/lib)
37 |
38 | ## For .a library
39 | install(TARGETS ${PROJNAME}.static EXPORT ${PROJNAME}
40 | ARCHIVE DESTINATION lib${LIB_SUFFIX}
41 | LIBRARY DESTINATION lib${LIB_SUFFIX}
42 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
43 | )
44 |
45 | ## For .so library
46 | install(TARGETS ${PROJNAME} EXPORT ${PROJNAME}
47 | ARCHIVE DESTINATION lib${LIB_SUFFIX}
48 | LIBRARY DESTINATION lib${LIB_SUFFIX}
49 | # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
50 | )
51 | install(FILES lfstack.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lfsaq)
52 |
53 | install(CODE "execute_process(COMMAND ldconfig)")
54 |
55 | configure_file(
56 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
57 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
58 | IMMEDIATE @ONLY)
59 |
60 | add_custom_target(uninstall
61 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
62 |
63 | set(CPACK_PACKAGE_NAME "lfstack")
64 | set(CPACK_PACKAGE_VERSION "1.0.0")
65 |
66 | # we don't want to split our program up into several things
67 | set(CPACK_MONOLITHIC_INSTALL 1)
68 |
69 | # This must be last
70 | include(CPack)
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lfstack [](https://travis-ci.org/Taymindis/lfstack)
2 |
3 | lock-free LIFO stack by C native built it, easy built cross platform(no extra dependencies needed) , guarantee thread safety memory management ever!
4 |
5 | # All Platform tests
6 |
7 | GCC/CLANG | [](https://travis-ci.org/Taymindis/lfstack)
8 |
9 | VS x64/x86 | [](https://ci.appveyor.com/project/Taymindis/lfstack/branch/master)
10 |
11 |
12 | ## API
13 | ```c
14 |
15 | extern int lfstack_init(lfstack_t *lfstack);
16 | extern int lfstack_push(lfstack_t *lfstack, void *value);
17 | extern void* lfstack_pop(lfstack_t *lfstack);
18 | extern void* lfstack_single_pop(lfstack_t *lfstack);
19 | extern void lfstack_destroy(lfstack_t *lfstack);
20 | extern size_t lfstack_size(lfstack_t *lfstack);
21 | extern void lfstack_sleep(unsigned int milisec);
22 |
23 | ```
24 |
25 |
26 | ## Example
27 |
28 | ```c
29 |
30 | int* int_data;
31 | lfstack_t mystack;
32 |
33 | if (lfstack_init(&mystack) == -1)
34 | return -1;
35 |
36 | /** Wrap This scope in other threads **/
37 | int_data = (int*) malloc(sizeof(int));
38 | assert(int_data != NULL);
39 | *int_data = i++;
40 | /*PUSH*/
41 | while (lfstack_push(&mystack, int_data) == -1) {
42 | printf("ENQ Full ?\n");
43 | }
44 |
45 | /** Wrap This scope in other threads **/
46 | /*POP*/
47 | while ( (int_data = lfstack_pop(&mystack)) == NULL) {
48 | printf("POP EMPTY ..\n");
49 | }
50 |
51 | // printf("%d\n", *(int*) int_data );
52 | free(int_data);
53 | /** End **/
54 |
55 | lfstack_destroy(&mystack);
56 |
57 | ```
58 |
59 |
60 | #### If you are using single thread POP. Please use `lfstack_single_pop` to get better performance
61 |
62 |
63 | ## Build and Installation
64 |
65 | For linux OS, you may use cmake build, for other platforms, please kindly include the source code and header file into the project, e.g. VS2017, DEV-C++, Xcode
66 |
67 | ```bash
68 | mkdir build
69 |
70 | cd build
71 |
72 | cmake ..
73 |
74 | make
75 |
76 | ./lfstack-example
77 |
78 | valgrind --tool=memcheck --leak-check=full ./lfstack-example
79 |
80 | sudo make install
81 |
82 |
83 | ```
84 |
85 | ## continuously Test
86 |
87 | For continuously test until N number, if you having any issue while testing, please kindly raise an issue
88 |
89 | ```bash
90 |
91 | ./keep-testing.sh
92 |
93 | ```
94 |
95 |
96 | ## Uninstallation
97 |
98 | ```bash
99 | cd build
100 |
101 | sudo make uninstall
102 |
103 | ```
104 |
105 |
106 | ## You may also like lock free queue FIFO
107 |
108 | [lfqueue](https://github.com/Taymindis/lfqueue)
--------------------------------------------------------------------------------
/lfstack.h:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * BSD 2-Clause License
4 | *
5 | * Copyright (c) 2018, Taymindis Woon
6 | * All rights reserved.
7 | *
8 | * Redistribution and use in source and binary forms, with or without
9 | * modification, are permitted provided that the following conditions are met:
10 | *
11 | * * Redistributions of source code must retain the above copyright notice, this
12 | * list of conditions and the following disclaimer.
13 | *
14 | * * Redistributions in binary form must reproduce the above copyright notice,
15 | * this list of conditions and the following disclaimer in the documentation
16 | * and/or other materials provided with the distribution.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | *
29 | */
30 |
31 | #ifndef LFSTACK_H
32 | #define LFSTACK_H
33 |
34 | #include
35 | #include
36 |
37 | #ifdef __cplusplus
38 | extern "C" {
39 | #endif
40 |
41 | typedef struct lfstack_cas_node_s lfstack_cas_node_t;
42 | typedef void* (*lfstack_malloc_fn)(void*, size_t);
43 | typedef void (*lfstack_free_fn)(void*, void*);
44 |
45 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
46 | #define lfs_bool_t int
47 | #else
48 | #ifdef _WIN64
49 | #define lfs_bool_t int64_t
50 | #else
51 | #define lfs_bool_t int
52 | #endif
53 | #endif
54 |
55 | typedef struct {
56 | lfstack_cas_node_t *head, *root_free, *move_free;
57 | volatile size_t size;
58 | volatile lfs_bool_t in_free_mode;
59 | lfstack_malloc_fn _malloc;
60 | lfstack_free_fn _free;
61 | void *pl;
62 | } lfstack_t;
63 |
64 | extern int lfstack_init(lfstack_t *lfstack);
65 | extern int lfstack_init_mf(lfstack_t *lfs, void* pl, lfstack_malloc_fn lfs_malloc, lfstack_free_fn lfs_free);
66 | extern int lfstack_push(lfstack_t *lfstack, void *value);
67 | extern void* lfstack_pop(lfstack_t *lfstack);
68 | extern void* lfstack_single_pop(lfstack_t *lfstack);
69 |
70 | /** loop until value been pop, it sleeps 1ms if not found, to reduce cpu high usage **/
71 | extern void* lfstack_pop_must(lfstack_t *lfstack);
72 | extern void* lfstack_single_pop_must(lfstack_t *lfstack);
73 |
74 | /*** lfstack_flush to flush all the inacitve element ***/
75 | extern void lfstack_flush(lfstack_t *lfstack);
76 | extern void lfstack_destroy(lfstack_t *lfstack);
77 | extern size_t lfstack_size(lfstack_t *lfstack);
78 | extern void lfstack_sleep(unsigned int milisec);
79 |
80 |
81 | #ifdef __cplusplus
82 | }
83 | #endif
84 |
85 | #endif
86 |
87 |
--------------------------------------------------------------------------------
/lfstack_vs/lfstack_vs.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {C08C7611-D4DA-4FBE-8808-3E474223F691}
24 | lfstackvs
25 | 8.1
26 |
27 |
28 |
29 | Application
30 | true
31 | v140
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v140
38 | true
39 | MultiByte
40 |
41 |
42 | Application
43 | true
44 | v140
45 | MultiByte
46 |
47 |
48 | Application
49 | false
50 | v140
51 | true
52 | MultiByte
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | Level3
76 | Disabled
77 | true
78 |
79 |
80 |
81 |
82 | Level3
83 | Disabled
84 | true
85 |
86 |
87 |
88 |
89 | Level3
90 | MaxSpeed
91 | true
92 | true
93 | true
94 |
95 |
96 | true
97 | true
98 |
99 |
100 |
101 |
102 | Level3
103 | MaxSpeed
104 | true
105 | true
106 | true
107 |
108 |
109 | true
110 | true
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/example.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "lfstack.h"
10 |
11 |
12 | typedef void (*test_function)(pthread_t*);
13 |
14 | void one_push_and_multi_pop(pthread_t *threads);
15 | void one_pop_and_multi_push(pthread_t *threads);
16 | void multi_push_pop(pthread_t *threads);
17 | void* worker_push_pop(void *);
18 | void* worker_push(void *);
19 | void* worker_pop(void *);
20 | void* worker_pushingle_c(void *);
21 |
22 | /**Testing must**/
23 | void one_push_and_multi_pop_must(pthread_t *threads);
24 | void one_pop_must_and_multi_push(pthread_t *threads);
25 | void multi_push_pop_must(pthread_t *threads);
26 | void* worker_push_pop_must(void *);
27 | void* worker_push_must(void *);
28 | void* worker_pop_must(void *);
29 | void* worker_single_pop_must(void *);
30 |
31 | void running_test(test_function testfn);
32 |
33 | struct timeval tv1, tv2;
34 | #define total_put 50000
35 | #define total_running_loop 50
36 | int nthreads = 4;
37 | int one_thread = 1;
38 | int nthreads_exited = 0;
39 | lfstack_t *mystack;
40 |
41 |
42 | void* worker_pop_must(void *arg) {
43 | int i = 0;
44 | int *int_data;
45 | int total_loop = total_put * (*(int*)arg);
46 | while (i++ < total_loop) {
47 | /*Pop*/
48 | int_data = lfstack_pop_must(mystack);
49 | // printf("%d\n", *int_data);
50 |
51 | free(int_data);
52 | }
53 | __sync_add_and_fetch(&nthreads_exited, 1);
54 | return 0;
55 | }
56 |
57 | void* worker_single_pop_must(void *arg) {
58 | int i = 0;
59 | int *int_data;
60 | int total_loop = total_put * (*(int*)arg);
61 | while (i++ < total_loop) {
62 | /*Pop*/
63 | int_data = lfstack_single_pop_must(mystack);
64 | // printf("%d\n", *int_data);
65 |
66 | free(int_data);
67 | }
68 | __sync_add_and_fetch(&nthreads_exited, 1);
69 | return 0;
70 | }
71 |
72 | void* worker_push_pop_must(void *arg)
73 | {
74 | int i = 0;
75 | int *int_data;
76 | while (i < total_put) {
77 | int_data = (int*)malloc(sizeof(int));
78 | assert(int_data != NULL);
79 | *int_data = i++;
80 | /*Push*/
81 | while (lfstack_push(mystack, int_data)) {
82 | printf("ENQ FULL?\n");
83 | }
84 |
85 | /*Pop*/
86 | int_data = lfstack_pop_must(mystack);
87 | // printf("%d\n", *int_data);
88 | free(int_data);
89 | }
90 | __sync_add_and_fetch(&nthreads_exited, 1);
91 | return 0;
92 | }
93 |
94 | void* worker_pop(void *arg) {
95 | int i = 0;
96 | int *int_data;
97 | int total_loop = total_put * (*(int*)arg);
98 | while (i++ < total_loop) {
99 | /*Pop*/
100 | while ((int_data = lfstack_pop(mystack)) == NULL) {
101 | lfstack_sleep(1);
102 | }
103 | // printf("%d\n", *int_data);
104 |
105 | free(int_data);
106 | }
107 | __sync_add_and_fetch(&nthreads_exited, 1);
108 | return 0;
109 | }
110 |
111 | void* worker_pushingle_c(void *arg) {
112 | int i = 0;
113 | int *int_data;
114 | int total_loop = total_put * (*(int*)arg);
115 | while (i++ < total_loop) {
116 | /*Pop*/
117 | while ((int_data = lfstack_single_pop(mystack)) == NULL) {
118 | lfstack_sleep(1);
119 | }
120 | // printf("%d\n", *int_data);
121 |
122 | free(int_data);
123 | }
124 | __sync_add_and_fetch(&nthreads_exited, 1);
125 | return 0;
126 | }
127 |
128 | /** Worker Keep Sending at the same time, do not try instensively **/
129 | void* worker_push(void *arg)
130 | {
131 | int i = 0, *int_data;
132 | int total_loop = total_put * (*(int*)arg);
133 | while (i++ < total_loop) {
134 | int_data = (int*)malloc(sizeof(int));
135 | assert(int_data != NULL);
136 | *int_data = i;
137 | /*Push*/
138 |
139 | while (lfstack_push(mystack, int_data)) {
140 | // printf("ENQ FULL?\n");
141 | }
142 | }
143 | // __sync_add_and_fetch(&nthreads_exited, 1);
144 | return 0;
145 | }
146 |
147 | /** Worker Send And Consume at the same time **/
148 | void* worker_push_pop(void *arg)
149 | {
150 | int i = 0;
151 | int *int_data;
152 | while (i < total_put) {
153 | int_data = (int*)malloc(sizeof(int));
154 | assert(int_data != NULL);
155 | *int_data = i++;
156 | /*Push*/
157 | while (lfstack_push(mystack, int_data)) {
158 | printf("ENQ FULL?\n");
159 | }
160 |
161 | /*Pop*/
162 | while ((int_data = lfstack_pop(mystack)) == NULL) {
163 | lfstack_sleep(1);
164 | }
165 | // printf("%d\n", *int_data);
166 | free(int_data);
167 | }
168 | __sync_add_and_fetch(&nthreads_exited, 1);
169 | return 0;
170 | }
171 |
172 | #define join_threads \
173 | for (i = 0; i < nthreads; i++) {\
174 | pthread_join(threads[i], NULL); \
175 | }
176 |
177 | #define detach_thread_and_loop \
178 | for (i = 0; i < nthreads; i++)\
179 | pthread_detach(threads[i]);\
180 | while ( nthreads_exited < nthreads ) \
181 | lfstack_sleep(10);\
182 | if(lfstack_size(mystack) != 0){\
183 | lfstack_sleep(10);\
184 | }
185 |
186 | void multi_push_pop(pthread_t *threads) {
187 | printf("-----------%s---------------\n", "multi_push_pop");
188 | int i;
189 | for (i = 0; i < nthreads; i++) {
190 | pthread_create(threads + i, NULL, worker_push_pop, NULL);
191 | }
192 |
193 | join_threads;
194 | // detach_thread_and_loop;
195 | }
196 |
197 | void one_pop_and_multi_push(pthread_t *threads) {
198 | printf("-----------%s---------------\n", "one_pop_and_multi_push");
199 | int i;
200 | for (i = 0; i < nthreads; i++)
201 | pthread_create(threads + i, NULL, worker_push, &one_thread);
202 |
203 | worker_pushingle_c(&nthreads);
204 |
205 | join_threads;
206 | // detach_thread_and_loop;
207 | }
208 |
209 | void one_push_and_multi_pop(pthread_t *threads) {
210 | printf("-----------%s---------------\n", "one_push_and_multi_pop");
211 | int i;
212 | for (i = 0; i < nthreads; i++)
213 | pthread_create(threads + i, NULL, worker_pop, &one_thread);
214 |
215 | worker_push(&nthreads);
216 |
217 | #pragma GCC diagnostic push
218 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
219 | detach_thread_and_loop;
220 | #pragma GCC diagnostic pop
221 |
222 | }
223 |
224 |
225 | void one_pop_must_and_multi_push(pthread_t *threads) {
226 | printf("-----------%s---------------\n", "one_pop_must_and_multi_push");
227 | int i;
228 | for (i = 0; i < nthreads; i++)
229 | pthread_create(threads + i, NULL, worker_push, &one_thread);
230 |
231 | worker_single_pop_must(&nthreads);
232 |
233 | join_threads;
234 | // detach_thread_and_loop;
235 | }
236 |
237 | void one_push_and_multi_pop_must(pthread_t *threads) {
238 | printf("-----------%s---------------\n", "one_push_and_multi_pop_must");
239 | int i;
240 | for (i = 0; i < nthreads; i++)
241 | pthread_create(threads + i, NULL, worker_pop_must, &one_thread);
242 |
243 | worker_push(&nthreads);
244 |
245 | #pragma GCC diagnostic push
246 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
247 | detach_thread_and_loop;
248 | #pragma GCC diagnostic pop
249 |
250 | }
251 |
252 | void multi_push_pop_must(pthread_t *threads) {
253 | printf("-----------%s---------------\n", "multi_push_pop_must");
254 | int i;
255 | for (i = 0; i < nthreads; i++) {
256 | pthread_create(threads + i, NULL, worker_push_pop_must, NULL);
257 | }
258 |
259 | join_threads;
260 | // detach_thread_and_loop;
261 | }
262 |
263 | void running_test(test_function testfn) {
264 | int n;
265 | for (n = 0; n < total_running_loop; n++) {
266 | printf("Current running at =%d, ", n);
267 | nthreads_exited = 0;
268 | /* Spawn threads. */
269 | pthread_t threads[nthreads];
270 | printf("Using %d thread%s.\n", nthreads, nthreads == 1 ? "" : "s");
271 | printf("Total requests %d \n", total_put);
272 | gettimeofday(&tv1, NULL);
273 |
274 | testfn(threads);
275 |
276 | gettimeofday(&tv2, NULL);
277 | printf ("Total time = %f seconds\n",
278 | (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
279 | (double) (tv2.tv_sec - tv1.tv_sec));
280 |
281 | lfstack_sleep(10);
282 | assert ( 0 == lfstack_size(mystack) && "Error, all stack should be consumed but not");
283 | }
284 | }
285 |
286 | int main(void) {
287 | mystack = malloc(sizeof (lfstack_t));
288 | if (lfstack_init(mystack) == -1)
289 | return -1;
290 |
291 | running_test(one_push_and_multi_pop);
292 | running_test(one_push_and_multi_pop_must);
293 |
294 | running_test(one_pop_and_multi_push);
295 | running_test(one_pop_must_and_multi_push);
296 |
297 | running_test(multi_push_pop);
298 | running_test(multi_push_pop_must);
299 |
300 |
301 | lfstack_destroy(mystack);
302 | // sleep(3);
303 | free(mystack);
304 |
305 | printf("Test Pass!\n");
306 |
307 | return 0;
308 | }
309 |
310 |
--------------------------------------------------------------------------------
/lfstack.c:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * BSD 2-Clause License
4 | *
5 | * Copyright (c) 2018, Taymindis Woon
6 | * All rights reserved.
7 | *
8 | * Redistribution and use in source and binary forms, with or without
9 | * modification, are permitted provided that the following conditions are met:
10 | *
11 | * * Redistributions of source code must retain the above copyright notice, this
12 | * list of conditions and the following disclaimer.
13 | *
14 | * * Redistributions in binary form must reproduce the above copyright notice,
15 | * this list of conditions and the following disclaimer in the documentation
16 | * and/or other materials provided with the distribution.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 | *
29 | */
30 | #include
31 | #include
32 | #include
33 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
34 |
35 | #include
36 | #include // for usleep
37 | #include
38 |
39 | #define __LFS_VAL_COMPARE_AND_SWAP __sync_val_compare_and_swap
40 | #define __LFS_BOOL_COMPARE_AND_SWAP __sync_bool_compare_and_swap
41 | #define __LFS_FETCH_AND_ADD __sync_fetch_and_add
42 | #define __LFS_ADD_AND_FETCH __sync_add_and_fetch
43 | #define __LFS_YIELD_THREAD sched_yield
44 | #define __LFS_SYNC_MEMORY __sync_synchronize
45 |
46 | #else
47 |
48 | #include
49 | #include
50 | #ifdef _WIN64
51 | inline BOOL __SYNC_BOOL_CAS(LONG64 volatile *dest, LONG64 input, LONG64 comparand) {
52 | return InterlockedCompareExchangeNoFence64(dest, input, comparand) == comparand;
53 | }
54 | #define __LFS_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
55 | InterlockedCompareExchangeNoFence64((LONG64 volatile *)dest, (LONG64)input, (LONG64)comparand)
56 | #define __LFS_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \
57 | __SYNC_BOOL_CAS((LONG64 volatile *)dest, (LONG64)input, (LONG64)comparand)
58 | #define __LFS_FETCH_AND_ADD InterlockedExchangeAddNoFence64
59 | #define __LFS_ADD_AND_FETCH InterlockedAddNoFence64
60 | #define __LFS_SYNC_MEMORY MemoryBarrier
61 |
62 | #else
63 | #ifndef asm
64 | #define asm __asm
65 | #endif
66 | inline BOOL __SYNC_BOOL_CAS(LONG volatile *dest, LONG input, LONG comparand) {
67 | return InterlockedCompareExchangeNoFence(dest, input, comparand) == comparand;
68 | }
69 | #define __LFS_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
70 | InterlockedCompareExchangeNoFence((LONG volatile *)dest, (LONG)input, (LONG)comparand)
71 | #define __LFS_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \
72 | __SYNC_BOOL_CAS((LONG volatile *)dest, (LONG)input, (LONG)comparand)
73 | #define __LFS_FETCH_AND_ADD InterlockedExchangeAddNoFence
74 | #define __LFS_ADD_AND_FETCH InterlockedAddNoFence
75 | #define __LFS_SYNC_MEMORY() asm mfence
76 |
77 | #endif
78 | #include
79 | #define __LFS_YIELD_THREAD SwitchToThread
80 | #endif
81 |
82 | #include "lfstack.h"
83 | #define DEF_LFS_ASSIGNED_SPIN 2048
84 |
85 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
86 | #define lfs_time_t long
87 | #define lfs_get_curr_time(_time_sec) \
88 | struct timeval _time_; \
89 | gettimeofday(&_time_, NULL); \
90 | *_time_sec = _time_.tv_sec
91 | #define lfs_diff_time(_etime_, _stime_) _etime_ - _stime_
92 | #else
93 | #define lfs_time_t time_t
94 | #define lfs_get_curr_time(_time_sec) time(_time_sec)
95 | #define lfs_diff_time(_etime_, _stime_) difftime(_etime_, _stime_)
96 | #endif
97 |
98 | struct lfstack_cas_node_s {
99 | void * value;
100 | struct lfstack_cas_node_s *prev, *nextfree;
101 | lfs_time_t _deactivate_tm;
102 | };
103 |
104 | static void __lfs_recycle_free(lfstack_t *, lfstack_cas_node_t*);
105 | static void _lfs_check_free(lfstack_t *);
106 | static void *_pop(lfstack_t *);
107 | static void *_single_pop(lfstack_t *);
108 | static int _push(lfstack_t *, void* );
109 | static inline void* _lfstack_malloc(void* pl, size_t sz) {
110 | return malloc(sz);
111 | }
112 | static inline void _lfstack_free(void* pl, void* ptr) {
113 | free(ptr);
114 | }
115 |
116 | static void *
117 | _pop(lfstack_t *lfs) {
118 | lfstack_cas_node_t *head, *prev;
119 | void *val;
120 |
121 | for (;;) {
122 | head = lfs->head;
123 | __LFS_SYNC_MEMORY();
124 | /** ABA PROBLEM? in order to solve this, I use time free to avoid realloc the same aligned address **/
125 | if (lfs->head == head) {
126 | prev = head->prev;
127 | if (prev) {
128 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->head, head, prev)) {
129 | val = head->value;
130 | break;
131 | }
132 | } else {
133 | /** Empty **/
134 | val = NULL;
135 | goto _done;
136 | }
137 | }
138 | }
139 | __lfs_recycle_free(lfs, head);
140 | __LFS_YIELD_THREAD();
141 | _done:
142 | // __asm volatile("" ::: "memory");
143 | __LFS_SYNC_MEMORY();
144 | _lfs_check_free(lfs);
145 | return val;
146 | }
147 |
148 | static void *
149 | _single_pop(lfstack_t *lfs) {
150 | lfstack_cas_node_t *head, *prev;
151 | void *val;
152 |
153 | for (;;) {
154 | head = lfs->head;
155 | __LFS_SYNC_MEMORY();
156 | if (lfs->head == head) {
157 | prev = head->prev;
158 | if (prev) {
159 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->head, head, prev)) {
160 | val = head->value;
161 | lfs->_free(lfs->pl, head);
162 | break;
163 | }
164 | } else {
165 | /** Empty **/
166 | return NULL;
167 | }
168 | }
169 | }
170 | return val;
171 | }
172 |
173 | static int
174 | _push(lfstack_t *lfs, void* value) {
175 | lfstack_cas_node_t *head, *new_head;
176 | new_head = (lfstack_cas_node_t*) lfs->_malloc(lfs->pl, sizeof(lfstack_cas_node_t));
177 | if (new_head == NULL) {
178 | perror("malloc");
179 | return errno;
180 | }
181 | new_head->value = value;
182 | new_head->nextfree = NULL;
183 | for (;;) {
184 | __LFS_SYNC_MEMORY();
185 | new_head->prev = head = lfs->head;
186 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->head, head, new_head)) {
187 | // always check any free value
188 | _lfs_check_free(lfs);
189 | return 0;
190 | }
191 | }
192 |
193 | /*It never be here*/
194 | return -1;
195 | }
196 |
197 | static void
198 | __lfs_recycle_free(lfstack_t *lfs, lfstack_cas_node_t* freenode) {
199 | lfstack_cas_node_t *freed;
200 | do {
201 | freed = lfs->move_free;
202 | } while (!__LFS_BOOL_COMPARE_AND_SWAP(&freed->nextfree, NULL, freenode) );
203 |
204 | lfs_get_curr_time(&freenode->_deactivate_tm);
205 |
206 | __LFS_BOOL_COMPARE_AND_SWAP(&lfs->move_free, freed, freenode);
207 | }
208 |
209 | static void
210 | _lfs_check_free(lfstack_t *lfs) {
211 | lfs_time_t curr_time;
212 | if (__LFS_BOOL_COMPARE_AND_SWAP(&lfs->in_free_mode, 0, 1)) {
213 | lfs_get_curr_time(&curr_time);
214 | lfstack_cas_node_t *rtfree = lfs->root_free, *nextfree;
215 | while ( rtfree && (rtfree != lfs->move_free) ) {
216 | nextfree = rtfree->nextfree;
217 | if ( lfs_diff_time(curr_time, rtfree->_deactivate_tm) > 2) {
218 | // printf("%p\n", rtfree);
219 | lfs->_free(lfs->pl, rtfree);
220 | rtfree = nextfree;
221 | } else {
222 | break;
223 | }
224 | }
225 | lfs->root_free = rtfree;
226 | __LFS_BOOL_COMPARE_AND_SWAP(&lfs->in_free_mode, 1, 0);
227 | }
228 | __LFS_SYNC_MEMORY();
229 | }
230 |
231 | int
232 | lfstack_init(lfstack_t *lfs) {
233 | return lfstack_init_mf(lfs, NULL, _lfstack_malloc, _lfstack_free);
234 | }
235 |
236 | int
237 | lfstack_init_mf(lfstack_t *lfs, void* pl, lfstack_malloc_fn lfs_malloc, lfstack_free_fn lfs_free) {
238 | lfs->_malloc = lfs_malloc;
239 | lfs->_free = lfs_free;
240 | lfs->pl = pl;
241 |
242 | lfstack_cas_node_t *base = lfs->_malloc(lfs->pl, sizeof(lfstack_cas_node_t));
243 | lfstack_cas_node_t *freebase = lfs->_malloc(lfs->pl, sizeof(lfstack_cas_node_t));
244 | if (base == NULL || freebase == NULL) {
245 | perror("malloc");
246 | return errno;
247 | }
248 | base->value = NULL;
249 | base->prev = NULL;
250 | base->nextfree = NULL;
251 | base->_deactivate_tm = 0;
252 |
253 | freebase->value = NULL;
254 | freebase->prev = NULL;
255 | freebase->nextfree = NULL;
256 | freebase->_deactivate_tm = 0;
257 |
258 | lfs->head = base; // Not yet to be free for first node only
259 | lfs->root_free = lfs->move_free = freebase; // Not yet to be free for first node only
260 | lfs->size = 0;
261 | lfs->in_free_mode = 0;
262 |
263 | return 0;
264 | }
265 |
266 | void
267 | lfstack_destroy(lfstack_t *lfs) {
268 | void* p;
269 | while ((p = lfstack_pop(lfs))) {
270 | lfs->_free(lfs->pl, p);
271 | }
272 | // Clear the recycle chain nodes
273 | lfstack_cas_node_t *rtfree = lfs->root_free, *nextfree;
274 | while (rtfree && (rtfree != lfs->move_free) ) {
275 | nextfree = rtfree->nextfree;
276 | lfs->_free(lfs->pl, rtfree);
277 | rtfree = nextfree;
278 | }
279 | if (rtfree) {
280 | lfs->_free(lfs->pl, rtfree);
281 | }
282 |
283 | lfs->_free(lfs->pl, lfs->head); // Last free
284 |
285 | lfs->size = 0;
286 | }
287 |
288 | void lfstack_flush(lfstack_t *lfstack) {
289 | _lfs_check_free(lfstack);
290 | }
291 |
292 | int
293 | lfstack_push(lfstack_t *lfs, void *value) {
294 | if (_push(lfs, value)) {
295 | return -1;
296 | }
297 | __LFS_ADD_AND_FETCH(&lfs->size, 1);
298 | return 0;
299 | }
300 |
301 | void*
302 | lfstack_pop(lfstack_t *lfs) {
303 | void *v;
304 | if (//__LFS_ADD_AND_FETCH(&lfs->size, 0) &&
305 | (v = _pop(lfs))
306 | ) {
307 |
308 | __LFS_FETCH_AND_ADD(&lfs->size, -1);
309 | return v;
310 | }
311 | // Rest the thread for other thread, to avoid keep looping force
312 | lfstack_sleep(1);
313 | return NULL;
314 | }
315 |
316 | void*
317 | lfstack_pop_must(lfstack_t *lfs) {
318 | void *v;
319 | while ( !(v = _pop(lfs)) ) {
320 | // Rest the thread for other thread, to avoid keep looping force
321 | lfstack_sleep(1);
322 | }
323 | __LFS_FETCH_AND_ADD(&lfs->size, -1);
324 | return v;
325 | }
326 |
327 | /**This is only applicable when only single thread consume only**/
328 | void*
329 | lfstack_single_pop(lfstack_t *lfs) {
330 | void *v;
331 | if (//__LFS_ADD_AND_FETCH(&lfs->size, 0) &&
332 | (v = _single_pop(lfs))
333 | ) {
334 |
335 | __LFS_FETCH_AND_ADD(&lfs->size, -1);
336 | return v;
337 | }
338 | // Rest the thread for other thread, to avoid keep looping force
339 | lfstack_sleep(1);
340 | return NULL;
341 | }
342 |
343 | void*
344 | lfstack_single_pop_must(lfstack_t *lfs) {
345 | void *v;
346 | while ( !(v = _single_pop(lfs)) ) {
347 | // Rest the thread for other thread, to avoid keep looping force
348 | lfstack_sleep(1);
349 | }
350 | __LFS_FETCH_AND_ADD(&lfs->size, -1);
351 | return v;
352 | }
353 |
354 | size_t
355 | lfstack_size(lfstack_t *lfs) {
356 | return __LFS_ADD_AND_FETCH(&lfs->size, 0);
357 | }
358 |
359 | void
360 | lfstack_sleep(unsigned int milisec) {
361 | #if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
362 | #pragma GCC diagnostic push
363 | #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
364 | usleep(milisec * 1000);
365 | #pragma GCC diagnostic pop
366 | #else
367 | Sleep(milisec);
368 | #endif
369 | }
370 |
371 | #ifdef __cplusplus
372 | }
373 | #endif
374 |
--------------------------------------------------------------------------------