-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathlstack.c
65 lines (59 loc) · 1.82 KB
/
lstack.c
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
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdlib.h>
#include <errno.h>
#include "lstack.h"
int lstack_init(lstack_t *lstack, size_t max_size)
{
struct lstack_head head_init = {0, NULL};
lstack->head = ATOMIC_VAR_INIT(head_init);
lstack->size = ATOMIC_VAR_INIT(0);
/* Pre-allocate all nodes. */
lstack->node_buffer = malloc(max_size * sizeof(struct lstack_node));
if (lstack->node_buffer == NULL)
return ENOMEM;
for (size_t i = 0; i < max_size - 1; i++)
lstack->node_buffer[i].next = lstack->node_buffer + i + 1;
lstack->node_buffer[max_size - 1].next = NULL;
struct lstack_head free_init = {0, lstack->node_buffer};
lstack->free = ATOMIC_VAR_INIT(free_init);
return 0;
}
static struct lstack_node *pop(_Atomic struct lstack_head *head)
{
struct lstack_head next, orig = atomic_load(head);
do {
if (orig.node == NULL)
return NULL;
next.aba = orig.aba + 1;
next.node = orig.node->next;
} while (!atomic_compare_exchange_weak(head, &orig, next));
return orig.node;
}
static void push(_Atomic struct lstack_head *head, struct lstack_node *node)
{
struct lstack_head next, orig = atomic_load(head);
do {
node->next = orig.node;
next.aba = orig.aba + 1;
next.node = node;
} while (!atomic_compare_exchange_weak(head, &orig, next));
}
int lstack_push(lstack_t *lstack, void *value)
{
struct lstack_node *node = pop(&lstack->free);
if (node == NULL)
return ENOMEM;
node->value = value;
push(&lstack->head, node);
atomic_fetch_add(&lstack->size, 1);
return 0;
}
void *lstack_pop(lstack_t *lstack)
{
struct lstack_node *node = pop(&lstack->head);
if (node == NULL)
return NULL;
atomic_fetch_sub(&lstack->size, 1);
void *value = node->value;
push(&lstack->free, node);
return value;
}