aboutsummaryrefslogtreecommitdiffstats
path: root/libaxl_deallocate_id.c
blob: 0a27de0ad0dced6c59094b439bbedd342ce320ab (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
47
48
49
50
51
52
/* See LICENSE file for copyright and license details. */
#include "common.h"

int
libaxl_deallocate_id(LIBAXL_CONTEXT *ctx, libaxl_id_t id)
{
	LIBAXL_CONNECTION *conn = ctx->conn;
	struct id_pool *pool = NULL, *node;
	uint32_t inc = (uint32_t)1 << conn->xid_shift;
	int ret = 0;

	pool = atomic_exchange(&conn->xid_pool, pool);
	if (pool) {
		for (node = pool;; node = node->next) {
			if (id + inc == node->first) {
				node->first = id;
				goto out;
			} else if (node->last + inc == id) {
				node->last = id;
				goto out;
			}
			if (!node->next)
				break;
		}
		node->next = liberror_malloc(sizeof(*node->next));
		if (node->next) {
			node->next->first = id;
			node->next->last = id;
			atomic_init(&node->next->next, NULL);
		} else {
			ret = -1;
		}
	} else {
		pool = liberror_malloc(sizeof(*pool));
		if (pool) {
			pool->first = id;
			pool->last = id;
			atomic_init(&pool->next, NULL);
		} else {
			ret = -1;
		}
	}

out:
	while ((pool = atomic_exchange(&conn->xid_pool, pool))) {
		for (node = pool; node->next; node = node->next);
		node->next = atomic_exchange(&conn->xid_pool, NULL);
	}

	return ret;
}