Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
8acf2a4
refactor: improve code readability and consistency in shared memory c…
draugvar Oct 15, 2025
46f1b7d
refactor: enhance code formatting and consistency in shared memory cl…
draugvar Oct 15, 2025
07f4371
refactor: improve code formatting and consistency in test cases
draugvar Oct 15, 2025
680abfe
refactor: update .gitignore and clean up README.md
draugvar Oct 15, 2025
57e79cc
ci: add build and test workflow with CMake integration
draugvar Oct 15, 2025
af5463b
refactor: update EXPECT statements to use unsigned long literals for …
draugvar Oct 15, 2025
03e176f
refactor: include cstdint for fixed-width integer types
draugvar Oct 15, 2025
d6d41af
refactor: fix constructor and method signature for Memory class
draugvar Oct 15, 2025
b7ae226
refactor: enhance Memory class with persistence file handling and imp…
draugvar Oct 15, 2025
8dc8058
refactor: ensure NOMINMAX is defined for Windows compatibility
draugvar Oct 15, 2025
9b5ac0c
refactor: update GitHub Actions workflow for improved build and relea…
draugvar Oct 15, 2025
14a9a9d
refactor: add release notes generation to GitHub Actions workflow
draugvar Oct 15, 2025
70b4fd0
refactor: fix tag existence check in release workflow
draugvar Oct 15, 2025
3afe1ec
refactor: fix tag existence check logic in release workflow and reord…
draugvar Oct 15, 2025
8f50b48
bump version to 0.1.0
draugvar Oct 15, 2025
8664142
refactor: remove package.json and package-lock.json; enhance test out…
draugvar Oct 15, 2025
95e8859
refactor: update library version to 1.0.0 and remove conditional rele…
draugvar Oct 15, 2025
75cc1e8
Merge pull request #1 from draugvar/tests
draugvar Oct 15, 2025
7ec949a
refactor: increment LIBSHAREDMEMORY_VERSION_MINOR to 1 and clean up i…
draugvar Oct 16, 2025
b1927a0
refactor: update compiler options for MSVC and add POSIX shared memor…
draugvar Oct 16, 2025
14e34a6
refactor: increment LIBSHAREDMEMORY_VERSION_MINOR to 2
draugvar Oct 17, 2025
63e1c7c
Initial plan
Copilot Nov 4, 2025
2f238ea
Modernize library to C++20 with enhanced type safety and features
Copilot Nov 4, 2025
edc49cb
Address code review feedback: remove unused include and trailing whit…
Copilot Nov 4, 2025
20e4ff2
Complete C++20/23 modernization with security validation
Copilot Nov 4, 2025
b585722
Update libsharedmemory.hpp
draugvar Nov 4, 2025
40dc976
Update .gitignore to exclude CodeQL build artifacts
Copilot Nov 4, 2025
dd87919
Update libsharedmemory.hpp
draugvar Nov 4, 2025
8ffe5de
Merge pull request #3 from draugvar/copilot/add-support-for-cpp20-23
draugvar Nov 4, 2025
712803a
feat: add SharedMemoryQueue for FIFO message handling and enhance sha…
draugvar Nov 5, 2025
dd3679c
refactor: replace string literals with std::runtime_error in shared m…
draugvar Nov 5, 2025
8b789e7
refactor: improve error handling with std::runtime_error and enhance …
draugvar Nov 5, 2025
5d851af
refactor: enhance SharedMemoryQueue with atomic count management for …
draugvar Nov 5, 2025
60a2808
feat: add GetSystemStorageDirectory function to manage shared memory …
draugvar Feb 6, 2026
6255352
refactor: simplify persistence_file_path function by using GetSystemS…
draugvar Feb 6, 2026
6989cd0
Merge pull request #4 from draugvar/fix-windows
draugvar Feb 6, 2026
e86e815
feat: add CHANGELOG.md for version 1.7.0 and update README.md with ne…
draugvar Feb 6, 2026
afaa4d0
Merge pull request #5 from draugvar/fix-permission
draugvar Feb 6, 2026
200c9cb
acl setup with inheritance, clean handle close/set permissions/reopen…
amassuoli Feb 6, 2026
c6a59f6
Simplify build_and_test workflow triggers
draugvar Feb 6, 2026
52b1776
Merge branch 'main' into custom-acl
amassuoli Feb 6, 2026
3420004
step version v1.8.0
amassuoli Feb 6, 2026
c42f565
Merge branch 'custom-acl' of https://github.com/draugvar/libsharedmem…
amassuoli Feb 6, 2026
3eaffd7
update changelog
amassuoli Feb 6, 2026
6b6be31
Merge pull request #6 from draugvar/custom-acl
draugvar Feb 6, 2026
0e023d4
change linux shm file perm to 777
amassuoli Feb 13, 2026
aa6ac36
v1.9.0 - paperwork
amassuoli Feb 13, 2026
c9c7d7c
add sys/stat.h explicit include (linux)
amassuoli Feb 13, 2026
ddf17c5
Merge pull request #7 from draugvar/linux-shm-perm
draugvar Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
name: Build and Test

