#include "lfds611_freelist_internal.h" /****************************************************************************/ struct lfds611_freelist_element *lfds611_freelist_pop( struct lfds611_freelist_state *fs, struct lfds611_freelist_element **fe ) { LFDS611_ALIGN(LFDS611_ALIGN_DOUBLE_POINTER) struct lfds611_freelist_element *fe_local[LFDS611_FREELIST_PAC_SIZE]; assert( fs != NULL ); assert( fe != NULL ); LFDS611_BARRIER_LOAD; fe_local[LFDS611_FREELIST_COUNTER] = fs->top[LFDS611_FREELIST_COUNTER]; fe_local[LFDS611_FREELIST_POINTER] = fs->top[LFDS611_FREELIST_POINTER]; /* TRD : note that lfds611_abstraction_dcas loads the original value of the destination (fs->top) into the compare (fe_local) (this happens of course after the CAS itself has occurred inside lfds611_abstraction_dcas) */ do { if( fe_local[LFDS611_FREELIST_POINTER] == NULL ) { *fe = NULL; return( *fe ); } } while( 0 == lfds611_abstraction_dcas((volatile lfds611_atom_t *) fs->top, (lfds611_atom_t *) fe_local[LFDS611_FREELIST_POINTER]->next, (lfds611_atom_t *) fe_local) ); *fe = (struct lfds611_freelist_element *) fe_local[LFDS611_FREELIST_POINTER]; return( *fe ); } /****************************************************************************/ struct lfds611_freelist_element *lfds611_freelist_guaranteed_pop( struct lfds611_freelist_state *fs, struct lfds611_freelist_element **fe ) { assert( fs != NULL ); assert( fe != NULL ); lfds611_freelist_internal_new_element( fs, fe ); return( *fe ); } /****************************************************************************/ void lfds611_freelist_push( struct lfds611_freelist_state *fs, struct lfds611_freelist_element *fe ) { LFDS611_ALIGN(LFDS611_ALIGN_DOUBLE_POINTER) struct lfds611_freelist_element *fe_local[LFDS611_FREELIST_PAC_SIZE], *original_fe_next[LFDS611_FREELIST_PAC_SIZE]; assert( fs != NULL ); assert( fe != NULL ); LFDS611_BARRIER_LOAD; fe_local[LFDS611_FREELIST_POINTER] = fe; fe_local[LFDS611_FREELIST_COUNTER] = (struct lfds611_freelist_element *) lfds611_abstraction_increment( (lfds611_atom_t *) &fs->aba_counter ); original_fe_next[LFDS611_FREELIST_POINTER] = fs->top[LFDS611_FREELIST_POINTER]; original_fe_next[LFDS611_FREELIST_COUNTER] = fs->top[LFDS611_FREELIST_COUNTER]; /* TRD : note that lfds611_abstraction_dcas loads the original value of the destination (fs->top) into the compare (original_fe_next) (this happens of course after the CAS itself has occurred inside lfds611_abstraction_dcas) this then causes us in our loop, should we repeat it, to update fe_local->next to a more up-to-date version of the head of the lfds611_freelist */ do { fe_local[LFDS611_FREELIST_POINTER]->next[LFDS611_FREELIST_POINTER] = original_fe_next[LFDS611_FREELIST_POINTER]; fe_local[LFDS611_FREELIST_POINTER]->next[LFDS611_FREELIST_COUNTER] = original_fe_next[LFDS611_FREELIST_COUNTER]; } while( 0 == lfds611_abstraction_dcas((volatile lfds611_atom_t *) fs->top, (lfds611_atom_t *) fe_local, (lfds611_atom_t *) original_fe_next) ); return; }