jamesmunns / bbqueue

A SPSC, lockless, no_std, thread safe, queue, based on BipBuffers
Apache License 2.0
431 stars 51 forks source link

Add functions to take/release just producer or consumer #78

Open timvisee opened 4 years ago

timvisee commented 4 years ago

This implements:

I choose to use an AtomicU8 for the already_split state with a bit for the producer and consumer parts which are defined in BIT_PRODUCER and BIT_CONSUMER respectively. I thought this would be the right approach as updating the state for both the producer and consumer can still be done in a single atomic operation. That wouldn't be the case when using two separate AtomicBool's.

Things to resolve before merge:

The above things I'm currently uncertain about. My knowledge is lacking on this, thus I'd like to ask to make sure the implementation is sound. The PR branch is open, so feel free to make an edit.

Fixes https://github.com/jamesmunns/bbqueue/issues/40

Related https://github.com/jamesmunns/bbqueue/issues/67

timvisee commented 4 years ago

Ping @jamesmunns (due to draft PR)

timvisee commented 4 years ago

This uses fetch_or and fetch_add, do we need to implement this for thumbv6?

Apparently, yes: https://github.com/jamesmunns/bbqueue/runs/1390103704

Edit: this is now implemented

jamesmunns commented 4 years ago

Do we still need to zero the buffer when taking just the producer or consumer, like try_split? (currently commented-out)

Yes, I would suggest doing either on the first one that is taken, or doing it for the consumer alone is probably enough. Otherwise it is undefined behavior.

Do we still need to reinitialize the buffer when releasing just the producer or consumer, like try_release?

This is optional. It's generally not safe to do unless BOTH halves have been released. When in doubt, skip it.

timvisee commented 4 years ago

Do we still need to zero the buffer when taking just the producer or consumer, like try_split? (currently commented-out)

Yes, I would suggest doing either on the first one that is taken, or doing it for the consumer alone is probably enough. Otherwise it is undefined behavior.

Do we still need to reinitialize the buffer when releasing just the producer or consumer, like try_release?

This is optional. It's generally not safe to do unless BOTH halves have been released. When in doubt, skip it.

This has been implemented in de43a301adc7eaae872f782a5c0ca686b07b8da0

Zeroes on try_take_consumer. Reinitializes when both the producer and consumer are released.

jamesmunns commented 4 years ago

Hey @timvisee, I'll plan on reviewing this PR this weekend, but I realized that I was wrong - you'll need to zero-init the buffer when the PRODUCER (not consumer) is taken - as the producer will be the one to "see" the contents of the data first (e.g. if a producer is taken, then a grant is requested, the grant will be able to "see" uninitialized data if no consumer has been taken). Sorry for the wrong guidance before.

timvisee commented 3 years ago

@jamesmunns It now zeroes when the producer is taken. I amended this change to the last commit (03b97746e5af06c82f6a10841c54e2601a14ab5d).

ithinuel commented 1 year ago

Will conflict with #103