Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.arch.embedded > #30831

Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on

From pozz <pozzugno@gmail.com>
Newsgroups comp.arch.embedded
Subject Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on
Date 2021-10-24 17:39 +0200
Organization A noiseless patient Spider
Message-ID <sl3ums$r4$1@dont-email.me> (permalink)
References <skvcnd$5dv$1@dont-email.me> <sl1c3a$dfr$1@dont-email.me> <sl1sh2$vq6$1@dont-email.me> <sl3eg8$674$1@dont-email.me>

Show all headers | View raw


Il 24/10/2021 13:02, David Brown ha scritto:
> On 23/10/2021 22:49, pozz wrote:
>> Il 23/10/2021 18:09, David Brown ha scritto:
>>> On 23/10/2021 00:07, pozz wrote:
>>>> Even I write software for embedded systems for more than 10 years,
>>>> there's an argument that from time to time let me think for hours and
>>>> leave me with many doubts.
>>>
>>> It's nice to see a thread like this here - the group needs such
>>> discussions!
>>>
>>>>
>>>> Consider a simple embedded system based on a MCU (AVR8 or Cortex-Mx).
>>>> The software is bare metal, without any OS. The main pattern is the well
>>>> known mainloop (background code) that is interrupted by ISR.
>>>>
>>>> Interrupts are used mainly for timings and for low-level driver. For
>>>> example, the UART reception ISR move the last received char in a FIFO
>>>> buffer, while the mainloop code pops new data from the FIFO.
>>>>
>>>>
>>>> static struct {
>>>>     unsigned char buf[RXBUF_SIZE];
>>>>     uint8_t in;
>>>>     uint8_t out;
>>>> } rxfifo;
>>>>
>>>> /* ISR */
>>>> void uart_rx_isr(void) {
>>>>     unsigned char c = UART->DATA;
>>>>     rxfifo.buf[in % RXBUF_SIZE] = c;
>>>>     rxfifo.in++;
>>>
>>> Unless you are sure that RXBUF_SIZE is a power of two, this is going to
>>> be quite slow on an AVR.  Modulo means division, and while division by a
>>> constant is usually optimised to a multiplication by the compiler, you
>>> still have a multiply, a shift, and some compensation for it all being
>>> done as signed integer arithmetic.
>>>
>>> It's also wrong, for non-power of two sizes, since the wrapping of your
>>> increment and your modulo RXBUF_SIZE get out of sync.
>>
>> Yes, RXBUF_SIZE is a power of two.
>>
> 
> If your code relies on that, make sure the code will fail to compile if
> it is not the case.  Documentation is good, compile-time check is better:
> 
> static_assert((RXBUF_SIZE & (RXBUF_SIZE - 1)) == 0, "Needs power of 2");

Good point.


>>> The usual choice is to track "head" and "tail", and use something like:
>>>
>>> void uart_rx_isr(void) {
>>>     unsigned char c = UART->DATA;
>>>     // Reset interrupt flag
>>>     uint8_t next = rxfifo.tail;
>>>     rxfifo.buf[next] = c;
>>>     next++;
>>>     if (next >= RXBUF_SIZE) next -= RXBUF_SIZE;
>>>     rxfifo.tail = next;
>>> }
>>
>> This isn't the point of this thread, anyway...
>> You insist that tail is always in the range [0...RXBUF_SIZE - 1]. My
>> approach is different.
>>
>> RXBUF_SIZE is a power of two, usualy <=256. head and tail are uint8_t
>> and *can* reach the maximum value of 255, even RXBUF_SIZE is 128. All
>> works well.
>>
> 
> Yes, your approach will work - /if/ you have a power-of-two buffer size.
>   It has no noticeable efficiency advantages, merely an extra
> inconvenient restriction and the possible confusion caused by doing
> things in a different way from common idioms.
> 
> However, this is not the point of the thread - so I am happy to leave
> that for now.

If you want, we can start a small [OT].

<OT>
I know my ring-buffer implementation has the restriction of having a 
buffer with a power-of-two size. However I like it, because I can avoid 
introducing a new variable (actual number of elements in the buffer) or 
waste an element to solve the ambiguity when the buffer is full or empty.
</OT>


>> Suppose rxfifo.in=rxfifo.out=127, FIFO is empty. When a new char is
>> received, it is saved into rxfifo.buf[127 % 128=127] and rxfifo.in will
>> be increased to 128.
>> Now mainloop detect the new char (in != out), reads the new char at
>> rxfifo.buf[127 % 128=127] and increase out that will be 128.
>>
>> The next byte will be saved into rxfifo.rxbuf[rxfifo.in % 128=128 % 128
>> = 0] and rxfifo.in will be 129. Again, the next byte will be saved to
>> rxbuf[rxfifo.in % 128=129 % 128=1] and rxfifo.in will be 130.
>>
>> When the mainloop tries to pop data from fifo, it tests
>>
>>     rxfifo.in(130) !=rxfifo.out(128)
>>
>> The test is true, so the code extracts chars from rxbuf[out % 128] that
>> is rxbuf[0]... and so on.
>>
>> I hope that explanation is good.
>>
>>
>>>
>>>>     // Reset interrupt flag
>>>> }
>>>>
>>>> /* Called regularly from mainloop code */
>>>> int uart_task(void) {
>>>>     int c = -1;
>>>>     if (out != in) {
>>>>       c = rxfifo.buf[out % RXBUF_SIZE];
>>>>       out++;
>>>>     }
>>>>     return -1;
>>>> }
>>>
>>> int uart_task(void) {
>>>     int c = -1;
>>>     uint8_t next = rxfifo.head;
>>>     if (next != rxfifo.tail) {
>>>         c = rxfifo.buf[next];
>>>         next++;
>>>         if (next >= RXBUF_SIZE) next -= RXBUF_SIZE;
>>>         rxfifo.head = next;
>>>     }
>>>     return c;
>>> }
>>>
>>> These don't track buffer overflow at all - you need to call uart_task()
>>> often enough to avoid that.
>>
>> Sure, with a good number for RXBUF_SIZE, buffer overflow shouldn't
>> happen ever. Anyway, if it happens, the higher level layers (protocol)
>> should detect a corrupted packet.
>>
> 
> You risk getting seriously out of sync if there is an overflow.
> Normally, on an overflow there will be a dropped character or two (which
> as you say, must be caught at a higher level).  Here you could end up
> going round your buffer an extra time and /gaining/ RXBUF_SIZE extra
> characters.
> 
> Still, if you are sure that your functions are called fast enough so
> that overflow is not a concern, then that's fine.  Extra code to check
> for a situation that can't occur is not helpful.
> 
>>
>>> (I'm skipping volatiles so we don't get ahead of your point.)
>>>
>>>>
>>>>
>>>>   From a 20-years old article[1] by Nigle Jones, this seems a situation
>>>> where volatile must be used for rxfifo.in, because is modified by an ISR
>>>> and used in the mainloop code.
>>>>
>>>
>>> Certainly whenever data is shared between ISR's and mainloop code, or
>>> different threads, then you need to think about how to make sure data is
>>> synchronised and exchanged.  "volatile" is one method, atomics are
>>> another, and memory barriers can be used.
>>>
>>>> I don't think so, rxfifo.in is read from memory only one time in
>>>> uart_task(), so there isn't the risk that compiler can optimize badly.
>>>
>>> That is incorrect in two ways.  One - baring compiler bugs (which do
>>> occur, but they are very rare compared to user bugs), there is no such
>>> thing as "optimising badly".  If optimising changes the behaviour of the
>>> code, other than its size and speed, the code is wrong.
>>
>> Yes of course, but I don't think the absence of volatile for rxfifo.in,
>> even if it can change in ISR, could be a *real* problem with *modern and
>> current* compilers.
>>
> 
> Personally, I am not satisfied with "it's unlikely to be a problem in
> practice" - I prefer "The language guarantees it is not a problem".
> Remember, when you know the data needs to be read at this point, then
> using a volatile read is free.  Volatile does not make code less
> efficient unless you use it incorrectly and force more accesses than are
> necessary.  So using volatile accesses for "rxfifo.in" here turns
> "probably safe" into "certainly safe" without cost.  What's not to like?
> 
>> voltile attribute needs to avoid compiler optimization (that would be a
>> bad thing, because of volatile nature of the variabile), but on that
>> code it's difficult to think of an optimization, caused by the absence
>> of volatile, that changes the behaviour erroneously... except reorering.
>>
>>
>>> Two - it is a
>>> very bad idea to imagine that having code inside a function somehow
>>> "protects" it from re-ordering or other optimisation.
>>
>> I didn't say this, at the contrary I was thinking exactly to reordering
>> issues.
>>
>>
>>> Functions can be inlined, outlined, cloned, and shuffled about.
>>> Link-time optimisation, code in headers, C++ modules, and other
>>> cross-unit optimisations are becoming more and more common.  So while it
>>> might be true /today/ that the compiler has no alternative but to read
>>> rxfifo.in once per call to uart_task(), you cannot assume that will be
>>> the case with later compilers or with more advanced optimisation
>>> techniques enabled.  It is safer, more portable, and more future-proof
>>> to avoid such assumptions.
>>
>> Ok, you are talking of future scenarios. I don't think actually this
>> could be a real problem. Anyway your observation makes sense.
>>
>>
>>>
>>>> Even if ISR is fired immediately after the if statement, this doesn't
>>>> bring to a dangerous state: the just received data will be processed at
>>>> the next call to uart_task().
>>>>
>>>> So IMHO volatile isn't necessary here. And critical sections (i.e.
>>>> disabling interrupts) aren't useful too.
>>>>
>>>> However I'm thinking about memory barrier. Suppose the compiler reorder
>>>> the instructions in uart_task() as follows:
>>>>
>>>>
>>>>     c = rxfifo.buf[out % RXBUF_SIZE]
>>>>     if (out != in) {
>>>>       out++;
>>>>       return c;
>>>>     } else {
>>>>       return -1;
>>>>     }
>>>>
>>>>
>>>> Here there's a big problem, because compiler decided to firstly read
>>>> rxfifo.buf[] and then test in and out equality. If the ISR is fired
>>>> immediately after moving data to c (most probably an internal register),
>>>> the condition in the if statement will be true and the register value is
>>>> returned. However the register value isn't correct.
>>>
>>> You are absolutely correct.
>>>
>>>>
>>>> I don't think any modern C compiler reorder uart_task() in this way, but
>>>> we can't be sure. The result shouldn't change for the compiler, so it
>>>> can do this kind of things.
>>>
>>> It is not an unreasonable re-arrangement.  On processors with
>>> out-of-order execution (which does not apply to the AVR or Cortex-M),
>>> compilers will often push loads as early as they can in the instruction
>>> stream so that they start the cache loading process as quickly as
>>> possible.  (But note that on such "big" processors, much of this
>>> discussion on volatile and memory barriers is not sufficient, especially
>>> if there is more than one core.  You need atomics and fences, but that's
>>> a story for another day.)
>>>
>>>>
>>>> How to fix this issue if I want to be extremely sure the compiler will
>>>> not reorder this way? Applying volatile to rxfifo.in shouldn't help for
>>>> this, because compiler is allowed to reorder access of non volatile
>>>> variables yet[2].
>>>>
>>>
>>> The important thing about "volatile" is that it is /accesses/ that are
>>> volatile, not objects.  A volatile object is nothing more than an object
>>> for which all accesses are volatile by default.  But you can use
>>> volatile accesses on non-volatile objects.  This macro is your friend:
>>>
>>> #define volatileAccess(v) *((volatile typeof((v)) *) &(v))
>>>
>>> (Linux has the same macro, called ACCESS_ONCE.  It uses a gcc extension
>>> - if you are using other compilers then you can make an uglier
>>> equivalent using _Generic.  However, if you are using a C compiler that
>>> supports C11, it is probably gcc or clang, and you can use the "typeof"
>>> extension.)
>>>
>>> That macro will let you make a volatile read or write to an object
>>> without requiring that /all/ accesses to it are volatile.
>>
>> This is a good point. The code in ISR can't be interrupted, so there's
>> no need to have volatile access in ISR.
>>
> 
> Correct.  (Well, /almost/ correct - bigger microcontrollers have
> multiple interrupt priorities.  But it should be correct in this case,
> as no other interrupt would be messing with the same variables anyway.)

