1 #include "lfds610_queue_internal.h"
7 /****************************************************************************/
8 int lfds610_queue_enqueue( struct lfds610_queue_state *qs, void *user_data )
10 LFDS610_ALIGN(LFDS610_ALIGN_DOUBLE_POINTER) struct lfds610_queue_element
11 *qe[LFDS610_QUEUE_PAC_SIZE];
14 // TRD : user_data can be NULL
16 lfds610_queue_internal_new_element_from_freelist( qs, qe, user_data );
18 if( qe[LFDS610_QUEUE_POINTER] == NULL )
21 lfds610_queue_internal_queue( qs, qe );
30 /****************************************************************************/
31 int lfds610_queue_guaranteed_enqueue( struct lfds610_queue_state *qs, void *user_data )
33 LFDS610_ALIGN(LFDS610_ALIGN_DOUBLE_POINTER) struct lfds610_queue_element
34 *qe[LFDS610_QUEUE_PAC_SIZE];
37 // TRD : user_data can be NULL
39 lfds610_queue_internal_guaranteed_new_element_from_freelist( qs, qe, user_data );
41 if( qe[LFDS610_QUEUE_POINTER] == NULL )
44 lfds610_queue_internal_queue( qs, qe );
53 /****************************************************************************/
54 void lfds610_queue_internal_queue( struct lfds610_queue_state *qs, struct lfds610_queue_element *qe[LFDS610_QUEUE_PAC_SIZE] )
56 LFDS610_ALIGN(LFDS610_ALIGN_DOUBLE_POINTER) struct lfds610_queue_element
57 *enqueue[LFDS610_QUEUE_PAC_SIZE],
58 *next[LFDS610_QUEUE_PAC_SIZE];
66 // TRD : the DCAS operation issues a read and write barrier, so we don't need a read barrier in the do() loop
72 enqueue[LFDS610_QUEUE_POINTER] = qs->enqueue[LFDS610_QUEUE_POINTER];
73 enqueue[LFDS610_QUEUE_COUNTER] = qs->enqueue[LFDS610_QUEUE_COUNTER];
75 next[LFDS610_QUEUE_POINTER] = enqueue[LFDS610_QUEUE_POINTER]->next[LFDS610_QUEUE_POINTER];
76 next[LFDS610_QUEUE_COUNTER] = enqueue[LFDS610_QUEUE_POINTER]->next[LFDS610_QUEUE_COUNTER];
78 /* TRD : this if() ensures that the next we read, just above,
79 really is from qs->enqueue (which we copied into enqueue)
84 if( qs->enqueue[LFDS610_QUEUE_POINTER] == enqueue[LFDS610_QUEUE_POINTER] and qs->enqueue[LFDS610_QUEUE_COUNTER] == enqueue[LFDS610_QUEUE_COUNTER] )
86 if( next[LFDS610_QUEUE_POINTER] == NULL )
88 qe[LFDS610_QUEUE_COUNTER] = next[LFDS610_QUEUE_COUNTER] + 1;
89 cas_result = lfds610_abstraction_dcas( (volatile lfds610_atom_t *) enqueue[LFDS610_QUEUE_POINTER]->next, (lfds610_atom_t *) qe, (lfds610_atom_t *) next );
93 next[LFDS610_QUEUE_COUNTER] = enqueue[LFDS610_QUEUE_COUNTER] + 1;
94 lfds610_abstraction_dcas( (volatile lfds610_atom_t *) qs->enqueue, (lfds610_atom_t *) next, (lfds610_atom_t *) enqueue );
98 while( cas_result == 0 );
100 qe[LFDS610_QUEUE_COUNTER] = enqueue[LFDS610_QUEUE_COUNTER] + 1;
101 lfds610_abstraction_dcas( (volatile lfds610_atom_t *) qs->enqueue, (lfds610_atom_t *) qe, (lfds610_atom_t *) enqueue );
110 /****************************************************************************/
111 int lfds610_queue_dequeue( struct lfds610_queue_state *qs, void **user_data )
113 LFDS610_ALIGN(LFDS610_ALIGN_DOUBLE_POINTER) struct lfds610_queue_element
114 *enqueue[LFDS610_QUEUE_PAC_SIZE],
115 *dequeue[LFDS610_QUEUE_PAC_SIZE],
116 *next[LFDS610_QUEUE_PAC_SIZE];
123 state = LFDS610_QUEUE_STATE_UNKNOWN,
124 finished_flag = LOWERED;
126 assert( qs != NULL );
127 assert( user_data != NULL );
129 // TRD : the DCAS operation issues a read and write barrier, so we don't need a read barrier in the do() loop
131 LFDS610_BARRIER_LOAD;
135 dequeue[LFDS610_QUEUE_POINTER] = qs->dequeue[LFDS610_QUEUE_POINTER];
136 dequeue[LFDS610_QUEUE_COUNTER] = qs->dequeue[LFDS610_QUEUE_COUNTER];
138 enqueue[LFDS610_QUEUE_POINTER] = qs->enqueue[LFDS610_QUEUE_POINTER];
139 enqueue[LFDS610_QUEUE_COUNTER] = qs->enqueue[LFDS610_QUEUE_COUNTER];
141 next[LFDS610_QUEUE_POINTER] = dequeue[LFDS610_QUEUE_POINTER]->next[LFDS610_QUEUE_POINTER];
142 next[LFDS610_QUEUE_COUNTER] = dequeue[LFDS610_QUEUE_POINTER]->next[LFDS610_QUEUE_COUNTER];
144 /* TRD : confirm that dequeue didn't move between reading it
145 and reading its next pointer
148 LFDS610_BARRIER_LOAD;
150 if( dequeue[LFDS610_QUEUE_POINTER] == qs->dequeue[LFDS610_QUEUE_POINTER] and dequeue[LFDS610_QUEUE_COUNTER] == qs->dequeue[LFDS610_QUEUE_COUNTER] )
152 if( enqueue[LFDS610_QUEUE_POINTER] == dequeue[LFDS610_QUEUE_POINTER] and next[LFDS610_QUEUE_POINTER] == NULL )
153 state = LFDS610_QUEUE_STATE_EMPTY;
155 if( enqueue[LFDS610_QUEUE_POINTER] == dequeue[LFDS610_QUEUE_POINTER] and next[LFDS610_QUEUE_POINTER] != NULL )
156 state = LFDS610_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE;
158 if( enqueue[LFDS610_QUEUE_POINTER] != dequeue[LFDS610_QUEUE_POINTER] )
159 state = LFDS610_QUEUE_STATE_ATTEMPT_DELFDS610_QUEUE;
163 case LFDS610_QUEUE_STATE_EMPTY:
166 finished_flag = RAISED;
169 case LFDS610_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE:
170 next[LFDS610_QUEUE_COUNTER] = enqueue[LFDS610_QUEUE_COUNTER] + 1;
171 lfds610_abstraction_dcas( (volatile lfds610_atom_t *) qs->enqueue, (lfds610_atom_t *) next, (lfds610_atom_t *) enqueue );
174 case LFDS610_QUEUE_STATE_ATTEMPT_DELFDS610_QUEUE:
175 *user_data = next[LFDS610_QUEUE_POINTER]->user_data;
177 next[LFDS610_QUEUE_COUNTER] = dequeue[LFDS610_QUEUE_COUNTER] + 1;
178 cas_result = lfds610_abstraction_dcas( (volatile lfds610_atom_t *) qs->dequeue, (lfds610_atom_t *) next, (lfds610_atom_t *) dequeue );
180 if( cas_result == 1 )
181 finished_flag = RAISED;
186 while( finished_flag == LOWERED );
188 if( cas_result == 1 )
189 lfds610_freelist_push( qs->fs, dequeue[LFDS610_QUEUE_POINTER]->fe );