/*************************************************************************************** function: int read_one_packet(u_int8_t **packet_addr, u_int32_t *packet_size) input: packet_addr: pointer to the address of the packet for read packet_size: pointer to the size of the packet for read return value: 0: successful, -1: failed remarks: value-result arguments are used ***************************************************************************************/ int read_one_packet(u_int8_t **packet_addr, u_int32_t *packet_size) { #if defined( __linux__ ) u_int32_t entry_index_for_this_read; free_last_read_packet(); pthread_mutex_lock(&fifo_core.mutex); // wait on the condition variable if fifo is empty while (fifo_core.used_entry_num == 0) { // printf("fifo empty, waiting...\n"); //jay pthread_cond_wait(&fifo_core.cond, &fifo_core.mutex); } entry_index_for_this_read = fifo_core.entry_index_for_next_read; // advertise the packet *packet_addr = myFIFO.packet_info_entries[entry_index_for_this_read].packet_addr; *packet_size = myFIFO.packet_info_entries[entry_index_for_this_read].packet_size; // update entry index for next read fifo_core.entry_index_for_next_read++; wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_read); // update related info fifo_core.entry_index_being_used = entry_index_for_this_read; pthread_mutex_unlock(&fifo_core.mutex); #elif defined( _WIN32 ) u_int32_t entry_index_for_this_read; free_last_read_packet(); DWORD Error = ::WaitForSingleObject( fifo_core.mutex, INFINITE ); // wait on the condition variable if fifo is empty while (fifo_core.used_entry_num == 0) { // printf("fifo empty, waiting...\n"); //jay WaitForSingleObject( fifo_core.cond, INFINITE ); } entry_index_for_this_read = fifo_core.entry_index_for_next_read; // advertise the packet *packet_addr = myFIFO.packet_info_entries[entry_index_for_this_read].packet_addr; *packet_size = myFIFO.packet_info_entries[entry_index_for_this_read].packet_size; // update entry index for next read fifo_core.entry_index_for_next_read++; wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_read); // update related info fifo_core.entry_index_being_used = entry_index_for_this_read; ::ReleaseMutex( fifo_core.mutex ); #endif return 0; }
/* ***************************************************************************/ int fifo_read_one_packet(fifo_t *fifo, u8 *header, u8 **packet_addr, u32 *packet_size) { int entry_index_for_this_read; // printf("lock, read\n"); pthread_mutex_lock(&fifo->mutex); // printf("locked, read\n"); free_last_read_packet(fifo); // wait on the condition variable if fifo is empty while (fifo->used_entry_num == 0) { // printf("unlock, waiting...\n"); //jay pthread_cleanup_push(cancel_read_wait, (void *) &fifo->mutex); pthread_cond_wait(&fifo->cond, &fifo->mutex); // printf("lock, awake\n"); pthread_cleanup_pop(0); } entry_index_for_this_read = fifo->entry_index_for_next_read; while (fifo->packet_info_entries[entry_index_for_this_read].entry_state == ENTRY_INVALID) { fifo_printf("\t\t\t\tskip entry %d\n", entry_index_for_this_read); entry_index_for_this_read++; wraparound_entry_index_if_necessary(fifo, &entry_index_for_this_read); } fifo_printf("\t\t\t\t\t[%x]read %d, entry %d\n", (u32)fifo&0xf, entry_index_for_this_read, fifo->used_entry_num); // advertise the packet *packet_addr = fifo->packet_info_entries[entry_index_for_this_read].packet_addr; *packet_size = fifo->packet_info_entries[entry_index_for_this_read].packet_size; memcpy(header, &fifo->header_entries[entry_index_for_this_read*(fifo->header_size)], fifo->header_size); // update entry index for next read fifo->entry_index_for_next_read = entry_index_for_this_read + 1; wraparound_entry_index_if_necessary(fifo, &fifo->entry_index_for_next_read); // update related info fifo->entry_index_being_used = entry_index_for_this_read; // printf("unlock, read\n"); pthread_mutex_unlock(&fifo->mutex); return 0; }
/*************************************************************************************** function: int fifo_write_one_packet(u8 *packet_addr, u32 packet_size) input: packet_addr: address of the packet to be stored into the fifo packet_size: size of packet to be stored into the fifo return value: 0: successful, -1: failed remarks: the algorithm gives priority to writers for sharing the free entries ***************************************************************************************/ int fifo_write_one_packet(fifo_t *fifo, u8 *header, u8 *packet_addr, u32 packet_size) { u8 *addr_for_this_write; int entry_index_for_this_write; // printf("lock, write\n"); pthread_mutex_lock(&fifo->mutex); // printf("locked, write\n"); addr_for_this_write = fifo->addr_for_next_write; entry_index_for_this_write = fifo->entry_index_for_next_write; // skip the entry being used for this write if (entry_index_for_this_write == fifo->entry_index_being_used) { entry_index_for_this_write++; wraparound_entry_index_if_necessary(fifo, &entry_index_for_this_write); } fifo_printf("[%x]write %d, using %d, next read %d, entry %d\n", (u32)fifo&0xf, entry_index_for_this_write, fifo->entry_index_being_used, fifo->entry_index_for_next_read, fifo->used_entry_num); // if necessary, adjust write address to avoid wrapping around data if ((addr_for_this_write + packet_size) > (fifo->buffer_end_addr + 1)) addr_for_this_write = fifo->buffer_start_addr; // save the packet memcpy(addr_for_this_write, packet_addr, packet_size); // save the header memcpy(&fifo->header_entries[entry_index_for_this_write*(fifo->header_size)], header, fifo->header_size); // update related info if (fifo->packet_info_entries[entry_index_for_this_write].entry_state == ENTRY_INVALID) fifo->used_entry_num++; // fill the entry fifo->packet_info_entries[entry_index_for_this_write].packet_addr = addr_for_this_write; fifo->packet_info_entries[entry_index_for_this_write].packet_size = packet_size; fifo->packet_info_entries[entry_index_for_this_write].entry_state = ENTRY_VALID; // advance the entry for next read, if it is overwirtten by this write, when fifo is full if (entry_index_for_this_write == fifo->entry_index_for_next_read && fifo->used_entry_num > 2) { // being used entry is still ocupying one entry // if fifo is nearly full fifo->entry_index_for_next_read++; wraparound_entry_index_if_necessary(fifo, &fifo->entry_index_for_next_read); if (fifo->entry_index_for_next_read == fifo->entry_index_being_used) { fifo->entry_index_for_next_read++; // skip the entry being used for next read wraparound_entry_index_if_necessary(fifo, &fifo->entry_index_for_next_read); } fifo_printf("fifo full, advance read entry to %d >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", fifo->entry_index_for_next_read); } // update entry index for next write fifo->entry_index_for_next_write = entry_index_for_this_write + 1; wraparound_entry_index_if_necessary(fifo, &fifo->entry_index_for_next_write); // update address for next write fifo->addr_for_next_write = addr_for_this_write + packet_size; if (fifo->addr_for_next_write > fifo->buffer_end_addr) fifo->addr_for_next_write -= fifo->buffer_total_size; // signal the condition variable if necessary if (fifo->used_entry_num <= 1) pthread_cond_signal(&fifo->cond); // fifo->buffer_used_size += packet_size; // printf("unlock, write\n"); pthread_mutex_unlock(&fifo->mutex); #if 0 printf("fifo_write_one_packet\n"); for (i = 0; i < 4; i++) { printf("%p\t", fifo->packet_info_entries[i].packet_addr); } printf("\nnow %d entry used\n", fifo->used_entry_num); #endif return 0; }
/*************************************************************************************** function: int write_one_packet(u_int8_t *packet_addr, u_int32_t packet_size) input: packet_addr: address of the packet to be stored into the fifo packet_size: size of packet to be stored into the fifo return value: 0: successful, -1: failed remarks: the algorithm gives priority to writers for sharing the free entries ***************************************************************************************/ int write_one_packet(u_int8_t *packet_addr, u_int32_t packet_size) { #if defined( __linux__ ) u_int8_t *addr_for_this_write; int entry_index_for_this_write = 0; pthread_mutex_lock(&fifo_core.mutex); addr_for_this_write = fifo_core.addr_for_next_write; entry_index_for_this_write = fifo_core.entry_index_for_next_write; // skip the entry being used for this write if (entry_index_for_this_write == fifo_core.entry_index_being_used) { entry_index_for_this_write++; wraparound_entry_index_if_necessary(&entry_index_for_this_write); } // if necessary, adjust write address to avoid wrapping around data if ((addr_for_this_write + packet_size) > (myFIFO.buffer_end_addr + 1)) addr_for_this_write = myFIFO.buffer_start_addr; // save the packet memcpy(addr_for_this_write, packet_addr, packet_size); // fill the entry myFIFO.packet_info_entries[entry_index_for_this_write].packet_addr = addr_for_this_write; myFIFO.packet_info_entries[entry_index_for_this_write].packet_size = packet_size; // advance the entry for next read, if it is overwirtten by this write, when fifo is full if (entry_index_for_this_write == fifo_core.entry_index_for_next_read && fifo_core.used_entry_num == myFIFO.max_entry_num) { // if fifo is full fifo_core.entry_index_for_next_read++; wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_read); printf("fifo full, dropping frame...\n"); } // update entry index for next write fifo_core.entry_index_for_next_write++; wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_write); if (fifo_core.entry_index_for_next_write == fifo_core.entry_index_being_used) { fifo_core.entry_index_for_next_write++; // skip entry being used by last read wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_write); } // update address for next write fifo_core.addr_for_next_write = addr_for_this_write + packet_size; if (fifo_core.addr_for_next_write > myFIFO.buffer_end_addr) fifo_core.addr_for_next_write -= myFIFO.buffer_total_size; // signal the condition variable if (fifo_core.used_entry_num == 0) pthread_cond_signal(&fifo_core.cond); // update related info fifo_core.used_entry_num++; fifo_core.buffer_used_size += packet_size; pthread_mutex_unlock(&fifo_core.mutex); #elif defined( _WIN32 ) u_int8_t *addr_for_this_write; int entry_index_for_this_write = 0; DWORD Error = WaitForSingleObject( fifo_core.mutex, INFINITE ); addr_for_this_write = fifo_core.addr_for_next_write; entry_index_for_this_write = fifo_core.entry_index_for_next_write; // skip the entry being used for this write if (entry_index_for_this_write == fifo_core.entry_index_being_used) { entry_index_for_this_write++; wraparound_entry_index_if_necessary(&entry_index_for_this_write); } // if necessary, adjust write address to avoid wrapping around data if ((addr_for_this_write + packet_size) > (myFIFO.buffer_end_addr + 1)) addr_for_this_write = myFIFO.buffer_start_addr; // save the packet memcpy(addr_for_this_write, packet_addr, packet_size); // fill the entry myFIFO.packet_info_entries[entry_index_for_this_write].packet_addr = addr_for_this_write; myFIFO.packet_info_entries[entry_index_for_this_write].packet_size = packet_size; // advance the entry for next read, if it is overwirtten by this write, when fifo is full if (entry_index_for_this_write == fifo_core.entry_index_for_next_read && fifo_core.used_entry_num == myFIFO.max_entry_num) { // if fifo is full fifo_core.entry_index_for_next_read++; wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_read); printf("fifo full, dropping frame...\n"); } // update entry index for next write fifo_core.entry_index_for_next_write++; wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_write); if (fifo_core.entry_index_for_next_write == fifo_core.entry_index_being_used) { fifo_core.entry_index_for_next_write++; // skip entry being used by last read wraparound_entry_index_if_necessary(&fifo_core.entry_index_for_next_write); } // update address for next write fifo_core.addr_for_next_write = addr_for_this_write + packet_size; if (fifo_core.addr_for_next_write > myFIFO.buffer_end_addr) fifo_core.addr_for_next_write -= myFIFO.buffer_total_size; // signal the condition variable if (fifo_core.used_entry_num == 0) { ::SetEvent( fifo_core.cond ); } // update related info fifo_core.used_entry_num++; fifo_core.buffer_used_size += packet_size; ::ReleaseMutex( fifo_core.mutex ); #endif #if 0 int i; printf("write_one_packet\n"); for (i = 0; i < 4; i++) { printf("%p\t", myFIFO.packet_info_entries[i].packet_addr); } printf("\nnow %d entry used\n", fifo_core.used_entry_num); #endif return 0; }