Compare commits
3 commits
d4f1a29c25
...
e323dafdbd
Author | SHA1 | Date | |
---|---|---|---|
e323dafdbd | |||
08378522f3 | |||
93330e4b0f |
11 changed files with 818 additions and 841 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
_release
|
||||||
|
_debug
|
24
.github/workflows/ci.yaml
vendored
24
.github/workflows/ci.yaml
vendored
|
@ -9,6 +9,14 @@ concurrency:
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: sudo apt-get install -y make clang-format
|
||||||
|
- run: make lint
|
||||||
|
- run: git diff --exit-code
|
||||||
|
|
||||||
build-with-gcc:
|
build-with-gcc:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
@ -16,29 +24,35 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with: {fetch-depth: 0}
|
||||||
- run: sudo apt-get install -y build-essential
|
- run: sudo apt-get install -y build-essential
|
||||||
- run: make CFG=${{ matrix.cfg}} -j$(nproc)
|
- run: make VERBOSE=1 CFG=${{ matrix.cfg}} -j$(nproc)
|
||||||
- run: _${{ matrix.cfg }}/inotify-info
|
- run: |
|
||||||
|
_${{ matrix.cfg }}/inotify-info --version
|
||||||
|
_${{ matrix.cfg }}/inotify-info
|
||||||
|
|
||||||
build-with-zig:
|
build-with-zig:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with: {fetch-depth: 0}
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: zig-sdk-and-cache-${{ hashFiles('.github/workflows/ci.yaml') }}
|
key: zig-sdk-and-cache-${{ hashFiles('.github/workflows/ci.yaml') }}
|
||||||
path: ~/.cache/zig
|
path: ~/.cache/zig
|
||||||
- run: |
|
- run: |
|
||||||
wget --progress=dot:mega \
|
wget --progress=dot:mega \
|
||||||
https://ziglang.org/download/0.11.0/zig-linux-$(uname -m)-0.11.0.tar.xz
|
https://ziglang.org/download/0.13.0/zig-linux-$(uname -m)-0.13.0.tar.xz
|
||||||
tar -xJf zig-linux-*.tar.xz
|
tar -xJf zig-linux-*.tar.xz
|
||||||
rm zig-linux-*.xz
|
rm zig-linux-*.xz
|
||||||
mv zig-linux-* zig-sdk
|
mv zig-linux-* zig-sdk
|
||||||
- run: |
|
- run: |
|
||||||
make -j$(nproc) \
|
make VERBOSE=1 -j$(nproc) \
|
||||||
CC="zig-sdk/zig cc -target $(uname -m)-linux-musl" \
|
CC="zig-sdk/zig cc -target $(uname -m)-linux-musl" \
|
||||||
CXX="zig-sdk/zig c++ -target $(uname -m)-linux-musl"
|
CXX="zig-sdk/zig c++ -target $(uname -m)-linux-musl"
|
||||||
- run: _release/inotify-info
|
- run: |
|
||||||
|
_release/inotify-info --version
|
||||||
|
_release/inotify-info
|
||||||
|
|
||||||
build-with-docker:
|
build-with-docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
17
.github/workflows/release.yaml
vendored
Normal file
17
.github/workflows/release.yaml
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
name: release
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
with:
|
||||||
|
generate_release_notes: true
|
||||||
|
draft: true
|
||||||
|
prerelease: true
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,4 @@
|
||||||
_debug/
|
_debug/
|
||||||
_release/
|
_release/
|
||||||
|
|
||||||
|
/inotify-info-*.tar.gz
|
||||||
|
|
19
Dockerfile
19
Dockerfile
|
@ -1,23 +1,14 @@
|
||||||
FROM alpine
|
FROM alpine:edge
|
||||||
|
|
||||||
# zig is installed from the upstream tarball, because:
|
RUN apk add make zig git
|
||||||
# - as of writing, alpine has zig only in testing (which is cumbersome to use)
|
|
||||||
# - apk get zig pulls in libllvm, which is huge.
|
|
||||||
#
|
|
||||||
# Upstream tarball is statically linked, making it small and convenient to use.
|
|
||||||
RUN apk add make \
|
|
||||||
&& wget https://ziglang.org/download/0.11.0/zig-linux-$(uname -m)-0.11.0.tar.xz \
|
|
||||||
&& tar -xJf zig-linux-*.tar.xz \
|
|
||||||
&& rm zig-linux-*.xz \
|
|
||||||
&& mv zig-linux-* zig
|
|
||||||
|
|
||||||
WORKDIR inotify-info
|
WORKDIR inotify-info
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN CC="/zig/zig cc -target $(uname -m)-linux-musl" \
|
RUN CC="zig cc -target $(uname -m)-linux-musl" \
|
||||||
CXX="/zig/zig c++ -target $(uname -m)-linux-musl" \
|
CXX="zig c++ -target $(uname -m)-linux-musl" \
|
||||||
make
|
make VERBOSE=1
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=0 /inotify-info/_release/inotify-info /inotify-info
|
COPY --from=0 /inotify-info/_release/inotify-info /inotify-info
|
||||||
|
|
44
Makefile
44
Makefile
|
@ -20,11 +20,16 @@ ifeq ($(CFG), debug)
|
||||||
ASAN ?= 1
|
ASAN ?= 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
BINDIR := $(PREFIX)/bin
|
||||||
|
|
||||||
LD = $(CC)
|
LD = $(CC)
|
||||||
RM = rm -f
|
RM = rm -f
|
||||||
MKDIR = mkdir -p
|
MKDIR = mkdir -p
|
||||||
VERBOSE ?= 0
|
VERBOSE ?= 0
|
||||||
|
|
||||||
|
INOTIFYINFO_VERSION ?= $(shell git describe --tags --dirty 2>/dev/null || echo unknown)
|
||||||
|
|
||||||
COMPILER = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc)
|
COMPILER = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc)
|
||||||
|
|
||||||
WARNINGS = -Wall -Wextra -Wpedantic -Wmissing-include-dirs -Wformat=2 -Wshadow
|
WARNINGS = -Wall -Wextra -Wpedantic -Wmissing-include-dirs -Wformat=2 -Wshadow
|
||||||
|
@ -33,10 +38,15 @@ ifneq ($(COMPILER),clang)
|
||||||
WARNINGS += -Wsuggest-attribute=format -Wall
|
WARNINGS += -Wsuggest-attribute=format -Wall
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS = $(WARNINGS) -march=native -fno-exceptions -gdwarf-4 -g2 -ggnu-pubnames -gsplit-dwarf
|
DEFINES = -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
||||||
CFLAGS += -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
DEFINES += -DINOTIFYINFO_VERSION=\"$(INOTIFYINFO_VERSION)\"
|
||||||
CXXFLAGS = -fno-rtti -Woverloaded-virtual
|
|
||||||
LDFLAGS = -march=native -gdwarf-4 -g2 -Wl,--build-id=sha1
|
CFLAGS += $(WARNINGS) $(DEFINES)
|
||||||
|
CFLAGS += -std=gnu99 -fno-exceptions
|
||||||
|
|
||||||
|
CXXFLAGS += $(WARNINGS) $(DEFINES)
|
||||||
|
CXXFLAGS += -std=c++11 -fno-exceptions -fno-rtti -Woverloaded-virtual
|
||||||
|
|
||||||
LIBS = -Wl,--no-as-needed -lm -ldl -lpthread -lstdc++
|
LIBS = -Wl,--no-as-needed -lm -ldl -lpthread -lstdc++
|
||||||
|
|
||||||
CFILES = \
|
CFILES = \
|
||||||
|
@ -59,6 +69,7 @@ ifeq ($(ASAN), 1)
|
||||||
ASAN_FLAGS += -fsanitize=object-size # enable object size checking, detect various out-of-bounds accesses.
|
ASAN_FLAGS += -fsanitize=object-size # enable object size checking, detect various out-of-bounds accesses.
|
||||||
ASAN_FLAGS += -fsanitize=alignment # enable alignment checking, detect various misaligned objects;
|
ASAN_FLAGS += -fsanitize=alignment # enable alignment checking, detect various misaligned objects;
|
||||||
CFLAGS += $(ASAN_FLAGS)
|
CFLAGS += $(ASAN_FLAGS)
|
||||||
|
CXXFLAGS += $(ASAN_FLAGS)
|
||||||
LDFLAGS += $(ASAN_FLAGS)
|
LDFLAGS += $(ASAN_FLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -72,7 +83,6 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PROJ = $(ODIR)/$(NAME)
|
PROJ = $(ODIR)/$(NAME)
|
||||||
$(info Building $(ODIR)/$(NAME)...)
|
|
||||||
|
|
||||||
ifeq ($(VERBOSE), 1)
|
ifeq ($(VERBOSE), 1)
|
||||||
VERBOSE_PREFIX=
|
VERBOSE_PREFIX=
|
||||||
|
@ -94,12 +104,16 @@ $(ODIR)/$(NAME): $(OBJS)
|
||||||
$(ODIR)/%.o: %.c Makefile
|
$(ODIR)/%.o: %.c Makefile
|
||||||
$(VERBOSE_PREFIX)echo "---- $< ----";
|
$(VERBOSE_PREFIX)echo "---- $< ----";
|
||||||
@$(MKDIR) $(dir $@)
|
@$(MKDIR) $(dir $@)
|
||||||
$(VERBOSE_PREFIX)$(CC) -MMD -MP -std=gnu99 $(CFLAGS) -o $@ -c $<
|
$(VERBOSE_PREFIX)$(CC) -MMD -MP $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
$(ODIR)/%.o: %.cpp Makefile
|
$(ODIR)/%.o: %.cpp Makefile
|
||||||
$(VERBOSE_PREFIX)echo "---- $< ----";
|
$(VERBOSE_PREFIX)echo "---- $< ----";
|
||||||
@$(MKDIR) $(dir $@)
|
@$(MKDIR) $(dir $@)
|
||||||
$(VERBOSE_PREFIX)$(CXX) -MMD -MP -std=c++11 $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
|
$(VERBOSE_PREFIX)$(CXX) -MMD -MP $(CXXFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
find . -name '*.h' -o -name '*.c' -o -name '*.cpp' | xargs clang-format -i --style=webkit
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
|
@ -109,3 +123,19 @@ clean:
|
||||||
$(VERBOSE_PREFIX)$(RM) $(OBJS)
|
$(VERBOSE_PREFIX)$(RM) $(OBJS)
|
||||||
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.d)
|
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.d)
|
||||||
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.dwo)
|
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.dwo)
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
|
||||||
|
install: all
|
||||||
|
install -D $(PROJ) $(BINDIR)/$(NAME)
|
||||||
|
|
||||||
|
.PHONY: uninstall
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
$(RM) $(BINDIR)/$(NAME)
|
||||||
|
|
||||||
|
define RELEASE_RULES
|
||||||
|
inotify-info-$(TAG).tar.gz:
|
||||||
|
git archive --prefix=inotify-info-$(TAG)/ v$(TAG) | gzip -n > $$@
|
||||||
|
endef
|
||||||
|
$(foreach TAG,$(shell git tag 2>/dev/null | sed -n '/^v/ s/^v//p'),$(eval $(RELEASE_RULES)))
|
||||||
|
|
21
README.md
21
README.md
|
@ -22,17 +22,11 @@ Building _debug/inotify-info...
|
||||||
Linking _debug/inotify-info...
|
Linking _debug/inotify-info...
|
||||||
```
|
```
|
||||||
|
|
||||||
Or you can build Docker image.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker build . -t inotify-info
|
|
||||||
```
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
You are free to copy the resulting executable to any suitable location in your `$PATH`.
|
|
||||||
```
|
The resulting executable will be at `_release/inotify-info`. You are free to
|
||||||
cp _release/inotify-info /usr/local/bin/
|
copy the resulting executable to any suitable location in your `$PATH` or run
|
||||||
```
|
`make install` to install to `/usr/local/bin`.
|
||||||
|
|
||||||
## Run (Prints Summary)
|
## Run (Prints Summary)
|
||||||
```
|
```
|
||||||
|
@ -160,12 +154,16 @@ Searching '/' for listed inodes... (8 threads)
|
||||||
94111468 [10304h] /home/mikesart/.cache/xfce4/xfce4-appfinder/
|
94111468 [10304h] /home/mikesart/.cache/xfce4/xfce4-appfinder/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run on Docker
|
## Run on Docker/podman
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
docker build . -t inotify-info
|
||||||
docker run --rm --privileged -v /proc:/proc inotify-info
|
docker run --rm --privileged -v /proc:/proc inotify-info
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When running under [podman][podman] non-root mode, append `--ulimit
|
||||||
|
nofile=65535:65535` to the `podman build` command.
|
||||||
|
|
||||||
## Run on Nix(OS)
|
## Run on Nix(OS)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -181,3 +179,4 @@ nix run nixpkgs#inotify-info
|
||||||
[problem2]: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
|
[problem2]: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
|
||||||
[lfqueue]: https://github.com/Taymindis/lfqueue
|
[lfqueue]: https://github.com/Taymindis/lfqueue
|
||||||
[bsd]: https://github.com/Taymindis/lfqueue/blob/master/LICENSE
|
[bsd]: https://github.com/Taymindis/lfqueue/blob/master/LICENSE
|
||||||
|
[podman]: https://podman.io/
|
||||||
|
|
861
inotify-info.cpp
861
inotify-info.cpp
File diff suppressed because it is too large
Load diff
|
@ -22,39 +22,38 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define RESET "\x1b[0m"
|
#define RESET "\x1b[0m"
|
||||||
#define GRAY "\x1b[0;30m"
|
#define GRAY "\x1b[0;30m"
|
||||||
#define RED "\x1b[0;31m"
|
#define RED "\x1b[0;31m"
|
||||||
#define GREEN "\x1b[0;32m"
|
#define GREEN "\x1b[0;32m"
|
||||||
#define YELLOW "\x1b[0;33m"
|
#define YELLOW "\x1b[0;33m"
|
||||||
#define BLUE "\x1b[0;34m"
|
#define BLUE "\x1b[0;34m"
|
||||||
#define MAGENTA "\x1b[0;35m"
|
#define MAGENTA "\x1b[0;35m"
|
||||||
#define CYAN "\x1b[0;36m"
|
#define CYAN "\x1b[0;36m"
|
||||||
#define WHITE "\x1b[0;37m"
|
#define WHITE "\x1b[0;37m"
|
||||||
#define BGRAY "\x1b[1;30m"
|
#define BGRAY "\x1b[1;30m"
|
||||||
#define BRED "\x1b[1;31m"
|
#define BRED "\x1b[1;31m"
|
||||||
#define BGREEN "\x1b[1;32m"
|
#define BGREEN "\x1b[1;32m"
|
||||||
#define BYELLOW "\x1b[1;33m"
|
#define BYELLOW "\x1b[1;33m"
|
||||||
#define BBLUE "\x1b[1;34m"
|
#define BBLUE "\x1b[1;34m"
|
||||||
#define BMAGENTA "\x1b[1;35m"
|
#define BMAGENTA "\x1b[1;35m"
|
||||||
#define BCYAN "\x1b[1;36m"
|
#define BCYAN "\x1b[1;36m"
|
||||||
#define BWHITE "\x1b[1;37m"
|
#define BWHITE "\x1b[1;37m"
|
||||||
|
|
||||||
#define TO_STR( x ) #x
|
#define TO_STR(x) #x
|
||||||
#define TO_STR_VALUE( x ) TO_STR( x )
|
#define TO_STR_VALUE(x) TO_STR(x)
|
||||||
|
|
||||||
#define ATTRIBUTE_PRINTF( _x, _y ) __attribute__( ( __format__( __printf__, _x, _y ) ) )
|
#define ATTRIBUTE_PRINTF(_x, _y) __attribute__((__format__(__printf__, _x, _y)))
|
||||||
|
|
||||||
#define GCC_DIAG_STR( s ) #s
|
#define GCC_DIAG_STR(s) #s
|
||||||
#define GCC_DIAG_JOINSTR( x, y ) GCC_DIAG_STR( x##y )
|
#define GCC_DIAG_JOINSTR(x, y) GCC_DIAG_STR(x##y)
|
||||||
#define GCC_DIAG_DO_PRAGMA( x ) _Pragma( #x )
|
#define GCC_DIAG_DO_PRAGMA(x) _Pragma(#x)
|
||||||
#define GCC_DIAG_PRAGMA( x ) GCC_DIAG_DO_PRAGMA( GCC diagnostic x )
|
#define GCC_DIAG_PRAGMA(x) GCC_DIAG_DO_PRAGMA(GCC diagnostic x)
|
||||||
|
|
||||||
#define GCC_DIAG_PUSH_OFF( x ) \
|
#define GCC_DIAG_PUSH_OFF(x) \
|
||||||
GCC_DIAG_PRAGMA( push ) \
|
GCC_DIAG_PRAGMA(push) \
|
||||||
GCC_DIAG_PRAGMA( ignored GCC_DIAG_JOINSTR( -W, x ) )
|
GCC_DIAG_PRAGMA(ignored GCC_DIAG_JOINSTR(-W, x))
|
||||||
#define GCC_DIAG_POP() GCC_DIAG_PRAGMA( pop )
|
#define GCC_DIAG_POP() GCC_DIAG_PRAGMA(pop)
|
||||||
|
|
||||||
std::string string_formatv(const char *fmt, va_list ap) ATTRIBUTE_PRINTF(1, 0);
|
|
||||||
std::string string_format(const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
|
|
||||||
|
|
||||||
|
std::string string_formatv(const char* fmt, va_list ap) ATTRIBUTE_PRINTF(1, 0);
|
||||||
|
std::string string_format(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2);
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* BSD 2-Clause License
|
* BSD 2-Clause License
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018, Taymindis Woon
|
* Copyright (c) 2018, Taymindis Woon
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
*
|
*
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
* list of conditions and the following disclaimer.
|
* list of conditions and the following disclaimer.
|
||||||
*
|
*
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
* and/or other materials provided with the distribution.
|
* and/or other materials provided with the distribution.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
* 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
|
* 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.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
|
||||||
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h> // for usleep
|
#include <unistd.h> // for usleep
|
||||||
#include <sched.h>
|
|
||||||
|
|
||||||
#define __LFQ_VAL_COMPARE_AND_SWAP __sync_val_compare_and_swap
|
#define __LFQ_VAL_COMPARE_AND_SWAP __sync_val_compare_and_swap
|
||||||
#define __LFQ_BOOL_COMPARE_AND_SWAP __sync_bool_compare_and_swap
|
#define __LFQ_BOOL_COMPARE_AND_SWAP __sync_bool_compare_and_swap
|
||||||
|
@ -48,13 +48,14 @@
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
inline BOOL __SYNC_BOOL_CAS(LONG64 volatile *dest, LONG64 input, LONG64 comparand) {
|
inline BOOL __SYNC_BOOL_CAS(LONG64 volatile* dest, LONG64 input, LONG64 comparand)
|
||||||
return InterlockedCompareExchangeNoFence64(dest, input, comparand) == comparand;
|
{
|
||||||
|
return InterlockedCompareExchangeNoFence64(dest, input, comparand) == comparand;
|
||||||
}
|
}
|
||||||
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
||||||
InterlockedCompareExchangeNoFence64((LONG64 volatile *)dest, (LONG64)input, (LONG64)comparand)
|
InterlockedCompareExchangeNoFence64((LONG64 volatile*)dest, (LONG64)input, (LONG64)comparand)
|
||||||
#define __LFQ_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \
|
#define __LFQ_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \
|
||||||
__SYNC_BOOL_CAS((LONG64 volatile *)dest, (LONG64)input, (LONG64)comparand)
|
__SYNC_BOOL_CAS((LONG64 volatile*)dest, (LONG64)input, (LONG64)comparand)
|
||||||
#define __LFQ_FETCH_AND_ADD InterlockedExchangeAddNoFence64
|
#define __LFQ_FETCH_AND_ADD InterlockedExchangeAddNoFence64
|
||||||
#define __LFQ_ADD_AND_FETCH InterlockedAddNoFence64
|
#define __LFQ_ADD_AND_FETCH InterlockedAddNoFence64
|
||||||
#define __LFQ_SYNC_MEMORY MemoryBarrier
|
#define __LFQ_SYNC_MEMORY MemoryBarrier
|
||||||
|
@ -63,13 +64,14 @@ inline BOOL __SYNC_BOOL_CAS(LONG64 volatile *dest, LONG64 input, LONG64 comparan
|
||||||
#ifndef asm
|
#ifndef asm
|
||||||
#define asm __asm
|
#define asm __asm
|
||||||
#endif
|
#endif
|
||||||
inline BOOL __SYNC_BOOL_CAS(LONG volatile *dest, LONG input, LONG comparand) {
|
inline BOOL __SYNC_BOOL_CAS(LONG volatile* dest, LONG input, LONG comparand)
|
||||||
return InterlockedCompareExchangeNoFence(dest, input, comparand) == comparand;
|
{
|
||||||
|
return InterlockedCompareExchangeNoFence(dest, input, comparand) == comparand;
|
||||||
}
|
}
|
||||||
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
||||||
InterlockedCompareExchangeNoFence((LONG volatile *)dest, (LONG)input, (LONG)comparand)
|
InterlockedCompareExchangeNoFence((LONG volatile*)dest, (LONG)input, (LONG)comparand)
|
||||||
#define __LFQ_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \
|
#define __LFQ_BOOL_COMPARE_AND_SWAP(dest, comparand, input) \
|
||||||
__SYNC_BOOL_CAS((LONG volatile *)dest, (LONG)input, (LONG)comparand)
|
__SYNC_BOOL_CAS((LONG volatile*)dest, (LONG)input, (LONG)comparand)
|
||||||
#define __LFQ_FETCH_AND_ADD InterlockedExchangeAddNoFence
|
#define __LFQ_FETCH_AND_ADD InterlockedExchangeAddNoFence
|
||||||
#define __LFQ_ADD_AND_FETCH InterlockedAddNoFence
|
#define __LFQ_ADD_AND_FETCH InterlockedAddNoFence
|
||||||
#define __LFQ_SYNC_MEMORY() asm mfence
|
#define __LFQ_SYNC_MEMORY() asm mfence
|
||||||
|
@ -85,9 +87,9 @@ inline BOOL __SYNC_BOOL_CAS(LONG volatile *dest, LONG input, LONG comparand) {
|
||||||
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
||||||
#define lfq_time_t long
|
#define lfq_time_t long
|
||||||
#define lfq_get_curr_time(_time_sec) \
|
#define lfq_get_curr_time(_time_sec) \
|
||||||
struct timeval _time_; \
|
struct timeval _time_; \
|
||||||
gettimeofday(&_time_, NULL); \
|
gettimeofday(&_time_, NULL); \
|
||||||
*_time_sec = _time_.tv_sec
|
*_time_sec = _time_.tv_sec
|
||||||
#define lfq_diff_time(_etime_, _stime_) _etime_ - _stime_
|
#define lfq_diff_time(_etime_, _stime_) _etime_ - _stime_
|
||||||
#else
|
#else
|
||||||
#define lfq_time_t time_t
|
#define lfq_time_t time_t
|
||||||
|
@ -96,281 +98,285 @@ gettimeofday(&_time_, NULL); \
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct lfqueue_cas_node_s {
|
struct lfqueue_cas_node_s {
|
||||||
void * value;
|
void* value;
|
||||||
struct lfqueue_cas_node_s *next, *nextfree;
|
struct lfqueue_cas_node_s *next, *nextfree;
|
||||||
lfq_time_t _deactivate_tm;
|
lfq_time_t _deactivate_tm;
|
||||||
};
|
};
|
||||||
|
|
||||||
//static lfqueue_cas_node_t* __lfq_assigned(lfqueue_t *);
|
// static lfqueue_cas_node_t* __lfq_assigned(lfqueue_t *);
|
||||||
static void __lfq_recycle_free(lfqueue_t *, lfqueue_cas_node_t*);
|
static void __lfq_recycle_free(lfqueue_t*, lfqueue_cas_node_t*);
|
||||||
static void __lfq_check_free(lfqueue_t *);
|
static void __lfq_check_free(lfqueue_t*);
|
||||||
static void *_dequeue(lfqueue_t *);
|
static void* _dequeue(lfqueue_t*);
|
||||||
static void *_single_dequeue(lfqueue_t *);
|
static void* _single_dequeue(lfqueue_t*);
|
||||||
static int _enqueue(lfqueue_t *, void* );
|
static int _enqueue(lfqueue_t*, void*);
|
||||||
static inline void* _lfqueue_malloc(__attribute__ ((unused)) void* pl, size_t sz) {
|
static inline void* _lfqueue_malloc(__attribute__((unused)) void* pl, size_t sz)
|
||||||
return malloc(sz);
|
{
|
||||||
|
return malloc(sz);
|
||||||
}
|
}
|
||||||
static inline void _lfqueue_free(__attribute__ ((unused)) void* pl, void* ptr) {
|
static inline void _lfqueue_free(__attribute__((unused)) void* pl, void* ptr)
|
||||||
free(ptr);
|
{
|
||||||
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void*
|
||||||
_dequeue(lfqueue_t *lfqueue) {
|
_dequeue(lfqueue_t* lfqueue)
|
||||||
lfqueue_cas_node_t *head, *next;
|
{
|
||||||
void *val;
|
lfqueue_cas_node_t *head, *next;
|
||||||
|
void* val;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
head = lfqueue->head;
|
head = lfqueue->head;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, head)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, head)) {
|
||||||
next = head->next;
|
next = head->next;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->tail, head, head)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->tail, head, head)) {
|
||||||
if (next == NULL) {
|
if (next == NULL) {
|
||||||
val = NULL;
|
val = NULL;
|
||||||
goto _done;
|
goto _done;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (next) {
|
||||||
if (next) {
|
val = next->value;
|
||||||
val = next->value;
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
break;
|
||||||
break;
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
val = NULL;
|
||||||
val = NULL;
|
goto _done;
|
||||||
goto _done;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
__lfq_recycle_free(lfqueue, head);
|
__lfq_recycle_free(lfqueue, head);
|
||||||
_done:
|
_done:
|
||||||
// __asm volatile("" ::: "memory");
|
// __asm volatile("" ::: "memory");
|
||||||
__LFQ_SYNC_MEMORY();
|
__LFQ_SYNC_MEMORY();
|
||||||
__lfq_check_free(lfqueue);
|
__lfq_check_free(lfqueue);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void*
|
||||||
_single_dequeue(lfqueue_t *lfqueue) {
|
_single_dequeue(lfqueue_t* lfqueue)
|
||||||
lfqueue_cas_node_t *head, *next;
|
{
|
||||||
void *val;
|
lfqueue_cas_node_t *head, *next;
|
||||||
|
void* val;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
head = lfqueue->head;
|
head = lfqueue->head;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, head)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, head)) {
|
||||||
next = head->next;
|
next = head->next;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->tail, head, head)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->tail, head, head)) {
|
||||||
if (next == NULL) {
|
if (next == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (next) {
|
||||||
if (next) {
|
val = next->value;
|
||||||
val = next->value;
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
lfqueue->_free(lfqueue->pl, head);
|
||||||
lfqueue->_free(lfqueue->pl, head);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return val;
|
||||||
return val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_enqueue(lfqueue_t *lfqueue, void* value) {
|
_enqueue(lfqueue_t* lfqueue, void* value)
|
||||||
lfqueue_cas_node_t *tail, *node;
|
{
|
||||||
node = (lfqueue_cas_node_t*) lfqueue->_malloc(lfqueue->pl, sizeof(lfqueue_cas_node_t));
|
lfqueue_cas_node_t *tail, *node;
|
||||||
if (node == NULL) {
|
node = (lfqueue_cas_node_t*)lfqueue->_malloc(lfqueue->pl, sizeof(lfqueue_cas_node_t));
|
||||||
perror("malloc");
|
if (node == NULL) {
|
||||||
return errno;
|
perror("malloc");
|
||||||
}
|
return errno;
|
||||||
node->value = value;
|
}
|
||||||
node->next = NULL;
|
node->value = value;
|
||||||
node->nextfree = NULL;
|
node->next = NULL;
|
||||||
for (;;) {
|
node->nextfree = NULL;
|
||||||
__LFQ_SYNC_MEMORY();
|
for (;;) {
|
||||||
tail = lfqueue->tail;
|
__LFQ_SYNC_MEMORY();
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&tail->next, NULL, node)) {
|
tail = lfqueue->tail;
|
||||||
// compulsory swap as tail->next is no NULL anymore, it has fenced on other thread
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&tail->next, NULL, node)) {
|
||||||
__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->tail, tail, node);
|
// compulsory swap as tail->next is no NULL anymore, it has fenced on other thread
|
||||||
__lfq_check_free(lfqueue);
|
__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->tail, tail, node);
|
||||||
return 0;
|
__lfq_check_free(lfqueue);
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*It never be here*/
|
/*It never be here*/
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
__lfq_recycle_free(lfqueue_t *lfqueue, lfqueue_cas_node_t* freenode) {
|
__lfq_recycle_free(lfqueue_t* lfqueue, lfqueue_cas_node_t* freenode)
|
||||||
lfqueue_cas_node_t *freed;
|
{
|
||||||
do {
|
lfqueue_cas_node_t* freed;
|
||||||
freed = lfqueue->move_free;
|
do {
|
||||||
} while (!__LFQ_BOOL_COMPARE_AND_SWAP(&freed->nextfree, NULL, freenode) );
|
freed = lfqueue->move_free;
|
||||||
|
} while (!__LFQ_BOOL_COMPARE_AND_SWAP(&freed->nextfree, NULL, freenode));
|
||||||
|
|
||||||
lfq_get_curr_time(&freenode->_deactivate_tm);
|
lfq_get_curr_time(&freenode->_deactivate_tm);
|
||||||
|
|
||||||
__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->move_free, freed, freenode);
|
__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->move_free, freed, freenode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
__lfq_check_free(lfqueue_t *lfqueue) {
|
__lfq_check_free(lfqueue_t* lfqueue)
|
||||||
lfq_time_t curr_time;
|
{
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->in_free_mode, 0, 1)) {
|
lfq_time_t curr_time;
|
||||||
lfq_get_curr_time(&curr_time);
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->in_free_mode, 0, 1)) {
|
||||||
lfqueue_cas_node_t *rtfree = lfqueue->root_free, *nextfree;
|
lfq_get_curr_time(&curr_time);
|
||||||
while ( rtfree && (rtfree != lfqueue->move_free) ) {
|
lfqueue_cas_node_t *rtfree = lfqueue->root_free, *nextfree;
|
||||||
nextfree = rtfree->nextfree;
|
while (rtfree && (rtfree != lfqueue->move_free)) {
|
||||||
if ( lfq_diff_time(curr_time, rtfree->_deactivate_tm) > 2) {
|
nextfree = rtfree->nextfree;
|
||||||
// printf("%p\n", rtfree);
|
if (lfq_diff_time(curr_time, rtfree->_deactivate_tm) > 2) {
|
||||||
lfqueue->_free(lfqueue->pl, rtfree);
|
// printf("%p\n", rtfree);
|
||||||
rtfree = nextfree;
|
lfqueue->_free(lfqueue->pl, rtfree);
|
||||||
} else {
|
rtfree = nextfree;
|
||||||
break;
|
} else {
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
lfqueue->root_free = rtfree;
|
}
|
||||||
__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->in_free_mode, 1, 0);
|
lfqueue->root_free = rtfree;
|
||||||
}
|
__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->in_free_mode, 1, 0);
|
||||||
__LFQ_SYNC_MEMORY();
|
}
|
||||||
|
__LFQ_SYNC_MEMORY();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lfqueue_init(lfqueue_t* lfqueue)
|
||||||
lfqueue_init(lfqueue_t *lfqueue) {
|
{
|
||||||
return lfqueue_init_mf(lfqueue, NULL, _lfqueue_malloc, _lfqueue_free);
|
return lfqueue_init_mf(lfqueue, NULL, _lfqueue_malloc, _lfqueue_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lfqueue_init_mf(lfqueue_t* lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc, lfqueue_free_fn lfqueue_free)
|
||||||
lfqueue_init_mf(lfqueue_t *lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc, lfqueue_free_fn lfqueue_free) {
|
{
|
||||||
lfqueue->_malloc = lfqueue_malloc;
|
lfqueue->_malloc = lfqueue_malloc;
|
||||||
lfqueue->_free = lfqueue_free;
|
lfqueue->_free = lfqueue_free;
|
||||||
lfqueue->pl = pl;
|
lfqueue->pl = pl;
|
||||||
|
|
||||||
lfqueue_cas_node_t *base = lfqueue_malloc(pl, sizeof(lfqueue_cas_node_t));
|
lfqueue_cas_node_t* base = lfqueue_malloc(pl, sizeof(lfqueue_cas_node_t));
|
||||||
lfqueue_cas_node_t *freebase = lfqueue_malloc(pl, sizeof(lfqueue_cas_node_t));
|
lfqueue_cas_node_t* freebase = lfqueue_malloc(pl, sizeof(lfqueue_cas_node_t));
|
||||||
if (base == NULL || freebase == NULL) {
|
if (base == NULL || freebase == NULL) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
base->value = NULL;
|
base->value = NULL;
|
||||||
base->next = NULL;
|
base->next = NULL;
|
||||||
base->nextfree = NULL;
|
base->nextfree = NULL;
|
||||||
base->_deactivate_tm = 0;
|
base->_deactivate_tm = 0;
|
||||||
|
|
||||||
freebase->value = NULL;
|
freebase->value = NULL;
|
||||||
freebase->next = NULL;
|
freebase->next = NULL;
|
||||||
freebase->nextfree = NULL;
|
freebase->nextfree = NULL;
|
||||||
freebase->_deactivate_tm = 0;
|
freebase->_deactivate_tm = 0;
|
||||||
|
|
||||||
lfqueue->head = lfqueue->tail = base; // Not yet to be free for first node only
|
lfqueue->head = lfqueue->tail = base; // Not yet to be free for first node only
|
||||||
lfqueue->root_free = lfqueue->move_free = freebase; // Not yet to be free for first node only
|
lfqueue->root_free = lfqueue->move_free = freebase; // Not yet to be free for first node only
|
||||||
lfqueue->size = 0;
|
lfqueue->size = 0;
|
||||||
lfqueue->in_free_mode = 0;
|
lfqueue->in_free_mode = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lfqueue_destroy(lfqueue_t* lfqueue)
|
||||||
lfqueue_destroy(lfqueue_t *lfqueue) {
|
{
|
||||||
void* p;
|
void* p;
|
||||||
while ((p = lfqueue_deq(lfqueue))) {
|
while ((p = lfqueue_deq(lfqueue))) {
|
||||||
lfqueue->_free(lfqueue->pl, p);
|
lfqueue->_free(lfqueue->pl, p);
|
||||||
}
|
}
|
||||||
// Clear the recycle chain nodes
|
// Clear the recycle chain nodes
|
||||||
lfqueue_cas_node_t *rtfree = lfqueue->root_free, *nextfree;
|
lfqueue_cas_node_t *rtfree = lfqueue->root_free, *nextfree;
|
||||||
while (rtfree && (rtfree != lfqueue->move_free) ) {
|
while (rtfree && (rtfree != lfqueue->move_free)) {
|
||||||
nextfree = rtfree->nextfree;
|
nextfree = rtfree->nextfree;
|
||||||
lfqueue->_free(lfqueue->pl, rtfree);
|
lfqueue->_free(lfqueue->pl, rtfree);
|
||||||
rtfree = nextfree;
|
rtfree = nextfree;
|
||||||
}
|
}
|
||||||
if (rtfree) {
|
if (rtfree) {
|
||||||
lfqueue->_free(lfqueue->pl, rtfree);
|
lfqueue->_free(lfqueue->pl, rtfree);
|
||||||
}
|
}
|
||||||
|
|
||||||
lfqueue->_free(lfqueue->pl, lfqueue->tail); // Last free
|
lfqueue->_free(lfqueue->pl, lfqueue->tail); // Last free
|
||||||
|
|
||||||
lfqueue->size = 0;
|
lfqueue->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lfqueue_enq(lfqueue_t* lfqueue, void* value)
|
||||||
lfqueue_enq(lfqueue_t *lfqueue, void *value) {
|
{
|
||||||
if (_enqueue(lfqueue, value)) {
|
if (_enqueue(lfqueue, value)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
__LFQ_ADD_AND_FETCH(&lfqueue->size, 1);
|
__LFQ_ADD_AND_FETCH(&lfqueue->size, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* lfqueue_deq(lfqueue_t* lfqueue)
|
||||||
lfqueue_deq(lfqueue_t *lfqueue) {
|
{
|
||||||
void *v;
|
void* v;
|
||||||
if (//__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
if ( //__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
||||||
(v = _dequeue(lfqueue))
|
(v = _dequeue(lfqueue))) {
|
||||||
) {
|
|
||||||
|
|
||||||
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* lfqueue_deq_must(lfqueue_t* lfqueue)
|
||||||
lfqueue_deq_must(lfqueue_t *lfqueue) {
|
{
|
||||||
void *v;
|
void* v;
|
||||||
while ( !(v = _dequeue(lfqueue)) ) {
|
while (!(v = _dequeue(lfqueue))) {
|
||||||
// Rest the thread for other thread, to avoid keep looping force
|
// Rest the thread for other thread, to avoid keep looping force
|
||||||
lfqueue_sleep(1);
|
lfqueue_sleep(1);
|
||||||
}
|
}
|
||||||
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**This is only applicable when only single thread consume only**/
|
/**This is only applicable when only single thread consume only**/
|
||||||
void*
|
void* lfqueue_single_deq(lfqueue_t* lfqueue)
|
||||||
lfqueue_single_deq(lfqueue_t *lfqueue) {
|
{
|
||||||
void *v;
|
void* v;
|
||||||
if (//__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
if ( //__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
||||||
(v = _single_dequeue(lfqueue))
|
(v = _single_dequeue(lfqueue))) {
|
||||||
) {
|
|
||||||
|
|
||||||
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**This is only applicable when only single thread consume only**/
|
/**This is only applicable when only single thread consume only**/
|
||||||
void*
|
void* lfqueue_single_deq_must(lfqueue_t* lfqueue)
|
||||||
lfqueue_single_deq_must(lfqueue_t *lfqueue) {
|
{
|
||||||
void *v;
|
void* v;
|
||||||
while ( !(v = _single_dequeue(lfqueue)) ) {
|
while (!(v = _single_dequeue(lfqueue))) {
|
||||||
// Rest the thread for other thread, to avoid keep looping force
|
// Rest the thread for other thread, to avoid keep looping force
|
||||||
lfqueue_sleep(1);
|
lfqueue_sleep(1);
|
||||||
}
|
}
|
||||||
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
lfqueue_size(lfqueue_t *lfqueue) {
|
lfqueue_size(lfqueue_t* lfqueue)
|
||||||
return __LFQ_ADD_AND_FETCH(&lfqueue->size, 0);
|
{
|
||||||
|
return __LFQ_ADD_AND_FETCH(&lfqueue->size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lfqueue_sleep(unsigned int milisec)
|
||||||
lfqueue_sleep(unsigned int milisec) {
|
{
|
||||||
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
|
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
|
||||||
usleep(milisec * 1000);
|
usleep(milisec * 1000);
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#else
|
#else
|
||||||
Sleep(milisec);
|
Sleep(milisec);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* BSD 2-Clause License
|
* BSD 2-Clause License
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018, Taymindis Woon
|
* Copyright (c) 2018, Taymindis Woon
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
*
|
*
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
* list of conditions and the following disclaimer.
|
* list of conditions and the following disclaimer.
|
||||||
*
|
*
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
* and/or other materials provided with the distribution.
|
* and/or other materials provided with the distribution.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
* 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
|
* 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.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LFQUEUE_H
|
#ifndef LFQUEUE_H
|
||||||
#define LFQUEUE_H
|
#define LFQUEUE_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -53,32 +53,30 @@ typedef void (*lfqueue_free_fn)(void*, void*);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
lfqueue_cas_node_t *head, *tail, *root_free, *move_free;
|
lfqueue_cas_node_t *head, *tail, *root_free, *move_free;
|
||||||
volatile size_t size;
|
volatile size_t size;
|
||||||
volatile lfq_bool_t in_free_mode;
|
volatile lfq_bool_t in_free_mode;
|
||||||
lfqueue_malloc_fn _malloc;
|
lfqueue_malloc_fn _malloc;
|
||||||
lfqueue_free_fn _free;
|
lfqueue_free_fn _free;
|
||||||
void *pl;
|
void* pl;
|
||||||
} lfqueue_t;
|
} lfqueue_t;
|
||||||
|
|
||||||
extern int lfqueue_init(lfqueue_t *lfqueue);
|
extern int lfqueue_init(lfqueue_t* lfqueue);
|
||||||
extern int lfqueue_init_mf(lfqueue_t *lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc, lfqueue_free_fn lfqueue_free);
|
extern int lfqueue_init_mf(lfqueue_t* lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc, lfqueue_free_fn lfqueue_free);
|
||||||
extern int lfqueue_enq(lfqueue_t *lfqueue, void *value);
|
extern int lfqueue_enq(lfqueue_t* lfqueue, void* value);
|
||||||
extern void* lfqueue_deq(lfqueue_t *lfqueue);
|
extern void* lfqueue_deq(lfqueue_t* lfqueue);
|
||||||
extern void* lfqueue_single_deq(lfqueue_t *lfqueue);
|
extern void* lfqueue_single_deq(lfqueue_t* lfqueue);
|
||||||
|
|
||||||
/** loop until value been dequeue, it sleeps 1ms if not found to reduce cpu high usage **/
|
/** loop until value been dequeue, it sleeps 1ms if not found to reduce cpu high usage **/
|
||||||
extern void* lfqueue_deq_must(lfqueue_t *lfqueue);
|
extern void* lfqueue_deq_must(lfqueue_t* lfqueue);
|
||||||
extern void* lfqueue_single_deq_must(lfqueue_t *lfqueue);
|
extern void* lfqueue_single_deq_must(lfqueue_t* lfqueue);
|
||||||
|
|
||||||
extern void lfqueue_destroy(lfqueue_t *lfqueue);
|
extern void lfqueue_destroy(lfqueue_t* lfqueue);
|
||||||
extern size_t lfqueue_size(lfqueue_t *lfqueue);
|
extern size_t lfqueue_size(lfqueue_t* lfqueue);
|
||||||
extern void lfqueue_sleep(unsigned int milisec);
|
extern void lfqueue_sleep(unsigned int milisec);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue