work on issue:


Nice crate! I had started building something like this but stumbled on this serendipitously.
1. Have you put much thought into crash safety? e.g. what happens if either the reader or writer crashes at various points?
2. I think there might be an issue of a deadlock because the raw_sync crate does use locks, even in the events module.


Derived tasks:
1. write test that lets either the reader or writer crash at reproducible 
   various points, lets see how it reacts/ where bugs might be.
2. Lets get rid of raw_sync and try to be lock-free


My answer potential
Thank you for your interest in my crate!
And sorry for coming back late to you @jeromegn.

For context: I've implemented this small library for a dynamic malware analysis system I am building as a side project and shove load of raw introspection data back to an agent. These are json events, but the agent will not parse it and compresses it to a file for post-execution analysis to guarantee a low overhead during execution.
This library is just my first proof-of-concept and not battle tested by any means.

However I could finally find some time to address your two concerns.

1. Crash Safety
   I have added failpoints and tests to verify various crash scenarios.
   At a higher abstraction level something like PID files would make
   sense. However, I am unsure if I want this level of abstraction 
   within that library, and rather have the client handle this.

2. Possible deadlocks, I am looking into it. Best case would be to
   get rid of raw_sync overall. - you are totally right, only __my__ "data-pipeline" is lock-free, but not raw_sync...

If you have any elegant suggestion for either of the two, I'd
be happy to hear it!




  Crash Outcomes

  - ring_writer::after_wrap_publish → wrap marker written, no READY; reader keeps returning None. Message lost.
  - ring_writer::after_wrap_advance → write index advanced but marker not signaled; reader never woken. Message lost until reader polls again.
  - ring_writer::after_wrap_signal → wrap marker signaled, writer crashes before payload write; reader consumes marker then waits. Message lost.
  - ring_writer::after_write_header → len set without READY; reader sees header but waits for publish. Message lost.
  - ring_writer::after_write_payload → payload copied but no READY bit; reader never consumes, subsequent writer retry overwrites. Data lost.
  - ring_writer::after_publish_header → READY set but index not advanced; reader thinks queue empty, next writer overwrites slot. Data lost.
  - ring_writer::after_write_advance → indices advanced, signal missing; blocking reader stalls forever. Message still in buffer when reader retries.
  - ring_writer::after_data_signal → data published and signal sent; crash afterward has no additional effect. Reader consumes normally.
  - ring_writer::create::after_init → metadata and events initialized; panic leaves a valid ring file. New reader/writer can reopen cleanly.
  - ring_reader::after_wrap_read_advance → read index advanced, signal missing; writer may block waiting for space. Reopening reader replays same message.
  - ring_reader::after_wrap_space_signal → wrap marker cleared, signal lost; writer might block until timeout. No data lost.
  - ring_reader::before_read_advance → payload copied but read index unchanged; writer sees ring full. Restarted reader replays message.
  - ring_reader::after_read_advance → read index advanced but writer not signaled; writer can stall. Message consumed (no replay).
  - ring_reader::after_space_signal → signal sent; crash afterward harmless. Ring drained.
  - ring_reader::open::after_map → panic during open; retry succeeds, ring untouched.



  Crash Outcomes

  - Writer failpoints:
    after_wrap_publish/advance/signal, after_write_header/payload/publish_header → message dropped (header not READY or writer index not advanced).
    after_write_advance → bytes committed but wake-up missing; reader can still poll data.
    after_data_signal → already signaled; no regression.
    before_space_wait → panic pre-block; ring remains full, no new bytes.
    after_space_wait → wait succeeded but crash stops publish; existing data intact, payload absent.
    create::after_init → ring metadata ready; retrying reader/writer works.
  - Reader failpoints:
    after_wrap_read_advance / after_wrap_space_signal → writer may block until retry, data replayable.
    before_read_advance → duplicate-delivery risk; writer sees full.
    after_read_advance / after_space_signal → data consumed, writer resumes only on timeout or new signal.
    before_data_wait → panic before sleep; state untouched.
    after_data_wait → wake-up processed but crash before drain; message is replayable.
    open::after_map → retry succeeds; ring file unchanged.



---
- Every failpoint now has a deterministic, tested outcome. Writer-side assertions live in tests/failpoints.rs:223 and tests/failpoints.rs:271; reader-side coverage is at tests/
    failpoints.rs:344 and tests/failpoints.rs:380. Creation/open crashes are checked in tests/failpoints.rs:462. These were verified with cargo test --features failpoints --test
    failpoints.
  - Most crashes that happen before the READY bit is set (e.g., ring_writer::after_write_header, ring_writer::after_write_payload in src/lib.rs:389-399) simply drop the in-flight message
    and keep the ring consistent. That behaviour matches typical logless SPSC expectations and the tests confirm no divergence.
  - Wait-loop failpoints (ring_writer::before_space_wait, ring_reader::before_data_wait in src/lib.rs:420-545) show that a crash before the actual block leaves the ring untouched; the
    subsequent retry proceeds cleanly. Again, this is acceptable.


Gaps That Need Hardening

  - ring_writer::after_write_advance (src/lib.rs:397-405) and the analogous wrap-marker paths leave the reader blocked forever if it was inside pop(None, …). The test
    writer_failpoints_cover_crash_windows treats that as expected, but in practice you probably want the writer to record a “publish token” and the reader to notice an unconsumed header
    even without a signal. Alternatively, make blocking consumers pass a finite timeout so they can detect a silent crash.
  - Symmetrically, ring_reader::after_read_advance (src/lib.rs:515-524) advances the consumer index without signalling. Writers waiting in push hang until their timeout fires. Consider
    signalling before updating read, or tracking a generation counter so a restarted writer can spot “consumer crashed after commit.”
  - Both sides ignore Event::set failures; the failpoints don’t cover the Err branches because we return early. If an OS-level event call fails, you’ll lose wakeups without knowing.
    Wrapping those calls in failpoints or converting errors into state markers would help.
  - After a writer crash, there is no way to “reopen” the existing ring (no RingWriter::open), so ring_writer::before_space_wait scenarios leave the system wedged until an operator
    recreates the file. If graceful restart is a requirement, you’ll need an attach API plus fencing to ensure two writers never collide.



---

add some fuzzy tests and race tests to try to find bugs
