//-------------------------------------------------------------------------------------- // FUNCTION: RCCE_wait_until //-------------------------------------------------------------------------------------- // wait until flag in local MPB becomes set or unset. To avoid reading stale data from // the cache instead of new flag value from the MPB, issue MPB cache invalidation before // each read, including within the spin cycle //-------------------------------------------------------------------------------------- int RCCE_wait_until(RCCE_FLAG flag, RCCE_FLAG_STATUS val) { t_vcharp cflag; cflag = flag.line_address; // avoid tests if we use the simplified API #ifdef GORY if (val != RCCE_FLAG_UNSET && val != RCCE_FLAG_SET) return(RCCE_error_return(RCCE_debug_synch,RCCE_ERROR_FLAG_STATUS_UNDEFINED)); if (!cflag) return(RCCE_error_return(RCCE_debug_synch,RCCE_ERROR_FLAG_NOT_ALLOCATED)); // check to see if flag is properly contained in the local comm buffer if (cflag - RCCE_comm_buffer[RCCE_IAM]>=0 && cflag+RCCE_LINE_SIZE - (RCCE_comm_buffer[RCCE_IAM] + RCCE_BUFF_SIZE)<0){} else { return(RCCE_error_return(RCCE_debug_synch,RCCE_ERROR_FLAG_NOT_IN_COMM_BUFFER)); } #endif // always flush/invalidate to ensure we read the most recent value of *flag // keep reading it until it has the required value do { #ifdef _OPENMP #pragma omp flush #endif RC_cache_invalidate(); } while ((RCCE_bit_value(cflag, flag.location) != val)); return(RCCE_SUCCESS); }
//-------------------------------------------------------------------------------------- // FUNCTION: RCCE_probe //-------------------------------------------------------------------------------------- // nonblocking function to check if a flag has been set //-------------------------------------------------------------------------------------- int RCCE_probe(RCCE_FLAG flag) { #ifdef _OPENMP #pragma omp flush #endif RC_cache_invalidate(); return (RCCE_bit_value(flag.flag_addr, flag.location%RCCE_FLAGS_PER_BYTE) == RCCE_FLAG_SET); }
//-------------------------------------------------------------------------------------- // FUNCTION: RCCE_barrier //-------------------------------------------------------------------------------------- // very simple, linear barrier //-------------------------------------------------------------------------------------- int RCCE_barrier(RCCE_COMM *comm) { int counter, i, error; int ROOT = 0; t_vchar cyclechar[RCCE_LINE_SIZE]; t_vchar valchar [RCCE_LINE_SIZE]; t_vcharp gatherp, releasep; RCCE_FLAG_STATUS cycle; counter = 0; gatherp = comm->gather.line_address; if (RCCE_debug_synch) fprintf(STDERR,"UE %d has checked into barrier\n", RCCE_IAM); // flip local barrier variable if (error = RCCE_get(cyclechar, gatherp, RCCE_LINE_SIZE, RCCE_IAM)) return(RCCE_error_return(RCCE_debug_synch,error)); cycle = RCCE_flip_bit_value(cyclechar, comm->gather.location); if (error = RCCE_put(comm->gather.line_address, cyclechar, RCCE_LINE_SIZE, RCCE_IAM)) return(RCCE_error_return(RCCE_debug_synch,error)); if (RCCE_IAM==comm->member[ROOT]) { // read "remote" gather flags; once all equal "cycle" (i.e counter==comm->size), // we know all UEs have reached the barrier while (counter != comm->size) { // skip the first member (#0), because that is the ROOT for (counter=i=1; i<comm->size; i++) { // copy flag values out of comm buffer if (error = RCCE_get(valchar, comm->gather.line_address, RCCE_LINE_SIZE, comm->member[i])) return(RCCE_error_return(RCCE_debug_synch,error)); if (RCCE_bit_value(valchar, comm->gather.location) == cycle) counter++; } } // set release flags for (i=1; i<comm->size; i++) if (error = RCCE_flag_write(&(comm->release), cycle, comm->member[i])) return(RCCE_error_return(RCCE_debug_synch,error)); } else { if (error = RCCE_wait_until(comm->release, cycle)) return(RCCE_error_return(RCCE_debug_synch,error)); } if (RCCE_debug_synch) fprintf(STDERR,"UE %d has cleared barrier\n", RCCE_IAM); return(RCCE_SUCCESS); }
//-------------------------------------------------------------------------------------- // FUNCTION: RCCE_flag_read //-------------------------------------------------------------------------------------- // This routine is rarely needed. We typically only read a flag when we're waiting for // it to change value (function RCCE_wait_until). Reading does not require locking. The // moment the target flag we're trying to read changes value, it is OK to read and // return that value //-------------------------------------------------------------------------------------- int RCCE_flag_read(RCCE_FLAG flag, RCCE_FLAG_STATUS *val, int ID) { t_vchar val_array[1]; #ifdef GORY if (flag.location < 0 || flag.location > RCCE_FLAGS_PER_LINE) return(RCCE_error_return(RCCE_debug_synch,RCCE_ERROR_FLAG_UNDEFINED)); if (!val) return(RCCE_error_return(RCCE_debug_synch,RCCE_ERROR_VAL_UNDEFINED)); if (ID<0 || ID>=RCCE_NP) return(RCCE_error_return(RCCE_debug_synch,RCCE_ERROR_ID)); #endif // Should be able to use same technique as in RCCE_wait_until, i.e., should not need // to copy out of MPB first. However, this function is not time critical RCCE_get_char(val_array, flag.flag_addr, ID); *val = RCCE_bit_value(val_array, (flag.location)%RCCE_FLAGS_PER_BYTE); return(RCCE_SUCCESS); }