Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
{
"permissions": {
"allow": [
"Bash(wc -l /c/Users/iwank/Documents/github/threadpool-fp/src/*.pas)"
"Bash(wc -l /c/Users/iwank/Documents/github/threadpool-fp/src/*.pas)",
"Bash(grep -iE '\\\\.\\(o|ppu|a|compiled|bak|lps|res\\)$|/lib/|/backup/')",
"Bash(grep -iE 'threadpool.*\\\\.pas$|\\\\.lpk$|\\\\.lpi$|\\\\.lpr$')",
"Bash(grep -iE '\\\\.\\(o|ppu|bak\\)$|/lib/|/backup/')",
"Bash(fpc -iV)",
"Bash(grep '\\\\.lpi$')",
"Bash(lazbuild tests/TestRunner.lpi)",
"Bash(git remote *)",
"Bash(git status *)"
]
}
}
64 changes: 64 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: 🐛 Bug Report
description: Report something that isn't working as expected
labels: ["bug"]
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a bug report!
- type: textarea
id: what-happened
attributes:
label: What happened?
description: A clear description of the bug, including what you expected instead.
validations:
required: true
- type: textarea
id: repro
attributes:
label: Steps to reproduce
description: A minimal code snippet or the steps that trigger the problem.
placeholder: |
1. Create a TSimpleThreadPool with ...
2. Queue ...
3. Call WaitForAll ...
render: pascal
validations:
required: true
- type: dropdown
id: pool
attributes:
label: Which implementation?
options:
- ThreadPool.Simple
- ThreadPool.ProducerConsumer
- Both / not sure
validations:
required: true
- type: input
id: fpc-version
attributes:
label: Free Pascal version
placeholder: "3.2.2"
validations:
required: true
- type: input
id: lazarus-version
attributes:
label: Lazarus version (if used)
placeholder: "3.6.0"
- type: dropdown
id: os
attributes:
label: Operating system
options:
- Windows
- Linux
- macOS
- Other
validations:
required: true
- type: textarea
id: extra
attributes:
label: Anything else?
description: Logs, error messages, or context that might help.
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Questions & Discussion
url: https://github.com/ikelaiah/threadpool-fp/discussions
about: Ask usage questions or share what you built.
22 changes: 22 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 💡 Feature Request
description: Suggest an idea or improvement
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: What problem would this solve?
description: Describe the use case or pain point motivating the request.
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
description: What would you like to see? An API sketch is welcome.
render: pascal
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Other approaches or workarounds you've thought about.
24 changes: 24 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- Thanks for contributing! Please fill out the sections below. -->

## What does this PR do?

<!-- A clear description of the change and the motivation behind it. -->

## Related issue

<!-- e.g. Closes #123 -->

## Type of change

- [ ] 🐛 Bug fix
- [ ] ✨ New feature
- [ ] 📝 Documentation / examples
- [ ] 🔧 Refactor / internal change

## Checklist

- [ ] Tests pass locally (`lazbuild tests/TestRunner.lpi` then run `TestRunner`)
- [ ] Added/updated tests where it makes sense
- [ ] Updated `CHANGELOG.md`
- [ ] Updated docs in `docs/` if behavior or API changed
- [ ] New units use `{$mode objfpc}{$H+}{$J-}` and filenames match unit casing
67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
build-and-test:
name: Build & Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]

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

- name: Install Lazarus + FPC
uses: gcarreno/setup-lazarus@v3
with:
lazarus-version: stable

- name: Build package
run: lazbuild package/lazarus/threadpool_fp.lpk

- name: Build test runner
run: lazbuild tests/TestRunner.lpi

- name: Run tests
shell: bash
run: |
if [ -f tests/TestRunner.exe ]; then
./tests/TestRunner.exe -a -p --format=plain
else
./tests/TestRunner -a -p --format=plain
fi

build-examples:
name: Build examples (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]

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

- name: Install Lazarus + FPC
uses: gcarreno/setup-lazarus@v3
with:
lazarus-version: stable

