blob: 1071834b17d8997b12922a55d754ec2a2765ccbf [file] [log] [blame]
/* Copyright (c) 2014 The Regents of the University of California
* Kevin Klues <klueska@cs.berkeley.edu>
* Andrew Waterman <waterman@cs.berkeley.edu>
* See LICENSE for details.
*/
#include <parlib/assert.h>
#include <stdlib.h>
#include <parlib/arch/atomic.h>
#include <parlib/waitfreelist.h>
void wfl_init(struct wfl *list)
{
list->first.next = NULL;
list->first.data = NULL;
list->head = &list->first;
}
void wfl_destroy(struct wfl *list)
{
assert(list->first.data == NULL);
struct wfl_entry *p = list->first.next; // don't free the first element
while (p != NULL) {
assert(p->data == NULL);
struct wfl_entry *tmp = p;
p = p->next;
free(tmp);
}
}
size_t wfl_capacity(struct wfl *list)
{
size_t res = 0;
for (struct wfl_entry *p = list->head; p != NULL; p = p->next)
res++;
return res;
}
size_t wfl_size(struct wfl *list)
{
size_t res = 0;
for (struct wfl_entry *p = list->head; p != NULL; p = p->next)
res += p->data != NULL;
return res;
}
#if 0
void wfl_insert(struct wfl *list, void *data)
{
retry:
struct wfl_entry *p = list->head; // list head is never null
struct wfl_entry *new_entry = NULL;
while (1) {
if (p->data == NULL) {
if (__sync_bool_compare_and_swap(&p->data, NULL, data)) {
free(new_entry);
return;
}
}
if (p->next != NULL) {
p = p->next;
continue;
}
if (new_entry == NULL) {
new_entry = malloc(sizeof(struct wfl_entry));
if (new_entry == NULL)
abort();
new_entry->data = data;
new_entry->next = NULL;
wmb();
}
if (__sync_bool_compare_and_swap(&p->next, NULL, new_entry))
return;
goto retry;
p = list->head;
}
}
#endif
void wfl_insert(struct wfl *list, void *data)
{
struct wfl_entry *p = list->head; // list head is never null
while (1) {
if (p->data == NULL) {
if (__sync_bool_compare_and_swap(&p->data, NULL, data))
return;
}
if (p->next == NULL)
break;
p = p->next;
}
struct wfl_entry *new_entry = malloc(sizeof(struct wfl_entry));
if (new_entry == NULL)
abort();
new_entry->data = data;
new_entry->next = NULL;
wmb();
struct wfl_entry *next;
while ((next = __sync_val_compare_and_swap(&p->next, NULL, new_entry)))
p = next;
}
void *wfl_remove(struct wfl *list)
{
for (struct wfl_entry *p = list->head; p != NULL; p = p->next) {
if (p->data != NULL) {
void *data = atomic_swap_ptr(&p->data, 0);
if (data != NULL)
return data;
}
}
return NULL;
}
size_t wfl_remove_all(struct wfl *list, void *data)
{
size_t n = 0;
for (struct wfl_entry *p = list->head; p != NULL; p = p->next) {
if (p->data == data)
n += __sync_bool_compare_and_swap(&p->data, data, NULL);
}
return n;
}