X-Git-Url: https://pd.if.org/git/?p=nbds;a=blobdiff_plain;f=runtime%2Fhazard.c;fp=runtime%2Fhazard.c;h=72ed0c12c609d4de0f04854948fdf81c7d59e3ff;hp=0000000000000000000000000000000000000000;hb=a03cf3b0c40e6c3b8b4877b49a64288cb3fcb919;hpb=e592519ef19f890e551c27f47ef8b773bb4860da diff --git a/runtime/hazard.c b/runtime/hazard.c new file mode 100644 index 0000000..72ed0c1 --- /dev/null +++ b/runtime/hazard.c @@ -0,0 +1,164 @@ +/* + * Written by Josh Dybnis and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + * + * hazard pointers + * + * www.research.ibm.com/people/m/michael/ieeetpds-2004.pdf + * + */ +#include "common.h" +#include "lwt.h" +#include "mem.h" +#include "tls.h" +#include "runtime.h" +#include "hazard.h" + +typedef struct pending { + void * ptr; + free_t free_; +} pending_t; + +typedef struct haz_local { + pending_t *pending; // to be freed + int pending_size; + int pending_count; + + haz_t static_haz[STATIC_HAZ_PER_THREAD]; + + haz_t **dynamic; + int dynamic_size; + int dynamic_count; + +} haz_local_t; + +static haz_local_t haz_local_[MAX_NUM_THREADS] = {}; + +static void sort_hazards (haz_t *hazards, int n) { + return; +} + +static int search_hazards (void *p, haz_t *hazards, int n) { + for (int i = 0; i < n; ++i) { + if (hazards[i] == p) + return TRUE; + } + return FALSE; +} + +static void resize_pending (void) { + LOCALIZE_THREAD_LOCAL(tid_, int); + haz_local_t *l = haz_local_ + tid_; + pending_t *p = nbd_malloc(sizeof(pending_t) * l->pending_size * 2); + memcpy(p, l->pending, l->pending_size); + nbd_free(l->pending); + l->pending = p; + l->pending_size *= 2; +} + +void haz_defer_free (void *d, free_t f) { + assert(d); + assert(f); + LOCALIZE_THREAD_LOCAL(tid_, int); + haz_local_t *l = haz_local_ + tid_; + while (l->pending_count == l->pending_size) { + + if (l->pending_size == 0) { + l->pending_size = MAX_NUM_THREADS * STATIC_HAZ_PER_THREAD; + l->pending = nbd_malloc(sizeof(pending_t) * l->pending_size); + break; + } + + // scan for hazard pointers + haz_t *hazards = nbd_malloc(sizeof(haz_t) * l->pending_size); + int hazard_count = 0; + for (int i = 0; i < MAX_NUM_THREADS; ++i) { + haz_local_t *h = haz_local_ + i; + for (int j = 0; j < STATIC_HAZ_PER_THREAD; ++j) { + if (h->static_haz[j] != NULL) { + if (hazard_count == l->pending_size) { + resize_pending(); + nbd_free(hazards); + haz_defer_free(d, f); + return; + } + hazards[hazard_count++] = h->static_haz[j]; + } + } + for (int j = 0; j < h->dynamic_count; ++j) { + if (h->dynamic[j] != NULL && *h->dynamic[j] != NULL) { + if (hazard_count == l->pending_size) { + resize_pending(); + nbd_free(hazards); + haz_defer_free(d, f); + return; + } + hazards[hazard_count++] = *h->dynamic[j]; + } + } + } + sort_hazards(hazards, hazard_count); + + // check for conflicts + int conflicts_count = 0; + for (int i = 0; i < l->pending_count; ++i) { + pending_t *p = l->pending + i; + if (search_hazards(p->ptr, hazards, hazard_count)) { + l->pending[conflicts_count++] = *p; // put conflicts back on the pending list + } else { + assert(p->free_); + assert(p->ptr); + p->free_(p->ptr); // free pending item + } + } + l->pending_count = conflicts_count; + nbd_free(hazards); + } + l->pending[ l->pending_count ].ptr = d; + l->pending[ l->pending_count ].free_ = f; + l->pending_count++; +} + +haz_t *haz_get_static (int i) { + if (i >= STATIC_HAZ_PER_THREAD) + return NULL; + LOCALIZE_THREAD_LOCAL(tid_, int); + return &haz_local_[tid_].static_haz[i]; +} + +void haz_register_dynamic (haz_t *haz) { + LOCALIZE_THREAD_LOCAL(tid_, int); + haz_local_t *l = haz_local_ + tid_; + + if (l->dynamic_size == 0) { + l->dynamic_size = MAX_NUM_THREADS * STATIC_HAZ_PER_THREAD; + l->dynamic = nbd_malloc(sizeof(haz_t *) * l->dynamic_size); + } + + if (l->dynamic_count == l->dynamic_size) { + haz_t **d = nbd_malloc(sizeof(haz_t *) * l->dynamic_size * 2); + memcpy(d, l->dynamic, l->dynamic_size); + nbd_free(l->dynamic); + l->dynamic = d; + l->dynamic_size *= 2; + } + + l->dynamic[ l->dynamic_count++ ] = haz; +} + +// assumes was registered in the same thread +void haz_unregister_dynamic (void **haz) { + LOCALIZE_THREAD_LOCAL(tid_, int); + haz_local_t *l = haz_local_ + tid_; + + for (int i = 0; i < l->dynamic_count; ++i) { + if (l->dynamic[i] == haz) { + if (i != l->dynamic_count - 1) { + l->dynamic[i] = l->dynamic[ l->dynamic_count ]; + } + l->dynamic_count--; + return; + } + } + assert(0); +}