|  | /* 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; | 
|  | } |