/** Drain the input channel * * @param[in] nr the network * @param[in] ch the channel to drain * @param[in] cd the message (if any) to start with */ static void fr_network_drain_input(fr_network_t *nr, fr_channel_t *ch, fr_channel_data_t *cd) { fr_network_worker_t *worker; if (!cd) { cd = fr_channel_recv_reply(ch); if (!cd) { DEBUG3("empty reply from worker"); return; } } do { cd->channel.ch = ch; /* * Update stats for the worker. */ worker = fr_channel_master_ctx_get(ch); worker->stats.out++; worker->cpu_time = cd->reply.cpu_time; if (!worker->predicted) { worker->predicted = cd->reply.processing_time; } else { worker->predicted = RTT(worker->predicted, cd->reply.processing_time); } (void) fr_heap_insert(nr->replies, cd); } while ((cd = fr_channel_recv_reply(ch)) != NULL); }
int main(int argc, char **arg) { fr_heap_t *hp; int i, array[1024]; hp = fr_heap_create(heap_cmp, 0); if (!hp) { fprintf(stderr, "Failed creating heap!\n"); exit(1); } for (i = 0; i < 1024; i++) { array[i] = (i * 257) % 65537; if (!fr_heap_insert(hp, &array[i])) { fprintf(stderr, "Failed inserting %d\n", i); exit(1); } } for (i = 0; i < 1024; i++) { int *p = fr_heap_peek(hp); if (!p) { fprintf(stderr, "Failed peeking %d\n", i); exit(1); } printf("%d\t%d\n", i, *p); if (!fr_heap_extract(hp, NULL)) { fprintf(stderr, "Failed extracting %d\n", i); exit(1); } } fr_heap_delete(hp); return 0; }
int main(int argc, char **argv) { fr_heap_t *hp; int i; heap_thing array[ARRAY_SIZE]; int skip = 0; int left; if (argc > 1) { skip = atoi(argv[1]); } hp = fr_heap_create(heap_cmp, offsetof(heap_thing, heap)); if (!hp) { fprintf(stderr, "Failed creating heap!\n"); fr_exit(1); } for (i = 0; i < ARRAY_SIZE; i++) { array[i].data = rand() % 65537; if (!fr_heap_insert(hp, &array[i])) { fprintf(stderr, "Failed inserting %d\n", i); fr_exit(1); } if (!fr_heap_check(hp, &array[i])) { fprintf(stderr, "Inserted but not in heap %d\n", i); fr_exit(1); } } #if 0 for (i = 0; i < ARRAY_SIZE; i++) { printf("Array %d has value %d at offset %d\n", i, array[i].data, array[i].heap); } #endif if (skip) { int entry; printf("%d elements to remove\n", ARRAY_SIZE / skip); for (i = 0; i < ARRAY_SIZE / skip; i++) { entry = i * skip; if (!fr_heap_extract(hp, &array[entry])) { fprintf(stderr, "Failed removing %d\n", entry); } if (fr_heap_check(hp, &array[entry])) { fprintf(stderr, "Deleted but still in heap %d\n", entry); fr_exit(1); } if (array[entry].heap != -1) { fprintf(stderr, "heap offset is wrong %d\n", entry); fr_exit(1); } } } left = fr_heap_num_elements(hp); printf("%d elements left in the heap\n", left); for (i = 0; i < left; i++) { heap_thing *t = fr_heap_peek(hp); if (!t) { fprintf(stderr, "Failed peeking %d\n", i); fr_exit(1); } printf("%d\t%d\n", i, t->data); if (!fr_heap_extract(hp, NULL)) { fprintf(stderr, "Failed extracting %d\n", i); fr_exit(1); } } if (fr_heap_num_elements(hp) > 0) { fprintf(stderr, "%d elements left at the end", fr_heap_num_elements(hp)); fr_exit(1); } fr_heap_delete(hp); return 0; }
/** Handle replies after all FD and timer events have been serviced * * @param el the event loop * @param now the current time (mostly) * @param uctx the fr_network_t */ static void fr_network_post_event(UNUSED fr_event_list_t *el, UNUSED struct timeval *now, void *uctx) { fr_channel_data_t *cd; fr_network_t *nr = talloc_get_type_abort(uctx, fr_network_t); while ((cd = fr_heap_pop(nr->replies)) != NULL) { ssize_t rcode; fr_listen_t const *listen; fr_message_t *lm; fr_network_socket_t my_socket, *s; listen = cd->listen; /* * @todo - cache this somewhere so we don't need * to do an rbtree lookup for every packet. */ my_socket.listen = listen; s = rbtree_finddata(nr->sockets, &my_socket); /* * This shouldn't happen, but be safe... */ if (!s) { fr_message_done(&cd->m); continue; } rad_assert(s->outstanding > 0); s->outstanding--; /* * Just mark the message done, and skip it. */ if (s->dead) { fr_message_done(&cd->m); /* * No more packets, it's safe to delete * the socket. */ if (!s->outstanding) { talloc_free(s); } continue; } /* * No data to write to the socket, so we skip it. */ if (!cd->m.data_size) { fr_message_done(&cd->m); continue; } /* * There are queued entries for this socket. * Append the packet into the list of packets to * write. * * For sanity, we localize the message first. * Doing so ensures that the worker has it's * message buffers cleaned up quickly. */ if (s->pending) { lm = fr_message_localize(s, &cd->m, sizeof(*cd)); fr_message_done(&cd->m); if (!lm) { ERROR("Failed copying packet. Discarding it."); continue; } cd = (fr_channel_data_t *) lm; (void) fr_heap_insert(s->waiting, cd); continue; } /* * The write function is responsible for ensuring * that NAKs are not written to the network. */ rcode = listen->app_io->write(listen->app_io_instance, cd->packet_ctx, cd->reply.request_time, cd->m.data, cd->m.data_size, 0); if (rcode < 0) { s->pending = 0; if (errno == EWOULDBLOCK) { save_pending: if (fr_event_fd_insert(nr, nr->el, s->fd, fr_network_read, fr_network_write, fr_network_error, s) < 0) { PERROR("Failed adding write callback to event loop"); goto error; } /* * Localize the message, and add * it as the current pending / * partially written packet. */ lm = fr_message_localize(s, &cd->m, sizeof(*cd)); fr_message_done(&cd->m); if (!lm) { ERROR("Failed copying packet. Discarding it."); continue; } cd = (fr_channel_data_t *) lm; s->pending = cd; continue; } /* * Tell the socket that there was an error. * * Don't call close, as that will be done * in the destructor. */ PERROR("Failed writing to socket %d", s->fd); error: fr_message_done(&cd->m); if (listen->app_io->error) listen->app_io->error(listen->app_io_instance); fr_network_socket_dead(nr, s); continue; } /* * If there's a partial write, save the write * callback for later. */ if ((rcode > 0) && ((size_t) rcode < cd->m.data_size)) { s->written = rcode; goto save_pending; } DEBUG3("Sending reply to socket %d", s->fd); fr_message_done(&cd->m); s->pending = NULL; s->written = 0; /* * As a special case, allow write() to return * "0", which means "close the socket". */ if (rcode == 0) fr_network_socket_dead(nr, s); } }