Changeset 14c6c08


Ignore:
Timestamp:
03/27/15 16:16:33 (6 years ago)
Author:
Richard Sanger <rsangerarj@…>
Branches:
4.0.1-hotfixes, cachetimestamps, develop, dpdk-ndag, etsilive, libtrace4, master, ndag_format, pfring, rc-4.0.1, rc-4.0.2, rc-4.0.3, rc-4.0.4, ringdecrementfix, ringperformance, ringtimestampfixes
Children:
915b93c
Parents:
f50515e
Message:

Fix libtrace_ocache to work correctly on Mac.

Apple's implementation of pthreads_once destructor seems to occur
after thread storage is destroyed (or zeroed). This rewrite fixes
that by only using
thread storage as a means for quick access and
malloc()ing the storage.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/data-struct/object_cache.c

    r6a6e6a8 r14c6c08  
    88// pthread tls is most likely slower than __thread, but they have destructors so
    99// we use a combination of the two here!!
     10// Note Apples implementation of TLS means that memory is not available / has
     11// been zeroed by the time the pthread destructor is called.
    1012struct local_cache {
    1113        libtrace_ocache_t *oc;
     
    2628
    2729extern __thread struct mem_stats mem_hits;
    28 static __thread size_t t_mem_caches_used = 0;
    29 static __thread size_t t_mem_caches_total = 0;
    30 static __thread struct local_cache *t_mem_caches = NULL;
     30
     31struct local_caches {
     32        size_t t_mem_caches_used;
     33        size_t t_mem_caches_total;
     34        struct local_cache *t_mem_caches;
     35};
     36
    3137static pthread_key_t memory_destructor_key;
    3238static pthread_once_t memory_destructor_once = PTHREAD_ONCE_INIT;
     39static inline struct local_caches *get_local_caches();
    3340
    3441/**
     
    5158        }
    5259        if (i != ~0U) {
    53                 fprintf(stderr, "Umm this wasn't registered with us in the first place!!!!IGNORGING!!!!ANGRY\n");
     60                fprintf(stderr, "Attempted to unregistered a thread with an"
     61                         " ocache that had never registered this thread. Ignoring.\n");
    5462                pthread_spin_unlock(&lc->oc->spin);
    5563                return;
     
    8492}
    8593
    86 static void destroy_memory_cache(void *tlsaddr) {
    87         assert(tlsaddr == t_mem_caches);
     94static void destroy_memory_caches(void *tlsaddr) {
    8895        size_t a;
    89 
    90         for (a = 0; a < t_mem_caches_used; ++a) {
    91                 unregister_thread(&t_mem_caches[a]);
     96        struct local_caches *lcs = tlsaddr;
     97
     98        for (a = 0; a < lcs->t_mem_caches_used; ++a) {
     99                unregister_thread(&lcs->t_mem_caches[a]);
    92100                // Write these all back to the main buffer, this might have issues we would want to free these
    93                 free(t_mem_caches[a].cache);
    94         }
    95         free(t_mem_caches);
    96         t_mem_caches = NULL;
     101                free(lcs->t_mem_caches[a].cache);
     102        }
     103        free(lcs->t_mem_caches);
     104        lcs->t_mem_caches = NULL;
     105        free(lcs);
     106
    97107}
    98108
    99109static void once_memory_cache_key_init() {
    100         ASSERT_RET(pthread_key_create(&memory_destructor_key, &destroy_memory_cache), == 0);
     110        ASSERT_RET(pthread_key_create(&memory_destructor_key, &destroy_memory_caches), == 0);
    101111}
    102112
     
    104114 * Adds more space to our mem_caches
    105115 */
    106 static void resize_memory_caches() {
    107         if (t_mem_caches == NULL) {
     116static void resize_memory_caches(struct local_caches *lcs) {
     117        assert (lcs->t_mem_caches_total > 0);
     118        lcs->t_mem_caches += 0x10;
     119        lcs->t_mem_caches = realloc(lcs->t_mem_caches,
     120                                    lcs->t_mem_caches_total * sizeof(struct local_cache));
     121}
     122
     123/* Get TLS for the list of local_caches */
     124static inline struct local_caches *get_local_caches() {
     125        static __thread struct local_caches *lcs = NULL;
     126        if (lcs) {
     127                return lcs;
     128        } else {
     129                /* This thread has not been used with a memory pool before */
     130                /* Allocate our TLS */
     131                assert(lcs == NULL);
     132                lcs = calloc(1, sizeof (struct local_caches));
     133                assert(lcs);
     134                /* Hook into pthreads to destroy this when the thread ends */
    108135                pthread_once(&memory_destructor_once, &once_memory_cache_key_init);
    109                 t_mem_caches_total = 0x10;
    110                 t_mem_caches = calloc(0x10, sizeof(struct local_cache));
    111                 pthread_setspecific(memory_destructor_key, (void *) t_mem_caches);
    112         } else {
    113                 t_mem_caches += 0x10;
    114                 t_mem_caches = realloc(t_mem_caches, t_mem_caches_total * sizeof(struct local_cache));
    115                 pthread_setspecific(memory_destructor_key, t_mem_caches);
     136                pthread_setspecific(memory_destructor_key, (void *) lcs);
     137                lcs->t_mem_caches_total = 0x10;
     138                lcs->t_mem_caches = calloc(0x10, sizeof(struct local_cache));
     139                assert(lcs);
     140                assert(lcs->t_mem_caches);
     141                return lcs;
    116142        }
    117143}
    118144
    119145static inline struct local_cache * find_cache(libtrace_ocache_t *oc) {
     146        size_t i;
    120147        struct local_cache *lc = NULL;
    121         size_t i;
    122 
    123         for (i = 0; i < t_mem_caches_used; ++i) {
    124                 if (t_mem_caches[i].oc == oc) {
    125                         lc = &t_mem_caches[i];
     148        struct local_caches *lcs = get_local_caches();
     149
     150        for (i = 0; i < lcs->t_mem_caches_used; ++i) {
     151                if (lcs->t_mem_caches[i].oc == oc) {
     152                        lc = &lcs->t_mem_caches[i];
    126153                        break;
    127154                }
     
    133160        // Create a cache
    134161        if (!lc) {
    135                 if (t_mem_caches_used == t_mem_caches_total)
    136                         resize_memory_caches();
    137                 t_mem_caches[t_mem_caches_used].oc = oc;
    138                 t_mem_caches[t_mem_caches_used].used = 0;
    139                 t_mem_caches[t_mem_caches_used].total = oc->thread_cache_size;
    140                 t_mem_caches[t_mem_caches_used].cache = malloc(sizeof(void*) * oc->thread_cache_size);
    141                 t_mem_caches[t_mem_caches_used].invalid = false;
    142                 lc = &t_mem_caches[t_mem_caches_used];
     162                if (lcs->t_mem_caches_used == lcs->t_mem_caches_total)
     163                        resize_memory_caches(lcs);
     164                lcs->t_mem_caches[lcs->t_mem_caches_used].oc = oc;
     165                lcs->t_mem_caches[lcs->t_mem_caches_used].used = 0;
     166                lcs->t_mem_caches[lcs->t_mem_caches_used].total = oc->thread_cache_size;
     167                lcs->t_mem_caches[lcs->t_mem_caches_used].cache = malloc(sizeof(void*) * oc->thread_cache_size);
     168                lcs->t_mem_caches[lcs->t_mem_caches_used].invalid = false;
     169                lc = &lcs->t_mem_caches[lcs->t_mem_caches_used];
    143170                // Register it with the underlying ring_buffer
    144171                register_thread(lc->oc, lc);
    145                 ++t_mem_caches_used;
     172                ++lcs->t_mem_caches_used;
    146173        }
    147174
     
    438465DLLEXPORT void libtrace_ocache_unregister_thread(libtrace_ocache_t *oc) {
    439466        size_t i;
     467        struct local_caches *lcs = get_local_caches();
    440468        struct local_cache *lc = find_cache(oc);
    441469
    442470        if (lc) {
    443                 for (i = 0; i < t_mem_caches_used; ++i) {
    444                         if (&t_mem_caches[i] == lc) {
     471                for (i = 0; i < lcs->t_mem_caches_used; ++i) {
     472                        if (&lcs->t_mem_caches[i] == lc) {
    445473                                // Free the cache against the ocache
    446                                 unregister_thread(&t_mem_caches[i]);
    447                                 free(t_mem_caches[i].cache);
     474                                unregister_thread(&lcs->t_mem_caches[i]);
     475                                free(lcs->t_mem_caches[i].cache);
    448476                                // And remove it from the thread itself
    449                                 --t_mem_caches_used;
    450                                 t_mem_caches[i] = t_mem_caches[t_mem_caches_used];
    451                                 memset(&t_mem_caches[t_mem_caches_used], 0, sizeof(struct local_cache));
     477                                --lcs->t_mem_caches_used;
     478                                lcs->t_mem_caches[i] = lcs->t_mem_caches[lcs->t_mem_caches_used];
     479                                memset(&lcs->t_mem_caches[lcs->t_mem_caches_used], 0, sizeof(struct local_cache));
    452480                        }
    453481                }
Note: See TracChangeset for help on using the changeset viewer.