on:
pull_request:
branches:
- main

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Release]
include:
- os: ubuntu-latest
cc: gcc
cxx: g++
- os: windows-latest
cc: cl
cxx: cl

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup CMake
uses: jwlawson/actions-setup-cmake@master

- name: Configure CMake
run: cmake -B build

- name: Build
run: cmake --build build --config Release

- name: Test
run: cmake --build build --config Release --target run_test

release:
runs-on: ubuntu-latest
needs: build
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Determine library version
id: version
run: |
python - <<'PY'
import os
import re
from pathlib import Path

header = Path('include/libsharedmemory/libsharedmemory.hpp').read_text(encoding='utf-8')

def macro(name: str) -> str:
match = re.search(rf'#define\s+{name}\s+(\d+)', header)
if not match:
raise SystemExit(f'Macro {name} not found in header')
return match.group(1)

major = macro('LIBSHAREDMEMORY_VERSION_MAJOR')
minor = macro('LIBSHAREDMEMORY_VERSION_MINOR')
patch = macro('LIBSHAREDMEMORY_VERSION_PATCH')
version = f'v{major}.{minor}.{patch}'

with open(os.environ['GITHUB_OUTPUT'], 'a', encoding='utf-8') as output:
output.write(f'version={version}\n')
PY

- name: Check if tag already exists
id: tag_check
run: |
git fetch --tags --force
if git rev-parse "${{ steps.version.outputs.version }}" >/dev/null 2>&1; then
echo "exists=true" >>"$GITHUB_OUTPUT"
exit 1
else
echo "exists=false" >>"$GITHUB_OUTPUT"
exit 0
fi

- name: Generate release notes
if: steps.tag_check.outputs.exists == 'false'
id: notes
run: |
python - <<'PY'
import os
import subprocess

def git_output(args):
result = subprocess.run(args, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return result.stdout.strip()

last_tag = ""
try:
last_tag = git_output(["git", "describe", "--tags", "--abbrev=0"])
except subprocess.CalledProcessError:
last_tag = ""

if last_tag:
log_range = f"{last_tag}..HEAD"
else:
log_range = "HEAD"

try:
notes = git_output(["git", "log", log_range, "--pretty=format:- %s (%h)"])
except subprocess.CalledProcessError:
notes = ""

notes = notes.strip()
if not notes:
notes = "No commits since previous release."

if last_tag:
header = f"Changes since {last_tag}:"
else:
header = "Changes since repository start:"

body = f"{header}\n\n{notes}"

with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
fh.write("body<<EOF\n")
fh.write(body)
fh.write("\nEOF\n")
PY

- name: Create GitHub release
if: steps.tag_check.outputs.exists == 'false'
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.version.outputs.version }}
release_name: ${{ steps.version.outputs.version }}
commitish: ${{ github.sha }}
body: ${{ steps.notes.outputs.body }}
draft: false
prerelease: false
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.cache
.vscode
build
build
.idea
cmake-build-*
_codeql_build_dir
_codeql_detected_source_root
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.9.0] - 2026-02-13

### Added:

- **Linux**: Default permissions set to 0777.


## [1.8.0] - 2026-02-06

### Added:

- **Windows**: ACL inheritance for shared file, clean close/reopen when applying settings.

## [1.7.0] - 2026-02-06

### Added
- **SharedMemoryQueue**: New FIFO message queue functionality for inter-process communication
- Thread-safe enqueue/dequeue operations using atomic counters
- Configurable capacity and maximum message size
- `peek()` method to inspect messages without removing them
- Status methods: `isEmpty()`, `isFull()`, `size()`, `capacity()`
- Supports single producer/single consumer and single producer/multiple consumers patterns
- Windows persistency support for shared memory segments
- Persistent file-backed shared memory on Windows using `%PROGRAMDATA%/shared_memory/` directory
- Automatic directory creation and permission management on Windows
- Configurable persistence with `persist` parameter in constructor

### Changed
- Updated C++20 requirements with `std::atomic` support for queue operations
- Improved memory layout with atomic operations for queue counters
- Enhanced Windows implementation with better file handle management

### Fixed
- Memory leak prevention in queue implementation
- Proper cleanup of shared memory on all platforms

## Previous Versions

Prior to version 1.7.0, the library supported:
- Basic shared memory creation and access on Windows, Linux, and macOS
- Stream-based data transfer with `SharedMemoryWriteStream` and `SharedMemoryReadStream`
- Support for `std::string`, `float*`, and `double*` array types
- Change detection with flag bit flipping
- Single value access via `.data()[index]` API

9 changes: 5 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.12)
cmake_policy(SET CMP0042 NEW)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(LSM)
Expand All @@ -13,10 +14,10 @@ target_sources(lsm INTERFACE "$<BUILD_INTERFACE:${header_files}>")
target_include_directories(lsm INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/>)
target_include_directories(lsm SYSTEM INTERFACE $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>)

