aboutsummaryrefslogtreecommitdiffstats
path: root/libaxl_generate_id.c
blob: 91b5aa67c7d338e27c55a76a1bf698e214cfd414 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* See LICENSE file for copyright and license details. */
#include "common.h"

libaxl_id_t
libaxl_generate_id(LIBAXL_CONTEXT *ctx)
{
	LIBAXL_CONNECTION *conn = ctx->conn;
	struct id_pool *pool = NULL, *next, *last;
	uint32_t id;

	pool = atomic_exchange(&conn->xid_pool, pool);
	if (pool) {
		id = pool->first;
		pool->first += (uint32_t)1 << conn->xid_shift;
		if (id == pool->last) {
			next = pool->next;
			if (next) {
				free(pool);
				pool = next;
			}
			next = NULL;
			if (atomic_compare_exchange_strong(&conn->xid_pool, &next, pool))
				return id;
			if (!pool->next) {
				free(pool);
				return id;
			}
		}
		while ((pool = atomic_exchange(&conn->xid_pool, pool))) {
			for (last = pool; last->next; last = last->next);
			last->next = atomic_exchange(&conn->xid_pool, NULL);
		}
		return id;
	}

	id = atomic_fetch_add(&conn->xid_last, 1);
	if (id <= conn->xid_max)
		return (id << conn->xid_shift) | conn->xid_base;

	atomic_fetch_sub(&conn->xid_last, 1);

	liberror_save_backtrace(NULL);
	liberror_set_error("Request has been buffered and is ready to be sent",
	                   "libaxl_generate_id", "libaxl", LIBAXL_ERROR_OUT_OF_RESOURCE_IDS);
	return 0;
}