Yes, static variables defined in a uart driver aren't accessed from 
other interrupts.


>>>> One solution is adding a memory barrier in this way:
>>>>
>>>>
>>>> int uart_task(void) {
>>>>     int c = -1;
>>>>     if (out != in) {
>>>>       memory_barrier();
>>>>       c = rxfifo.buf[out % RXBUF_SIZE];
>>>>       out++;
>>>>     }
>>>>     return -1;
>>>> }
>>>>
>>>
>>> Note that you are forcing the compiler to read "out" twice here, as it
>>> can't keep the value of "out" in a register across the memory barrier.
>>
>> Yes, you're right. A small penalty to avoid the problem of reordering.
>>
> 
> But an unnecessary penalty.
> 
>>
>>> (And as I mentioned before, the compiler might be able to do larger
>>> scale optimisation across compilation units or functions, and in that
>>> way keep values across multiple calls to uart_task.)
>>>
>>>>
>>>> However this approach appears to me dangerous. You have to check and
>>>> double check if, when and where memory barriers are necessary and it's
>>>> simple to skip a barrier where it's nedded and add a barrier where it
>>>> isn't needed.
>>>
>>> Memory barriers are certainly useful, but they are a shotgun approach -
>>> they affect /everything/ involving reads and writes to memory.  (But
>>> remember they don't affect ordering of calculations.)
>>>
>>>>
>>>> So I'm thinking that a sub-optimal (regarding efficiency) but reliable
>>>> (regarding the risk to skip a barrier where it is needed) could be to
>>>> enter a critical section (disabling interrupts) anyway, if it isn't
>>>> strictly needed.
>>>>
>>>>
>>>> int uart_task(void) {
>>>>     ENTER_CRITICAL_SECTION();
>>>>     int c = -1;
>>>>     if (out != in) {
>>>>       c = rxfifo.buf[out % RXBUF_SIZE];
>>>>       out++;
>>>>     }
>>>>     EXIT_CRITICAL_SECTION();
>>>>     return -1;
>>>> }
>>>
>>> Critical sections for something like this are /way/ overkill.  And a
>>> critical section with a division in the middle?  Not a good idea.
>>>
>>>>
>>>>
>>>> Another solution could be to apply volatile keyword to rxfifo.in *AND*
>>>> rxfifo.buf too, so compiler can't change the order of accesses them.
>>>>
>>>> Do you have other suggestions?
>>>>
>>>
>>> Marking "in" and "buf" as volatile is /far/ better than using a critical
>>> section, and likely to be more efficient than a memory barrier.  You can
>>> also use volatileAccess rather than making buf volatile, and it is often
>>> slightly more efficient to cache volatile variables in a local variable
>>> while working with them.
>>
>> Yes, I think so too. Lastly I read many experts say volatile is often a
>> bad thing, so I'm re-thinking about its use compared with other approaches.
>>
> 
> People who say "volatile is a bad thing" are often wrong.  Remember, all
> generalisations are false :-)

