static inline void initialize_block_info(paper_input_databuf_t *paper_input_databuf_p, block_info_t * binfo, uint64_t pkt_mcnt) { int i; // We might be restarting so mark all currently active blocks, with the exception // of block_i, as filled. We will restart at block_i. On program startup, this loop // as no functional effect as no blocks are active and all block_active elements are 0. for(i = 0; i < N_INPUT_BLOCKS; i++) { if(i == binfo->block_i) { binfo->block_active[i] = 0; } else { if(binfo->block_active[i]) { paper_input_databuf_p->block[i].header.good_data = 0; // all data are bad at this point set_block_filled(paper_input_databuf_p, binfo, i); } } } // On program startup block_i will be zero. If we are restarting, this will set // us up to restart at the beginning of block_i. binfo->mcnt_start = pkt_mcnt - binfo->block_i * N_SUB_BLOCKS_PER_INPUT_BLOCK; binfo->mcnt_prior = pkt_mcnt; binfo->out_of_seq_cnt = 0; binfo->initialized = 1; }
// Method to process a received packet // Processing involves the following // (1) header extraction // (2) block population (output buffer data type is a block) // (3) buffer population (if block is filled) static inline uint64_t process_packet(flag_input_databuf_t * db, struct hashpipe_udp_packet *p) { static block_info_t binfo; packet_header_t pkt_header; // Parse packet header get_header(p, &pkt_header); uint64_t pkt_mcnt = pkt_header.mcnt; uint64_t cur_mcnt = binfo.mcnt_start; int dest_block_idx = get_block_idx(pkt_mcnt); // fprintf(stdout, "Block idx = %d\n", dest_block_idx); // Check mcnt to see if packet belongs in current block, next, or the one after uint64_t pkt_mcnt_dist = pkt_mcnt - cur_mcnt; if (pkt_mcnt_dist >= 2*Nm) { // 2nd next block (Current block + 2) set_block_filled(db, &binfo); // Advance mcnt_start to next block cur_mcnt += Nm; binfo.mcnt_start += Nm; binfo.block_i = (binfo.block_i + 1) % N_INPUT_BLOCKS; // Initialize next block flag_input_databuf_wait_free(db, dest_block_idx); initialize_block(db, pkt_mcnt); // Reset packet counter for this block binfo.packet_count[dest_block_idx] = 0; } // Increment packet count for block binfo.packet_count[dest_block_idx]++; // Validate FID and XID // Calculate "m" and "f" which index the buffer for writing packet payload if (calc_block_indices(&binfo, &pkt_header) == -1) { hashpipe_error(__FUNCTION__, "invalid FID and XID in header"); return -1; } // Calculate starting points for writing packet payload into buffer // POSSIBLE RACE CONDITION!!!! Need to lock db->block access with semaphore uint64_t * dest_p = db->block[dest_block_idx].data + flag_input_databuf_idx(binfo.m, binfo.f, 0, 0); const uint64_t * payload_p = (uint64_t *)(p->data+8); // Copy data into buffer memcpy(dest_p, payload_p, N_BYTES_PER_PACKET); // print_pkt_header(&pkt_header); return pkt_mcnt; }
// This function returns -1 unless the given packet causes a block to be marked // as filled in which case this function returns the marked block's first mcnt. // Any return value other than -1 will be stored in the status memory as // NETMCNT, so it is important that values other than -1 are returned rarely // (i.e. when marking a block as filled)!!! static inline uint64_t write_paper_packet_to_blocks(paper_input_databuf_t *paper_input_databuf_p, struct guppi_udp_packet *p) { static block_info_t binfo; packet_header_t pkt_header; const uint64_t *payload_p; int rv; int i; uint64_t *dest_p; uint64_t netmcnt = -1; // Value to store in status memory #if N_DEBUG_INPUT_BLOCKS == 1 static uint64_t debug_remaining = -1ULL; static off_t debug_offset = 0; uint64_t * debug_ptr; #endif // housekeeping for each packet get_header(p, &pkt_header); #if N_DEBUG_INPUT_BLOCKS == 1 debug_ptr = (uint64_t *)&paper_input_databuf_p->block[N_INPUT_BLOCKS]; debug_ptr[debug_offset++] = be64toh(*(uint64_t *)(p->data)); if(--debug_remaining == 0) { exit(1); } if(debug_offset >= sizeof(paper_input_block_t)/sizeof(uint64_t)) { debug_offset = 0; } #endif if(! binfo.initialized) { // insist that we start on a multiple of sub_blocks/block if(pkt_header.mcnt % N_SUB_BLOCKS_PER_INPUT_BLOCK != 0) { return -1; } initialize_block_info(paper_input_databuf_p, &binfo, pkt_header.mcnt); } if(out_of_seq_mcnt(&binfo, pkt_header.mcnt)) { return(handle_out_of_seq_mcnt(&binfo)); } if((rv = calc_block_indexes(&binfo, &pkt_header))) { return rv; } if(! binfo.block_active[binfo.block_i]) { // new block, pass along the block for N_INPUT_BLOCKS/2 blocks ago i = subtract_block_i(binfo.block_i, N_INPUT_BLOCKS/2); #if N_DEBUG_INPUT_BLOCKS == 1 #define DEBUG_EXTRA (0x10000) if(set_block_filled(paper_input_databuf_p, &binfo, i) && debug_remaining > DEBUG_EXTRA) { debug_remaining = DEBUG_EXTRA; } #else set_block_filled(paper_input_databuf_p, &binfo, i); #endif netmcnt = paper_input_databuf_p->block[i].header.mcnt; // Wait (hopefully not long!) for free block for this packet if((rv = paper_input_databuf_busywait_free(paper_input_databuf_p, binfo.block_i)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { // run_threads is 0 (i.e. shutting down) return -1; } else { guppi_error(__FUNCTION__, "error waiting for free databuf"); run_threads=0; pthread_exit(NULL); return -1; } } initialize_block(paper_input_databuf_p, &binfo, pkt_header.mcnt); } binfo.block_active[binfo.block_i]++; // increment packet count for block // end housekeeping // Calculate starting points for unpacking this packet into block's data buffer. dest_p = paper_input_databuf_p->block[binfo.block_i].data + paper_input_databuf_data_idx(binfo.m, binfo.x, binfo.q, binfo.f, 0, 0); payload_p = (uint64_t *)(p->data+8); // Copy data into buffer memcpy(dest_p, payload_p, N_BYTES_PER_PACKET); return netmcnt; }