parlib: Use a relative timer for abort_sysc
[akaros.git] / user / parlib / dtls.c
index 157517d..ea0e74c 100644 (file)
@@ -34,7 +34,7 @@ struct dtls_key {
 struct dtls_value {
        TAILQ_ENTRY(dtls_value) link;
        struct dtls_key *key;
-       void *dtls;
+       const void *dtls;
 };
 TAILQ_HEAD(dtls_list, dtls_value);
 
@@ -71,12 +71,12 @@ int dtls_cache_init(void)
        /* Initialize the global cache of dtls_keys */
        __dtls_keys_cache =
            kmem_cache_create("dtls_keys_cache", sizeof(struct dtls_key),
-                             __alignof__(struct dtls_key), 0, NULL, NULL);
+                             __alignof__(struct dtls_key), 0, NULL, NULL, NULL);
 
        /* Initialize the global cache of dtls_values */
        __dtls_values_cache =
            kmem_cache_create("dtls_values_cache", sizeof(struct dtls_value),
-                             __alignof__(struct dtls_value), 0, NULL, NULL);
+                             __alignof__(struct dtls_value), 0, NULL, NULL, NULL);
 
        return 0;
 }
@@ -142,7 +142,8 @@ void dtls_key_delete(dtls_key_t key)
        __maybe_free_dtls_key(key);
 }
 
-static inline void *__get_dtls(dtls_data_t *dtls_data, dtls_key_t key)
+static inline struct dtls_value *__get_dtls(dtls_data_t *dtls_data,
+                                            dtls_key_t key)
 {
        struct dtls_value *v;
 
@@ -150,17 +151,17 @@ static inline void *__get_dtls(dtls_data_t *dtls_data, dtls_key_t key)
        if (key->id < NUM_STATIC_KEYS) {
                v = &dtls_data->early_values[key->id];
                if (v->key != NULL)
-                       return v->dtls;
+                       return v;
        } else {
                TAILQ_FOREACH(v, &dtls_data->list, link)
                        if (v->key == key)
-                               return v->dtls;
+                               return v;
        }
        return NULL;
 }
 
 static inline void __set_dtls(dtls_data_t *dtls_data, dtls_key_t key,
-                              void *dtls)
+                              const void *dtls)
 {
        struct dtls_value *v;
 
@@ -179,7 +180,7 @@ static inline void __destroy_dtls(dtls_data_t *dtls_data)
 {
        struct dtls_value *v, *n;
        dtls_key_t key;
-       void *dtls;
+       const void *dtls;
 
        v = TAILQ_FIRST(&dtls_data->list);
        while (v != NULL) {
@@ -196,18 +197,23 @@ static inline void __destroy_dtls(dtls_data_t *dtls_data)
                if (key->valid && key->dtor) {
                        dtls = v->dtls;
                        v->dtls = NULL;
-                       key->dtor(dtls);
+                       key->dtor((void*)dtls);
                }
-               __maybe_free_dtls_key(key);
-
                n = TAILQ_NEXT(v, link);
                TAILQ_REMOVE(&dtls_data->list, v, link);
+               /* Free both the key (which is v->key) and v *after* removing v from the
+                * list.  It's possible that free() will call back into the DTLS (e.g.
+                * pthread_getspecific()), and v must be off the list by then.
+                *
+                * For a similar, hilarious bug in glibc, check out:
+                * https://sourceware.org/bugzilla/show_bug.cgi?id=3317 */
+               __maybe_free_dtls_key(key);
                __free_dtls_value(v);
                v = n;
        }
 }
 
-void set_dtls(dtls_key_t key, void *dtls)
+void set_dtls(dtls_key_t key, const void *dtls)
 {
        bool initialized = true;
        dtls_data_t *dtls_data = NULL;
@@ -225,11 +231,13 @@ void set_dtls(dtls_key_t key, void *dtls)
 void *get_dtls(dtls_key_t key)
 {
        dtls_data_t *dtls_data = NULL;
+       struct dtls_value *v;
 
        if (!__dtls_initialized)
                return NULL;
        dtls_data = &__dtls_data;
-       return __get_dtls(dtls_data, key);
+       v = __get_dtls(dtls_data, key);
+       return v ? (void*)v->dtls : NULL;
 }
 
 void destroy_dtls(void)