Ok, I wrote "volatile is **often** a bad thing".


> "volatile" is a tool.  It doesn't do everything that some people think
> it does, but it is a very useful tool nonetheless.  It has little place
> in big systems - Linus Torvalds wrote a rant against it as being both
> too much and too little, and in the context of writing Linux code, he
> was correct.  For Linux programming, you should be using OS-specific
> features (which rely on "volatile" for their implementation) or atomics,
> rather than using "volatile" directly.
> 
> But for small-systems embedded programming, it is very handy.  Used
> well, it is free - used excessively it has a cost, but an extra volatile
> will not make an otherwise correct program fail.
> 
> Memory barriers are great for utility functions such as interrupt
> enable/disable inline functions, but are usually sub-optimal compared to
> specific and targeted volatile accesses.

Just to say what I read:

https://blog.regehr.org/archives/28

https://mcuoneclipse.com/2021/10/12/spilling-the-beans-volatile-qualifier/


>>>> [1] https://barrgroup.com/embedded-systems/how-to/c-volatile-keyword
>>>> [2] https://blog.regehr.org/archives/28
>>>
>>
> 

Back to comp.arch.embedded | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-23 00:07 +0200
  Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Clifford Heath <no.spam@please.net> - 2021-10-23 13:40 +1100
  Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-22 22:09 -0700
    Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-23 22:12 +0200
      Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-23 15:59 -0700
  Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-23 18:09 +0200
    Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-23 22:49 +0200
      Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-24 13:02 +0200
        Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-24 17:39 +0200
          Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-24 18:37 +0200
    Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-25 20:15 +0200
      Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-25 20:54 +0200
      Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Richard Damon <Richard@Damon-Family.org> - 2021-10-25 20:31 -0400
  Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Johann Klammer <klammerj@NOSPAM.a1.net> - 2021-10-24 12:39 +0200
    Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-24 14:14 +0300
      Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-24 12:54 -0700
        Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-24 23:27 +0300
          Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-24 14:08 -0700
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-25 00:50 +0300
              Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-24 15:47 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-25 02:32 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-24 18:34 -0700
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-25 09:41 +0200
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 10:56 +0300
              Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 01:19 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 11:52 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 02:50 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-25 13:49 +0200
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 15:16 +0300
          Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 11:09 +0300
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 01:28 -0700
              Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 12:06 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 02:35 -0700
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-25 16:04 +0300
              Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 18:34 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 10:43 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-25 20:53 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 11:02 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-25 19:52 +0200
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 11:10 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 21:33 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-25 22:09 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Niklas Holsti <niklas.holsti@tidorum.invalid> - 2021-10-25 22:53 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Dimiter_Popoff <dp@tgi-sci.com> - 2021-10-25 23:02 +0300
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-26 00:05 +0200
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on pozz <pozzugno@gmail.com> - 2021-10-25 23:46 +0200
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-25 20:58 +0200
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Clifford Heath <no.spam@please.net> - 2021-10-26 08:43 +1100
        Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on antispam@math.uni.wroc.pl - 2021-10-25 21:32 +0000
          Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-25 15:24 -0700
            Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on antispam@math.uni.wroc.pl - 2021-10-27 00:20 +0000
              Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-26 17:52 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on antispam@math.uni.wroc.pl - 2021-10-27 05:22 +0000
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-29 15:36 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on antispam@math.uni.wroc.pl - 2021-10-31 22:54 +0000
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-10-31 20:37 -0700
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on antispam@math.uni.wroc.pl - 2021-11-11 04:34 +0000
                Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on Don Y <blockedofcourse@foo.invalid> - 2021-11-19 16:21 -0700
      Re: How to write a simple driver in bare metal systems: volatile, memory barrier, critical sections and so on David Brown <david.brown@hesbynett.no> - 2021-10-25 08:57 +0200

csiph-web