1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
13 #include "platform_defs.h"
17 * Per-thread Variables
19 * This data structure manages a lockless per-thread variable. We
20 * implement this by allocating an array of memory regions, and as each
21 * thread tries to acquire its own region, we hand out the array
22 * elements to each thread. This way, each thread gets its own
23 * cacheline and (after the first access) doesn't have to contend for a
24 * lock for each access.
32 unsigned char data
[0];
34 #define PTVAR_SIZE(nr, sz) (sizeof(struct ptvar) + ((nr) * (size)))
36 /* Initialize per-thread counter. */
45 #ifdef _SC_LEVEL1_DCACHE_LINESIZE
46 /* Try to prevent cache pingpong by aligning to cacheline size. */
47 size
= max(size
, sysconf(_SC_LEVEL1_DCACHE_LINESIZE
));
50 ptv
= malloc(PTVAR_SIZE(nr
, size
));
53 ptv
->data_size
= size
;
54 ptv
->nr_counters
= nr
;
56 memset(ptv
->data
, 0, nr
* size
);
57 ret
= pthread_mutex_init(&ptv
->lock
, NULL
);
60 ret
= pthread_key_create(&ptv
->key
, NULL
);
66 pthread_mutex_destroy(&ptv
->lock
);
72 /* Free per-thread counter. */
77 pthread_key_delete(ptv
->key
);
78 pthread_mutex_destroy(&ptv
->lock
);
82 /* Get a reference to this thread's variable. */
89 p
= pthread_getspecific(ptv
->key
);
91 pthread_mutex_lock(&ptv
->lock
);
92 assert(ptv
->nr_used
< ptv
->nr_counters
);
93 p
= &ptv
->data
[(ptv
->nr_used
++) * ptv
->data_size
];
94 pthread_setspecific(ptv
->key
, p
);
95 pthread_mutex_unlock(&ptv
->lock
);
100 /* Iterate all of the per-thread variables. */
110 pthread_mutex_lock(&ptv
->lock
);
111 for (i
= 0; i
< ptv
->nr_used
; i
++) {
112 ret
= fn(ptv
, &ptv
->data
[i
* ptv
->data_size
], foreach_arg
);
116 pthread_mutex_unlock(&ptv
->lock
);