Пример #1
0
/** 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);
}
Пример #2
0
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;
}
Пример #3
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;
}
Пример #4
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);
	}
}