Tushar Lachman
Melbourne · RMIT ’27
SYSTEMS PROGRAMMINGRMIT · individual

Multithreaded File Copier & Custom Memory Allocator

Two things you normally just call, implemented instead: a bounded work queue and a heap.

Operating Systems Principles · 2025
WHY IT EXISTS

Two projects in the same unit, both about implementing what a program normally takes for granted. First a multithreaded file copier — one thread per file, then a reader/writer team sharing a bounded queue. Then a heap allocator built directly on sbrk, with first-fit and best-fit as interchangeable strategies.

How it’s put together

L00
C
L01
C++
L02
pthreads
L03
mutexes & condition variables
L04
sbrk
L05
valgrind
L06
make

Built with

CC++pthreadsmutexes & condition variablessbrkvalgrindmake
PERIOD
Operating Systems Principles · 2025
ROLE
Solo — both projects

The hard parts

07 NOTES
1

The single-file copier is a real producer–consumer: a team of reader threads pulls lines from the input, a team of writer threads drains them to the output, and a shared queue capped at 20 lines sits between them.

2

Three mutexes with distinct jobs — one guarding the queue, one serialising reads of the input file, one serialising writes to the output — rather than one lock over everything, so readers and writers only contend where they genuinely share state.

3

No busy-waiting anywhere. Two condition variables carry the handoff: readers wait on `not_full` when the queue is at capacity, writers wait on `not_empty` when it is drained, and main broadcasts on `not_empty` once reading is finished so no writer can block forever on a queue that will never fill again.

4

Termination is the part that is easy to get subtly wrong: a writer exits only when the queue is empty *and* the reading-done flag is set, checked while holding the lock, so a writer can never mistake a momentary lull for the end of input. Verified under valgrind with no leaks and no errors.

5

The allocator asks the kernel for memory itself via `sbrk` and keeps two intrusive linked lists — allocated and free — instead of leaning on the C library it is replacing. Requests are rounded up to size classes of 32, 64, 128, 256 and 512 bytes.

6

First-fit and best-fit sit behind one function pointer, and `main` picks between them by inspecting `argv[0]` — so a single source file compiles to two binaries, `firstfit` and `bestfit`, that differ only in the strategy and can be run head-to-head on the same trace file.

7

What it deliberately does not do is coalesce: a freed chunk goes back on the tail of the free list at its original size class, so adjacent free blocks are never merged. That is the honest limitation of the design, and the reason the two strategies diverge on a long allocation trace at all.

Want the parts that aren’t on this page — the architecture arguments, the things that broke, a live walkthrough?

NEXTCloud Music — AWS Web App, Deployed to EC2 and ECS