if (${CMAKE_GENERATOR} MATCHES "Visual")
target_compile_options(lsm INTERFACE -W3 -EHsc)
if (MSVC)
target_compile_options(lsm INTERFACE /W3 /EHsc /std:c++20)
else()
target_compile_options(lsm INTERFACE -Wall -Wno-missing-braces -std=c++11 -fPIC)
target_compile_options(lsm INTERFACE -Wall -Wno-missing-braces -std=c++20 -fPIC)
endif()

option(LSM_BUILD_TEST "build test" ON)
Expand Down
85 changes: 55 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# `libsharedmemory`

`libsharedmemory` is a small C++11 header-only library for using shared memory on Windows, Linux and macOS. `libsharedmemory` makes it easy to transfer data between isolated host OS processes. It also helps inter-connecting modules of applications that are implemented in different programming languages. It allows for simple read/write data transfer using single, indexed memory address access and also using array-types like `std::string`, `float*`, `double*`.
`libsharedmemory` is a small C++20 header-only library for using shared memory on Windows, Linux and macOS. `libsharedmemory` makes it easy to transfer data between isolated host OS processes. It also helps inter-connecting modules of applications that are implemented in different programming languages. It supports:

- Simple read/write data transfer using single, indexed memory address access
- Array-types like `std::string`, `float*`, `double*`
- Message queue functionality with `SharedMemoryQueue` for FIFO communication

<img src="screenshot.png" width="350px" />

Expand Down Expand Up @@ -28,6 +32,34 @@ std::string dataString = read$.readString();
std::cout << "UTF8 string written and read" << dataString << std::endl;
```

### Message Queue Example

```cpp
// Create a message queue with capacity for 10 messages, max 256 bytes each
SharedMemoryQueue writer{"messageQueue", /*capacity*/ 10, /*maxMessageSize*/ 256, /*persistent*/ true, /*isWriter*/ true};
SharedMemoryQueue reader{"messageQueue", /*capacity*/ 10, /*maxMessageSize*/ 256, /*persistent*/ true, /*isWriter*/ false};

// Enqueue messages from writer
writer.enqueue("First message");
writer.enqueue("Second message");

// Dequeue messages from reader
std::string msg;
if (reader.dequeue(msg)) {
std::cout << "Received: " << msg << std::endl;
}

// Peek at next message without removing it
if (reader.peek(msg)) {
std::cout << "Next message: " << msg << std::endl;
}

// Check queue status
std::cout << "Queue size: " << reader.size() << std::endl;
std::cout << "Is empty: " << reader.isEmpty() << std::endl;
std::cout << "Is full: " << reader.isFull() << std::endl;
```

## Source code package management via `npm`

In case you want to use this library in your codebase,
Expand All @@ -45,27 +77,38 @@ reports that are announced when running `npm audit`. Finally, it's also much
easier for you to install all project dependencies by just running `npm install`
in your projects root directory. Managing third party code becomes obsolete at all.

## Limits
## Features

`libsharedmemory` does only support the following datatypes (array-like):
- `std::string`
- `float*`
- `double*`
### Stream-based Transfer
`libsharedmemory` supports the following datatypes for stream-based transfer:
- `std::string` (UTF-8 compatible)
- `float*` (arrays of floats)
- `double*` (arrays of doubles)

Single value access via `.data()[index]` API:
- all scalar datatypes supported in C/C++

- This library doesn't care for endinanness. This should be naturally fine
### Message Queue
`SharedMemoryQueue` provides FIFO message queue functionality:
- Thread-safe enqueue/dequeue operations
- Configurable capacity and maximum message size
- Peek functionality to inspect messages without removing them
- Suitable for single producer, single consumer or single producer, multiple consumers patterns

## Limits

- This library doesn't care for endianness. This should be naturally fine
because shared memory shouldn't be shared between different machine
architectures. However, if you plan to copy the shared buffer onto a
network layer prototcol, make sure to add an endianess indication bit.
network layer protocol, make sure to add an endianness indication bit.

- Although the binary memory layout should give you no headache
when compiling/linking using different compilers,
the behavior is undefined.

- At the time of writing, there is no support for shared memory persistency
on Windows. Shared memory is lost after the writing process is killed.
- **SharedMemoryQueue** currently works best for single producer, single consumer
or single producer, multiple consumers scenarios. Multiple concurrent producers
require additional external synchronization.

## Memory layout

Expand All @@ -92,29 +135,11 @@ enum DataType {
to indicate data change. Continuous data reader will thus be able
to catch every data change.

## Build

This project is meant to be built with `cmake` and `clang`.
However, it _should_ also build with MSVC and GCC.

```sh
./build.sh
```

## Test

Test executables are built automatically and can be executed
to verify the correct function of the implementation on your machine:

```sh
./test.sh
```

## License

`libsharedmemory` is released under the MIT license, see the `LICENSE` file.

## Roadmap

1) Windows shared memory persistency support
2) Multi-threaded non-blocking `onChange( lambda fn )` data change handler on the read stream
1) Multi-threaded non-blocking `onChange( lambda fn )` data change handler on the read stream
2) Support for multiple concurrent producers in SharedMemoryQueue with lock-free atomic operations
3 changes: 0 additions & 3 deletions build.sh

This file was deleted.

Loading