- name: Build all examples
shell: bash
run: |
set -e
for lpi in examples/*/*.lpi; do
echo "==> Building $lpi"
lazbuild "$lpi"
done
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@ 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.1.0/).

## [0.6.0] - 2026-06-11

### Added

- GitHub Actions CI (`.github/workflows/ci.yml`) — builds the package, runs the FPCUnit test suite, and builds all examples on both Linux and Windows for every push and pull request
- `CONTRIBUTING.md` — build/test instructions, code style guide (including the unit-filename casing rule), and pull-request workflow
- Issue templates (`.github/ISSUE_TEMPLATE/`) for bug reports and feature requests, plus a discussions contact link
- Pull request template (`.github/PULL_REQUEST_TEMPLATE.md`)
- README: Contributing section linking to `CONTRIBUTING.md`

### Changed

- Renamed source files to match their `unit` identifier casing so the library compiles on case-sensitive filesystems (Linux): `threadpool.simple.pas` → `ThreadPool.Simple.pas`, `threadpool.producerconsumer.pas` → `ThreadPool.ProducerConsumer.pas`, and `tests/threadpool.producerconsumer.tests.pas` → `tests/ThreadPool.ProducerConsumer.Tests.pas`
- Normalized the unit reference in `tests/TestRunner.lpr` (`Threadpool.` → `ThreadPool.`)
- README: replaced the hardcoded test-count badge with a live CI status badge

### Fixed

- **Access violation on Linux at runtime (exit code 217).** The test runner and example programs were missing the `cthreads` unit, which Unix/Linux requires (as the first unit) for any program that creates threads. Without it, constructing the thread pool crashed in the worker/sync-object setup. Added `{$IFDEF UNIX}cthreads{$ENDIF}` to `tests/TestRunner.lpr` and all 8 example programs. Windows was unaffected and did not need it
- `ThreadPool.Simple` now compiles on non-Windows targets: the `IWorkerThread` methods (`QueryInterface`/`_AddRef`/`_Release`) hardcoded the `stdcall` calling convention, which only matches `IInterface` on Windows — FPC uses `cdecl` elsewhere. Guarded with `{$IFDEF WINDOWS}stdcall{$ELSE}cdecl{$ENDIF}`
- `TSimpleWorkerThread` is now explicitly non-ref-counted (`_AddRef`/`_Release` return `-1`, the `TComponent` contract), so an `IWorkerThread` interface assignment can never free a worker the pool still owns via `ClearThreads`. Removed the now-unused `FRefCount` field
- `TSimpleThreadPool.Destroy` is now safe to call on a partially constructed pool: it skips `WaitForAll` and the queue/thread cleanup when the relevant fields are `nil`, instead of dereferencing them
- Example projects (all except `Starter`) only had the `src` search path in their `Release` build mode, so `lazbuild` (which builds the `Default` mode) could not find the units. Added the search path to each project's global compiler options
- Tests `Test04_CreateDestroy` and `Test11_ThreadCount` hardcoded thread-count expectations that only held on multi-core machines; on low-core CI runners the enforced minimum of 4 threads made them fail. They now assert against the actual `Max(Min(requested, 2×ProcessorCount), 4)` formula
- `Test08_QueueFullBehavior` assumed a single worker drains the queue, but the pool enforces a 4-thread minimum, so on Linux the queue drained before it could overflow. It now bursts `ThreadCount + QueueSize + 1` long-running tasks, which overflows a fixed queue deterministically regardless of core count or scheduling

## [0.5.0] - 2026-04-13

### Added
Expand Down
73 changes: 73 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Contributing to ThreadPool for Free Pascal

Thanks for your interest in improving this library! Contributions of all
sizes are welcome — bug reports, documentation fixes, new examples, and code.

## Ways to contribute

- 🐛 **Report a bug** — open an [issue](https://github.com/ikelaiah/threadpool-fp/issues) using the Bug Report template.
- 💡 **Request a feature** — open an issue using the Feature Request template.
- 📝 **Improve docs or examples** — these are especially appreciated and easy to start with.
- 🔧 **Fix a bug or add a feature** — see the workflow below.

## Prerequisites

- Free Pascal 3.2.2 or later
- Lazarus 3.6.0 or later (provides `lazbuild`)
- No external dependencies

## Building

Build the package:

```bash
lazbuild package/lazarus/threadpool_fp.lpk
```

Or compile a single example directly with FPC:

```bash
fpc -Fu./src examples/SimpleDemo/SimpleDemo.lpr
```

## Running the tests

```bash
lazbuild tests/TestRunner.lpi
# Windows
./tests/TestRunner.exe -a -p --format=plain
# Linux / macOS
./tests/TestRunner -a -p --format=plain
```

All tests should pass before you submit a change. The full suite can take a
few minutes to run because some tests exercise high task volumes.

CI runs the package build, the test suite, and all examples on Linux and
Windows for every pull request — please make sure your branch is green.

## Code style

- Use `{$mode objfpc}{$H+}{$J-}` at the top of new units and programs.
- Match the existing formatting: two-space indentation, `PascalCase` for
types/methods, and a descriptive comment for non-obvious logic.
- **Filenames must match the `unit` identifier's casing exactly**
(e.g. unit `ThreadPool.Simple` lives in `ThreadPool.Simple.pas`). This keeps
the library compiling on case-sensitive filesystems like Linux.
- Keep the library dependency-free (FCL only).

## Pull request workflow

1. Fork the repo and create a branch off `main`
(e.g. `feat/adaptive-threads` or `fix/queue-overflow`).
2. Make your change, including tests and/or an example where it makes sense.
3. Run the test suite locally and make sure it passes.
4. Update `CHANGELOG.md` and any relevant docs in `docs/`.
5. Open a pull request describing **what** changed and **why**.

## Reporting security issues

For anything sensitive, please email the maintainer rather than opening a
public issue.

Thank you for helping make this library better! 🙏
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# 🚀 ThreadPool for Free Pascal

[![Version](https://img.shields.io/badge/version-0.5.0-8B5CF6.svg)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-0.6.0-8B5CF6.svg)](CHANGELOG.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-1E3A8A.svg)](https://opensource.org/licenses/MIT)
[![Free Pascal](https://img.shields.io/badge/Free%20Pascal-3.2.2+-3B82F6.svg)](https://www.freepascal.org/)
[![Lazarus](https://img.shields.io/badge/Lazarus-4.0+-60A5FA.svg)](https://www.lazarus-ide.org/)
![Supports Windows](https://img.shields.io/badge/support-Windows-F59E0B?logo=Windows)
![Supports Linux](https://img.shields.io/badge/support-Linux-F59E0B?logo=Linux)
![No Dependencies](https://img.shields.io/badge/dependencies-none-10B981.svg)
![Tests](https://img.shields.io/badge/tests-35%20passed-10B981.svg)
[![CI](https://github.com/ikelaiah/threadpool-fp/actions/workflows/ci.yml/badge.svg)](https://github.com/ikelaiah/threadpool-fp/actions/workflows/ci.yml)
[![Documentation](https://img.shields.io/badge/Docs-Available-brightgreen.svg)](docs/)
[![Status](https://img.shields.io/badge/Status-Stable-10B981.svg)](README.md)

Expand Down Expand Up @@ -522,6 +522,11 @@ GlobalThreadPool.WaitForAll;
- More comprehensive tests
- More examples

## 🤝 Contributing

Contributions are welcome — bug reports, docs, examples, and code. See
[CONTRIBUTING.md](CONTRIBUTING.md) for how to build, test, and submit changes.

## 👏 Acknowledgments

Special thanks to the Free Pascal and Lazarus communities and the creators of the threading libraries mentioned above for inspiration!
Expand Down
Loading
Loading