| 1 | #ifndef _CIVL_COLLATE_
|
|---|
| 2 | #define _CIVL_COLLATE_
|
|---|
| 3 |
|
|---|
| 4 | #include<collate.cvh>
|
|---|
| 5 | #include<civlc.cvh>
|
|---|
| 6 | #include<seq.cvh>
|
|---|
| 7 |
|
|---|
| 8 | // Status of a collate state for a process
|
|---|
| 9 | #define NONARRIVED 0
|
|---|
| 10 | #define ARRIVED 1
|
|---|
| 11 | #define DEPARTED 2
|
|---|
| 12 | #define UNCHECKED 3
|
|---|
| 13 | #define CHECKED 4
|
|---|
| 14 | // The $gcollate_state whose state field is significant:
|
|---|
| 15 | #define _STATE_USED(gstate, place) ((gstate)->status[(place)] >= NONARRIVED && (gstate)->status[(place)] <= DEPARTED)
|
|---|
| 16 | #define _ARRIVED(gstate, place) ((gstate)->status[(place)] == ARRIVED || (gstate)->status[(place)] == DEPARTED)
|
|---|
| 17 | #define _DEPARTED(gstate, place) ((gstate)->status[(place)] == DEPARTED)
|
|---|
| 18 | // The $gcollate_state whose attribute field is significant:
|
|---|
| 19 | #define _ATTR_USED(gstate, place) ((gstate)->status[(place)] >= UNCHECKED && (gstate)->status[(place)] <= CHECKED)
|
|---|
| 20 | #define _CHECKED(gstate, place) ((gstate)->status[(place)] == CHECKED)
|
|---|
| 21 |
|
|---|
| 22 | /******************* Definition of datatypes: *******************/
|
|---|
| 23 | struct _gcollator {
|
|---|
| 24 | // The number of participants of a _gcollator object:
|
|---|
| 25 | int nprocs;
|
|---|
| 26 | // $proc array:
|
|---|
| 27 | $proc procs[];
|
|---|
| 28 | // The length of the queue of collation states:
|
|---|
| 29 | int queue_length;
|
|---|
| 30 | // The queue of collation states. Note that elements in this queue
|
|---|
| 31 | // are references to collate state objects:
|
|---|
| 32 | $gcollate_state queue[];
|
|---|
| 33 | _Bool entered[];
|
|---|
| 34 | };
|
|---|
| 35 |
|
|---|
| 36 | struct _collator {
|
|---|
| 37 | // The place of the process in a _gcollator who holds this handle:
|
|---|
| 38 | int place;
|
|---|
| 39 | // A handle to the _gcollator object:
|
|---|
| 40 | $gcollator gcollator;
|
|---|
| 41 | };
|
|---|
| 42 |
|
|---|
| 43 | // TODO: don't use one queue for collate states and collective attributes
|
|---|
| 44 | struct _gcollate_state {
|
|---|
| 45 | // An array of markers for whether a process has already arrived
|
|---|
| 46 | // this entry or departed:
|
|---|
| 47 | int status[];
|
|---|
| 48 | // collate $state:
|
|---|
| 49 | $state state;
|
|---|
| 50 | // A customized attribute, it can be used to check some attribute
|
|---|
| 51 | // that must be equivalent collectively at some point:
|
|---|
| 52 | $bundle attribute;
|
|---|
| 53 | // Note: for one $gcollate_state object, state and attribute cannot
|
|---|
| 54 | // be in use at the same time.
|
|---|
| 55 | };
|
|---|
| 56 |
|
|---|
| 57 | struct _collate_state {
|
|---|
| 58 | // The place of the process in a _gcollator who holds this handle:
|
|---|
| 59 | int place;
|
|---|
| 60 | // A reference to a _gcollate_state:
|
|---|
| 61 | $gcollate_state gstate;
|
|---|
| 62 | };
|
|---|
| 63 |
|
|---|
| 64 | /******************* Function definitions ***************************/
|
|---|
| 65 | /* Creates an global collator object. The object is allocated in the
|
|---|
| 66 | * given scope. It returns a handle $gcollator to the object.
|
|---|
| 67 | *
|
|---|
| 68 | * scope : The scope where the object is allocated.
|
|---|
| 69 | * nprocs: The number of processes included in the global collator.
|
|---|
| 70 | */
|
|---|
| 71 | $gcollator $gcollator_create($scope scope, int nprocs) {
|
|---|
| 72 | $gcollator gcollator = ($gcollator)$malloc(scope, sizeof(struct _gcollator));
|
|---|
| 73 |
|
|---|
| 74 | gcollator->nprocs = nprocs;
|
|---|
| 75 | gcollator->procs = ($proc[nprocs])$lambda(int i) $proc_null;
|
|---|
| 76 | gcollator->queue_length = 0;
|
|---|
| 77 | $seq_init(&(gcollator->queue), 0, NULL);
|
|---|
| 78 | gcollator->entered=(_Bool[nprocs])$lambda(int i) $false;
|
|---|
| 79 | return gcollator;
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | /* Creates a local collate object. The object is allocated in the
|
|---|
| 83 | * given scope. A local collate represents a local handle to part of
|
|---|
| 84 | * the global collate object.
|
|---|
| 85 | *
|
|---|
| 86 | * gcollator: The handle to the global collate object.
|
|---|
| 87 | * scope: The scope where the local collate object will be allocated.
|
|---|
| 88 | * place: The place of the participant process in the global collate
|
|---|
| 89 | * object. Each participant process has an unique place. Place shall
|
|---|
| 90 | * be greater than or equal to 0 and less than the number of all
|
|---|
| 91 | * participants.
|
|---|
| 92 | */
|
|---|
| 93 | $collator $collator_create($gcollator gcollator, $scope scope, int place) {
|
|---|
| 94 | $collator collator = ($collator)$malloc(scope, sizeof(struct _collator));
|
|---|
| 95 |
|
|---|
| 96 | collator->place = place;
|
|---|
| 97 | collator->gcollator = gcollator;
|
|---|
| 98 | collator->gcollator->procs[place] = $self;
|
|---|
| 99 | return collator;
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | $atomic_f void $collator_enters($collator collator){
|
|---|
| 103 | collator->gcollator->entered[collator->place] = $true;
|
|---|
| 104 | }
|
|---|
| 105 |
|
|---|
| 106 | $atomic_f _Bool $collator_has_entered($collator collator, $range range){
|
|---|
| 107 | $domain(1) dom=($domain(1)){range};
|
|---|
| 108 | _Bool *entered=collator->gcollator->entered;
|
|---|
| 109 |
|
|---|
| 110 | $for(int i: dom){
|
|---|
| 111 | if(!entered[i])
|
|---|
| 112 | return $false;
|
|---|
| 113 | }
|
|---|
| 114 | return $true;
|
|---|
| 115 | }
|
|---|
| 116 |
|
|---|
| 117 | $atomic_f $collate_state $collate_arrives($collator c, $scope scope) {
|
|---|
| 118 | int place = c->place;
|
|---|
| 119 | int queue_size, nprocs;
|
|---|
| 120 | _Bool first = $true;
|
|---|
| 121 | $gcollate_state * queue;
|
|---|
| 122 | $gcollate_state gcollate_state;
|
|---|
| 123 | $collate_state result;
|
|---|
| 124 |
|
|---|
| 125 | nprocs = c->gcollator->nprocs;
|
|---|
| 126 | queue = c->gcollator->queue;
|
|---|
| 127 | queue_size = c->gcollator->queue_length;
|
|---|
| 128 |
|
|---|
| 129 | // Looking for the first unarrived collate state. If no such a collate
|
|---|
| 130 | // state, create and insert one:
|
|---|
| 131 | for (int i = 0; i < queue_size; i++)
|
|---|
| 132 | if (_STATE_USED(queue[i], place) && !_ARRIVED(queue[i], place)) {
|
|---|
| 133 | gcollate_state = queue[i];
|
|---|
| 134 | first = $false;
|
|---|
| 135 | break;
|
|---|
| 136 | }
|
|---|
| 137 | if (first) {
|
|---|
| 138 | _Bool initValue = $false;
|
|---|
| 139 | $scope root = $scopeof(*c->gcollator);
|
|---|
| 140 |
|
|---|
| 141 | gcollate_state = ($gcollate_state)$malloc(root, sizeof(struct _gcollate_state));
|
|---|
| 142 | gcollate_state->status = (int[nprocs])$lambda(int i) NONARRIVED;
|
|---|
| 143 | gcollate_state->state = $state_null;
|
|---|
| 144 | $seq_append(&c->gcollator->queue, &gcollate_state, 1);
|
|---|
| 145 | c->gcollator->queue_length++;
|
|---|
| 146 | }
|
|---|
| 147 | result.place = place;
|
|---|
| 148 | result.gstate = gcollate_state;
|
|---|
| 149 | $collate_snapshot(result, nprocs, scope);
|
|---|
| 150 | gcollate_state->status[place] = ARRIVED;
|
|---|
| 151 | return result;
|
|---|
| 152 | }
|
|---|
| 153 |
|
|---|
| 154 | $atomic_f void $collate_departs($collator c, $collate_state cs) {
|
|---|
| 155 | int nprocs, queue_size, place, index;
|
|---|
| 156 | $gcollate_state *queue;
|
|---|
| 157 | $gcollate_state gcollate_state = cs.gstate;
|
|---|
| 158 |
|
|---|
| 159 | place = c->place;
|
|---|
| 160 | nprocs = c->gcollator->nprocs;
|
|---|
| 161 | queue_size = c->gcollator->queue_length;
|
|---|
| 162 | queue = c->gcollator->queue;
|
|---|
| 163 | $assert(_STATE_USED(gcollate_state, place)
|
|---|
| 164 | && _ARRIVED(gcollate_state, place),
|
|---|
| 165 | "Only an arrived collate state can be freed");
|
|---|
| 166 | // Mark the refered gcollate state as departed:
|
|---|
| 167 | gcollate_state->status[place] = DEPARTED;
|
|---|
| 168 |
|
|---|
| 169 | // Scan the queue in the gcollator to remove an entry
|
|---|
| 170 | // that has already been marked as DEPARTED by all processes:
|
|---|
| 171 | index = -1;
|
|---|
| 172 | for (int i = 0; i < queue_size; i++) {
|
|---|
| 173 | _Bool isGarbage = $true;
|
|---|
| 174 |
|
|---|
| 175 | for (int j = 0; j < nprocs; j++)
|
|---|
| 176 | if (!_DEPARTED(queue[i], j)) {
|
|---|
| 177 | isGarbage = $false;
|
|---|
| 178 | break;
|
|---|
| 179 | }
|
|---|
| 180 | if (isGarbage) {
|
|---|
| 181 | index = i;
|
|---|
| 182 | $free(gcollate_state);
|
|---|
| 183 | break;
|
|---|
| 184 | }
|
|---|
| 185 | }
|
|---|
| 186 | if (index >= 0) {
|
|---|
| 187 | $seq_remove(&c->gcollator->queue, index, NULL, 1);
|
|---|
| 188 | c->gcollator->queue_length--;
|
|---|
| 189 | }
|
|---|
| 190 | // set the gcollate state reference to NULL so that the process
|
|---|
| 191 | // cannot access it after the call of departs():
|
|---|
| 192 | cs.gstate = NULL;
|
|---|
| 193 | }
|
|---|
| 194 |
|
|---|
| 195 | $bundle $collate_check($collator c, $bundle bundle) {
|
|---|
| 196 | int nprocs, queue_size, place, index;
|
|---|
| 197 | _Bool first = $true;
|
|---|
| 198 | $gcollate_state attr;
|
|---|
| 199 | $bundle result;
|
|---|
| 200 |
|
|---|
| 201 | nprocs = c->gcollator->nprocs;
|
|---|
| 202 | place = c->place;
|
|---|
| 203 | queue_size = c->gcollator->queue_length;
|
|---|
| 204 | for (int i = 0; i < queue_size; i++) {
|
|---|
| 205 | if (_ATTR_USED(c->gcollator->queue[i], place)
|
|---|
| 206 | && !_CHECKED(c->gcollator->queue[i], place)) {
|
|---|
| 207 | first = $false;
|
|---|
| 208 | attr = c->gcollator->queue[i];
|
|---|
| 209 | index = i;
|
|---|
| 210 | break;
|
|---|
| 211 | }
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | if (first) {
|
|---|
| 215 | $scope gcollate_scope = $scopeof(*c->gcollator);
|
|---|
| 216 |
|
|---|
| 217 | attr = ($gcollate_state)$malloc(gcollate_scope, sizeof(struct _gcollate_state));
|
|---|
| 218 | attr->status = ((int[nprocs])$lambda(int i)UNCHECKED);
|
|---|
| 219 | attr->attribute = bundle;
|
|---|
| 220 | $seq_append(&c->gcollator->queue, &attr, 1);
|
|---|
| 221 | index = c->gcollator->queue_length++;
|
|---|
| 222 | }
|
|---|
| 223 | attr->status[place] = CHECKED;
|
|---|
| 224 | result = attr->attribute;
|
|---|
| 225 |
|
|---|
| 226 | // if complete, dequeue; else modify the entry:
|
|---|
| 227 | _Bool complete = $true;
|
|---|
| 228 |
|
|---|
| 229 | for (int i = 0; i < nprocs; i++)
|
|---|
| 230 | if (!_CHECKED(attr, i)) {
|
|---|
| 231 | complete = $false;
|
|---|
| 232 | break;
|
|---|
| 233 | }
|
|---|
| 234 | if (complete) {
|
|---|
| 235 | $assert(index == 0);
|
|---|
| 236 | $free(c->gcollator->queue[0]);
|
|---|
| 237 | $seq_remove(&c->gcollator->queue, 0, NULL, 1);
|
|---|
| 238 | c->gcollator->queue_length--;
|
|---|
| 239 | }
|
|---|
| 240 | return result;
|
|---|
| 241 | }
|
|---|
| 242 |
|
|---|
| 243 | $atomic_f $state_f $state $collate_get_state($collate_state state){
|
|---|
| 244 | return state.gstate->state;
|
|---|
| 245 | }
|
|---|
| 246 |
|
|---|
| 247 | #endif
|
|---|