/* Enqueue a record to a stream and add a note to the todo list. */ void SNetWrite(snet_stream_desc_t **desc_ptr, snet_record_t *rec, bool last) { snet_stream_desc_t *desc = *desc_ptr; landing_t *land = desc->landing; worker_t *worker = desc->source->worker; /* Test if we can garbage collect this stream together with its landing. */ if (land->type == LAND_identity && trylock_landing(land, worker)) { desc = SNetMergeStreams(desc_ptr); land = desc->landing; } /* Increase the reference count to the destination stream. */ DESC_INCR(desc); /* If this write was the last statement in the caller function and we can * lock the destination landing then process the record right away. */ if (last && land->id == 0 && trylock_landing(land, worker)) { /* Make sure we process records in stream FIFO order. */ worker->continue_rec = (snet_record_t *) SNetFifoPutGet(&desc->fifo, rec); assert(worker->continue_rec); worker->continue_desc = desc; } else { /* Store the record into the destination stream. */ SNetFifoPut(&desc->fifo, rec); /* Add a todo item to this worker's todo queue. */ SNetWorkerTodo(worker, desc); } }
/* Try to read next input record: true iff successful. */ static bool SNetWorkerInput(worker_t *worker) { if (worker->has_input) { landing_t *land = worker->input_desc->landing; if (trylock_landing(land, worker)) { if (SNetInputAllowed(worker)) { input_state_t state = SNetGetNextInputRecord(land); if (state != INPUT_reading) { worker->has_input = false; if (state == INPUT_terminating) { SNetCloseInput(land->node); } } } unlock_landing(land); } } return worker->has_input; }
/* Work on an item. * * In case of a dissolved garbage stream update the source * stream of the work item. * * Return true iff a record was processed. * * If the contents of the item was merged with another item then * reset the item descriptor to NULL. */ static bool SNetWorkerWorkItem(work_item_t *const item, worker_t *worker) { work_item_t *lookup; /* Item must be owned and non-empty. */ assert(item->lock == worker->id); assert(item->count > 0); /* Claim destination landing. */ if (trylock_landing(item->desc->landing, worker) == false) { /* Nothing can be done. */ return false; } /* Bring item descriptors past any garbage collectable landings. */ while (item->desc->landing->type == LAND_garbage) { /* Get subsequent descriptor. */ snet_stream_desc_t *next_desc = DESC_LAND_SPEC(item->desc, siso)->outdesc; /* Release landing claim. */ unlock_landing(item->desc->landing); /* Decrease reference counts to descriptor. */ SNetDescRelease(item->desc, item->count); /* Take item out of hash table. */ SNetHashPtrRemove(worker->hash_ptab, item->desc); /* Update item descriptor. */ item->desc = next_desc; /* Also advance past subsequent garbage landings. */ while (next_desc->landing->type == LAND_garbage) { /* Get subsequent descriptor. */ item->desc = DESC_LAND_SPEC(next_desc, siso)->outdesc; /* Test if current descriptor is also in our hash table. */ lookup = (work_item_t *)SNetHashPtrLookup(worker->hash_ptab, next_desc); if (lookup && trylock_work_item(lookup, worker)) { /* Merge both descriptor counts into one. */ item->count += lookup->count; lookup->count = 0; unlock_work_item(lookup, worker); } /* Decrease reference counts to garbage descriptor. */ SNetDescRelease(next_desc, item->count); /* Advance to subsequent descriptor and repeat. */ next_desc = item->desc; } /* The new descriptor may already exist in hash table. */ lookup = (work_item_t *)SNetHashPtrLookup(worker->hash_ptab, next_desc); if (lookup) { /* Merge the two counts. */ AAF(&lookup->count, item->count); /* Reset item. */ item->count = 0; /* We already have this desciptor in lookup, so reset it. */ item->desc = NULL; /* We made progress. */ return true; } else /* (lookup == NULL) */ { /* Add new descriptor to hash table. */ SNetHashPtrStore(worker->hash_ptab, item->desc, item); /* Claim destination landing. */ if (trylock_landing(item->desc->landing, worker) == false) { /* We made progress anyway. */ return true; } } } /* Subtract one read license. */ --item->count; /* Unlock item so thieves can steal it while we work. */ unlock_work_item(item, worker); /* Finally, do the work by delegating to the streams layer. */ SNetStreamWork(item->desc, worker); /* We definitely made progress. */ return true; }