Monday 15 April 2013

c - Do I need to use volatile keyword for memory access in critical section? -



c - Do I need to use volatile keyword for memory access in critical section? -

i writing code single processor 32 bit microcontroller using gcc.

i need consume time-stamped objects linked list. part of code asynchronous (maybe in isr) adds them list.

the critical section implemented turning interrupts off , using barrier() function.

i'm confused gcc optimization break code cacheing pointers list items (next recent item remove, list head, or free list). dont want within while loop cached previous time around loop. memory barrier protect me compiler deciding load pointer 1 time @ start of function , never reload again? these list pointers might modified in critical section of producer code (not shown). trying understand if pqueue_first should volatile pointer, example.

presumably, if there no loop (which case adding list), ok if code in function in critical section?

please don't point me generic article volatile or critical sections because have read bunch of them, having problem seeing how apply specific code. understand volatile ensures compiler reload variable every time referenced. don't understand scope of optimization , interaction memory barriers.

typedef struct { ev_eventqueueentry_t *pqueue_alloc; // allocation (never changes) ev_eventqueueentry_t *pqueue_head; // head of active queue (isr can alter it) ev_eventqueueentry_t *pqueue_free; // head of free list (isr can alter it) ev_eventqueueentry_t *pqueue_first; // soonest item in queue (isr can alter it) ev_eventqueueentry_t *pqueue_first_prev; // pointer soonest item (isr can alter it) ev_uint_t max_event_count; } ev_eventqueue_t; void runloop(ev_eventqueue_t *pev) { while(not timeout) { // come in critical section disable_interrupts(); barrier(); // item recent timestamp // can changed isr add together queue operation ev_eventqueueentry_t *pfirst = pev->pqueue_first; if(pfirst!=null && ev_portisfuturetime(pfirst->event.timestamp, ev_portgettime())) { // re-create out message ev_event_t e = pfirst->event; // remove event queue if(pev->pqueue_first_prev != null) pev->pqueue_first_prev->pnext = pfirst->pnext; else pev->pqueue_head = pfirst->pnext; // set event on free list pfirst->pnext = pev->pqueue_free; pev->pqueue_free = pfirst; pfirst->event.message.type = ev_message_null; // find next soonest message process after 1 pev->pqueue_first = ...; pev->pqueue_first_prev = ...; // pointer // exit critical section barrier(); enable_interrupts(); // dispatch message ... } else { // exit critical section barrier(); enable_interrupts(); // waste time ... } } }

c++11 has standard feature this: std::atomic_signal_fence. c11 has similar feature, without namespace qualifier. suitable if programme uses single thread , trying stop compiler moving loads/stores across fence. utilize std::atomic_signal_fence(memory_order_acquire) before critical section , std:atomic_signal_fence(memory_order_release) after critical section.

if you're not using c++11 or c11, using gcc or compiler understands gcc asms, can utilize __asm__ __volatile__ ("": : :"memory") compiler barrier. asm says can't removed , threatens modify memory in mysterious ways, hence compiler won't able move loads/stores on it.

c volatile producer-consumer critical-section memory-barriers

No comments:

Post a Comment