示例#1
0
/** Pop control-plane message
 *
 *  This function is called ONLY from the receiving thread.
 *
 * @param[in] aq the recipients atomic queue for control-plane messages
 * @param[out] p_id the ident of this message.
 * @param[in,out] data where the data is stored
 * @param[in] data_size the size of the buffer where we store the data.
 * @return
 *	- <0 the size of the data we need to read the next message
 *	- 0 this kevent is not for us.
 *	- >0 the amount of data we've read
 */
ssize_t fr_control_message_pop(fr_atomic_queue_t *aq, uint32_t *p_id, void *data, size_t data_size)
{
	uint8_t *p;
	fr_control_message_t *m;

	MPRINT("CONTROL pop aq %p\n", aq);

	if (!fr_atomic_queue_pop(aq, (void **) &m)) return 0;

	rad_assert(m->status == FR_CONTROL_MESSAGE_USED);

	/*
	 *	There isn't enough room to store the data, die.
	 */
	if (data_size < m->data_size) {
		fr_strerror_printf("Allocation size should be at least %zd", m->data_size);
		return -(m->data_size);
	}

	p = (uint8_t *) m;
	data_size = m->data_size;
	memcpy(data, p + sizeof(*m), data_size);

	m->status = FR_CONTROL_MESSAGE_DONE;
	*p_id = m->id;
	return data_size;
}
int main(int argc, char *argv[])
{
	int			c, i, rcode = 0;
	int			size;
	intptr_t		val;
	void			*data;
	fr_atomic_queue_t	*aq;
	TALLOC_CTX		*autofree = talloc_autofree_context();

	size = 4;

	while ((c = getopt(argc, argv, "hs:tx")) != EOF) switch (c) {
		case 's':
			size = atoi(optarg);
			break;

		case 'x':
			debug_lvl++;
			break;

		case 'h':
		default:
			usage();
	}
#if 0
	argc -= (optind - 1);
	argv += (optind - 1);
#endif

	aq = fr_atomic_queue_create(autofree, size);

#ifndef NDEBUG
	if (debug_lvl) {
		printf("Start\n");
		fr_atomic_queue_debug(aq, stdout);

		if (debug_lvl > 1) printf("Filling with %d\n", size);
	}

#endif


	for (i = 0; i < size; i++) {
		val = i + OFFSET;
		data = (void *) val;

		if (!fr_atomic_queue_push(aq, data)) {
			fprintf(stderr, "Failed pushing at %d\n", i);
			exit(EXIT_FAILURE);
		}

#ifndef NDEBUG
		if (debug_lvl > 1) {
			printf("iteration %d\n", i);
			fr_atomic_queue_debug(aq, stdout);
		}
#endif
	}

	val = size + OFFSET;
	data = (void *) val;

	/*
	 *	Queue is full.  No more pushes are allowed.
	 */
	if (fr_atomic_queue_push(aq, data)) {
		fprintf(stderr, "Pushed an entry past the end of the queue.");
		exit(EXIT_FAILURE);
	}

#ifndef NDEBUG
	if (debug_lvl) {
		printf("Full\n");
		fr_atomic_queue_debug(aq, stdout);

		if (debug_lvl > 1) printf("Emptying\n");
	}
#endif

	/*
	 *	And now pop them all.
	 */
	for (i = 0; i < size; i++) {
		if (!fr_atomic_queue_pop(aq, &data)) {
			fprintf(stderr, "Failed popping at %d\n", i);
			exit(EXIT_FAILURE);
		}

		val = (intptr_t) data;
		if (val != (i + OFFSET)) {
			fprintf(stderr, "Pop expected %d, got %d\n",
				i + OFFSET, (int) val);
			exit(EXIT_FAILURE);
		}

#ifndef NDEBUG
		if (debug_lvl > 1) {
			printf("iteration %d\n", i);
			fr_atomic_queue_debug(aq, stdout);
		}
#endif
	}

	/*
	 *	Queue is empty.  No more pops are allowed.
	 */
	if (fr_atomic_queue_pop(aq, &data)) {
		fprintf(stderr, "Popped an entry past the end of the queue.");
		exit(EXIT_FAILURE);
	}

#ifndef NDEBUG
	if (debug_lvl) {
		printf("Empty\n");
		fr_atomic_queue_debug(aq, stdout);
	}
#endif

	return rcode;
}