PICC_Commit *PICC_try_output_action(PICC_Channel *chan, PICC_TryResult *res) { if (chan->global_rc == 1) { *res = PICC_TRY_DISABLED; return NULL; } PICC_Commit *commit = NULL; PICC_CommitStatus ok = PICC_CANNOT_ACQUIRE; do { // search for a valid commitment commit = PICC_fetch_input_commitment(chan); if (commit == NULL) { // if no valid or invalid commitment left, need to // make an output commitment *res = PICC_TRY_COMMIT; return NULL; } // here, we have a candidate input commitment // try to awake the commiting thread do { ok = PICC_process_can_awake(commit); if (ok == PICC_CANNOT_ACQUIRE) { sched_yield(); } } while (ok == PICC_CANNOT_ACQUIRE); // here we have either a valid commitment and an awoken thread, // or an invalid commitment that we just removed (lazy deletion) if (ok == PICC_VALID_COMMIT) { // ok, everything's fine: a synchronization will occur *res = PICC_TRY_ENABLED; return commit; } } while (!(PICC_commitlist_is_empty(chan->incommits))); PICC_CRASH(ERR_DEAD_CODE_REACHED); return NULL; }
/** * The runtime support for output actions. * * @param pt the PiThread structure of the thread trying to output * @param chan_ref the environment index of the output channel * @param chans the acquired channels (cf. compilation of output try) * @param nbchans the number of acquired channels * @param try_result an output variable for the result of the try (ENABLED if output can be performed, DISABLED if not, and COMMIT if a commiment must be recorded). * @return the matching input commitment, if any or NULL otherwise. */ PICC_Commit * PICC_try_output_action(PICC_PiThread *pt, int chan_ref, PICC_Channel* chans[], int nbchans, PICC_TryResult * try_result) { PICC_Channel* out_chan = PICC_channel_of_channel_value(&(pt->env[chan_ref])); // acquire the channel, if required if (chan_array_add(out_chan, chans, &nbchans)) { LOCK_CHANNEL(out_chan); } if(out_chan->global_rc == 1) { // if global reference count is one, then pt is the only // thread knowing the channel, hence the try is DISABLED. *try_result = PICC_TRY_DISABLED; return NULL; } PICC_Commit * commit = NULL; PICC_CommitStatus ok = PICC_CANNOT_ACQUIRE; do { // search for a valid input commitment commit = PICC_fetch_input_commitment(out_chan); if(commit == NULL) { // if no valid or invalid commitment left, need to // make an output commitment *try_result = PICC_TRY_COMMIT; return NULL; } // here, we have a candidate input commitment // try to awake the commiting thread do { ok = PICC_can_awake(commit->thread, commit); if(ok == PICC_CANNOT_ACQUIRE) { // to avoid contention on thread awaking PICC_low_level_yield(); } } while(ok == PICC_CANNOT_ACQUIRE); // here we have either a valid commitment // an an awoken thread, or an invalid commitment // that we just removed (lazy deletion). if (ok == PICC_VALID_COMMIT) { // ok, everything's fine a synchronization will occur *try_result = PICC_TRY_ENABLED; return commit; // we return the valid commitment } // otherwise it's invalid and deleted, and we will // try to find a further commitment } while (!(PICC_commit_list_is_empty(out_chan->incommits))); // TODO: raise a "dead code reached" error CRASH_NEW_ERROR(ERR_DEAD_CODE_REACHED); return NULL; }